Whamcloud - gitweb
LU-14337 lov: return valid stripe_count/size for PFL files 03/41803/6
authorEmoly Liu <emoly@whamcloud.com>
Tue, 16 Mar 2021 03:04:46 +0000 (11:04 +0800)
committerOleg Drokin <green@whamcloud.com>
Tue, 30 Mar 2021 04:16:13 +0000 (04:16 +0000)
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 <emoly@whamcloud.com>
Change-Id: I4023ca4baff1b1ad2a439aa497baaabc56e891d2
Reviewed-on: https://review.whamcloud.com/41803
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Bobi Jam <bobijam@hotmail.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/llite/file.c
lustre/lov/lov_pack.c
lustre/tests/Makefile.am
lustre/tests/lov_getstripe_old.c [new file with mode: 0644]
lustre/tests/sanity-pfl.sh

index 5791569..76350c0 100644 (file)
@@ -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,
index b715ec9..d3dae1f 100644 (file)
@@ -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.
index 8353687..110e0f8 100644 (file)
@@ -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 (file)
index 0000000..c7fed91
--- /dev/null
@@ -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 <file>:
+ * - to verify if the striping information of composite layout files returned
+ *   by llapi_file_get_stripe() is valid.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/vfs.h>
+#include <lustre/lustreapi.h>
+#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 <filename>\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;
+}
index 387d2b2..05ce531 100644 (file)
@@ -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