Whamcloud - gitweb
LU-13560 lod: set default LMV for "lfs mkdir -c 1" 90/45290/11
authorLai Siyao <lai.siyao@whamcloud.com>
Wed, 13 Oct 2021 05:55:15 +0000 (01:55 -0400)
committerOleg Drokin <green@whamcloud.com>
Thu, 6 Jan 2022 22:02:38 +0000 (22:02 +0000)
With the introduction of filesystem-wide default LMV, dirs will be
created on MDT by space usage, but if dir is created by
"lfs mkdir -c 1 ...", its subdirs should be kept on the same MDT.
To achieve this, set default LMV on such dirs, NB if user doesn't
want this, he needs to create dir with
"lfs mkdir -c 1 --max-inherit=0 ...".

The policy to choose MDT in mkdir is as below:
1. is "lfs mkdir -i N"? mkdir on MDT N.
2. is "lfs mkdir -i -1"? mkdir by space usage.
3. is starting MDT specified in default LMV? mkdir on MDT N.
4. is default LMV space balanced? mkdir by space usage.

Changes on server side:
* Don't inherit default LMV for "lfs mkdir".
* Don't migrate default LMV in dir migration/split.

Remove setting default LMV in mkdir_on_mdt().

Update sanity 412.

Signed-off-by: Lai Siyao <lai.siyao@whamcloud.com>
Change-Id: I0ffdcf7a4a85a31e2df788198aeb5e9a910160d8
Reviewed-on: https://review.whamcloud.com/45290
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Hongchao Zhang <hongchao@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/lmv/lmv_obd.c
lustre/lod/lod_object.c
lustre/mdd/mdd_dir.c
lustre/tests/sanity.sh
lustre/tests/test-framework.sh
lustre/utils/lfs.c

index 3e876f5..38a2c97 100644 (file)
@@ -1796,46 +1796,39 @@ int lmv_old_layout_lookup(struct lmv_obd *lmv, struct md_op_data *op_data)
        return rc;
 }
 
+/* mkdir by QoS upon 'lfs mkdir -i -1'.
+ *
+ * NB, mkdir by QoS only if parent is not striped, this is to avoid remote
+ * directories under striped directory.
+ */
 static inline bool lmv_op_user_qos_mkdir(const struct md_op_data *op_data)
 {
        const struct lmv_user_md *lum = op_data->op_data;
 
+       if (op_data->op_code != LUSTRE_OPC_MKDIR)
+               return false;
+
+       if (lmv_dir_striped(op_data->op_mea1))
+               return false;
+
        return (op_data->op_cli_flags & CLI_SET_MEA) && lum &&
               le32_to_cpu(lum->lum_magic) == LMV_USER_MAGIC &&
               le32_to_cpu(lum->lum_stripe_offset) == LMV_OFFSET_DEFAULT;
 }
 
+/* mkdir by QoS if either ROOT or parent default LMV is space balanced. */
 static inline bool lmv_op_default_qos_mkdir(const struct md_op_data *op_data)
 {
        const struct lmv_stripe_md *lsm = op_data->op_default_mea1;
 
-       return (op_data->op_flags & MF_QOS_MKDIR) ||
-              (lsm && lsm->lsm_md_master_mdt_index == LMV_OFFSET_DEFAULT);
-}
-
-/* mkdir by QoS in three cases:
- * 1. ROOT default LMV is space balanced.
- * 2. 'lfs mkdir -i -1'
- * 3. parent default LMV master_mdt_index is -1
- *
- * NB, mkdir by QoS only if parent is not striped, this is to avoid remote
- * directories under striped directory.
- */
-static inline bool lmv_op_qos_mkdir(const struct md_op_data *op_data)
-{
        if (op_data->op_code != LUSTRE_OPC_MKDIR)
                return false;
 
        if (lmv_dir_striped(op_data->op_mea1))
                return false;
 
-       if (lmv_op_user_qos_mkdir(op_data))
-               return true;
-
-       if (lmv_op_default_qos_mkdir(op_data))
-               return true;
-
-       return false;
+       return (op_data->op_flags & MF_QOS_MKDIR) ||
+              (lsm && lsm->lsm_md_master_mdt_index == LMV_OFFSET_DEFAULT);
 }
 
 /* if parent default LMV is space balanced, and
@@ -1879,6 +1872,38 @@ lmv_op_default_specific_mkdir(const struct md_op_data *op_data)
                        LMV_OFFSET_DEFAULT;
 }
 
+/* locate MDT by space usage */
+static struct lu_tgt_desc *lmv_locate_tgt_by_space(struct lmv_obd *lmv,
+                                                  struct md_op_data *op_data,
+                                                  struct lmv_tgt_desc *tgt)
+{
+       struct lmv_tgt_desc *tmp = tgt;
+
+       tgt = lmv_locate_tgt_qos(lmv, op_data->op_mds, op_data->op_dir_depth);
+       if (tgt == ERR_PTR(-EAGAIN)) {
+               if (ltd_qos_is_balanced(&lmv->lmv_mdt_descs) &&
+                   !lmv_op_default_rr_mkdir(op_data) &&
+                   !lmv_op_user_qos_mkdir(op_data))
+                       /* if not necessary, don't create remote directory. */
+                       tgt = tmp;
+               else
+                       tgt = lmv_locate_tgt_rr(lmv);
+       }
+
+       /*
+        * only update statfs after QoS mkdir, this means the cached statfs may
+        * be stale, and current mkdir may not follow QoS accurately, but it's
+        * not serious, and avoids periodic statfs when client doesn't mkdir by
+        * QoS.
+        */
+       if (!IS_ERR(tgt)) {
+               op_data->op_mds = tgt->ltd_index;
+               lmv_statfs_check_update(lmv2obd_dev(lmv), tgt);
+       }
+
+       return tgt;
+}
+
 int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
                const void *data, size_t datalen, umode_t mode, uid_t uid,
                gid_t gid, kernel_cap_t cap_effective, __u64 rdev,
@@ -1914,6 +1939,12 @@ int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
        if (IS_ERR(tgt))
                RETURN(PTR_ERR(tgt));
 
+       /* the order to apply policy in mkdir:
+        * 1. is "lfs mkdir -i N"? mkdir on MDT N.
+        * 2. is "lfs mkdir -i -1"? mkdir by space usage.
+        * 3. is starting MDT specified in default LMV? mkdir on MDT N.
+        * 4. is default LMV space balanced? mkdir by space usage.
+        */
        if (lmv_op_user_specific_mkdir(op_data)) {
                struct lmv_user_md *lum = op_data->op_data;
 
@@ -1921,39 +1952,20 @@ int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
                tgt = lmv_tgt(lmv, op_data->op_mds);
                if (!tgt)
                        RETURN(-ENODEV);
+       } else if (lmv_op_user_qos_mkdir(op_data)) {
+               tgt = lmv_locate_tgt_by_space(lmv, op_data, tgt);
+               if (IS_ERR(tgt))
+                       RETURN(PTR_ERR(tgt));
        } else if (lmv_op_default_specific_mkdir(op_data)) {
                op_data->op_mds =
                        op_data->op_default_mea1->lsm_md_master_mdt_index;
                tgt = lmv_tgt(lmv, op_data->op_mds);
                if (!tgt)
                        RETURN(-ENODEV);
-       } else if (lmv_op_qos_mkdir(op_data)) {
-               struct lmv_tgt_desc *tmp = tgt;
-
-               tgt = lmv_locate_tgt_qos(lmv, op_data->op_mds,
-                                        op_data->op_dir_depth);
-               if (tgt == ERR_PTR(-EAGAIN)) {
-                       if (ltd_qos_is_balanced(&lmv->lmv_mdt_descs) &&
-                           !lmv_op_default_rr_mkdir(op_data) &&
-                           !lmv_op_user_qos_mkdir(op_data))
-                               /* if it's not necessary, don't create remote
-                                * directory.
-                                */
-                               tgt = tmp;
-                       else
-                               tgt = lmv_locate_tgt_rr(lmv);
-               }
+       } else if (lmv_op_default_qos_mkdir(op_data)) {
+               tgt = lmv_locate_tgt_by_space(lmv, op_data, tgt);
                if (IS_ERR(tgt))
                        RETURN(PTR_ERR(tgt));
-
-               op_data->op_mds = tgt->ltd_index;
-               /*
-                * only update statfs after QoS mkdir, this means the cached
-                * statfs may be stale, and current mkdir may not follow QoS
-                * accurately, but it's not serious, and avoids periodic statfs
-                * when client doesn't mkdir by QoS.
-                */
-               lmv_statfs_check_update(obd, tgt);
        }
 
 retry:
index bf4a5bd..1003ad1 100644 (file)
@@ -4364,6 +4364,12 @@ static int lod_dir_striping_create_internal(const struct lu_env *env,
                        RETURN(rc);
        }
 
+       /* ldo_def_striping is not allocated, clear after use, in case directory
+        * layout is changed later.
+        */
+       if (!declare)
+               lo->ldo_def_striping = NULL;
+
        RETURN(0);
 }
 
@@ -5519,18 +5525,8 @@ static void lod_ah_init(const struct lu_env *env,
                        RETURN_EXIT;
                }
 
-               /*
-                * If parent object is not root directory,
-                * then get default striping from parent object.
-                */
-               if (likely(lp != NULL)) {
+               if (likely(lp != NULL))
                        lod_get_default_striping(env, lp, lds);
-                       /* inherit default striping except ROOT */
-                       if ((lds->lds_def_striping_set ||
-                            lds->lds_dir_def_striping_set) &&
-                           !fid_is_root(lod_object_fid(lp)))
-                               lc->ldo_def_striping = lds;
-               }
 
                /* It should always honour the specified stripes */
                /* Note: old client (< 2.7)might also do lfs mkdir, whose EA
@@ -5551,7 +5547,57 @@ static void lod_ah_init(const struct lu_env *env,
                                lc->ldo_dir_stripe_count,
                                (int)lc->ldo_dir_stripe_offset,
                                lc->ldo_dir_hash_type);
+
+                       if (d->lod_mdt_descs.ltd_lmv_desc.ld_active_tgt_count &&
+                           lc->ldo_dir_stripe_count < 2 &&
+                           lum1->lum_max_inherit != LMV_INHERIT_NONE) {
+                               /* when filesystem-wide default LMV is set, dirs
+                                * will be created on MDT by space usage, but if
+                                * dir is created with "lfs mkdir -c 1 ...", its
+                                * subdirs should be kept on the same MDT. To
+                                * guarantee this, set default LMV for such dir.
+                                */
+                               lds->lds_dir_def_stripe_count =
+                                       le32_to_cpu(lum1->lum_stripe_count);
+                               /* if "-1" stripe offset is set, save current
+                                * MDT index in default LMV.
+                                */
+                               if (le32_to_cpu(lum1->lum_stripe_offset) ==
+                                   LMV_OFFSET_DEFAULT)
+                                       lds->lds_dir_def_stripe_offset =
+                                               lod2lu_dev(d)->ld_site->ld_seq_site->ss_node_id;
+                               else
+                                       lds->lds_dir_def_stripe_offset =
+                                               le32_to_cpu(lum1->lum_stripe_offset);
+                               lds->lds_dir_def_hash_type =
+                                       le32_to_cpu(lum1->lum_hash_type);
+                               lds->lds_dir_def_max_inherit =
+                                       lum1->lum_max_inherit;
+                               /* it will be decreased by 1 later in setting */
+                               if (lum1->lum_max_inherit >= LMV_INHERIT_END &&
+                                   lum1->lum_max_inherit < LMV_INHERIT_MAX)
+                                       lds->lds_dir_def_max_inherit++;
+                               lds->lds_dir_def_max_inherit_rr =
+                                       lum1->lum_max_inherit_rr;
+                               lds->lds_dir_def_striping_set = 1;
+                               /* don't inherit LOV from ROOT */
+                               if (lds->lds_def_striping_set &&
+                                   fid_is_root(lod_object_fid(lp)))
+                                       lds->lds_def_striping_set = 0;
+                               lc->ldo_def_striping = lds;
+                       } else if (lds->lds_def_striping_set &&
+                                  !fid_is_root(lod_object_fid(lp))) {
+                               /* don't inherit default LMV for "lfs mkdir" */
+                               lds->lds_dir_def_striping_set = 0;
+                               lc->ldo_def_striping = lds;
+                       }
                } else {
+                       /* inherit default striping except ROOT */
+                       if ((lds->lds_def_striping_set ||
+                            lds->lds_dir_def_striping_set) &&
+                           !fid_is_root(lod_object_fid(lp)))
+                               lc->ldo_def_striping = lds;
+
                        /* transfer defaults LMV to new directory */
                        lod_striping_from_default(lc, lds, child_mode);
 
index 03b308d..7448147 100644 (file)
@@ -3414,13 +3414,14 @@ static inline void mdd_xattrs_fini(struct mdd_xattrs *xattrs)
        lu_buf_free(&xattrs->mx_namebuf);
 }
 
-/* read xattrs into buf, but ignore LMA, LMV, and LINKEA if 'skip_linkea' is
- * set.
+/* read xattrs into buf, but skip LMA, LMV, LINKEA if 'skip_linkea' is
+ * set, and DMV if 'skip_dmv" is set.
  */
 static int mdd_xattrs_migrate_prep(const struct lu_env *env,
                                   struct mdd_xattrs *xattrs,
                                   struct mdd_object *sobj,
-                                  bool skip_linkea)
+                                  bool skip_linkea,
+                                  bool skip_dmv)
 {
        struct mdd_xattr_entry *entry;
        char *xname;
@@ -3460,6 +3461,10 @@ static int mdd_xattrs_migrate_prep(const struct lu_env *env,
                    strcmp(XATTR_NAME_LINK, xname) == 0)
                        continue;
 
+               if (skip_dmv &&
+                   strcmp(XATTR_NAME_DEFAULT_LMV, xname) == 0)
+                       continue;
+
                xsize = mdo_xattr_get(env, sobj, &LU_BUF_NULL, xname);
                if (xsize == -ENODATA)
                        continue;
@@ -4326,7 +4331,7 @@ static int mdd_migrate_object(const struct lu_env *env,
         * RPCs inside transaction.
         */
        if (!spec->sp_migrate_nsonly) {
-               rc = mdd_xattrs_migrate_prep(env, &xattrs, sobj, false);
+               rc = mdd_xattrs_migrate_prep(env, &xattrs, sobj, true, true);
                if (rc)
                        GOTO(out, rc);
        }
@@ -4726,7 +4731,8 @@ int mdd_dir_layout_shrink(const struct lu_env *env,
                }
 
                if (!lmv_is_fixed(lmv))
-                       rc = mdd_xattrs_migrate_prep(env, &xattrs, obj, true);
+                       rc = mdd_xattrs_migrate_prep(env, &xattrs, obj, false,
+                                                    false);
        }
 
        handle = mdd_trans_create(env, mdd);
@@ -4816,6 +4822,8 @@ static int mdd_dir_declare_split_plain(const struct lu_env *env,
 
        count = lum->lum_stripe_count;
        lum->lum_stripe_count = 0;
+       /* don't set default LMV since it will become a striped dir  */
+       lum->lum_max_inherit = LMV_INHERIT_NONE;
        mdd_object_make_hint(env, pobj, tobj, mlc->mlc_attr, mlc->mlc_spec,
                             hint);
        rc = mdd_declare_create(env, mdo2mdd(&pobj->mod_obj), pobj, tobj,
@@ -4992,7 +5000,7 @@ int mdd_dir_layout_split(const struct lu_env *env, struct md_object *o,
 
        mdd_xattrs_init(&xattrs);
        if (is_plain)
-               rc = mdd_xattrs_migrate_prep(env, &xattrs, obj, true);
+               rc = mdd_xattrs_migrate_prep(env, &xattrs, obj, true, true);
 
        handle = mdd_trans_create(env, mdd);
        if (IS_ERR(handle))
index 1ae0337..914c4a3 100755 (executable)
@@ -25081,10 +25081,9 @@ test_411() {
 run_test 411 "Slab allocation error with cgroup does not LBUG"
 
 test_412() {
-       [ $MDSCOUNT -lt 2 ] && skip_env "needs >= 2 MDTs"
-       if [ $MDS1_VERSION -lt $(version_code 2.10.55) ]; then
+       (( $MDSCOUNT > 1 )) || skip_env "needs >= 2 MDTs"
+       (( $MDS1_VERSION >= $(version_code 2.10.55) )) ||
                skip "Need server version at least 2.10.55"
-       fi
 
        $LFS mkdir -i $((MDSCOUNT - 1)),$((MDSCOUNT - 2)) $DIR/$tdir ||
                error "mkdir failed"
@@ -25095,6 +25094,47 @@ test_412() {
        local stripe_count=$($LFS getdirstripe -T $DIR/$tdir)
        [ $stripe_count -eq 2 ] ||
                error "expect 2 get $stripe_count"
+
+       (( $MDS1_VERSION >= $(version_code 2.14.55) )) || return 0
+
+       local index
+       local index2
+
+       # subdirs should be on the same MDT as parent
+       for i in $(seq 0 $((MDSCOUNT - 1))); do
+               $LFS mkdir -i $i $DIR/$tdir/mdt$i || error "mkdir mdt$i failed"
+               mkdir $DIR/$tdir/mdt$i/sub || error "mkdir sub failed"
+               index=$($LFS getstripe -m $DIR/$tdir/mdt$i/sub)
+               (( index == i )) || error "mdt$i/sub on MDT$index"
+       done
+
+       # stripe offset -1, ditto
+       for i in {1..10}; do
+               $LFS mkdir -i -1 $DIR/$tdir/qos$i || error "mkdir qos$i failed"
+               index=$($LFS getstripe -m $DIR/$tdir/qos$i)
+               mkdir $DIR/$tdir/qos$i/sub || error "mkdir sub failed"
+               index2=$($LFS getstripe -m $DIR/$tdir/qos$i/sub)
+               (( index == index2 )) ||
+                       error "qos$i on MDT$index, sub on MDT$index2"
+       done
+
+       local testdir=$DIR/$tdir/inherit
+
+       $LFS mkdir -i 1 --max-inherit=3 $testdir || error "mkdir inherit failed"
+       # inherit 2 levels
+       for i in 1 2; do
+               testdir=$testdir/s$i
+               mkdir $testdir || error "mkdir $testdir failed"
+               index=$($LFS getstripe -m $testdir)
+               (( index == 1 )) ||
+                       error "$testdir on MDT$index"
+       done
+
+       # not inherit any more
+       testdir=$testdir/s3
+       mkdir $testdir || error "mkdir $testdir failed"
+       getfattr -d -m dmv $testdir | grep dmv &&
+               error "default LMV set on $testdir" || true
 }
 run_test 412 "mkdir on specific MDTs"
 
index 636a7ca..22d914c 100755 (executable)
@@ -10643,8 +10643,6 @@ mkdir_on_mdt() {
        shift $((OPTIND - 1))
 
        $LFS mkdir -i $mdt -c 1 $*
-       # setting default LMV in non-DNE system will cause sanity-quota 41 fail
-       ((MDSCOUNT < 2)) || $LFS setdirstripe -D -i $mdt -c 1 $*
 }
 
 mkdir_on_mdt0() {
index 96ff2f4..c4ee1f1 100644 (file)
@@ -6767,12 +6767,6 @@ static int lfs_setdirstripe(int argc, char **argv)
                        xattr = optarg;
                        break;
                case 'X':
-                       if (!default_stripe) {
-                               fprintf(stderr,
-                                       "%s %s: '--max-inherit' must be specified with '-D'\n",
-                                       progname, argv[0]);
-                               return CMD_HELP;
-                       }
                        errno = 0;
                        max_inherit = strtol(optarg, &end, 10);
                        if (errno != 0 || *end != '\0' || max_inherit < -2) {
@@ -6944,12 +6938,12 @@ static int lfs_setdirstripe(int argc, char **argv)
                param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
        param->lsp_pool = lsa.lsa_pool_name;
        param->lsp_is_specific = false;
+       if (max_inherit == LAYOUT_INHERIT_UNSET)
+               max_inherit = LMV_INHERIT_DEFAULT;
+       param->lsp_max_inherit = max_inherit;
        if (default_stripe) {
-               if (max_inherit == LAYOUT_INHERIT_UNSET)
-                       max_inherit = LMV_INHERIT_DEFAULT;
                if (max_inherit_rr == LAYOUT_INHERIT_UNSET)
                        max_inherit_rr = LMV_INHERIT_RR_DEFAULT;
-               param->lsp_max_inherit = max_inherit;
                param->lsp_max_inherit_rr = max_inherit_rr;
        }
        if (strcmp(argv[0], "mkdir") == 0)