Whamcloud - gitweb
LU-12273 lod: metadata overstriping
authorPatrick Farrell <pfarrell@whamcloud.com>
Thu, 19 Jan 2023 20:05:38 +0000 (15:05 -0500)
committerAndreas Dilger <adilger@whamcloud.com>
Mon, 13 May 2024 22:36:34 +0000 (22:36 +0000)
This adds overstriping for MDTs, similar to overstriping
for OSTs (added in LU-9846).  This adds a new option to
setdirstripe, -C, allowing creation of more than one stripe
per MDT.  It is also possible to place multiple stripes on
the same MDT using specific striping with -m.

This allows a single directory to more fully use the full
capability of each MDT in the file system.

Two limitations of note:
1. This requires > 1 MDT, otherwise the DNE subsystem is
not initialized.
2. Due to recovery limitations, we allow a max of only 5
stripes per MDT.

MDT overstriping increases mdtest-hard-write performance by
up to 13%, mdtest-hard-stat by 93%, at the cost of a slight
drop in mdtest-hard-read (7%), with no change in delete.

4 MDTs, 1 stripe/MDT:
mdtest-hard-write      117.399467 kIOPS : time 339.496 seconds
mdtest-hard-stat      727.020749 kIOPS : time 55.666 seconds
mdtest-hard-read      245.556392 kIOPS : time 162.897 seconds
mdtest-hard-delete      104.379111 kIOPS : time 382.710 seconds

4 MDTs, 4 stripes/MDTs:
mdtest-hard-write      132.963290 kIOPS : time 309.093 seconds
mdtest-hard-stat     1408.161148 kIOPS : time 30.107 seconds
mdtest-hard-read      229.383910 kIOPS : time 179.576 seconds
mdtest-hard-delete      103.284369 kIOPS : time 398.442 seconds

Lustre-change: https://review.whamcloud.com/35034
Lustre-commit: 81ac7c0c989dd862e2215a4635c77e5123289658

Signed-off-by: Patrick Farrell <pfarrell@whamcloud.com>
Signed-off-by: Qian Yingjin <qian@ddn.com>
Signed-off-by: Lai Siyao <lai.siyao@whamcloud.com>
Change-Id: I11556b223029820bd335e87c7bf073970e03468d
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/c/ex/lustre-release/+/53570
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
20 files changed:
lustre/doc/lfs-getdirstripe.1
lustre/doc/lfs-setdirstripe.1
lustre/include/lustre_net.h
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/lod/lod_internal.h
lustre/lod/lod_object.c
lustre/lod/lod_qos.c
lustre/lod/lproc_lod.c
lustre/mdt/mdt_handler.c
lustre/mdt/mdt_recovery.c
lustre/mdt/mdt_xattr.c
lustre/ptlrpc/layout.c
lustre/ptlrpc/service.c
lustre/ptlrpc/wiretest.c
lustre/tests/sanity.sh
lustre/tests/test-framework.sh
lustre/utils/lfs.c
lustre/utils/liblustreapi.c
lustre/utils/wirecheck.c
lustre/utils/wiretest.c

index 6045bbb..380b69c 100644 (file)
@@ -18,7 +18,8 @@ Only show the number of MDTs the directory is striped across.
 Show the default layout used when creating new subdirectories.
 .TP
 .BR \-H ", " \-\-mdt-hash
-Only show the hash function being used for this directory.
+Only show the hash function being used for this directory.  Also shows hash
+flags, such as overstriping (>1 stripe per MDT).
 .TP
 .BR \-i ", " \-m ", " \-\-mdt-index
 Only show the master MDT index of the directory.
index 08e36ae..4be03c1 100644 (file)
@@ -2,7 +2,7 @@
 .SH NAME
 lfs setdirstripe, mkdir \- set striping pattern of a directory.
 .SH SYNOPSIS
-.B lfs setdirstripe [\fR-cdDHioTxX\fR] \fIDIR\fR...
+.B lfs setdirstripe [\fR-cCdDHioTxX\fR] \fIDIR\fR...
 .br
 .SH DESCRIPTION
 Create a striped directory with specified striping pattern. This
@@ -25,6 +25,12 @@ Stripe the new directory over
 .I COUNT
 MDTs.
 .TP
+.B -C\fR, \fB--overstripe-count \fISTRIPE_COUNT\fR
+The number of stripes to create, creating > 1 stripe MDT if \fISTRIPE_COUNT\fR
+exceeds the number of MDTs in the file system. \fB0 \fRmeans to use the
+filesystem-wide default stripe count (default 1), and \fB-1 \fRmeans to stripe
+over all available MDTs.  Max of 5 stripes/MDT.
+.TP
 .BR \-i ", " \-\-mdt\-index =\fISTART_MDT_INDEX\fR[,\fIMDT_INDEX ...]
 Use the MDT whose index is
 .I START_MDT_INDEX
index 38b0376..b306a44 100644 (file)
@@ -628,8 +628,12 @@ struct ptlrpc_cb_id {
        void *cbid_arg;                         /* additional arg */
 };
 
-/** Maximum number of locks to fit into reply state */
-#define RS_MAX_LOCKS 8
+/** Maximum number of locks to fit into reply state, migrating directory max
+ * stripe count is 2 * LMV_MAX_STRIPES_PER_MDT, plus source parent, target
+ * parent, source and target master object:
+ *     2 * LMV_MAX_STRIPES_PER_MDT + 4
+ */
+#define RS_MAX_LOCKS 14
 #define RS_DEBUG     0
 
 /**
@@ -702,8 +706,6 @@ struct ptlrpc_reply_state {
 
        /** Handles of locks awaiting client reply ACK */
        struct lustre_handle    rs_locks[RS_MAX_LOCKS];
-       /** Lock modes of locks in \a rs_locks */
-       enum ldlm_mode          rs_modes[RS_MAX_LOCKS];
 };
 
 struct ptlrpc_thread;
@@ -2196,7 +2198,7 @@ struct ptlrpc_service_conf {
  * @{
  */
 void ptlrpc_save_lock(struct ptlrpc_request *req, struct lustre_handle *lock,
-                     int mode, bool no_ack, bool convert_lock);
+                     bool no_ack, bool convert_lock);
 void ptlrpc_commit_replies(struct obd_export *exp);
 void ptlrpc_dispatch_difficult_reply(struct ptlrpc_reply_state *rs);
 void ptlrpc_schedule_difficult_reply(struct ptlrpc_reply_state *rs);
index 5ed032f..20cbfcd 100644 (file)
@@ -1102,6 +1102,8 @@ static inline bool lmv_is_known_hash_type(__u32 type)
               (type & LMV_HASH_TYPE_MASK) == LMV_HASH_TYPE_CRUSH;
 }
 
+/* This flag indicates that overstriping (>1 stripe per MDT) is desired */
+#define LMV_HASH_FLAG_OVERSTRIPED      0x01000000
 /* fixed layout, such directories won't split automatically */
 /* NB, update LMV_HASH_FLAG_KNOWN when adding new flag */
 #define LMV_HASH_FLAG_FIXED            0x02000000
@@ -1119,7 +1121,7 @@ static inline bool lmv_is_known_hash_type(__u32 type)
 #define LMV_HASH_FLAG_LAYOUT_CHANGE    \
        (LMV_HASH_FLAG_MIGRATION | LMV_HASH_FLAG_SPLIT | LMV_HASH_FLAG_MERGE)
 
-#define LMV_HASH_FLAG_KNOWN            0xbe000000
+#define LMV_HASH_FLAG_KNOWN            0xbf000000
 
 /* migration failure may leave hash type as
  * LMV_HASH_TYPE_UNKNOWN|LMV_HASH_FLAG_BAD_TYPE, which should be treated as
@@ -1191,6 +1193,7 @@ extern struct lustre_foreign_type lu_foreign_types[];
 /* Got this according to how get LOV_MAX_STRIPE_COUNT, see above,
  * (max buffer size - lmv+rpc header) / sizeof(struct lmv_user_mds_data) */
 #define LMV_MAX_STRIPE_COUNT 2000  /* ((12 * 4096 - 256) / 24) */
+#define LMV_MAX_STRIPES_PER_MDT 5 /* (RS_MAX_LOCKS - 4) / 2 */
 #define lmv_user_md lmv_user_md_v1
 struct lmv_user_md_v1 {
        __u32   lum_magic;         /* must be the first field */
@@ -1236,7 +1239,9 @@ enum {
        LMV_INHERIT_DEFAULT_PLAIN       = LMV_INHERIT_UNLIMITED,
        /* not inherit any more */
        LMV_INHERIT_END                 = 1,
-       /* for multiple stripes, the default lum_max_inherit is 3 */
+       /* for overstriped dirs, the default limit is 1 level of inheritance */
+       LMV_INHERIT_DEFAULT_OVERSTRIPED = 2,
+       /* for multiple stripes, the default limit is 2 levels of inheritance*/
        LMV_INHERIT_DEFAULT_STRIPED     = 3,
        /* max inherit depth */
        LMV_INHERIT_MAX                 = 250,
index 6a5db6e..898ad68 100644 (file)
@@ -163,6 +163,7 @@ struct lod_device {
 
        /* max stripe count if stripe count is set to -1. 0 means unlimited */
        unsigned int            lod_max_stripecount;
+       unsigned int            lod_max_mdt_stripecount;
 };
 
 #define lod_ost_bitmap         lod_ost_descs.ltd_tgt_bitmap
index 45f4bd4..54bd74b 100644 (file)
@@ -2098,11 +2098,17 @@ static int lod_mdt_alloc_specific(const struct lu_env *env,
                        bool already_allocated = false;
                        __u32 k;
 
-                       CDEBUG(D_INFO, "try idx %d, mdt cnt %u, allocated %u\n",
-                              idx, lod->lod_remote_mdt_count + 1, stripe_idx);
+                       CDEBUG(D_INFO,
+                              "try idx %d, mdt cnt %u, allocated %u, specific %d count %hu offset %d hash %#X\n",
+                              idx, lod->lod_remote_mdt_count + 1, stripe_idx,
+                              is_specific, lo->ldo_dir_stripe_count,
+                              (int)lo->ldo_dir_stripe_offset,
+                              lo->ldo_dir_hash_type);
 
                        if (likely(!is_specific &&
-                                  !OBD_FAIL_CHECK(OBD_FAIL_LARGE_STRIPE))) {
+                                  !CFS_FAIL_CHECK(OBD_FAIL_LARGE_STRIPE) &&
+                                  !(lo->ldo_dir_hash_type &
+                                    LMV_HASH_FLAG_OVERSTRIPED))) {
                                /* check whether the idx already exists
                                 * in current allocated array */
                                for (k = 0; k < stripe_idx; k++) {
@@ -2218,6 +2224,7 @@ static int lod_prep_md_striped_create(const struct lu_env *env,
        struct dt_object **stripes;
        struct lu_object_conf conf = { .loc_flags = LOC_F_NEW };
        struct lu_fid fid = { 0 };
+       int mdt_count = lod->lod_remote_mdt_count + 1;
        __u32 stripe_count;
        int i;
        int rc = 0;
@@ -2229,6 +2236,17 @@ static int lod_prep_md_striped_create(const struct lu_env *env,
                le32_to_cpu(lum->lum_magic) == LMV_USER_MAGIC_SPECIFIC);
 
        stripe_count = lo->ldo_dir_stripe_count;
+       if (!(lo->ldo_dir_hash_type & LMV_HASH_FLAG_OVERSTRIPED) &&
+           stripe_count > mdt_count)
+               RETURN(-E2BIG);
+
+       if ((lo->ldo_dir_hash_type & LMV_HASH_FLAG_OVERSTRIPED) &&
+           (stripe_count > mdt_count * LMV_MAX_STRIPES_PER_MDT ||
+       /* a single MDT doesn't initialize the infrastructure for striped
+        * directories, so we just don't support overstriping in that case
+        */
+                  mdt_count == 1))
+               RETURN(-E2BIG);
 
        OBD_ALLOC_PTR_ARRAY(stripes, stripe_count);
        if (!stripes)
@@ -2259,7 +2277,23 @@ static int lod_prep_md_striped_create(const struct lu_env *env,
                        GOTO(out, rc = -ENOMEM);
 
                if (le32_to_cpu(lum->lum_magic) == LMV_USER_MAGIC_SPECIFIC) {
+                       int stripes_per_mdt;
+                       int mdt;
+
                        is_specific = true;
+
+                       /* Verify we do not exceed the stripes per MDT limit */
+                       for (mdt = 0; mdt < mdt_count + 1; mdt++) {
+                               stripes_per_mdt = 0;
+                               for (i = 0; i < stripe_count; i++) {
+                                       if (mdt == le32_to_cpu(
+                                           lum->lum_objects[i].lum_mds))
+                                               stripes_per_mdt++;
+                               }
+                               if (stripes_per_mdt > LMV_MAX_STRIPES_PER_MDT)
+                                       GOTO(out_free, rc = -EINVAL);
+                       }
+
                        for (i = 0; i < stripe_count; i++)
                                idx_array[i] =
                                       le32_to_cpu(lum->lum_objects[i].lum_mds);
@@ -2270,6 +2304,7 @@ static int lod_prep_md_striped_create(const struct lu_env *env,
                        lu_site2seq(lod2lu_dev(lod)->ld_site)->ss_node_id;
                rc = lod_mdt_alloc_specific(env, lo, stripes, idx_array,
                                            is_specific);
+out_free:
                OBD_FREE_PTR_ARRAY(idx_array, stripe_count);
        }
 
@@ -5466,6 +5501,7 @@ static void lod_ah_init(const struct lu_env *env,
 
        if (S_ISDIR(child_mode)) {
                const struct lmv_user_md_v1 *lum1 = ah->dah_eadata;
+               int max_stripe_count;
 
                /* other default values are 0 */
                lc->ldo_dir_stripe_offset = -1;
@@ -5562,10 +5598,22 @@ static void lod_ah_init(const struct lu_env *env,
                                lc->ldo_dir_stripe_count = 0;
                }
 
-               /* shrink the stripe_count to the avaible MDT count */
-               if (lc->ldo_dir_stripe_count > d->lod_remote_mdt_count + 1 &&
-                   !OBD_FAIL_CHECK(OBD_FAIL_LARGE_STRIPE)) {
-                       lc->ldo_dir_stripe_count = d->lod_remote_mdt_count + 1;
+               /* shrink the stripe count to max_mdt_stripecount if it is -1
+                * and max_mdt_stripecount is not 0
+                */
+               if (lc->ldo_dir_stripe_count == (__u16)(-1) &&
+                   d->lod_max_mdt_stripecount)
+                       lc->ldo_dir_stripe_count = d->lod_max_mdt_stripecount;
+
+               max_stripe_count = d->lod_remote_mdt_count + 1;
+               if (lc->ldo_dir_hash_type & LMV_HASH_FLAG_OVERSTRIPED)
+                       max_stripe_count =
+                               max_stripe_count * LMV_MAX_STRIPES_PER_MDT;
+
+               /* shrink the stripe_count to max stripe count */
+               if (lc->ldo_dir_stripe_count > max_stripe_count &&
+                   !CFS_FAIL_CHECK(OBD_FAIL_LARGE_STRIPE)) {
+                       lc->ldo_dir_stripe_count = max_stripe_count;
                        if (lc->ldo_dir_stripe_count == 1)
                                lc->ldo_dir_stripe_count = 0;
                }
@@ -5583,7 +5631,7 @@ static void lod_ah_init(const struct lu_env *env,
                        lc->ldo_def_striping = lds;
                }
 
-               CDEBUG(D_INFO, "final dir stripe [%hu %d %u]\n",
+               CDEBUG(D_INFO, "final dir stripe_count=%hu offset=%d hash=%x\n",
                       lc->ldo_dir_stripe_count,
                       (int)lc->ldo_dir_stripe_offset, lc->ldo_dir_hash_type);
 
@@ -8688,6 +8736,7 @@ static int lod_dir_declare_layout_split(const struct lu_env *env,
        struct dt_object_format *dof = &info->lti_format;
        struct lmv_user_md_v1 *lum = mlc->mlc_spec->u.sp_ea.eadata;
        struct dt_object **stripes;
+       int mdt_count = lod->lod_remote_mdt_count + 1;
        u32 stripe_count;
        u32 saved_count;
        int i;
@@ -8703,6 +8752,29 @@ static int lod_dir_declare_layout_split(const struct lu_env *env,
        if (stripe_count <= saved_count)
                RETURN(-EINVAL);
 
+       /* if the split target is overstriped, we need to put that flag in the
+        * current layout so it can allocate the larger number of stripes
+        *
+        * Note we need to pick up any hash *flags* which affect allocation
+        * *before* allocation, so they're used in allocating the directory,
+        * rather than after when we finalize directory setup (at the end of
+        * this function).
+        */
+       if (le32_to_cpu(lum->lum_hash_type) & LMV_HASH_FLAG_OVERSTRIPED)
+               lo->ldo_dir_hash_type |= LMV_HASH_FLAG_OVERSTRIPED;
+
+       if (!(lo->ldo_dir_hash_type & LMV_HASH_FLAG_OVERSTRIPED) &&
+           stripe_count > mdt_count) {
+               RETURN(-E2BIG);
+       } else if ((lo->ldo_dir_hash_type & LMV_HASH_FLAG_OVERSTRIPED) &&
+                  (stripe_count > mdt_count * LMV_MAX_STRIPES_PER_MDT ||
+       /* a single MDT doesn't initialize the infrastructure for striped
+        * directories, so we just don't support overstriping in that case
+        */
+                  mdt_count == 1)) {
+               RETURN(-E2BIG);
+       }
+
        dof->dof_type = DFT_DIR;
 
        OBD_ALLOC(stripes, sizeof(*stripes) * stripe_count);
@@ -8713,6 +8785,7 @@ static int lod_dir_declare_layout_split(const struct lu_env *env,
                stripes[i] = lo->ldo_stripe[i];
 
        lod_qos_statfs_update(env, lod, &lod->lod_mdt_descs);
+
        rc = lod_mdt_alloc_qos(env, lo, stripes, saved_count, stripe_count);
        if (rc == -EAGAIN)
                rc = lod_mdt_alloc_rr(env, lo, stripes, saved_count,
index e07c8ad..27e2077 100644 (file)
@@ -935,15 +935,16 @@ int lod_mdt_alloc_rr(const struct lu_env *env, struct lod_object *lo,
        struct lu_tgt_descs *ltd = &lod->lod_mdt_descs;
        struct lu_tgt_pool *pool;
        struct lu_qos_rr *lqr;
-       struct lu_tgt_desc *mdt;
        struct lu_object_conf conf = { .loc_flags = LOC_F_NEW };
        struct lu_fid fid = { 0 };
        struct dt_object *dto;
        unsigned int pool_idx;
        unsigned int i;
        u32 saved_idx = stripe_idx;
+       int stripes_per_mdt = 1;
        u32 mdt_idx;
        bool use_degraded = false;
+       bool overstriped = false;
        int tgt_connecting = 0;
        int rc;
 
@@ -955,6 +956,14 @@ int lod_mdt_alloc_rr(const struct lu_env *env, struct lod_object *lo,
        if (rc)
                RETURN(rc);
 
+       overstriped = lo->ldo_dir_hash_type & LMV_HASH_FLAG_OVERSTRIPED;
+
+       if (stripe_count > lod->lod_remote_mdt_count + 1 && !overstriped)
+               RETURN(-E2BIG);
+
+       if (lo->ldo_dir_hash_type & LMV_HASH_FLAG_OVERSTRIPED)
+               stripes_per_mdt = stripe_count / (pool->op_count + 1);
+
        rc = lod_qos_mdt_in_use_init(env, ltd, stripe_idx, stripe_count, pool,
                                     stripes);
        if (rc)
@@ -971,7 +980,8 @@ int lod_mdt_alloc_rr(const struct lu_env *env, struct lod_object *lo,
        } else if (atomic_read(&lqr->lqr_start_idx) >= pool->op_count) {
                /* If we have allocated from all of the tgts, slowly
                 * precess the next start if the tgt/stripe count isn't
-                * already doing this for us. */
+                * already doing this for us.
+                */
                atomic_sub(pool->op_count, &lqr->lqr_start_idx);
                if (stripe_count - 1 > 1 &&
                    (pool->op_count % (stripe_count - 1)) != 1)
@@ -980,65 +990,111 @@ int lod_mdt_alloc_rr(const struct lu_env *env, struct lod_object *lo,
        spin_unlock(&lqr->lqr_alloc);
 
 repeat_find:
-       QOS_DEBUG("want=%d start_idx=%d start_count=%d offset=%d active=%d count=%d\n",
-                 stripe_count - 1, atomic_read(&lqr->lqr_start_idx),
-                 lqr->lqr_start_count, lqr->lqr_offset_idx, pool->op_count,
-                 pool->op_count);
-
-       for (i = 0; i < pool->op_count && stripe_idx < stripe_count; i++) {
+       CDEBUG(D_OTHER,
+              "want=%d start_idx=%d start_count=%d offset=%d active=%d count=%d\n",
+              stripe_count - 1, atomic_read(&lqr->lqr_start_idx),
+              lqr->lqr_start_count, lqr->lqr_offset_idx,
+              /* if we're overstriped, the local MDT is available and is
+               * included in the count
+               */
+              pool->op_count + overstriped,
+              lqr->lqr_pool.op_count + overstriped);
+
+       for (i = 0; i < (pool->op_count + overstriped) * stripes_per_mdt &&
+            stripe_idx < stripe_count; i++) {
+               struct lu_tgt_desc *mdt = NULL;
+               struct dt_device *mdt_tgt;
+               bool local_alloc = false;
                int idx;
 
                idx = atomic_inc_return(&lqr->lqr_start_idx);
                pool_idx = (idx + lqr->lqr_offset_idx) %
-                           pool->op_count;
-               mdt_idx = lqr->lqr_pool.op_array[pool_idx];
-               mdt = LTD_TGT(ltd, mdt_idx);
+                           (pool->op_count + overstriped);
+               /* in the overstriped case, we must be able to allocate a stripe
+                * to the local MDT, ie, the one doing the allocation
+                */
+               if (pool_idx == pool->op_count) {
+                       LASSERT(overstriped);
+                       /* because there is already a stripe on the local MDT,
+                        * do not allocate from the local MDT until we've
+                        * allocated at least as many stripes as we have MDTs
+                        */
+                       if (stripe_idx < (pool->op_count + 1)) {
+                               CDEBUG(D_OTHER,
+                                      "Skipping local alloc, not enough stripes yet\n");
+                               continue;
+                       }
+                       CDEBUG(D_OTHER, "Attempting to allocate locally\n");
+                       local_alloc = true;
+                       mdt_tgt = lod->lod_child;
+                       rc = lodname2mdt_index(lod2obd(lod)->obd_name,
+                                              &mdt_idx);
+                       /* this parsing can't fail here because we're working
+                        * with a known-good MDT
+                        */
+                       LASSERT(!rc);
+               } else {
+                       mdt_idx = lqr->lqr_pool.op_array[pool_idx];
+                       mdt = LTD_TGT(ltd, mdt_idx);
+                       mdt_tgt = mdt->ltd_tgt;
+               }
 
                QOS_DEBUG("#%d strt %d act %d strp %d ary %d idx %d\n",
                          i, idx, /* XXX: active*/ 0,
                          stripe_idx, pool_idx, mdt_idx);
 
-               if (mdt_idx == LOV_QOS_EMPTY ||
-                   !test_bit(mdt_idx, ltd->ltd_tgt_bitmap))
-                       continue;
-
-               /* do not put >1 objects on one MDT */
-               if (lod_qos_is_tgt_used(env, mdt_idx, stripe_idx))
-                       continue;
-
-               if (mdt->ltd_discon) {
-                       tgt_connecting = 1;
+               if (!local_alloc &&  (mdt_idx == LOV_QOS_EMPTY ||
+                   !test_bit(mdt_idx, ltd->ltd_tgt_bitmap))) {
+                       CDEBUG(D_OTHER, "mdt_idx not found %d\n", mdt_idx);
                        continue;
                }
 
-               if (lod_statfs_check(ltd, mdt))
-                       continue;
+               /* do not put >1 objects on one MDT, except for overstriping */
+               if (!local_alloc) {
+                       if (lo->ldo_dir_hash_type & LMV_HASH_FLAG_OVERSTRIPED) {
+                               CDEBUG(D_OTHER, "overstriped\n");
+                       } else if (lod_qos_is_tgt_used(env, mdt_idx,
+                                                      stripe_idx)) {
+                               CDEBUG(D_OTHER, "#%d: already used\n", mdt_idx);
+                               continue;
+                       }
+               }
 
-               if (mdt->ltd_statfs.os_state & OS_STATFS_NOCREATE)
-                       continue;
+               /* we know the local MDT is usable */
+               if (!local_alloc) {
+                       if (mdt->ltd_discon) {
+                               tgt_connecting = 1;
+                               CDEBUG(D_OTHER, "#%d: unusable\n", mdt_idx);
+                               continue;
+                       }
+                       if (lod_statfs_check(ltd, mdt))
+                               continue;
+                       if (mdt->ltd_statfs.os_state & OS_STATFS_NOCREATE)
+                               continue;
+               }
 
                /* try to use another OSP if this one is degraded */
-               if (mdt->ltd_statfs.os_state & OS_STATFS_DEGRADED &&
-                   !use_degraded) {
-                       QOS_DEBUG("#%d: degraded\n", mdt_idx);
+               if (!local_alloc && !use_degraded &&
+                   mdt->ltd_statfs.os_state & OS_STATFS_DEGRADED) {
+                       CDEBUG(D_OTHER, "#%d: degraded\n", mdt_idx);
                        continue;
                }
 
-               rc = dt_fid_alloc(env, mdt->ltd_tgt, &fid, NULL, NULL);
+               rc = dt_fid_alloc(env, mdt_tgt, &fid, NULL, NULL);
                if (rc < 0) {
                        QOS_DEBUG("#%d: alloc FID failed: %dl\n", mdt_idx, rc);
                        continue;
                }
 
-               dto = dt_locate_at(env, mdt->ltd_tgt, &fid,
+               dto = dt_locate_at(env, mdt_tgt, &fid,
                                lo->ldo_obj.do_lu.lo_dev->ld_site->ls_top_dev,
                                &conf);
 
                if (IS_ERR(dto)) {
-                       QOS_DEBUG("can't alloc stripe on #%u: %d\n",
-                                 mdt->ltd_index, (int) PTR_ERR(dto));
+                       CDEBUG(D_OTHER, "can't alloc stripe on #%u: %d\n",
+                              mdt_idx, (int) PTR_ERR(dto));
 
-                       if (mdt->ltd_discon)
+                       if (!local_alloc && mdt->ltd_discon)
                                tgt_connecting = 1;
                        continue;
                }
@@ -1056,9 +1112,15 @@ repeat_find:
        }
        up_read(&ltd->ltd_qos.lq_rw_sem);
 
-       if (stripe_idx > saved_idx)
+       if (stripe_idx > saved_idx) {
+               /* If there are enough MDTs, we will not actually do
+                * overstriping, and the hash flags should reflect this.
+                */
+               if (!overstriped)
+                       lo->ldo_dir_hash_type &= ~LMV_HASH_FLAG_OVERSTRIPED;
                /* at least one stripe is allocated */
                RETURN(stripe_idx);
+       }
 
        /* nobody provided us with a single object */
        if (tgt_connecting)
@@ -1837,6 +1899,16 @@ int lod_mdt_alloc_qos(const struct lu_env *env, struct lod_object *lo,
        if (stripe_idx == stripe_count)
                RETURN(stripe_count);
 
+       /* we do not use qos for overstriping, since it will always use all the
+        * MDTs.  So we check if it's truly needed, falling back to rr if it is,
+        * and otherwise we remove the flag and continue
+        */
+       if (lo->ldo_dir_hash_type & LMV_HASH_FLAG_OVERSTRIPED) {
+               if (stripe_count > lod->lod_remote_mdt_count + 1)
+                       RETURN(-EAGAIN);
+               lo->ldo_dir_hash_type &= ~LMV_HASH_FLAG_OVERSTRIPED;
+       }
+
        /* use MDT pool in @ltd, once MDT pool is supported in the future, it
         * can be passed in as argument like OST object allocation.
         */
index de3d34c..ecda0af 100644 (file)
@@ -313,6 +313,39 @@ static ssize_t max_stripecount_store(struct kobject *kobj,
 
 LUSTRE_RW_ATTR(max_stripecount);
 
+static ssize_t max_mdt_stripecount_show(struct kobject *kobj,
+                                   struct attribute *attr, char *buf)
+{
+       struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj);
+       struct lod_device *lod = dt2lod_dev(dt);
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n", lod->lod_max_mdt_stripecount);
+}
+
+static ssize_t max_mdt_stripecount_store(struct kobject *kobj,
+                                    struct attribute *attr,
+                                    const char *buffer, size_t count)
+{
+       struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj);
+       struct lod_device *lod = dt2lod_dev(dt);
+       long val;
+       int rc;
+
+       rc = kstrtol(buffer, 0, &val);
+       if (rc)
+               return rc;
+
+       if (val < 0 || val > LMV_MAX_STRIPE_COUNT) /* any limitation? */
+               return -ERANGE;
+
+       lod->lod_max_mdt_stripecount = val;
+
+       return count;
+}
+
+LUSTRE_RW_ATTR(max_mdt_stripecount);
+
+
 /**
  * Show default striping pattern (LOV_PATTERN_*).
  */
@@ -1296,6 +1329,7 @@ static struct attribute *lod_attrs[] = {
        &lustre_attr_stripeoffset.attr,
        &lustre_attr_stripecount.attr,
        &lustre_attr_max_stripecount.attr,
+       &lustre_attr_max_mdt_stripecount.attr,
        &lustre_attr_stripetype.attr,
        &lustre_attr_activeobd.attr,
        &lustre_attr_desc_uuid.attr,
index ec108f7..729e740 100644 (file)
@@ -4032,7 +4032,7 @@ void mdt_save_lock(struct mdt_thread_info *info, struct lustre_handle *h,
                                if (req->rq_export->exp_disconnected)
                                        mdt_fid_unlock(h, mode);
                                else
-                                       ptlrpc_save_lock(req, h, mode, cos,
+                                       ptlrpc_save_lock(req, h, cos,
                                                         convert_lock);
                        } else {
                                mdt_fid_unlock(h, mode);
index 31bf906..a498d0d 100644 (file)
@@ -104,8 +104,7 @@ static void mdt_steal_ack_locks(struct ptlrpc_request *req)
                spin_lock(&rs->rs_lock);
                for (i = 0; i < rs->rs_nlocks; i++)
                        ptlrpc_save_lock(req, &rs->rs_locks[i],
-                                        rs->rs_modes[i], rs->rs_no_ack,
-                                        rs->rs_convert_lock);
+                                        rs->rs_no_ack, rs->rs_convert_lock);
                rs->rs_nlocks = 0;
 
                DEBUG_REQ(D_HA, req, "stole locks for");
@@ -122,7 +121,7 @@ static void mdt_steal_ack_locks(struct ptlrpc_request *req)
                rs = req->rq_reply_state;
 
                for (i = 0; i < rs->rs_nlocks; i++)
-                       ldlm_lock_decref(&rs->rs_locks[i], rs->rs_modes[i]);
+                       ldlm_lock_decref(&rs->rs_locks[i], LCK_PW);
 
                rs->rs_nlocks = 0;
        }
index f1b2d98..93c8def 100644 (file)
@@ -439,10 +439,11 @@ int mdt_dir_layout_update(struct mdt_thread_info *info)
                 * directory.
                 */
 
-               if (lum_stripe_count > 1 && lmu->lum_hash_type &&
-                   lmu->lum_hash_type !=
+               if (lum_stripe_count > 1 &&
+                   (lmu->lum_hash_type & cpu_to_le32(LMV_HASH_TYPE_MASK)) &&
+                   (lmu->lum_hash_type & cpu_to_le32(LMV_HASH_TYPE_MASK)) !=
                    (lmv->lmv_hash_type & cpu_to_le32(LMV_HASH_TYPE_MASK))) {
-                       CERROR("%s: "DFID" migrate mdt hash mismatch %u != %u\n",
+                       CERROR("%s: "DFID" migrate mdt hash mismatch %x != %x\n",
                                mdt_obd_name(info->mti_mdt), PFID(rr->rr_fid1),
                                lmv->lmv_hash_type, lmu->lum_hash_type);
                        GOTO(unlock_obj, rc = -EINVAL);
index 2af3a3e..3a75d9d 100644 (file)
@@ -2666,7 +2666,6 @@ int req_capsule_server_grow(struct req_capsule *pill,
                nrs->rs_convert_lock = rs->rs_convert_lock;
                 for (i = 0; i < rs->rs_nlocks; i++) {
                         nrs->rs_locks[i] = rs->rs_locks[i];
-                        nrs->rs_modes[i] = rs->rs_modes[i];
                         nrs->rs_nlocks++;
                 }
                 rs->rs_nlocks = 0;
index d5debae..bccd8b6 100644 (file)
@@ -178,17 +178,17 @@ static int ptlrpc_grow_req_bufs(struct ptlrpc_service_part *svcpt, int post)
  * Puts a lock and its mode into reply state assotiated to request reply.
  */
 void ptlrpc_save_lock(struct ptlrpc_request *req, struct lustre_handle *lock,
-                     int mode, bool no_ack, bool convert_lock)
+                     bool no_ack, bool convert_lock)
 {
        struct ptlrpc_reply_state *rs = req->rq_reply_state;
        int idx;
 
        LASSERT(rs != NULL);
+       CDEBUG(D_RPCTRACE, "nlocks %d\n", rs->rs_nlocks);
        LASSERT(rs->rs_nlocks < RS_MAX_LOCKS);
 
        idx = rs->rs_nlocks++;
        rs->rs_locks[idx] = *lock;
-       rs->rs_modes[idx] = mode;
        rs->rs_difficult = 1;
        rs->rs_no_ack = no_ack;
        rs->rs_convert_lock = convert_lock;
@@ -2435,7 +2435,6 @@ static int ptlrpc_handle_rs(struct ptlrpc_reply_state *rs)
                                                        &rs->rs_locks[nlocks]);
                                        LASSERT(lock);
                                        ack_locks[nlocks] = lock;
-                                       rs->rs_modes[nlocks] = LCK_COS;
                                }
                                nlocks = rs->rs_nlocks;
                                rs->rs_convert_lock = 0;
@@ -2498,8 +2497,7 @@ static int ptlrpc_handle_rs(struct ptlrpc_reply_state *rs)
                }
 
                while (nlocks-- > 0)
-                       ldlm_lock_decref(&rs->rs_locks[nlocks],
-                                        rs->rs_modes[nlocks]);
+                       ldlm_lock_decref(&rs->rs_locks[nlocks], LCK_PW);
 
                spin_lock(&rs->rs_lock);
        }
index 875968d..42813d2 100644 (file)
@@ -2114,6 +2114,7 @@ void lustre_assert_wire_constants(void)
        BUILD_BUG_ON(LMV_MAGIC_V1 != 0x0CD20CD0);
        BUILD_BUG_ON(LMV_MAGIC_STRIPE != 0x0CD40CD0);
        BUILD_BUG_ON(LMV_HASH_TYPE_MASK != 0x0000ffff);
+       BUILD_BUG_ON(LMV_HASH_FLAG_OVERSTRIPED != 0x01000000);
        BUILD_BUG_ON(LMV_HASH_FLAG_FIXED != 0x02000000);
        BUILD_BUG_ON(LMV_HASH_FLAG_MERGE != 0x04000000);
        BUILD_BUG_ON(LMV_HASH_FLAG_SPLIT != 0x08000000);
index a98e063..1485793 100644 (file)
@@ -24178,32 +24178,41 @@ cleanup_test_300() {
        trap 0
        umask $SAVE_UMASK
 }
+
 test_striped_dir() {
        local mdt_index=$1
-       local stripe_count
+       local stripe_count=$2
+       local overstriping=$3
        local stripe_index
+       local getstripe_count
 
        mkdir -p $DIR/$tdir
 
        SAVE_UMASK=$(umask)
        trap cleanup_test_300 RETURN EXIT
 
-       $LFS setdirstripe -i $mdt_index -c 2 -H all_char -o 755 \
-                                               $DIR/$tdir/striped_dir ||
-               error "set striped dir error"
+       if [ -z $overstriping ]; then
+               $LFS setdirstripe -i $mdt_index -c $stripe_count -H all_char \
+                                       -o 755 $DIR/$tdir/striped_dir ||
+                       error "set striped dir error"
+       else
+               $LFS setdirstripe -i $mdt_index -C $stripe_count -H all_char \
+                                       -o 755 $DIR/$tdir/striped_dir ||
+                       error "set striped dir error"
+       fi
 
        local mode=$(stat -c%a $DIR/$tdir/striped_dir)
        [ "$mode" = "755" ] || error "expect 755 got $mode"
 
        $LFS getdirstripe $DIR/$tdir/striped_dir > /dev/null 2>&1 ||
                error "getdirstripe failed"
-       stripe_count=$($LFS getdirstripe -c $DIR/$tdir/striped_dir)
-       if [ "$stripe_count" != "2" ]; then
-               error "1:stripe_count is $stripe_count, expect 2"
+       getstripe_count=$($LFS getdirstripe -c $DIR/$tdir/striped_dir)
+       if [ "$getstripe_count" != "$stripe_count" ]; then
+               error "1:stripe_count is $getstripe_count, expect $stripe_count"
        fi
-       stripe_count=$($LFS getdirstripe -T $DIR/$tdir/striped_dir)
-       if [ "$stripe_count" != "2" ]; then
-               error "2:stripe_count is $stripe_count, expect 2"
+       getstripe_count=$($LFS getdirstripe -T $DIR/$tdir/striped_dir)
+       if [ "$getstripe_count" != "$stripe_count" ]; then
+               error "2:stripe_count is $getstripe_count, expect $stripe_count"
        fi
 
        stripe_index=$($LFS getdirstripe -i $DIR/$tdir/striped_dir)
@@ -24252,8 +24261,8 @@ test_300a() {
        [ $PARALLEL == "yes" ] && skip "skip parallel run"
        [ $MDSCOUNT -lt 2 ] && skip_env "needs >= 2 MDTs"
 
-       test_striped_dir 0 || error "failed on striped dir on MDT0"
-       test_striped_dir 1 || error "failed on striped dir on MDT0"
+       test_striped_dir 0 || error "failed on striped dir on MDT0"
+       test_striped_dir 1 || error "failed on striped dir on MDT0"
 }
 run_test 300a "basic striped dir sanity test"
 
@@ -24949,6 +24958,352 @@ test_300s() {
 }
 run_test 300s "test lfs mkdir -c without -i"
 
+test_300t() {
+       (( $MDS1_VERSION >= $(version_code 2.14.55) )) ||
+               skip "need MDS 2.14.55 or later"
+       (( $MDSCOUNT >= 2 )) || skip "needs at least 2 MDTs"
+
+       local testdir="$DIR/$tdir/striped_dir"
+       local dir1=$testdir/dir1
+       local dir2=$testdir/dir2
+
+       mkdir -p $testdir
+
+       $LFS setdirstripe -D -c -1 --max-inherit=3 $testdir ||
+               error "failed to set default stripe count for $testdir"
+
+       mkdir $dir1
+       local stripe_count=$($LFS getdirstripe -c $dir1)
+
+       (( $stripe_count == $MDSCOUNT )) || error "wrong stripe count"
+
+       local max_count=$((MDSCOUNT - 1))
+       local mdts=$(comma_list $(mdts_nodes))
+
+       do_nodes $mdts $LCTL set_param lod.*.max_mdt_stripecount=$max_count
+       stack_trap "do_nodes $mdts $LCTL set_param lod.*.max_mdt_stripecount=0"
+
+       mkdir $dir2
+       stripe_count=$($LFS getdirstripe -c $dir2)
+
+       (( $stripe_count == $max_count )) || error "wrong stripe count"
+}
+run_test 300t "test max_mdt_stripecount"
+MDT_OVSTRP_VER="2.14.0.145"
+# 300u family tests MDT overstriping
+test_300ua() {
+       (( MDSCOUNT > 1 )) || skip "needs >= 2 MDTs"
+
+       local setcount=$((MDSCOUNT * 2))
+
+       local expected_count
+
+       mkdir $DIR/$tdir
+       $LFS setdirstripe -C $setcount $DIR/$tdir/${tdir}.0 ||
+               error "(0) failed basic overstriped dir creation test"
+       local getstripe_count=$($LFS getdirstripe -c $DIR/$tdir/${tdir}.0)
+
+       # This does a basic interop test - if the MDS does not support mdt
+       # overstriping, we should get stripes == number of MDTs
+       if (( $MDS1_VERSION < $(version_code $MDT_OVSTRP_VER) )); then
+               expected_count=$MDSCOUNT
+       else
+               expected_count=$setcount
+       fi
+       (( getstripe_count == expected_count )) ||
+               error "(1) incorrect stripe count for simple overstriped dir"
+
+       rm -rf $DIR/$tdir/${tdir}.0 ||
+               error "(2) unable to rm overstriped dir"
+
+       # Tests after this require overstriping support
+       (( MDS1_VERSION >= $(version_code $MDT_OVSTRP_VER) )) ||
+               { echo "skipped for MDS < $MDT_OVSTRP_VER"; return 0; }
+
+       test_striped_dir 0 $setcount true ||
+               error "(3)failed on overstriped dir"
+       test_striped_dir 1 $setcount true ||
+               error "(4)failed on overstriped dir"
+
+       local setcount=$((MDSCOUNT * $LMV_MAX_STRIPES_PER_MDT))
+
+       test_striped_dir 0 $setcount true ||
+               error "(5)failed on overstriped dir"
+}
+run_test 300ua "basic overstriped dir sanity test"
+
+test_300ub() {
+       (( MDS1_VERSION >= $(version_code $MDT_OVSTRP_VER) )) ||
+               skip "skipped for MDS < $MDT_OVSTRP_VER"
+       (( MDSCOUNT > 1 )) || skip "needs >= 2 MDTs"
+
+       mkdir $DIR/$tdir
+
+       echo "Testing invalid stripe count, failure expected"
+       local setcount=$((MDSCOUNT * 2))
+
+       $LFS setdirstripe -c $setcount $DIR/$tdir/${tdir}.0
+       local getstripe_count=$($LFS getdirstripe -c $DIR/$tdir/${tdir}.0)
+
+       (( getstripe_count <= MDSCOUNT )) ||
+               error "(0)stripe count ($setcount) > MDT count ($MDSCOUNT) succeeded with -c"
+
+       # When a user requests > LMV_MAX_STRIPES_PER_MDT, we reduce to that
+       setcount=$((MDSCOUNT * 2 * LMV_MAX_STRIPES_PER_MDT))
+       $LFS setdirstripe -C $setcount $DIR/$tdir/${tdir}.1
+
+       local maxcount=$((MDSCOUNT * LMV_MAX_STRIPES_PER_MDT))
+
+       getstripe_count=$($LFS getdirstripe -c $DIR/$tdir/${tdir}.1)
+       (( getstripe_count == maxcount )) ||
+               error "(1)stripe_count is $getstripe_count, expect $maxcount"
+
+       # Test specific striping with -i
+       $LFS setdirstripe -i 0,0,0,0 $DIR/$tdir/${tdir}.2
+
+       getstripe_count=$($LFS getdirstripe -c $DIR/$tdir/${tdir}.2)
+       (( getstripe_count == 4 )) ||
+               error "(2)stripe_count is $getstripe_count, expect 4"
+
+       local nonzeroindices=$($LFS getdirstripe $DIR/$tdir/${tdir}.2 | grep "\[" | \
+                              grep -v mdtidx | awk '{print $1}' | grep -c -v 0)
+
+       [[ -n "$nonzeroindices" ]] ||
+               error "(3) stripes indices not all 0: $nonzeroindices"
+
+       # Test specific striping with too many stripes on one MDT
+       echo "Testing invalid striping, failure expected"
+       $LFS setdirstripe -i 0,1,0,1,0,1,0,1,0,1,0 $DIR/$tdir/${tdir}.3
+       $LFS getdirstripe $DIR/$tdir/${tdir}.3
+       getstripe_count=$($LFS getdirstripe $DIR/$tdir/${tdir}.3 | grep "\[" | \
+                         grep -v mdtidx | awk '{print $1}' | grep -c '0')
+       echo "stripes on MDT0: $getstripe_count"
+       (( getstripe_count <= LMV_MAX_STRIPES_PER_MDT )) ||
+               error "(4) setstripe with too many stripes on MDT0 succeeded"
+
+       setcount=$((MDSCOUNT * 2))
+       $LFS setdirstripe -C $setcount -H all_char $DIR/${tdir}.4 ||
+               error "(5) can't setdirstripe with manually set hash function"
+
+       getstripe_count=$($LFS getdirstripe -c $DIR/${tdir}.4)
+       (( getstripe_count == setcount )) ||
+               error "(6)stripe_count is $getstripe_count, expect $setcount"
+
+       setcount=$((MDSCOUNT * 2))
+       mkdir $DIR/${tdir}.5
+       $LFS setdirstripe -C $setcount -D -H crush $DIR/${tdir}.5 ||
+               error "(7) can't setdirstripe with manually set hash function"
+       mkdir $DIR/${tdir}.5/${tdir}.6
+
+       getstripe_count=$($LFS getdirstripe -c $DIR/${tdir}.5/${tdir}.6)
+       (( getstripe_count == setcount )) ||
+               error "(8)stripe_count is $getstripe_count, expect $setcount"
+}
+run_test 300ub "test MDT overstriping interface & limits"
+
+test_300uc() {
+       (( MDS1_VERSION >= $(version_code $MDT_OVSTRP_VER) )) ||
+               skip "skipped for MDS < $MDT_OVSTRP_VER"
+       (( MDSCOUNT > 1 )) || skip "needs >= 2 MDTs"
+
+       mkdir $DIR/$tdir
+
+       local setcount=$((MDSCOUNT * 2))
+
+       $LFS setdirstripe -D -C $setcount $DIR/$tdir
+
+       mkdir $DIR/$tdir/${tdir}.1
+
+       local getstripe_count=$($LFS getdirstripe -c $DIR/$tdir/${tdir}.1)
+
+       (( getstripe_count == setcount )) ||
+               error "(0)stripe_count is $getstripe_count, expect $setcount"
+
+       mkdir $DIR/$tdir/${tdir}.1/${tdir}.2
+
+       local getstripe_count=$($LFS getdirstripe -c \
+                               $DIR/$tdir/${tdir}.1/${tdir}.2)
+
+       (( getstripe_count == setcount )) ||
+               error "(1)stripe_count is $getstripe_count, expect $setcount"
+}
+run_test 300uc "test MDT overstriping as default & inheritance"
+
+test_300ud() {
+       (( MDS1_VERSION >= $(version_code $MDT_OVSTRP_VER) )) ||
+               skip "skipped for MDS < $MDT_OVSTRP_VER"
+       (( MDSCOUNT > 1 )) || skip "needs >= 2 MDTs"
+
+       local mdts=$(comma_list $(mdts_nodes))
+       local timeout=100
+
+       local restripe_status
+       local delta
+       local i
+
+       [[ $mds1_FSTYPE == zfs ]] && timeout=300
+
+       # in case "crush" hash type is not set
+       do_nodes $mdts "$LCTL set_param lod.*.mdt_hash=crush"
+
+       restripe_status=$(do_facet mds1 $LCTL get_param -n \
+                          mdt.*MDT0000.enable_dir_restripe)
+       do_nodes $mdts "$LCTL set_param mdt.*.enable_dir_restripe=1"
+       stack_trap "do_nodes $mdts $LCTL set_param \
+                   mdt.*.enable_dir_restripe=$restripe_status"
+
+       mkdir $DIR/$tdir
+       createmany -m $DIR/$tdir/f $((50 * MDSCOUNT)) ||
+               error "create files under remote dir failed $i"
+       createmany -d $DIR/$tdir/d $((50 * MDSCOUNT)) ||
+               error "create dirs under remote dir failed $i"
+
+       local setcount=$((MDSCOUNT * $LMV_MAX_STRIPES_PER_MDT))
+
+       (( setcount < 13 )) || setcount=12
+       for i in $(seq 2 $setcount); do
+               do_nodes $mdts "$LCTL set_param mdt.*.md_stats=clear >/dev/null"
+               $LFS setdirstripe -C $i $DIR/$tdir ||
+                       error "split -C $i $tdir failed"
+               wait_update $HOSTNAME \
+                       "$LFS getdirstripe -H $DIR/$tdir" "crush" $timeout ||
+                       error "dir split not finished"
+               delta=$(do_nodes $mdts "lctl get_param -n mdt.*MDT*.md_stats" |
+                       awk '/migrate/ {sum += $2} END { print sum }')
+               echo "$delta migrated when dir split $((i - 1)) to $i stripes"
+               # delta is around total_files/stripe_count, deviation 3%
+               (( delta < 100 * MDSCOUNT / i + 3 * MDSCOUNT )) ||
+                       error "$delta files migrated >= $((100 * MDSCOUNT / i + 3 * MDSCOUNT))"
+       done
+}
+run_test 300ud "dir split"
+
+test_300ue() {
+       (( MDS1_VERSION >= $(version_code $MDT_OVSTRP_VER) )) ||
+               skip "skipped for MDS < $MDT_OVSTRP_VER"
+       (( MDSCOUNT > 1 )) || skip "needs >= 2 MDTs"
+
+       local mdts=$(comma_list $(mdts_nodes))
+       local timeout=100
+
+       local restripe_status
+       local delta
+       local c
+
+       [[ $mds1_FSTYPE == zfs ]] && timeout=300
+
+       do_nodes $mdts "$LCTL set_param lod.*.mdt_hash=crush"
+
+       restripe_status=$(do_facet mds1 $LCTL get_param -n \
+                          mdt.*MDT0000.enable_dir_restripe)
+       do_nodes $mdts "$LCTL set_param mdt.*.enable_dir_restripe=1"
+       stack_trap "do_nodes $mdts $LCTL set_param \
+                   mdt.*.enable_dir_restripe=$restripe_status"
+
+       local setcount=$((MDSCOUNT * $LMV_MAX_STRIPES_PER_MDT))
+
+       (( setcount < 13 )) || setcount=12
+       test_mkdir -C $setcount -H crush $DIR/$tdir
+       createmany -m $DIR/$tdir/f $((50 * MDSCOUNT)) ||
+               error "create files under remote dir failed"
+       createmany -d $DIR/$tdir/d $((50 * MDSCOUNT)) ||
+               error "create dirs under remote dir failed"
+
+       for c in $(seq $((setcount - 1)) -1 1); do
+               do_nodes $mdts "$LCTL set_param mdt.*.md_stats=clear >/dev/null"
+               $LFS setdirstripe -C $c $DIR/$tdir ||
+                       error "split -C $c $tdir failed"
+               wait_update $HOSTNAME \
+                       "$LFS getdirstripe -H $DIR/$tdir" "crush,fixed" $timeout ||
+                       error "dir merge not finished"
+               delta=$(do_nodes $mdts "lctl get_param -n mdt.*MDT*.md_stats" |
+                       awk '/migrate/ {sum += $2} END { print sum }')
+               echo "$delta migrated when dir merge $((c + 1)) to $c stripes"
+               # delta is around total_files/stripe_count, deviation 3%
+               (( delta < 100 * MDSCOUNT / c + 3 * MDSCOUNT )) ||
+                       error "$delta files migrated >= $((100 * MDSCOUNT / c + 3 * MDSCOUNT))"
+       done
+}
+run_test 300ue "dir merge"
+
+test_300uf() {
+       (( MDS1_VERSION >= $(version_code $MDT_OVSTRP_VER) )) ||
+               skip "skipped for MDS < $MDT_OVSTRP_VER"
+       (( MDSCOUNT > 1 )) || skip "needs >= 2 MDTs"
+
+       # maximum amount of local locks:
+       # parent striped dir - 2 locks
+       # new stripe in parent to migrate to - 1 lock
+       # source and target - 2 locks
+       # Total 5 locks for regular file
+       #
+       # NB: Overstriping should add several extra local locks
+       # FIXME: Remove this once understood
+       #lctl set_param *debug=-1 debug_mb=10000
+       lctl clear
+       lctl mark "touch/create"
+       mkdir -p $DIR/$tdir
+       local setcount=$((MDSCOUNT * $LMV_MAX_STRIPES_PER_MDT))
+       local setcount=$((MDSCOUNT * 5))
+
+       $LFS mkdir -i1 -C $setcount $DIR/$tdir/dir1
+       touch $DIR/$tdir/dir1/eee
+
+       lctl mark "hardlinks"
+       # create 4 hardlink for 4 more locks
+       # Total: 9 locks > RS_MAX_LOCKS (8)
+       $LFS mkdir -i1 -c1 $DIR/$tdir/dir2
+       $LFS mkdir -i1 -c1 $DIR/$tdir/dir3
+       $LFS mkdir -i1 -c1 $DIR/$tdir/dir4
+       $LFS mkdir -i1 -c1 $DIR/$tdir/dir5
+       ln $DIR/$tdir/dir1/eee $DIR/$tdir/dir2/eee
+       ln $DIR/$tdir/dir1/eee $DIR/$tdir/dir3/eee
+       ln $DIR/$tdir/dir1/eee $DIR/$tdir/dir4/eee
+       ln $DIR/$tdir/dir1/eee $DIR/$tdir/dir5/eee
+
+       lctl mark "cancel lru"
+       cancel_lru_locks mdc
+
+       lctl mark "migrate"
+       $LFS migrate -m1 -c1 $DIR/$tdir/dir1 ||
+               error "migrate dir fails"
+
+       rm -rf $DIR/$tdir || error "rm dir failed after migration"
+}
+run_test 300uf "migrate with too many local locks"
+
+test_300ug() {
+       (( MDS1_VERSION >= $(version_code $MDT_OVSTRP_VER) )) ||
+               skip "skipped for MDS < $MDT_OVSTRP_VER"
+       (( MDSCOUNT > 1 )) || skip "needs >= 2 MDTs"
+
+       mkdir -p $DIR/$tdir
+       local migrate_dir=$DIR/$tdir/migrate_dir
+       local setcount=$((MDSCOUNT * $LMV_MAX_STRIPES_PER_MDT))
+       local setcount2=$((setcount - 2))
+
+       $LFS setdirstripe -c 2 $migrate_dir ||
+               error "(0) failed to create striped directory"
+
+       $LFS migrate -m 0 -C $setcount $migrate_dir ||
+               error "(1)failed to migrate to overstriped directory"
+       local getstripe_count=$($LFS getdirstripe -c $migrate_dir)
+
+       (( getstripe_count == setcount )) ||
+               error "(2)stripe_count is $getstripe_count, expect $setcount"
+       touch $DIR/$tdir/migrate_dir/$tfile ||
+               error "(3)failed to create file in overstriped directory"
+       $LFS migrate -m 0 -C $setcount2 $migrate_dir ||
+               error "(4)failed to migrate overstriped directory"
+       # Check stripe count after migration
+       $LFS getdirstripe $migrate_dir
+       getstripe_count=$($LFS getdirstripe -c $migrate_dir)
+       (( getstripe_count == setcount2 )) ||
+               error "(5)stripe_count is $getstripe_count, expect $setcount2"
+
+       rm -rf $migrate_dir || error "(6) unable to rm overstriped dir"
+}
+run_test 300ug "migrate overstriped dirs"
 
 prepare_remote_file() {
        mkdir $DIR/$tdir/src_dir ||
index 4cc3b3c..2d87a55 100755 (executable)
@@ -441,6 +441,8 @@ init_test_env() {
 
        # Constants used in more than one test script
        export LOV_MAX_STRIPE_COUNT=2000
+       export LMV_MAX_STRIPES_PER_MDT=5
+       export DELETE_OLD_POOLS=${DELETE_OLD_POOLS:-false}
 
        export MACHINEFILE=${MACHINEFILE:-$TMP/$(basename $0 .sh).machines}
        get_lustre_env
@@ -9652,10 +9654,13 @@ test_mkdir() {
        local dirstripe_count=${DIRSTRIPE_COUNT:-"2"}
        local dirstripe_index=${DIRSTRIPE_INDEX:-$((base % $MDSCOUNT))}
        local OPTIND=1
+       local overstripe_count
+       local stripe_command="-c"
 
-       while getopts "c:H:i:p" opt; do
+       while getopts "c:C:H:i:p" opt; do
                case $opt in
                        c) dirstripe_count=$OPTARG;;
+                       C) overstripe_count=$OPTARG;;
                        H) hash_type=$OPTARG;;
                        i) dirstripe_index=$OPTARG;;
                        p) p_option="-p";;
@@ -9676,6 +9681,11 @@ test_mkdir() {
                fi
        fi
 
+       if [[ -n "$overstripe_count" ]]; then
+               stripe_command="-C"
+               dirstripe_count=$overstripe_count
+       fi
+
        if [ $MDSCOUNT -le 1 ] || ! is_lustre ${parent}; then
                mkdir $path || error "mkdir '$path' failed"
        else
@@ -9699,9 +9709,9 @@ test_mkdir() {
                        dirstripe_count=1
                fi
 
-               echo "striped dir -i$mdt_index -c$dirstripe_count -H $hash_type $path"
-               $LFS mkdir -i$mdt_index -c$dirstripe_count -H $hash_type $path ||
-                       error "mkdir -i $mdt_index -c$dirstripe_count -H $hash_type $path failed"
+               echo "striped dir -i$mdt_index $stripe_command$dirstripe_count -H $hash_type $path"
+               $LFS mkdir -i$mdt_index $stripe_command$dirstripe_count -H $hash_type $path ||
+                       error "mkdir -i $mdt_index $stripe_command$dirstripe_count -H $hash_type $path failed"
        fi
 }
 
index 4b4c82b..62f06ca 100644 (file)
@@ -248,6 +248,7 @@ static inline int lfs_mirror_delete(int argc, char **argv)
        "               [--mdt-count|-c stripe_count>\n"                \
        "               [--mdt-hash|-H mdt_hash]\n"                     \
        "               [--mdt-index|-i mdt_index[,mdt_index,...]\n"    \
+       "               [--mdt-overcount|-C stripe_count>\n"            \
        "               [--default|-D] [--mode|-o mode]\n"              \
        "               [--max-inherit|-X max_inherit]\n"               \
        "               [--max-inherit-rr max_inherit_rr] <dir>\n"              \
@@ -574,6 +575,7 @@ command_t cmdlist[] = {
        {"migrate", lfs_setstripe_migrate, 0,
         "migrate a directory between MDTs.\n"
         "usage: migrate [--mdt-count|-c] <stripe_count> [--directory|-d]\n"
+        "               [--mdt-overcount|-C OVERSTRIPE_COUNT\n"
         "               [--mdt-hash|-H] <hash_type>\n"
         "               [--mdt-index|-m] <start_mdt_index> [--verbose|-v]\n"
         "               <directory>\n"
@@ -2642,19 +2644,18 @@ out:
  * \param[in] size             size of \a tgts array
  * \param[in] offset           starting index in \a tgts
  * \param[in] arg              string containing OST index list
- * \param[in/out] overstriping index list may contain duplicates
+ * \param[out] duplicates      tell caller list contains duplicates
  *
  * \retval positive    number of indices in \a tgts
  * \retval -EINVAL     unable to parse \a arg
  */
 static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
-                        unsigned long long *pattern)
+                        bool *duplicates)
 {
        int rc;
        int nr = offset;
        int slots = size - offset;
        char *ptr = NULL;
-       bool overstriped = false;
        bool end_of_loop;
 
        if (!arg)
@@ -2695,13 +2696,10 @@ static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
                for (i = start_index; i <= end_index && slots > 0; i++) {
                        int j;
 
-                       /* remove duplicate */
+                       /* note presence of duplicates */
                        for (j = 0; j < offset; j++) {
-                               if (tgts[j] == i && pattern &&
-                                   *pattern == LLAPI_LAYOUT_OVERSTRIPING)
-                                       overstriped = true;
-                               else if (tgts[j] == i)
-                                       return -EINVAL;
+                               if (tgts[j] == i)
+                                       *duplicates = true;
                        }
 
                        j = offset;
@@ -2723,9 +2721,6 @@ static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
        if (!end_of_loop && ptr)
                *ptr = ',';
 
-       if (!overstriped && pattern)
-               *pattern = LLAPI_LAYOUT_DEFAULT;
-
        return rc < 0 ? rc : nr;
 }
 
@@ -3631,6 +3626,7 @@ static int lfs_setstripe_internal(int argc, char **argv,
        char *template = NULL;
        bool foreign_mode = false;
        char *xattr = NULL;
+       bool overstriped = false;
        uint32_t type = LU_FOREIGN_TYPE_NONE, flags = 0;
        char *mode_opt = NULL;
        mode_t previous_umask = 0;
@@ -3697,6 +3693,8 @@ static int lfs_setstripe_internal(int argc, char **argv,
        { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument},
        { .val = 'C',   .name = "overstripe-count",
                                                .has_arg = required_argument},
+       { .val = 'C',   .name = "mdt-overcount",
+                                               .has_arg = required_argument},
        { .val = 'd',   .name = "delete",       .has_arg = no_argument},
        { .val = 'd',   .name = "destroy",      .has_arg = no_argument},
        /* used with "lfs migrate -m" */
@@ -3927,7 +3925,10 @@ static int lfs_setstripe_internal(int argc, char **argv,
                                        progname, argv[0]);
                                goto usage_error;
                        }
-                       lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
+                       if (migrate_mode)
+                               overstriped = true;
+                       else
+                               lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
                        fallthrough;
                case 'c':
                        errno = 0;
@@ -4097,8 +4098,9 @@ static int lfs_setstripe_internal(int argc, char **argv,
                        }
                        migrate_mdt_mode = true;
                        lsa.lsa_nr_tgts = parse_targets(tgts,
-                                               sizeof(tgts) / sizeof(__u32),
-                                               lsa.lsa_nr_tgts, optarg, NULL);
+                                                       sizeof(tgts) / sizeof(__u32),
+                                                       lsa.lsa_nr_tgts, optarg,
+                                                       &overstriped);
                        if (lsa.lsa_nr_tgts < 0) {
                                fprintf(stderr,
                                        "%s %s: invalid MDT target(s) '%s'\n",
@@ -4183,11 +4185,10 @@ static int lfs_setstripe_internal(int argc, char **argv,
                         * parse_targets is shared with MDT striping, which
                         * does not allow duplicates
                         */
-                       lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
                        lsa.lsa_nr_tgts = parse_targets(tgts,
                                                sizeof(tgts) / sizeof(__u32),
                                                lsa.lsa_nr_tgts, optarg,
-                                               &lsa.lsa_pattern);
+                                               &overstriped);
                        if (lsa.lsa_nr_tgts < 0) {
                                fprintf(stderr,
                                        "%s %s: invalid OST target(s) '%s'\n",
@@ -4195,6 +4196,9 @@ static int lfs_setstripe_internal(int argc, char **argv,
                                goto usage_error;
                        }
 
+                       if (overstriped)
+                               lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
+
                        lsa.lsa_tgts = tgts;
                        if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
                                lsa.lsa_stripe_off = tgts[0];
@@ -4514,10 +4518,15 @@ static int lfs_setstripe_internal(int argc, char **argv,
                        goto usage_error;
                }
                lmu->lum_stripe_offset = lsa.lsa_stripe_off;
+
                if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
                        lmu->lum_hash_type = lsa.lsa_pattern;
                else
                        lmu->lum_hash_type = LMV_HASH_TYPE_UNKNOWN;
+
+               if (overstriped)
+                       lmu->lum_hash_type |= LMV_HASH_FLAG_OVERSTRIPED;
+
                if (lsa.lsa_pool_name) {
                        strncpy(lmu->lum_pool_name, lsa.lsa_pool_name,
                                sizeof(lmu->lum_pool_name) - 1);
@@ -6938,6 +6947,7 @@ static int lfs_setdirstripe(int argc, char **argv)
        bool default_stripe = false;
        bool delete = false;
        bool foreign_mode = false;
+       bool overstriped = false;
        mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
        mode_t previous_mode = 0;
        char *xattr = NULL;
@@ -6947,6 +6957,7 @@ static int lfs_setdirstripe(int argc, char **argv)
        struct option long_opts[] = {
        { .val = 'c',   .name = "count",        .has_arg = required_argument },
        { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
+       { .val = 'C',   .name = "mdt-overcount", .has_arg = required_argument },
        { .val = 'd',   .name = "delete",       .has_arg = no_argument },
        { .val = 'D',   .name = "default",      .has_arg = no_argument },
        { .val = 'D',   .name = "default_stripe", .has_arg = no_argument },
@@ -6982,13 +6993,17 @@ static int lfs_setdirstripe(int argc, char **argv)
 
        setstripe_args_init(&lsa);
 
-       while ((c = getopt_long(argc, argv, "c:dDi:H:m:o:t:T:x:X:",
+       while ((c = getopt_long(argc, argv, "c:C:dDi:H:m:o:t:T:x:X:",
                                long_opts, NULL)) >= 0) {
                switch (c) {
                case 0:
                        /* Long options. */
                        break;
+               case 'C':
+                       overstriped = true;
+                       fallthrough;
                case 'c':
+                       fallthrough;
                case 'T':
                        errno = 0;
                        lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
@@ -7074,7 +7089,8 @@ static int lfs_setdirstripe(int argc, char **argv)
 #endif
                        lsa.lsa_nr_tgts = parse_targets(mdts,
                                                sizeof(mdts) / sizeof(__u32),
-                                               lsa.lsa_nr_tgts, optarg, NULL);
+                                               lsa.lsa_nr_tgts, optarg,
+                                               &overstriped);
                        if (lsa.lsa_nr_tgts < 0) {
                                fprintf(stderr,
                                        "%s %s: invalid MDT target(s) '%s'\n",
@@ -7276,10 +7292,17 @@ static int lfs_setdirstripe(int argc, char **argv)
                param->lsp_stripe_offset = LMV_OFFSET_DEFAULT;
        else
                param->lsp_stripe_offset = lsa.lsa_stripe_off;
+
        if (lsa.lsa_pattern != LLAPI_LAYOUT_RAID0)
                param->lsp_stripe_pattern = lsa.lsa_pattern;
        else
                param->lsp_stripe_pattern = LMV_HASH_TYPE_UNKNOWN;
+
+       if (overstriped) {
+               param->lsp_stripe_pattern |= LMV_HASH_FLAG_OVERSTRIPED;
+               max_inherit = LMV_INHERIT_DEFAULT_OVERSTRIPED;
+       }
+
        param->lsp_pool = lsa.lsa_pool_name;
        param->lsp_is_specific = false;
        if (max_inherit == LAYOUT_INHERIT_UNSET) {
index dba01f2..8718c13 100644 (file)
@@ -3004,6 +3004,8 @@ static void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name,
                else
                        llapi_printf(LLAPI_MSG_NORMAL, "%#x", type);
 
+               if (flags & LMV_HASH_FLAG_OVERSTRIPED)
+                       llapi_printf(LLAPI_MSG_NORMAL, ",overstriped");
                if (flags & LMV_HASH_FLAG_MIGRATION)
                        llapi_printf(LLAPI_MSG_NORMAL, ",migrating");
                if (flags & LMV_HASH_FLAG_BAD_TYPE)
@@ -3012,7 +3014,10 @@ static void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name,
                        llapi_printf(LLAPI_MSG_NORMAL, ",lost_lmv");
                if (flags & LMV_HASH_FLAG_FIXED)
                        llapi_printf(LLAPI_MSG_NORMAL, ",fixed");
-               if (flags & ~LMV_HASH_FLAG_KNOWN)
+               /* NB: OVERSTRIPED is not in KNOWN until implementation patch
+                * is landed, but we do recognize it
+                */
+               if (flags & ~(LMV_HASH_FLAG_KNOWN|LMV_HASH_FLAG_OVERSTRIPED))
                        llapi_printf(LLAPI_MSG_NORMAL, ",unknown_%04x",
                                     flags & ~LMV_HASH_FLAG_KNOWN);
 
index 245a368..4bf0ace 100644 (file)
@@ -1014,6 +1014,7 @@ check_lmv_mds_md_v1(void)
        CHECK_CDEFINE(LMV_MAGIC_V1);
        CHECK_CDEFINE(LMV_MAGIC_STRIPE);
        CHECK_CDEFINE(LMV_HASH_TYPE_MASK);
+       CHECK_CDEFINE(LMV_HASH_FLAG_OVERSTRIPED);
        CHECK_CDEFINE(LMV_HASH_FLAG_FIXED);
        CHECK_CDEFINE(LMV_HASH_FLAG_MERGE);
        CHECK_CDEFINE(LMV_HASH_FLAG_SPLIT);
index a3e8108..b5e2cd3 100644 (file)
@@ -2149,6 +2149,7 @@ void lustre_assert_wire_constants(void)
        BUILD_BUG_ON(LMV_MAGIC_V1 != 0x0CD20CD0);
        BUILD_BUG_ON(LMV_MAGIC_STRIPE != 0x0CD40CD0);
        BUILD_BUG_ON(LMV_HASH_TYPE_MASK != 0x0000ffff);
+       BUILD_BUG_ON(LMV_HASH_FLAG_OVERSTRIPED != 0x01000000);
        BUILD_BUG_ON(LMV_HASH_FLAG_FIXED != 0x02000000);
        BUILD_BUG_ON(LMV_HASH_FLAG_MERGE != 0x04000000);
        BUILD_BUG_ON(LMV_HASH_FLAG_SPLIT != 0x08000000);