Whamcloud - gitweb
LU-12785 dom: fix DoM component deletion code 37/38337/5
authorMikhail Pershin <mpershin@whamcloud.com>
Thu, 23 Apr 2020 12:42:00 +0000 (15:42 +0300)
committerOleg Drokin <green@whamcloud.com>
Fri, 19 Jun 2020 16:50:22 +0000 (16:50 +0000)
The lod_erase_dom_stripe() deletes DoM entry from composite
layout upon file create if DoM is disabled on server.
That code works incorrectly if DoM is not the first component
in provided layout, e.g. in mirror.

Patch does correct DoM entry removal in generic case no matter
where it was placed in layout. Related test 270h is added into
sanity.sh

Signed-off-by: Mikhail Pershin <mpershin@whamcloud.com>
Change-Id: Ia1b3f25db16a7b59b83cd8f58ff44ddf082cab48
Reviewed-on: https://review.whamcloud.com/38337
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Lai Siyao <lai.siyao@whamcloud.com>
lustre/lod/lod_lov.c
lustre/tests/sanity.sh

index a023959..9861040 100644 (file)
@@ -1608,40 +1608,51 @@ int lod_erase_dom_stripe(struct lov_comp_md_v1 *comp_v1,
 {
        struct lov_comp_md_entry_v1 *ent;
        __u16 entries;
-       __u32 dom_off, dom_size, comp_size;
-       void *blob_src, *blob_dst;
-       unsigned int blob_size, blob_shift;
+       __u32 dom_off, dom_size, comp_size, off;
+       void *src, *dst;
+       unsigned int size, shift;
 
        entries = le16_to_cpu(comp_v1->lcm_entry_count) - 1;
-       /* if file has only DoM stripe return just error */
-       if (entries == 0)
-               return -EFBIG;
+       LASSERT(entries > 0);
+       comp_v1->lcm_entry_count = cpu_to_le16(entries);
 
        comp_size = le32_to_cpu(comp_v1->lcm_size);
        dom_off = le32_to_cpu(dom_ent->lcme_offset);
        dom_size = le32_to_cpu(dom_ent->lcme_size);
 
-       /* shift entries array first */
-       comp_v1->lcm_entry_count = cpu_to_le16(entries);
-       memmove(dom_ent, dom_ent + 1,
-               entries * sizeof(struct lov_comp_md_entry_v1));
-
-       /* now move blob of layouts */
-       blob_dst = (void *)comp_v1 + dom_off - sizeof(*dom_ent);
-       blob_src = (void *)comp_v1 + dom_off + dom_size;
-       blob_size = (unsigned long)((void *)comp_v1 + comp_size - blob_src);
-       blob_shift = sizeof(*dom_ent) + dom_size;
-
-       memmove(blob_dst, blob_src, blob_size);
-
+       /* all entries offsets are shifted by entry size at least */
+       shift = sizeof(*dom_ent);
        for_each_comp_entry_v1(comp_v1, ent) {
-               __u32 off;
-
                off = le32_to_cpu(ent->lcme_offset);
-               ent->lcme_offset = cpu_to_le32(off - blob_shift);
+               if (off == dom_off) {
+                       /* Entry deletion creates two holes in layout data:
+                        * - hole in entries array
+                        * - hole in layout data at dom_off with dom_size
+                        *
+                        * First memmove is one entry shift from next entry
+                        * start with size up to dom_off in blob
+                        */
+                       dst = (void *)ent;
+                       src = (void *)(ent + 1);
+                       size = (unsigned long)((void *)comp_v1 + dom_off - src);
+                       memmove(dst, src, size);
+                       /* take 'off' from just moved entry */
+                       off = le32_to_cpu(ent->lcme_offset);
+                       /* second memmove is blob tail after 'off' up to
+                        * component end
+                        */
+                       dst = (void *)comp_v1 + dom_off - sizeof(*ent);
+                       src = (void *)comp_v1 + off;
+                       size = (unsigned long)(comp_size - off);
+                       memmove(dst, src, size);
+                       /* all entries offsets after DoM entry are shifted by
+                        * dom_size additionally
+                        */
+                       shift += dom_size;
+               }
+               ent->lcme_offset = cpu_to_le32(off - shift);
        }
-
-       comp_v1->lcm_size = cpu_to_le32(comp_size - blob_shift);
+       comp_v1->lcm_size = cpu_to_le32(comp_size - shift);
 
        /* notify a caller to re-check entry */
        return -ERESTART;
@@ -1728,6 +1739,7 @@ int lod_dom_stripesize_choose(const struct lu_env *env, struct lod_device *d,
        __u32 max_stripe_size;
        __u16 mid, dom_mid;
        int rc = 0;
+       bool dom_next_entry = false;
 
        dom_ext = &dom_ent->lcme_extent;
        dom_mid = mirror_id_of(le32_to_cpu(dom_ent->lcme_id));
@@ -1742,6 +1754,10 @@ int lod_dom_stripesize_choose(const struct lu_env *env, struct lod_device *d,
               stripe_size, max_stripe_size);
        lum->lmm_stripe_size = cpu_to_le32(max_stripe_size);
 
+       /* In common case the DoM stripe is first entry in a mirror and
+        * can be deleted only if it is not single entry in layout or
+        * mirror, otherwise error should be returned.
+        */
        for_each_comp_entry_v1(comp_v1, ent) {
                if (ent == dom_ent)
                        continue;
@@ -1762,12 +1778,19 @@ int lod_dom_stripesize_choose(const struct lu_env *env, struct lod_device *d,
                 * always and don't need adjustment since use own layouts.
                 */
                ext->e_start = cpu_to_le64(max_stripe_size);
+               dom_next_entry = true;
                break;
        }
 
        if (max_stripe_size == 0) {
-               /* DoM component size is zero due to server setting,
-                * remove it from the layout */
+               /* DoM component size is zero due to server setting, remove
+                * it from the layout but only if next component exists in
+                * the same mirror. That must be checked prior calling the
+                * lod_erase_dom_stripe().
+                */
+               if (!dom_next_entry)
+                       return -EFBIG;
+
                rc = lod_erase_dom_stripe(comp_v1, dom_ent);
        } else {
                /* Update DoM extent end finally */
index ac3f1aa..e4ad1fe 100755 (executable)
@@ -19791,6 +19791,36 @@ test_270g() {
 }
 run_test 270g "DoM: default DoM stripe size depends on free space"
 
+test_270h() {
+       [[ $MDS1_VERSION -ge $(version_code 2.13.53) ]] ||
+               skip "Need MDS version at least 2.13.53"
+
+       local mdtname=${FSNAME}-MDT0000-mdtlov
+       local dom=$DIR/$tdir/$tfile
+       local save="$TMP/$TESTSUITE-$TESTNAME.parameters"
+
+       save_lustre_params mds1 "lod.*.dom_stripesize" > $save
+       stack_trap "restore_lustre_params < $save; rm -f $save" EXIT
+
+       $LFS mkdir -i 0 -c 1 $DIR/$tdir
+       $LFS setstripe -E 1M -c1  -E -1 -c2 ${dom}_1 ||
+               error "can't create OST file"
+       # mirrored file with DOM entry in the second mirror
+       $LFS mirror extend -N -E 1M -L mdt -E eof -c2 ${dom}_1 ||
+               error "can't create mirror with DoM component"
+
+       do_facet mds1 $LCTL set_param -n lod.$mdtname.dom_stripesize=0
+
+       # DOM component in the middle and has other enries in the same mirror,
+       # should succeed but lost DoM component
+       $LFS setstripe --copy=${dom}_1 $dom ||
+               error "Can't create file from OST|DOM mirror layout"
+       # check new file has no DoM layout after all
+       [[ $($LFS getstripe -L $dom) != "mdt" ]] ||
+               error "File has DoM component while DoM is disabled"
+}
+run_test 270h "DoM: DoM stripe removal when disabled on server"
+
 test_271a() {
        [ $MDS1_VERSION -lt $(version_code 2.10.55) ] &&
                skip "Need MDS version at least 2.10.55"