Whamcloud - gitweb
LU-14642 flr: abolish MDS transfer layout version to OST
authorBobi Jam <bobijam@whamcloud.com>
Thu, 13 Jan 2022 09:35:24 +0000 (17:35 +0800)
committerJohn L. Hammond <jhammond@whamcloud.com>
Fri, 21 Jan 2022 22:11:39 +0000 (22:11 +0000)
Quit setting layout version to OST object from MDS, and client
write request will carry the new layout version and OST object
rejects old layout version write and update new layout version
accordingly.

Lustre-change: https://review.whamcloud.com/c/45443/
Lustre-commit: TBD (from aea66b7d3fdc37d61704bd5df2a25a4747a6cce5)

Signed-off-by: Bobi Jam <bobijam@whamcloud.com>
Change-Id: I655044f69a4509a2b0cfe99f86de2ce4ee846979
Reviewed-on: https://review.whamcloud.com/45278
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: John L. Hammond <jhammond@whamcloud.com>
12 files changed:
lustre/include/obd_support.h
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/llite/file.c
lustre/lod/lod_internal.h
lustre/lod/lod_object.c
lustre/lod/lod_qos.c
lustre/mdd/mdd_object.c
lustre/ofd/ofd_internal.h
lustre/ofd/ofd_io.c
lustre/ofd/ofd_objects.c
lustre/osp/osp_sync.c
lustre/tests/sanity-flr.sh

index fb772c6..5bc64d1 100644 (file)
@@ -675,7 +675,7 @@ extern char obd_jobid_var[];
 /* FLR */
 #define OBD_FAIL_FLR_GLIMPSE_IMMUTABLE         0x1A00
 #define OBD_FAIL_FLR_LV_DELAY                  0x1A01
-#define OBD_FAIL_FLR_LV_INC                    0x1A02
+#define OBD_FAIL_FLR_LV_INC                    0x1A02 /* not used */
 #define OBD_FAIL_FLR_RANDOM_PICK_MIRROR        0x1A03
 
 /* DT */
index cc6f117..a55a76a 100644 (file)
@@ -889,10 +889,6 @@ enum lov_comp_md_entry_flags {
 #define LCME_TEMPLATE_FLAGS    (LCME_FL_PREF_RW | LCME_FL_NOSYNC | \
                                 LCME_FL_EXTENSION)
 
-/* the highest bit in obdo::o_layout_version is used to mark if the file is
- * being resynced. */
-#define LU_LAYOUT_RESYNC       LCME_FL_NEG
-
 /* lcme_id can be specified as certain flags, and the the first
  * bit of lcme_id is used to indicate that the ID is representing
  * certain LCME_FL_* but not a real ID. Which implies we can have
@@ -904,6 +900,15 @@ enum lcme_id {
        LCME_ID_NOT_ID  = LCME_FL_NEG
 };
 
+/* layout version equals to lcme_id, except some bits have special meanings */
+enum layout_version_flags {
+       /* layout version reaches the high water mark to be increased to
+        * circularly reuse the smallest value */
+       LU_LAYOUT_HIGEN         = 0x40000000,
+       /* the highest bit is used to mark if the file is being resynced */
+       LU_LAYOUT_RESYNC        = 0x80000000,
+};
+
 #define LCME_ID_MASK   LCME_ID_MAX
 
 struct lov_comp_md_entry_v1 {
index fe05eb3..3bdd9f2 100644 (file)
@@ -3612,6 +3612,7 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc,
        bool lease_broken = false;
        fmode_t fmode = 0;
        enum mds_op_bias bias = 0;
+       int fdv;
        struct file *layout_file = NULL;
        void *data = NULL;
        size_t data_size = 0;
@@ -3648,16 +3649,15 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc,
                bias = MDS_CLOSE_RESYNC_DONE;
                break;
        case LL_LEASE_LAYOUT_MERGE: {
-               int fd;
 
                if (ioc->lil_count != 1)
                        GOTO(out_lease_close, rc = -EINVAL);
 
                arg += sizeof(*ioc);
-               if (copy_from_user(&fd, (void __user *)arg, sizeof(__u32)))
+               if (copy_from_user(&fdv, (void __user *)arg, sizeof(__u32)))
                        GOTO(out_lease_close, rc = -EFAULT);
 
-               layout_file = fget(fd);
+               layout_file = fget(fdv);
                if (!layout_file)
                        GOTO(out_lease_close, rc = -EBADF);
 
@@ -3670,7 +3670,6 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc,
                break;
        }
        case LL_LEASE_LAYOUT_SPLIT: {
-               int fdv;
                int mirror_id;
 
                if (ioc->lil_count != 2)
@@ -3740,28 +3739,23 @@ out_lease_close:
        EXIT;
 
 out:
-       switch (ioc->lil_flags) {
-       case LL_LEASE_RESYNC_DONE:
-               if (data)
-                       OBD_FREE(data, data_size);
-               break;
-       case LL_LEASE_LAYOUT_MERGE:
-       case LL_LEASE_LAYOUT_SPLIT:
-               if (layout_file)
-                       fput(layout_file);
+       if (ioc->lil_flags == LL_LEASE_RESYNC_DONE && data)
+               OBD_FREE(data, data_size);
 
-               ll_layout_refresh(inode, &fd->fd_layout_version);
-               break;
-       case LL_LEASE_PCC_ATTACH:
+       if (layout_file)
+               fput(layout_file);
+
+       if (ioc->lil_flags == LL_LEASE_PCC_ATTACH) {
                if (!rc)
                        rc = rc2;
                rc = pcc_readwrite_attach_fini(file, inode,
                                               param.pa_layout_gen,
                                               lease_broken, rc,
                                               attached);
-               break;
        }
 
+       ll_layout_refresh(inode, &fd->fd_layout_version);
+
        if (!rc)
                rc = ll_lease_type_from_fmode(fmode);
        RETURN(rc);
index c00da61..31f4690 100644 (file)
@@ -409,8 +409,10 @@ static inline void lod_obj_inc_layout_gen(struct lod_object *lo)
        lo->ldo_layout_gen++;
        lo->ldo_layout_gen |= preserve;
        /* Zero is not a valid generation */
-       if (unlikely((lo->ldo_layout_gen & LCME_ID_MASK) == 0))
+       if (unlikely((lo->ldo_layout_gen & LCME_ID_MASK) == 0)) {
                lo->ldo_layout_gen++;
+               lo->ldo_layout_gen &= ~LU_LAYOUT_RESYNC;
+       }
 }
 
 struct lod_it {
index 4fa56fe..cc3df12 100644 (file)
@@ -7633,7 +7633,6 @@ static int lod_declare_update_rdonly(const struct lu_env *env,
                struct thandle *th)
 {
        struct lod_thread_info *info = lod_env_info(env);
-       struct lu_attr *layout_attr = &info->lti_layout_attr;
        struct lod_layout_component *lod_comp;
        struct lu_extent extent = { 0 };
        int rc;
@@ -7744,25 +7743,11 @@ static int lod_declare_update_rdonly(const struct lu_env *env,
         * This way it can make sure that the layout version is
         * monotonously increased in this writing era. */
        lod_obj_inc_layout_gen(lo);
-       if (lo->ldo_layout_gen > (LCME_ID_MAX >> 1)) {
-               __u32 layout_version;
-
-               get_random_bytes(&layout_version, sizeof(layout_version));
-               lo->ldo_layout_gen = layout_version & 0xffff;
-       }
 
        rc = lod_declare_instantiate_components(env, lo, th, 0);
        if (rc)
                GOTO(out, rc);
 
-       layout_attr->la_valid = LA_LAYOUT_VERSION;
-       layout_attr->la_layout_version = 0; /* set current version */
-       if (mlc->mlc_opc == MD_LAYOUT_RESYNC)
-               layout_attr->la_layout_version = LU_LAYOUT_RESYNC;
-       rc = lod_declare_attr_set(env, &lo->ldo_obj, layout_attr, th);
-       if (rc)
-               GOTO(out, rc);
-
 out:
        if (rc)
                lod_striping_free(env, lo);
@@ -7774,7 +7759,6 @@ static int lod_declare_update_write_pending(const struct lu_env *env,
                struct thandle *th)
 {
        struct lod_thread_info *info = lod_env_info(env);
-       struct lu_attr *layout_attr = &info->lti_layout_attr;
        struct lod_layout_component *lod_comp;
        struct lu_extent extent = { 0 };
        int primary = -1;
@@ -7908,19 +7892,6 @@ static int lod_declare_update_write_pending(const struct lu_env *env,
        if (rc)
                GOTO(out, rc);
 
-       /* 3. transfer layout version to OST objects.
-        * transfer new layout version to OST objects so that stale writes
-        * can be denied. It also ends an era of writing by setting
-        * LU_LAYOUT_RESYNC. Normal client can never use this bit to
-        * send write RPC; only resync RPCs could do it. */
-       layout_attr->la_valid = LA_LAYOUT_VERSION;
-       layout_attr->la_layout_version = 0; /* set current version */
-       if (mlc->mlc_opc == MD_LAYOUT_RESYNC)
-               layout_attr->la_layout_version = LU_LAYOUT_RESYNC;
-       rc = lod_declare_attr_set(env, &lo->ldo_obj, layout_attr, th);
-       if (rc)
-               GOTO(out, rc);
-
        lod_obj_inc_layout_gen(lo);
 out:
        if (rc)
@@ -8691,8 +8662,6 @@ static int lod_layout_change(const struct lu_env *env, struct dt_object *dt,
                             struct md_layout_change *mlc, struct thandle *th)
 {
        struct lu_attr *attr = &lod_env_info(env)->lti_attr;
-       struct lu_attr *layout_attr = &lod_env_info(env)->lti_layout_attr;
-       struct lod_object *lo = lod_dt_obj(dt);
        int rc;
 
        ENTRY;
@@ -8704,10 +8673,6 @@ static int lod_layout_change(const struct lu_env *env, struct dt_object *dt,
        }
 
        rc = lod_striped_create(env, dt, attr, NULL, th);
-       if (!rc && layout_attr->la_valid & LA_LAYOUT_VERSION) {
-               layout_attr->la_layout_version |= lo->ldo_layout_gen;
-               rc = lod_attr_set(env, dt, layout_attr, th);
-       }
 
        RETURN(rc);
 }
index 161f0a7..91f1fd6 100644 (file)
@@ -2608,6 +2608,7 @@ put_ldts:
                        }
                        lod_comp->llc_stripe_count = 0;
                } else {
+                       lod_comp->llc_layout_gen = 0;
                        lod_comp->llc_stripe = stripe;
                        lod_comp->llc_ost_indices = ost_indices;
                        lod_comp->llc_stripes_allocated = stripe_len;
index fc07f4a..ef93b05 100644 (file)
@@ -1647,7 +1647,7 @@ static int mdd_xattr_merge(const struct lu_env *env, struct md_object *md_obj,
                GOTO(out, rc);
 
        rc = mdo_xattr_del(env, vic, XATTR_NAME_LOV, handle);
-       if (rc) /* wtf? */
+       if (rc)
                GOTO(out_restore, rc);
 
        (void)mdd_changelog_data_store(env, mdd, CL_LAYOUT, 0, obj, handle,
index ce6561e..3be35a0 100644 (file)
@@ -505,4 +505,21 @@ static inline int ofd_validate_seq(struct obd_export *exp, __u64 seq)
        return 0;
 }
 
+/* whether the requestion IO contains older layout version than that on the
+ * disk. */
+static inline bool ofd_layout_version_less(__u32 req_version,
+                                          __u32 ondisk_version)
+{
+       __u32 req = req_version & ~LU_LAYOUT_RESYNC;
+       __u32 ondisk = ondisk_version & ~LU_LAYOUT_RESYNC;
+
+       /**
+        * request layout version could be circularly increased to the samllest
+        * value, in that case @req < @ondisk but @req does not have the high
+        * end bit set while @ondisk does.
+        */
+       return (req < ondisk) &&
+               ((req & LU_LAYOUT_HIGEN) == (ondisk & LU_LAYOUT_HIGEN));
+}
+
 #endif /* _OFD_INTERNAL_H */
index a87ec2f..791b464 100644 (file)
@@ -434,7 +434,6 @@ int ofd_verify_ff(const struct lu_env *env, struct ofd_object *fo,
 int ofd_verify_layout_version(const struct lu_env *env,
                              struct ofd_object *fo, const struct obdo *oa)
 {
-       __u32 layout_version;
        int rc;
        ENTRY;
 
@@ -444,25 +443,18 @@ int ofd_verify_layout_version(const struct lu_env *env,
        rc = ofd_object_ff_load(env, fo);
        if (rc < 0) {
                if (rc == -ENODATA)
-                       rc = -EINPROGRESS;
+                       rc = 0;
                GOTO(out, rc);
        }
 
-       layout_version = fo->ofo_ff.ff_layout_version;
-       if (oa->o_layout_version >= layout_version &&
-           oa->o_layout_version <= layout_version + fo->ofo_ff.ff_range)
-               GOTO(out, rc = 0);
-
-       /* normal traffic, decide if to return ESTALE or EINPROGRESS */
-       layout_version &= ~LU_LAYOUT_RESYNC;
-
-       /* this update is not legitimate */
-       if ((oa->o_layout_version & ~LU_LAYOUT_RESYNC) <= layout_version)
-               GOTO(out, rc = -ESTALE);
-
-       /* layout version may not be transmitted yet */
-       if ((oa->o_layout_version & ~LU_LAYOUT_RESYNC) > layout_version)
-               GOTO(out, rc = -EINPROGRESS);
+       /**
+        * this update is not legitimate, whose layout version is older than
+        * that on the disk.
+        */
+       if (ofd_layout_version_less(oa->o_layout_version,
+                                   fo->ofo_ff.ff_layout_version +
+                                   fo->ofo_ff.ff_range))
+               RETURN(-ESTALE);
 
        EXIT;
 
@@ -789,8 +781,6 @@ static int ofd_preprw_write(const struct lu_env *env, struct obd_export *exp,
                        ofd_object_put(env, fo);
                        GOTO(out, rc);
                }
-
-               oa->o_valid &= ~OBD_MD_LAYOUT_VERSION;
        }
 
        if (ptlrpc_connection_is_local(exp->exp_connection))
index 8c1b21a..01cd637 100644 (file)
@@ -593,23 +593,15 @@ int ofd_object_ff_update(const struct lu_env *env, struct ofd_object *fo,
                       PFID(lu_object_fid(&fo->ofo_obj.do_lu)),
                       ff->ff_layout_version, oa->o_layout_version);
 
-               /* only the MDS has the authority to update layout version */
-               if (!(exp_connect_flags(ofd_info(env)->fti_exp) &
-                     OBD_CONNECT_MDS)) {
-                       CERROR(DFID": update layout version from client\n",
-                              PFID(&fo->ofo_ff.ff_parent));
-
-                       RETURN(-EPERM);
-               }
-
                if (ff->ff_layout_version & LU_LAYOUT_RESYNC) {
                        /* this opens a new era of writing */
                        ff->ff_layout_version = 0;
                        ff->ff_range = 0;
                }
 
-               /* it's not allowed to change it to a smaller value */
-               if (oa->o_layout_version < ff->ff_layout_version)
+               /*it's not allowed to change it to a smaller value */
+               if (ofd_layout_version_less(oa->o_layout_version,
+                                           ff->ff_layout_version))
                        RETURN(-EINVAL);
 
                if (ff->ff_layout_version == 0 ||
@@ -916,8 +908,6 @@ int ofd_object_punch(const struct lu_env *env, struct ofd_object *fo,
                rc = ofd_verify_layout_version(env, fo, oa);
                if (rc)
                        GOTO(unlock, rc);
-
-               oa->o_valid &= ~OBD_MD_LAYOUT_VERSION;
        }
 
        if (oa->o_valid & OBD_MD_FLFLAGS && oa->o_flags & LUSTRE_ENCRYPT_FL) {
index 92a9e1b..d49190a 100644 (file)
@@ -759,12 +759,6 @@ static int osp_sync_new_setattr_job(struct osp_device *d,
        else
                body->oa.o_valid |= rec->lsr_valid;
 
-       if (body->oa.o_valid & OBD_MD_LAYOUT_VERSION) {
-               OBD_FAIL_TIMEOUT(OBD_FAIL_FLR_LV_DELAY, cfs_fail_val);
-               if (unlikely(OBD_FAIL_CHECK(OBD_FAIL_FLR_LV_INC)))
-                       ++body->oa.o_layout_version;
-       }
-
        osp_sync_send_new_rpc(d, llh, h, req);
        RETURN(0);
 }
index 56c0932..a46aaee 100644 (file)
@@ -1292,16 +1292,30 @@ test_35() {
 }
 run_test 35 "allow to write to mirrored files"
 
+get_file_layout_version() {
+       local tf=$1
+       local flv=$($LFS getstripe $tf | awk '/lcm_layout_gen/{print $2}')
+
+       echo -n $flv
+}
+
+get_ost_layout_version() {
+       local tf=$1
+       local olv=$($MULTIOP $tf oXc | awk '/ostlayoutversion/{print $2}')
+
+       echo -n $flv
+}
+
 verify_ost_layout_version() {
        local tf=$1
 
        # get file layout version
-       local flv=$($LFS getstripe $tf | awk '/lcm_layout_gen/{print $2}')
+       local flv=$(get_file_layout_version $tf)
 
        # layout version from OST objects
-       local olv=$($MULTIOP $tf oXc | awk '/ostlayoutversion/{print $2}')
+       local olv=$(get_ost_layout_version $tf)
 
-       [ $flv -eq $olv ] || error "layout version mismatch: $flv vs. $olv"
+       (( flv >= olv )) || error "layout version mismatch: $flv vs. $olv"
 }
 
 create_file_36() {
@@ -1316,7 +1330,7 @@ create_file_36() {
        done
 }
 
-test_36() {
+test_36a() {
        local tf=$DIR/$tfile
 
        create_file_36 $tf $tf-2 $tf-3
@@ -1349,27 +1363,112 @@ test_36() {
        local st=$(date +%s)
        $MULTIOP $tf-2 oO_WRONLY:w1024Yc || error "write mirrored file error"
 
-       [ $(date +%s) -ge $((st+delay_sec)) ] ||
-               error "write finished before layout version is transmitted"
-
        # verify OST layout version
        verify_ost_layout_version $tf
 
        do_facet $mds_facet $LCTL set_param fail_loc=0
+}
+run_test 36a "write to mirrored files"
 
-       # test case 3
-       mds_idx=mds$(($($LFS getstripe -m $tf-3) + 1))
+test_36b() {
+       local tf=$DIR/$tfile
 
-       #define OBD_FAIL_FLR_LV_INC 0x1A02
-       do_facet $mds_facet $LCTL set_param fail_loc=0x1A02
+       (( OSTCOUNT < 2 )) && skip "need >= 2 OSTs" && return
 
-       # write open file should return error
-       $MULTIOP $tf-3 oO_WRONLY:O_SYNC:w1024c &&
-               error "write a mirrored file succeeded" || true
+       # create 2 mirrors using different OSTs
+       $LFS setstripe -N -c1 -i0 --flags=prefer -N -c1 -i1 $tf ||
+               error "create mirrored file"
 
-       do_facet $mds_facet $LCTL set_param fail_loc=0
+       # write 1M data to one mirror
+       dd if=/dev/zero of=$tf bs=1M count=1 || error "write file error"
+       sync
+
+       # set prefer mirror to another mirror
+       $LFS setstripe --comp-set -I0x10001 --comp-flags=^prefer $tf ||
+               error "clear prefer mirror error"
+       $LFS setstripe --comp-set -I0x20002 --comp-flags=prefer $tf ||
+               error "set prefer mirror error"
+
+       # the second write should not hung
+       dd if=/dev/zero of=$tf bs=1M count=1 || error "write file error"
+}
+run_test 36b "write should not hung when prefered mirror is stale"
+
+test_36c() {
+       local tf=$DIR/$tfile
+
+       (( OSTCOUNT < 2 )) && skip "need >= 2 OSTs" && return
+
+       # create 2 mirrors using different OSTs
+       $LFS setstripe -N -c1 -i0 --flags=prefer -N -c1 -i1 $tf ||
+               error "create mirrored file"
+
+       # write it in the background
+       dd if=/dev/zero of=$tf bs=1M count=600 &
+       local pid=$!
+
+       sleep 1
+
+       $LFS setstripe --comp-set -I0x10001 --comp-flags=^prefer $tf ||
+               error "clear prefer mirror error"
+       $LFS setstripe --comp-set -I0x20002 --comp-flags=prefer $tf ||
+               error "set prefer mirror error"
+
+       wait $pid
+}
+run_test 36c "change prefer mirror during write shouldn't hung"
+
+test_36d() {
+       local tf=$DIR/$tfile
+
+       echo " ** create $tf"
+       $LFS mirror create -N $tf || error "create $tf failed"
+
+       for i in 1 2; do
+               echo " ** mirror extend $tf"
+               $LFS mirror extend -N $tf || error "mirror extend $tf failed"
+               flv=$(get_file_layout_version $tf)
+               olv=$(get_ost_layout_version $tf)
+               echo "    flv=$flv olv=$olv"
+       done
+
+       for i in 1 2; do
+               echo " ** write $tf"
+               dd if=/dev/zero of=$tf bs=1k count=1 || error "write $tf failed"
+               flv=$(get_file_layout_version $tf)
+               olv=$(get_ost_layout_version $tf)
+               echo "    flv=$flv olv=$olv"
+               (( flv == olv )) ||
+                       error "write update OST layout failed $flv/$olv"
+       done
+
+       echo " ** resync $tf"
+       $LFS mirror resync $tf || error "mirror resync $tf failed"
+       flv=$(get_file_layout_version $tf)
+       olv=$(get_ost_layout_version $tf)
+       echo "    flv=$flv olv=$olv"
+
+       for i in 1 2; do
+               echo " ** truncate $tf"
+               $TRUNCATE $tf $((1024 * 1024)) || error "truncate $tf fails"
+               flv=$(get_file_layout_version $tf)
+               olv=$(get_ost_layout_version $tf)
+               echo "    flv=$flv olv=$olv"
+               (( flv == olv || flv == olv + 1 )) ||
+                       error "truncate update OST layout failed $flv/$olv"
+       done
+
+       for i in 1 2; do
+               echo " ** write $tf"
+               dd if=/dev/zero of=$tf bs=1k count=1 || error "write $tf failed"
+               flv=$(get_file_layout_version $tf)
+               olv=$(get_ost_layout_version $tf)
+               echo "    flv=$flv olv=$olv"
+               (( flv == olv )) ||
+                       error "write update OST layout failed $flv/$olv"
+       done
 }
-run_test 36 "write to mirrored files"
+run_test 36d "write/punch FLR file update OST layout version"
 
 create_files_37() {
        local tf
@@ -2399,6 +2498,8 @@ run_test 50A "mirror split update layout generation"
 test_50a() {
        $LCTL get_param osc.*.import | grep -q 'connect_flags:.*seek' ||
                skip "OST does not support SEEK_HOLE"
+       [ "$FSTYPE" != "zfs" ] ||
+               skip "lseek for ZFS is not accurate if obj is not committed"
 
        local file=$DIR/$tdir/$tfile
        local offset
@@ -2497,6 +2598,8 @@ run_test 50a "mirror extend/copy preserves sparseness"
 test_50b() {
        $LCTL get_param osc.*.import | grep -q 'connect_flags:.*seek' ||
                skip "OST does not support SEEK_HOLE"
+       [ "$FSTYPE" != "zfs" ] ||
+               skip "lseek for ZFS is not accurate if obj is not committed"
 
        local file=$DIR/$tdir/$tfile
        local offset