From abf04e7ea356e8b1523e4183d5c46c0462f1f605 Mon Sep 17 00:00:00 2001 From: Emoly Liu Date: Tue, 16 Mar 2021 11:04:46 +0800 Subject: [PATCH] LU-14337 lov: return valid stripe_count/size for PFL files Dump struct lov_comp_md_v1 in function ll_lov_getstripe_ea_info() correctly to avoid stripe_count=0 or stripe_size=0 returned by old interface llapi_file_get_stripe(), which will cause divide-by-zero for older userspace that calls this ioctl, e.g. lustre ADIO driver. The rule is: - if stripe_count=0, return stripe_count=1; - if stripe_size=0, -- for DoM files, return the stripe size of the second component, since the first component of DoM file data is placed on the MDT for faster access; -- else, return the stripe size of the last component. Also, lov_getstripe_old.c and santy-pfl.sh test_25 is added to verify this patch. Test-parameters: testlist=sanity-pfl env=ONLY=25 Signed-off-by: Emoly Liu Change-Id: I4023ca4baff1b1ad2a439aa497baaabc56e891d2 Reviewed-on: https://review.whamcloud.com/41803 Tested-by: jenkins Reviewed-by: Andreas Dilger Reviewed-by: Bobi Jam Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/llite/file.c | 126 ++++++++++++++++++++++++++------------- lustre/lov/lov_pack.c | 7 --- lustre/tests/Makefile.am | 3 +- lustre/tests/lov_getstripe_old.c | 95 +++++++++++++++++++++++++++++ lustre/tests/sanity-pfl.sh | 47 +++++++++++++++ 5 files changed, 230 insertions(+), 48 deletions(-) create mode 100644 lustre/tests/lov_getstripe_old.c diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 5791569..76350c0 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -2149,44 +2149,45 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename, struct lov_mds_md **lmmp, int *lmm_size, struct ptlrpc_request **request) { - struct ll_sb_info *sbi = ll_i2sbi(inode); - struct mdt_body *body; - struct lov_mds_md *lmm = NULL; - struct ptlrpc_request *req = NULL; - struct md_op_data *op_data; - int rc, lmmsize; + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct mdt_body *body; + struct lov_mds_md *lmm = NULL; + struct ptlrpc_request *req = NULL; + struct md_op_data *op_data; + int rc, lmmsize; + + ENTRY; rc = ll_get_default_mdsize(sbi, &lmmsize); if (rc) RETURN(rc); - op_data = ll_prep_md_op_data(NULL, inode, NULL, filename, - strlen(filename), lmmsize, - LUSTRE_OPC_ANY, NULL); - if (IS_ERR(op_data)) - RETURN(PTR_ERR(op_data)); + op_data = ll_prep_md_op_data(NULL, inode, NULL, filename, + strlen(filename), lmmsize, + LUSTRE_OPC_ANY, NULL); + if (IS_ERR(op_data)) + RETURN(PTR_ERR(op_data)); - op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA; - rc = md_getattr_name(sbi->ll_md_exp, op_data, &req); - ll_finish_md_op_data(op_data); - if (rc < 0) { - CDEBUG(D_INFO, "md_getattr_name failed " - "on %s: rc %d\n", filename, rc); - GOTO(out, rc); - } + op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA; + rc = md_getattr_name(sbi->ll_md_exp, op_data, &req); + ll_finish_md_op_data(op_data); + if (rc < 0) { + CDEBUG(D_INFO, "md_getattr_name failed " + "on %s: rc %d\n", filename, rc); + GOTO(out, rc); + } - body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); - LASSERT(body != NULL); /* checked by mdc_getattr_name */ + body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); + LASSERT(body != NULL); /* checked by mdc_getattr_name */ lmmsize = body->mbo_eadatasize; if (!(body->mbo_valid & (OBD_MD_FLEASIZE | OBD_MD_FLDIREA)) || - lmmsize == 0) { - GOTO(out, rc = -ENODATA); - } + lmmsize == 0) + GOTO(out, rc = -ENODATA); - lmm = req_capsule_server_sized_get(&req->rq_pill, &RMF_MDT_MD, lmmsize); - LASSERT(lmm != NULL); + lmm = req_capsule_server_sized_get(&req->rq_pill, &RMF_MDT_MD, lmmsize); + LASSERT(lmm != NULL); if (lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V1) && lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_V3) && @@ -2196,11 +2197,10 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename, /* * This is coming from the MDS, so is probably in - * little endian. We convert it to host endian before + * little endian. We convert it to host endian before * passing it to userspace. */ - if ((lmm->lmm_magic & __swab32(LOV_MAGIC_MAGIC)) == - __swab32(LOV_MAGIC_MAGIC)) { + if (cpu_to_le32(LOV_MAGIC) != LOV_MAGIC) { int stripe_count = 0; if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V1) || @@ -2209,28 +2209,74 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename, if (le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED) stripe_count = 0; - } - - lustre_swab_lov_user_md((struct lov_user_md *)lmm, 0); + lustre_swab_lov_user_md((struct lov_user_md *)lmm, 0); - /* if function called for directory - we should - * avoid swab not existent lsm objects */ - if (lmm->lmm_magic == LOV_MAGIC_V1 && S_ISREG(body->mbo_mode)) - lustre_swab_lov_user_md_objects( + /* if function called for directory - we should + * avoid swab not existent lsm objects + */ + if (lmm->lmm_magic == LOV_MAGIC_V1 && + S_ISREG(body->mbo_mode)) + lustre_swab_lov_user_md_objects( ((struct lov_user_md_v1 *)lmm)->lmm_objects, stripe_count); - else if (lmm->lmm_magic == LOV_MAGIC_V3 && - S_ISREG(body->mbo_mode)) - lustre_swab_lov_user_md_objects( + else if (lmm->lmm_magic == LOV_MAGIC_V3 && + S_ISREG(body->mbo_mode)) + lustre_swab_lov_user_md_objects( ((struct lov_user_md_v3 *)lmm)->lmm_objects, stripe_count); + } else if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_COMP_V1)) { + lustre_swab_lov_comp_md_v1( + (struct lov_comp_md_v1 *)lmm); + } } + if (lmm->lmm_magic == LOV_MAGIC_COMP_V1) { + struct lov_comp_md_v1 *comp_v1 = NULL; + struct lov_comp_md_entry_v1 *ent; + struct lov_user_md_v1 *v1; + __u32 off; + int i = 0; + + comp_v1 = (struct lov_comp_md_v1 *)lmm; + /* Dump the striping information */ + for (; i < comp_v1->lcm_entry_count; i++) { + ent = &comp_v1->lcm_entries[i]; + off = ent->lcme_offset; + v1 = (struct lov_user_md_v1 *)((char *)lmm + off); + CDEBUG(D_INFO, + "comp[%d]: stripe_count=%u, stripe_size=%u\n", + i, v1->lmm_stripe_count, v1->lmm_stripe_size); + } + + /** + * Return valid stripe_count and stripe_size instead of 0 for + * DoM files to avoid divide-by-zero for older userspace that + * calls this ioctl, e.g. lustre ADIO driver. + */ + if (lmm->lmm_stripe_count == 0) + lmm->lmm_stripe_count = 1; + if (lmm->lmm_stripe_size == 0) { + /* Since the first component of the file data is placed + * on the MDT for faster access, the stripe_size of the + * second one is always that applications which are + * doing large IOs. + */ + if (lmm->lmm_pattern == LOV_PATTERN_MDT) + i = comp_v1->lcm_entry_count > 1 ? 1 : 0; + else + i = comp_v1->lcm_entry_count > 1 ? + comp_v1->lcm_entry_count - 1 : 0; + ent = &comp_v1->lcm_entries[i]; + off = ent->lcme_offset; + v1 = (struct lov_user_md_v1 *)((char *)lmm + off); + lmm->lmm_stripe_size = v1->lmm_stripe_size; + } + } out: *lmmp = lmm; *lmm_size = lmmsize; *request = req; - return rc; + RETURN(rc); } static int ll_lov_setea(struct inode *inode, struct file *file, diff --git a/lustre/lov/lov_pack.c b/lustre/lov/lov_pack.c index b715ec9..d3dae1f 100644 --- a/lustre/lov/lov_pack.c +++ b/lustre/lov/lov_pack.c @@ -468,13 +468,6 @@ int lov_getstripe(const struct lu_env *env, struct lov_object *obj, } /** - * Return stripe_count=1 instead of 0 for DoM files to avoid - * divide-by-zero for older userspace that calls this ioctl, - * e.g. lustre ADIO driver. - */ - if ((lum.lmm_stripe_count == 0) && (lum.lmm_pattern & LOV_PATTERN_MDT)) - lum.lmm_stripe_count = 1; - /** * User specified limited buffer size, usually the buffer is * from ll_lov_setstripe(), and the buffer can only hold basic * layout template info. diff --git a/lustre/tests/Makefile.am b/lustre/tests/Makefile.am index 8353687..110e0f8 100644 --- a/lustre/tests/Makefile.am +++ b/lustre/tests/Makefile.am @@ -78,7 +78,7 @@ THETESTS += swap_lock_test lockahead_test mirror_io mmap_mknod_test THETESTS += create_foreign_file parse_foreign_file THETESTS += create_foreign_dir parse_foreign_dir THETESTS += check_fallocate splice-test lseek_test expand_truncate_test -THETESTS += foreign_symlink_striping +THETESTS += foreign_symlink_striping lov_getstripe_old if LIBAIO THETESTS += aiocp @@ -122,6 +122,7 @@ rwv_LDADD = $(LIBLUSTREAPI) lockahead_test_LDADD = $(LIBLUSTREAPI) mirror_io_LDADD = $(LIBLUSTREAPI) ll_dirstripe_verify_LDADD = $(LIBLUSTREAPI) +lov_getstripe_old_LDADD = $(LIBLUSTREAPI) flocks_test_LDADD = $(LIBLUSTREAPI) $(PTHREAD_LIBS) create_foreign_dir_LDADD = $(LIBLUSTREAPI) check_fallocate_LDADD = $(LIBLUSTREAPI) diff --git a/lustre/tests/lov_getstripe_old.c b/lustre/tests/lov_getstripe_old.c new file mode 100644 index 0000000..c7fed91 --- /dev/null +++ b/lustre/tests/lov_getstripe_old.c @@ -0,0 +1,95 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2021, DDN Storage Corporation. + */ +/* + * lustre/tests/lov_getstripe_old.c + * + * ll_getstripe_old : + * - to verify if the striping information of composite layout files returned + * by llapi_file_get_stripe() is valid. + */ + +#include +#include +#include +#include +#include +#define LOV_MAGIC_MAGIC 0x0BD0 +#define LOV_MAGIC_MASK 0xFFFF +#define LOV_MAGIC_V1 (0x0BD10000 | LOV_MAGIC_MAGIC) +#define LOV_MAGIC_JOIN_V1 (0x0BD20000 | LOV_MAGIC_MAGIC) +#define LOV_MAGIC_V3 (0x0BD30000 | LOV_MAGIC_MAGIC) +static inline int maxint(int a, int b) +{ + return a > b ? a : b; +} + +static void *alloc_lum() +{ + int v1, v3; + + v1 = sizeof(struct lov_user_md_v1) + + LOV_MAX_STRIPE_COUNT * sizeof(struct lov_user_ost_data_v1); + v3 = sizeof(struct lov_user_md_v3) + + LOV_MAX_STRIPE_COUNT * sizeof(struct lov_user_ost_data_v1); + + return malloc(maxint(v1, v3)); +} + +int main(int argc, char **argv) +{ + struct lov_user_md *lum_file = NULL; + int rc; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + lum_file = alloc_lum(); + if (lum_file == NULL) { + rc = ENOMEM; + goto cleanup; + } + + rc = llapi_file_get_stripe(argv[1], lum_file); + if (rc) { + rc = errno; + goto cleanup; + } + /* stripe_size stripe_count */ + if (lum_file->lmm_magic == LOV_MAGIC_V1) + printf("lmm_magic: v1\n"); + else if (lum_file->lmm_magic == LOV_MAGIC_V3) + printf("lmm_magic: v3\n"); + else if (lum_file->lmm_magic == (0x0BD60000 | LOV_MAGIC_MAGIC)) + printf("lmm_magic: LOV_MAGIC component\n"); + + printf("stripe_count: %d\nstripe_size: %d\n", + lum_file->lmm_stripe_count, lum_file->lmm_stripe_size); + +cleanup: + if (lum_file != NULL) + free(lum_file); + return rc; +} diff --git a/lustre/tests/sanity-pfl.sh b/lustre/tests/sanity-pfl.sh index 387d2b2..05ce531 100644 --- a/lustre/tests/sanity-pfl.sh +++ b/lustre/tests/sanity-pfl.sh @@ -2398,6 +2398,53 @@ test_24a() { } run_test 24a "FIEMAP upon PFL file" +test_25() { + local pfl_f=$DIR/$tdir/"$tfile"_pfl + local dom_f=$DIR/$tdir/"$tfile"_dom + local common_f=$DIR/$tdir/"$tfile"_common + local stripe_count + local stripe_size + + mkdir -p $DIR/$tdir || error "mkdir $DIR/$tdir failed" + $LFS setstripe -E 10M -S 64k -c -1 -E 20M -S 1M -E -1 -S 2M -c 1 \ + $pfl_f || error "setstripe $pfl_f failed" + $LFS setstripe -E 256k -L mdt -E -1 -S 1M $dom_f || + error "setstripe $dom_f failed" + $LFS setstripe -S 512K -c -1 $common_f || + error "setstripe $common_f failed" + + #verify lov_getstripe_old with PFL file + stripe_count=$(lov_getstripe_old $pfl_f | + awk '/stripe_count/ { print $2 }') + stripe_size=$(lov_getstripe_old $pfl_f | + awk '/stripe_size/ { print $2 }') + [ $stripe_count -eq 1 ] || + error "stripe_count $stripe_count !=1 for $pfl_f" + [ $stripe_size -eq 2097152 ] || + error "stripe_size $stripe_size != 2097152 for $pfl_f" + + #verify lov_getstripe_old with DoM file + stripe_count=$(lov_getstripe_old $dom_f | + awk '/stripe_count/ { print $2 }') + stripe_size=$(lov_getstripe_old $dom_f | + awk '/stripe_size/ { print $2 }') + [ $stripe_count -eq 1 ] || + error "stripe_count $stripe_count !=1 for $dom_f" + [ $stripe_size -eq 1048576 ] || + error "stripe_size $stripe_size != 1048576 for $dom_f" + + #verify lov_getstripe_old with common file + stripe_count=$(lov_getstripe_old $common_f | + awk '/stripe_count/ { print $2 }') + stripe_size=$(lov_getstripe_old $common_f | + awk '/stripe_size/ { print $2 }') + [ $stripe_count -eq $OSTCOUNT ] || + error "stripe_count $stripe_count !=$OSTCOUNT for $common_f" + [ $stripe_size -eq 524288 ] || + error "stripe_size $stripe_size != 524288 for $common_f" +} +run_test 25 "Verify old lov stripe API with PFL files" + complete $SECONDS check_and_cleanup_lustre exit_status -- 1.8.3.1