Whamcloud - gitweb
LU-13062 llite: return stripe_offset -1 in trusted.lov 52/45252/10
authorAndreas Dilger <adilger@whamcloud.com>
Fri, 15 Oct 2021 02:31:48 +0000 (20:31 -0600)
committerOleg Drokin <green@whamcloud.com>
Sun, 24 Nov 2024 06:02:57 +0000 (06:02 +0000)
If the trusted.lov xattr is copied by userspace to be restored later,
this results in PFL files always being restored onto OST0000 because
the kernel replaces the lmm_layout_gen field with 0 to avoid confusion
in userspace between the layout generation and the stripe offset (both
use the same field, one for input, one for output).

Instead of always returning 0 for the layout generation, return -1
for PFL layouts, so that restoring the xattr will direct the MDS to
select an appropriate OST.

For setxattr attempt patch prevent setting specific offsets if
PFL layout has an initialized entry what is considered as layout
copy attempt.

Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Change-Id: Ia1af2bfcfa41cf1593aab44fe2fa792c3d254035
Signed-off-by: Mikhail Pershin <mpershin@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/45252
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Jian Yu <yujian@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/llite/xattr.c
lustre/tests/sanity-flr.sh
lustre/tests/sanity.sh

index ca30be6..fdf3ad9 100644 (file)
@@ -261,7 +261,7 @@ static int ll_adjust_lum(struct inode *inode, struct lov_user_md *lump,
        struct lov_user_md *v1 = lump;
        bool need_clear_release = false;
        bool release_checked = false;
-       bool is_composite = false;
+       bool default_offset = false;
        u16 entry_count = 1;
        int rc = 0;
        int i;
@@ -276,7 +276,37 @@ static int ll_adjust_lum(struct inode *inode, struct lov_user_md *lump,
                entry_count = comp_v1->lcm_entry_count;
                if (size < offsetof(typeof(*comp_v1), lcm_entries[entry_count]))
                        return -ERANGE;
-               is_composite = true;
+
+               for (i = 0; i < entry_count; i++) {
+                       void *ptr = comp_v1;
+
+                       ptr += comp_v1->lcm_entries[i].lcme_offset;
+                       v1 = ptr;
+                       /* Consider layout as copied if it has an initialized
+                        * entry.
+                        */
+                       if (comp_v1->lcm_entries[i].lcme_flags & LCME_FL_INIT) {
+                               default_offset = true;
+                               break;
+                       }
+               }
+       } else if (lump->lmm_magic == LOV_USER_MAGIC_V1) {
+               /* reset starting offset if xattr is copied */
+               if (v1->lmm_stripe_offset == 0 && size > sizeof(*v1) &&
+                   !fid_is_zero(&v1->lmm_objects[0].l_ost_oi.oi_fid)) {
+                       default_offset = true;
+               }
+       } else  if (lump->lmm_magic == LOV_USER_MAGIC_V3) {
+               struct lov_user_md_v3 *v3 = (void *)v1;
+
+               /* reset starting offset if xattr is copied */
+               if (v3->lmm_stripe_offset == 0 && size > sizeof(*v3) &&
+                   !fid_is_zero(&v3->lmm_objects[0].l_ost_oi.oi_fid)) {
+                       default_offset = true;
+               }
+       } else {
+               /* skip for other layout types */
+               return 0;
        }
 
        for (i = 0; i < entry_count; i++) {
@@ -297,8 +327,8 @@ static int ll_adjust_lum(struct inode *inode, struct lov_user_md *lump,
                 * should be allowed to pick the starting OST index.
                 * b=17846
                 */
-               if (!is_composite && v1->lmm_stripe_offset == 0)
-                       v1->lmm_stripe_offset = -1;
+               if (default_offset)
+                       v1->lmm_stripe_offset = LOV_OFFSET_DEFAULT;
 
                /* Avoid anyone directly setting the RELEASED flag. */
                if (v1->lmm_pattern & LOV_PATTERN_F_RELEASED) {
@@ -556,9 +586,69 @@ static int ll_xattr_get_common(const struct xattr_handler *handler,
        RETURN(rc);
 }
 
+static ssize_t ll_sanitize_xattr(struct inode *inode, void *buf,
+                                size_t buf_size, size_t lmm_size)
+{
+       struct lov_user_md *lum = buf;
+       struct lov_comp_md_v1 *comp = buf;
+       ssize_t rc = lmm_size;
+       int i;
+
+       if (!lmm_size)
+               return -ENODATA;
+       if (!buf_size)
+               return lmm_size;
+       if (buf_size < lmm_size)
+               return -ERANGE;
+       /*
+        * Do not return layout gen for getxattr() since otherwise it would
+        * confuse tar --xattr by recognizing layout gen as stripe offset
+        * when the file is restored (LU-2809).
+        * Instead, replace lmm_layout_gen (lmm_stripe_offset) with
+        * LOV_OFFSET_DEFAULT so restoring the xattr allows the MDS to select
+        * the OST index (LU-13062).
+        */
+       if ((lum->lmm_magic & __swab32(LOV_MAGIC_MAGIC)) ==
+           __swab32(LOV_MAGIC_MAGIC))
+               lustre_swab_lov_user_md(lum, lmm_size);
+
+       switch (lum->lmm_magic) {
+       case LOV_MAGIC_V1:
+       case LOV_MAGIC_V3:
+       case LOV_MAGIC_SPECIFIC:
+               lum->lmm_stripe_offset = LOV_OFFSET_DEFAULT;
+               break;
+       case LOV_MAGIC_COMP_V1:
+               for (i = 0; i < comp->lcm_entry_count; i++) {
+                       void *ptr = comp;
+
+                       ptr += comp->lcm_entries[i].lcme_offset;
+                       lum = ptr;
+                       lum->lmm_stripe_offset = LOV_OFFSET_DEFAULT;
+               }
+               break;
+       case LOV_MAGIC_FOREIGN:
+               break;
+       default:
+               /* report unknown magic for regular file, for directories
+                * that was checked in ll_dir_getstripe_default() already
+                */
+               if (S_ISREG(inode->i_mode)) {
+                       rc = -EPROTO;
+                       CERROR("%s: bad LOV magic %08x on "DFID": rc = %zd\n",
+                              ll_i2sbi(inode)->ll_fsname, lum->lmm_magic,
+                              PFID(ll_inode2fid(inode)), rc);
+               }
+               break;
+       }
+
+       return rc;
+}
+
 static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size)
 {
        ssize_t rc;
+       size_t xattr_size;
 
        if (S_ISREG(inode->i_mode)) {
                struct cl_object *obj = ll_i2info(inode)->lli_clob;
@@ -580,45 +670,8 @@ static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size)
                if (rc < 0)
                        GOTO(out_env, rc);
 
-               if (!cl.cl_size)
-                       GOTO(out_env, rc = -ENODATA);
-
-               rc = cl.cl_size;
-
-               if (!buf_size)
-                       GOTO(out_env, rc);
-
-               LASSERT(buf && rc <= buf_size);
-
-               /*
-                * Do not return layout gen for getxattr() since
-                * otherwise it would confuse tar --xattr by
-                * recognizing layout gen as stripe offset when the
-                * file is restored. See LU-2809.
-                */
-               if ((((struct lov_mds_md *)buf)->lmm_magic &
-                   __swab32(LOV_MAGIC_MAGIC)) == __swab32(LOV_MAGIC_MAGIC))
-                       lustre_swab_lov_user_md((struct lov_user_md *)buf,
-                                               cl.cl_size);
-
-               switch (((struct lov_mds_md *)buf)->lmm_magic) {
-               case LOV_MAGIC_V1:
-               case LOV_MAGIC_V3:
-               case LOV_MAGIC_SPECIFIC:
-                       ((struct lov_mds_md *)buf)->lmm_layout_gen = 0;
-                       break;
-               case LOV_MAGIC_COMP_V1:
-               case LOV_MAGIC_FOREIGN:
-                       goto out_env;
-               default:
-                       rc = -EINVAL;
-                       CERROR("%s: bad LOV magic %08x on "DFID": rc = %zd\n",
-                              ll_i2sbi(inode)->ll_fsname,
-                              ((struct lov_mds_md *)buf)->lmm_magic,
-                              PFID(ll_inode2fid(inode)), rc);
-                       GOTO(out_env, rc);
-               }
-
+               xattr_size = cl.cl_size;
+               rc = ll_sanitize_xattr(inode, buf, buf_size, xattr_size);
 out_env:
                cl_env_put(env, &refcheck);
 
@@ -634,14 +687,11 @@ out_env:
                if (rc < 0)
                        GOTO(out_req, rc);
 
-               if (!buf_size)
-                       GOTO(out_req, rc = lmm_size);
-
-               if (buf_size < lmm_size)
-                       GOTO(out_req, rc = -ERANGE);
-
-               memcpy(buf, lmm, lmm_size);
-               GOTO(out_req, rc = lmm_size);
+               xattr_size = lmm_size;
+               rc = ll_sanitize_xattr(inode, (void*)lmm, buf_size,
+                                      xattr_size);
+               if (buf && rc > 0)
+                       memcpy(buf, lmm, lmm_size);
 out_req:
                if (req)
                        ptlrpc_req_put(req);
index b294d78..e2e22ec 100644 (file)
@@ -2483,8 +2483,8 @@ verify_46() {
 
        $LFS setstripe --copy=$src $dst || error "setstripe $dst failed"
 
-       local layout1=$(get_layout_param $src)
-       local layout2=$(get_layout_param $dst)
+       local layout1=$(SKIP_INDEX=yes get_layout_param $src)
+       local layout2=$(SKIP_INDEX=yes get_layout_param $dst)
        # compare their layout info
        [ "$layout1" == "$layout2" ] ||
                error "$msg_prefix $src <=> $dst layouts are not equal"
index 80062d0..6b0833b 100755 (executable)
@@ -11176,6 +11176,47 @@ test_65q () { # LU-16194
 }
 run_test 65q "setstripe with >=8E offset should fail"
 
+65r_check_offsets() {
+       local offsets
+       local all_zeroes=1
+       local pfl=$1
+
+       offsets=$($LFS getstripe -y $pfl | awk '/stripe_offset:/ { print $2 }')
+       for off in ${offsets[@]}; do
+               ((off == 0)) || all_zeroes=0
+       done
+       echo $all_zeroes
+}
+
+test_65r() { #LU-13062
+       (( OSTCOUNT >= 2 )) || skip_env "needs >= 2 OSTs"
+
+       local dir=$DIR/$tdir
+       local pfl=$DIR/$tdir/$tfile
+
+       test_mkdir -p $DIR/$tdir
+       # lfs setstripe can set all 0 offsets directly
+       $LFS setstripe -E1m -c1 -i0 -E2m -c2 -i0 -E4m -c4 -i0 -E -1 -i0 $pfl ||
+               error "Create file $pfl failed"
+       (( $(65r_check_offsets $pfl) == 1 )) ||
+               error "lfs setstripe directions are ignored"
+
+       # lfs setstripe --copy should reset specified offsets to default
+       lfs setstripe --copy=$pfl ${pfl}.copy ||
+               error "lfs setstripe --copy failed"
+       (( $(65r_check_offsets ${pfl}.copy) == 0 )) ||
+               error "lfs setstripe --copy keeps specific offsets"
+
+       # directory layout copy should drop specific offsets
+       $LFS setstripe -E1m -c1 -i0 -E2m -c2 -i0 -E4m -c4 -i0 -E -1 -i0 $dir ||
+               error "Failed to set default layout for $dir"
+       lfs setstripe --copy=$dir ${pfl}.dircopy ||
+               error "lfs setstripe --copy from directory failed"
+       (( $(65r_check_offsets ${pfl}.dircopy) == 0 )) ||
+               error "lfs setstripe --copy for directory keeps offsets"
+}
+run_test 65r "prevent all-zero offsets"
+
 # bug 2543 - update blocks count on client
 test_66() {
        [ $PARALLEL == "yes" ] && skip "skip parallel run"