Whamcloud - gitweb
LU-11215 tests: replace "large_xattr" with "ea_inode"
[fs/lustre-release.git] / lustre / tests / sanity.sh
index 50e7abd..868be7a 100755 (executable)
@@ -1,4 +1,4 @@
-d#!/bin/bash
+#!/bin/bash
 # -*- tab-width: 8; indent-tabs-mode: t; -*-
 #
 # Run select tests by setting ONLY, or as arguments to the script.
@@ -8,12 +8,14 @@ d#!/bin/bash
 set -e
 
 ONLY=${ONLY:-"$*"}
-# bug number for skipped test: LU-9693 LU-6493 LU-9693
-ALWAYS_EXCEPT="$SANITY_EXCEPT  42a     42b     42c"
+# bug number for skipped test: LU-9693 LU-6493 LU-9693 LU-11058
+ALWAYS_EXCEPT="$SANITY_EXCEPT  42a     42b     42c     77k"
 # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
 
-# skipped tests: LU-8411 LU-9096 LU-9054 LU-10680 ..
-ALWAYS_EXCEPT="  407     253     312     160f  160g    $ALWAYS_EXCEPT"
+# skipped tests: LU-8411 LU-9096 LU-9054 ..
+ALWAYS_EXCEPT="  407     253     312     $ALWAYS_EXCEPT"
+# skipped tests: LU-4684
+ALWAYS_EXCEPT="  17n 160d 230 316      $ALWAYS_EXCEPT"
 
 # Check Grants after these tests
 GRANT_CHECK_LIST="$GRANT_CHECK_LIST 42a 42b 42c 42d 42e 63a 63b 64a 64b 64c"
@@ -59,6 +61,11 @@ init_test_env $@
 . ${CONFIG:=$LUSTRE/tests/cfg/${NAME}.sh}
 init_logging
 
+if [[ $MDSCOUNT -gt 1 ]]; then
+       # bug number:    LU-11161
+       ALWAYS_EXCEPT+=" 160g"
+fi
+
 #                                  5          12          (min)"
 [ "$SLOW" = "no" ] && EXCEPT_SLOW="27m 64b 68 71 115 300o"
 
@@ -200,7 +207,7 @@ test_0d() { # LU-3397
        $LCTL get_param mgc.*.import | tee $temp_imp
        # Check if client uuid is found in MGS export
        for exp_client_nid in $(do_facet mgs $LCTL get_param -N $mgs_exp.*); do
-               [ $(do_facet mgs $LCTL get_param $exp_client_nid.uuid) == \
+               [ $(do_facet mgs $LCTL get_param -n $exp_client_nid.uuid) == \
                        $client_uuid ] &&
                        break;
        done
@@ -660,7 +667,7 @@ test_17m() {
                ln -sf ${short_sym} $wdir/short-$i || error "short_sym failed"
        done
 
-       local mds_index=$(($($LFS getstripe -M $wdir) + 1))
+       local mds_index=$(($($LFS getstripe -m $wdir) + 1))
        local devname=$(mdsdevname $mds_index)
 
        echo "stop and checking mds${mds_index}:"
@@ -761,7 +768,7 @@ test_17o() {
 
        test_mkdir $wdir
        touch $wdir/$tfile
-       mdt_index=$($LFS getstripe -M $wdir/$tfile)
+       mdt_index=$($LFS getstripe -m $wdir/$tfile)
        mdt_index=$((mdt_index + 1))
 
        cancel_lru_locks mdc
@@ -901,6 +908,19 @@ test_23c() {
 }
 run_test 23c "O_APPEND size checks for tiny writes"
 
+# LU-11069 file offset is correct after appending writes
+test_23d() {
+       local file=$DIR/$tfile
+       local offset
+
+       echo CentaurHauls > $file
+       offset=$($MULTIOP $file oO_WRONLY:O_APPEND:w13Zp)
+       if ((offset != 26)); then
+               error "wrong offset, expected 26, got '$offset'"
+       fi
+}
+run_test 23d "file offset is correct after appending writes"
+
 # rename sanity
 test_24a() {
        echo '-- same directory rename'
@@ -1597,7 +1617,7 @@ exhaust_precreations() {
        local ofacet=ost$((OSTIDX + 1))
 
        test_mkdir -p -c1 $DIR/$tdir
-       local mdtidx=$($LFS getstripe -M $DIR/$tdir)
+       local mdtidx=$($LFS getstripe -m $DIR/$tdir)
        local mfacet=mds$((mdtidx + 1))
        echo OSTIDX=$OSTIDX MDTIDX=$mdtidx
 
@@ -2277,6 +2297,25 @@ test_27G() { #LU-10629
 }
 run_test 27G "Clear OST pool from stripe"
 
+test_27H() {
+       [[ $(lustre_version_code $SINGLEMDS) -le $(version_code 2.11.53) ]] &&
+               skip "Need MDS version newer than 2.11.53"
+       [[ $OSTCOUNT -lt 3 ]] && skip_env "needs >= 3 OSTs"
+       test_mkdir $DIR/$tdir
+       $LFS setstripe -o 0 -o 2 $DIR/$tdir || error "setstripe failed"
+       touch $DIR/$tdir/$tfile
+       $LFS getstripe -c $DIR/$tdir/$tfile
+       [ $($LFS getstripe -c $DIR/$tdir/$tfile) -eq 2 ] ||
+               error "two-stripe file doesn't have two stripes"
+
+       dd if=/dev/zero of=$DIR/$tdir/$tfile bs=4k count=4 || error "dd failed"
+       $LFS getstripe -y $DIR/$tdir/$tfile
+       (( $($LFS getstripe -y $DIR/$tdir/$tfile |
+            egrep -c "l_ost_idx: [02]$") == "2" )) ||
+               error "expected l_ost_idx: [02]$ not matched"
+}
+run_test 27H "Set specific OSTs stripe"
+
 # createtest also checks that device nodes are created and
 # then visible correctly (#2091)
 test_28() { # bug 2091
@@ -4357,7 +4396,7 @@ test_51b() {
 
        $LFS df
        $LFS df -i
-       local mdtidx=$(printf "%04x" $($LFS getstripe -M $dir))
+       local mdtidx=$(printf "%04x" $($LFS getstripe -m $dir))
        local numfree=$(lctl get_param -n mdc.$FSNAME-MDT$mdtidx*.filesfree)
        [[ $numfree -lt $nrdirs ]] &&
                skip "not enough free inodes ($numfree) on MDT$mdtidx"
@@ -4468,8 +4507,8 @@ test_51f() {
        local max=100000
        local ulimit_old=$(ulimit -n)
        local spare=20 # number of spare fd's for scripts/libraries, etc.
-       local mdt=$(lfs getstripe -M $DIR/$tdir)
-       local numfree=$(lfs df -i $DIR/$tdir | awk '/MDT:'$mdt'/ { print $4 }')
+       local mdt=$($LFS getstripe -m $DIR/$tdir)
+       local numfree=$($LFS df -i $DIR/$tdir | awk '/MDT:'$mdt'/ { print $4 }')
 
        echo "MDT$mdt numfree=$numfree, max=$max"
        [[ $numfree -gt $max ]] && numfree=$max || numfree=$((numfree * 7 / 8))
@@ -5265,21 +5304,21 @@ test_56u() { # LU-611
 run_test 56u "check lfs find -stripe-index works"
 
 test_56v() {
-       local MDT_IDX=0
+       local mdt_idx=0
        local dir=$DIR/$tdir
 
        setup_56 $dir $NUMFILES $NUMDIRS
 
-       UUID=$(mdtuuid_from_index $MDT_IDX $dir)
-       [ -z "$UUID" ] && error "mdtuuid_from_index cannot find MDT $MDT_IDX"
+       UUID=$(mdtuuid_from_index $mdt_idx $dir)
+       [ -z "$UUID" ] && error "mdtuuid_from_index cannot find MDT $mdt_idx"
 
-       for file in $($LFS find -mdt $UUID $dir); do
-               file_mdt_idx=$($LFS getstripe -M $file)
-               [ $file_mdt_idx -eq $MDT_IDX ] ||
-                       error "lfind -mdt $UUID != getstripe -M $file_mdt_idx"
+       for file in $($LFS find -m $UUID $dir); do
+               file_midx=$($LFS getstripe -m $file)
+               [ $file_midx -eq $mdt_idx ] ||
+                       error "lfs find -m $UUID != getstripe -m $file_midx"
        done
 }
-run_test 56v "check 'lfs find -mdt match with lfs getstripe -M' ======="
+run_test 56v "check 'lfs find -m match with lfs getstripe -m'"
 
 test_56w() {
        [[ $OSTCOUNT -lt 2 ]] && skip_env "needs >= 2 OSTs"
@@ -6025,50 +6064,54 @@ test_57b() {
        remote_mds_nodsh && skip "remote MDS with nodsh"
 
        local dir=$DIR/$tdir
-       local FILECOUNT=100
-       local FILE1=$dir/f1
-       local FILEN=$dir/f$FILECOUNT
+       local filecount=100
+       local file1=$dir/f1
+       local fileN=$dir/f$filecount
 
        rm -rf $dir || error "removing $dir"
        test_mkdir -c1 $dir
-       local mdtidx=$($LFS getstripe -M $dir)
+       local mdtidx=$($LFS getstripe -m $dir)
        local mdtname=MDT$(printf %04x $mdtidx)
        local facet=mds$((mdtidx + 1))
 
-       echo "mcreating $FILECOUNT files"
-       createmany -m $dir/f 1 $FILECOUNT || \
-               error "creating files in $dir"
+       echo "mcreating $filecount files"
+       createmany -m $dir/f 1 $filecount || error "creating files in $dir"
 
        # verify that files do not have EAs yet
-       $GETSTRIPE $FILE1 2>&1 | grep -q "no stripe" || error "$FILE1 has an EA"
-       $GETSTRIPE $FILEN 2>&1 | grep -q "no stripe" || error "$FILEN has an EA"
+       $LFS getstripe $file1 2>&1 | grep -q "no stripe" ||
+               error "$file1 has an EA"
+       $LFS getstripe $fileN 2>&1 | grep -q "no stripe" ||
+               error "$fileN has an EA"
 
        sync
        sleep 1
        df $dir  #make sure we get new statfs data
-       local MDSFREE=$(do_facet $facet \
-               lctl get_param -n osd*.*$mdtname.kbytesfree)
-       local MDCFREE=$(lctl get_param -n mdc.*$mdtname-mdc-*.kbytesfree)
+       local mdsfree=$(do_facet $facet \
+                       lctl get_param -n osd*.*$mdtname.kbytesfree)
+       local mdcfree=$(lctl get_param -n mdc.*$mdtname-mdc-*.kbytesfree)
+       local file
+
        echo "opening files to create objects/EAs"
-       local FILE
-       for FILE in `seq -f $dir/f%g 1 $FILECOUNT`; do
-               $OPENFILE -f O_RDWR $FILE > /dev/null 2>&1 || error "opening $FILE"
+       for file in $(seq -f $dir/f%g 1 $filecount); do
+               $OPENFILE -f O_RDWR $file > /dev/null 2>&1 ||
+                       error "opening $file"
        done
 
        # verify that files have EAs now
-       $GETSTRIPE $FILE1 | grep -q "obdidx" || error "$FILE1 missing EA"
-       $GETSTRIPE $FILEN | grep -q "obdidx" || error "$FILEN missing EA"
+       $LFS getstripe $file1 | grep -q "obdidx" || error "$file1 missing EA"
+       $LFS getstripe $fileN | grep -q "obdidx" || error "$fileN missing EA"
 
        sleep 1  #make sure we get new statfs data
        df $dir
-       local MDSFREE2=$(do_facet $facet \
-               lctl get_param -n osd*.*$mdtname.kbytesfree)
-       local MDCFREE2=$(lctl get_param -n mdc.*$mdtname-mdc-*.kbytesfree)
-       if [[ $MDCFREE2 -lt $((MDCFREE - 16)) ]]; then
-               if [ "$MDSFREE" != "$MDSFREE2" ]; then
-                       error "MDC before $MDCFREE != after $MDCFREE2"
+       local mdsfree2=$(do_facet $facet \
+                        lctl get_param -n osd*.*$mdtname.kbytesfree)
+       local mdcfree2=$(lctl get_param -n mdc.*$mdtname-mdc-*.kbytesfree)
+
+       if [[ $mdcfree2 -lt $((mdcfree - 16)) ]]; then
+               if [ "$mdsfree" != "$mdsfree2" ]; then
+                       error "MDC before $mdcfree != after $mdcfree2"
                else
-                       echo "MDC before $MDCFREE != after $MDCFREE2"
+                       echo "MDC before $mdcfree != after $mdcfree2"
                        echo "unable to confirm if MDS has large inodes"
                fi
        fi
@@ -6108,7 +6151,7 @@ test_60a() {
 
        log "$TEST60_HEAD - from kernel mode"
        do_facet mgs "$LCTL set_param debug=warning; $LCTL dk > /dev/null"
-       do_facet mgs "sh run-llog.sh" || error "run-llog.sh failed"
+       do_facet mgs "bash run-llog.sh" || error "run-llog.sh failed"
        do_facet mgs $LCTL dk > $TMP/$tfile
 
        # LU-6388: test llog_reader
@@ -6207,6 +6250,10 @@ run_test 60aa "llog_print works with FIDs and simple names"
 
 test_60ab() {
        # test llog_print with params
+
+       [[ $(lustre_version_code $SINGLEMDS) -gt $(version_code 2.11.51) ]] ||
+               skip "Need server version greater than 2.11.51"
+
        local yaml
        local orig_val
 
@@ -6943,8 +6990,8 @@ set_checksums()
 
 export ORIG_CSUM_TYPE="`lctl get_param -n osc.*osc-[^mM]*.checksum_type |
                         sed 's/.*\[\(.*\)\].*/\1/g' | head -n1`"
-CKSUM_TYPES=${CKSUM_TYPES:-"crc32 adler"}
-[ "$ORIG_CSUM_TYPE" = "crc32c" ] && CKSUM_TYPES="$CKSUM_TYPES crc32c"
+CKSUM_TYPES=${CKSUM_TYPES:-$(lctl get_param -n osc.*osc-[^mM]*.checksum_type |
+                            tr -d [] | head -n1)}
 set_checksum_type()
 {
        lctl set_param -n osc.*osc-[^mM]*.checksum_type $1
@@ -7003,8 +7050,8 @@ cleanup_77c() {
        $LCTL set_param osc.*osc-[^mM]*.checksum_dump=0
        $check_ost &&
                do_facet ost1 $LCTL set_param obdfilter.*-OST*.checksum_dump=0
-       [ -n $osc_file_prefix ] && rm -f ${osc_file_prefix}*
-       $check_ost && [ -n $ost_file_prefix ] &&
+       [ -n "$osc_file_prefix" ] && rm -f ${osc_file_prefix}*
+       $check_ost && [ -n "$ost_file_prefix" ] &&
                do_facet ost1 rm -f ${ost_file_prefix}\*
 }
 
@@ -7159,28 +7206,45 @@ test_77g() { # bug 10889
 }
 run_test 77g "checksum error on OST write, read"
 
-test_77j() { # bug 13805
+test_77k() { # LU-10906
        [ $PARALLEL == "yes" ] && skip "skip parallel run"
        $GSS && skip_env "could not run with gss"
 
-       #define OBD_FAIL_OSC_CKSUM_ADLER_ONLY    0x40c
-       lctl set_param fail_loc=0x40c
-       remount_client $MOUNT
-       lctl set_param fail_loc=0
-       # wait async osc connect to finish and reflect updated state value
+       local cksum_param="osc.$FSNAME*.checksums"
+       local get_checksum="$LCTL get_param -n $cksum_param | head -n1"
+       local checksum
        local i
-       for (( i=0; i < OSTCOUNT; i++ )) ; do
-               wait_osc_import_state client ost$((i+1)) FULL
+
+       [ "$ORIG_CSUM" ] || ORIG_CSUM=$(eval $get_checksum)
+       stack_trap "wait_update $HOSTNAME '$get_checksum' $ORIG_CSUM" EXIT
+       stack_trap "do_facet mgs $LCTL set_param -P $cksum_param=$ORIG_CSUM" \
+               EXIT
+
+       for i in 0 1; do
+               do_facet mgs $LCTL set_param -P $cksum_param=$i ||
+                       error "failed to set checksum=$i on MGS"
+               wait_update $HOSTNAME "$get_checksum" $i
+               #remount
+               echo "remount client, checksum should be $i"
+               remount_client $MOUNT || "failed to remount client"
+               checksum=$(eval $get_checksum)
+               [ $checksum -eq $i ] || error "checksum($checksum) != $i"
        done
 
-       for VALUE in $(lctl get_param osc.*osc-[^mM]*.checksum_type); do
-               PARAM=$(echo ${VALUE[0]} | cut -d "=" -f1)
-               algo=$(lctl get_param -n $PARAM | sed 's/.*\[\(.*\)\].*/\1/g')
-               [ "$algo" = "adler" ] || error "algo set to $algo instead of adler"
+       for opt in "checksum" "nochecksum"; do
+               #remount with mount option
+               echo "remount client with option $opt, checksum should be $i"
+               umount_client $MOUNT || "failed to umount client"
+               mount_client $MOUNT "$MOUNT_OPTS,$opt" ||
+                       "failed to mount client with option '$opt'"
+               checksum=$(eval $get_checksum)
+               [ $checksum -eq $i ] || error "checksum($checksum) != $i"
+               i=$((i - 1))
        done
-       remount_client $MOUNT
+
+       remount_client $MOUNT || "failed to remount client"
 }
-run_test 77j "client only supporting ADLER32"
+run_test 77k "enable/disable checksum correctly"
 
 [ "$ORIG_CSUM" ] && set_checksums $ORIG_CSUM || true
 rm -f $F77_TMP
@@ -8072,7 +8136,7 @@ test_102h() { # bug 15777
 run_test 102h "grow xattr from inside inode to external block"
 
 test_102ha() {
-       large_xattr_enabled || skip_env "large_xattr disabled"
+       large_xattr_enabled || skip_env "ea_inode feature disabled"
 
        grow_xattr $(max_xattr_size)
 }
@@ -8323,6 +8387,56 @@ test_102r() {
 }
 run_test 102r "set EAs with empty values"
 
+test_102s() {
+       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.11.52) ] &&
+               skip "MDS needs to be at least 2.11.52"
+
+       local save="$TMP/$TESTSUITE-$TESTNAME.parameters"
+
+       save_lustre_params client "llite.*.xattr_cache" > $save
+
+       for cache in 0 1; do
+               lctl set_param llite.*.xattr_cache=$cache
+
+               rm -f $DIR/$tfile
+               touch $DIR/$tfile || error "touch"
+               for prefix in lustre security system trusted user; do
+                       # Note getxattr() may fail with 'Operation not
+                       # supported' or 'No such attribute' depending
+                       # on prefix and cache.
+                       getfattr -n $prefix.n102s $DIR/$tfile &&
+                               error "getxattr '$prefix.n102s' should fail (cache = $cache)"
+               done
+       done
+
+       restore_lustre_params < $save
+}
+run_test 102s "getting nonexistent xattrs should fail"
+
+test_102t() {
+       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.11.52) ] &&
+               skip "MDS needs to be at least 2.11.52"
+
+       local save="$TMP/$TESTSUITE-$TESTNAME.parameters"
+
+       save_lustre_params client "llite.*.xattr_cache" > $save
+
+       for cache in 0 1; do
+               lctl set_param llite.*.xattr_cache=$cache
+
+               for buf_size in 0 256; do
+                       rm -f $DIR/$tfile
+                       touch $DIR/$tfile || error "touch"
+                       setfattr -n user.multiop $DIR/$tfile
+                       $MULTIOP $DIR/$tfile oa$buf_size ||
+                               error "cannot get zero length xattr value (buf_size = $buf_size)"
+               done
+       done
+
+       restore_lustre_params < $save
+}
+run_test 102t "zero length xattr values handled correctly"
+
 run_acl_subtest()
 {
     $LUSTRE/tests/acl/run $LUSTRE/tests/acl/$1.test
@@ -10642,6 +10756,9 @@ test_133b() {
                ls -l ${testdir}/${tfile} > /dev/null|| error "ls failed"
                check_stats $SINGLEMDS "getattr" 1
        fi
+       # Sleep to avoid a cached response.
+       #define OBD_STATFS_CACHE_SECONDS 1
+       sleep 2
        $LFS df || error "lfs failed"
        check_stats $SINGLEMDS "statfs" 1
 
@@ -10866,6 +10983,18 @@ run_test 133e "Verifying OST {read,write}_bytes nid stats ================="
 
 proc_regexp="/{proc,sys}/{fs,sys,kernel/debug}/{lustre,lnet}/"
 
+# Some versions of find (4.5.11, 4.5.14) included in CentOS 7.3-7.5 do
+# not honor the -ignore_readdir_race option correctly. So we call
+# error_ignore() rather than error() in these cases. See LU-11152.
+error_133() {
+       if (find --version; do_facet mds1 find --version) |
+               grep -q '\b4\.5\.1[1-4]\b'; then
+               error_ignore LU-11152 "$@"
+       else
+               error "$@"
+       fi
+}
+
 test_133f() {
        # First without trusting modes.
        local proc_dirs=$(eval \ls -d $proc_regexp 2>/dev/null)
@@ -10883,7 +11012,7 @@ test_133f() {
                -not -name force_lbug \
                -not -name changelog_mask \
                -exec badarea_io '{}' \; ||
-                       error "find $proc_dirs failed"
+                       error_133 "find $proc_dirs failed"
 }
 run_test 133f "Check reads/writes of client lustre proc files with bad area io"
 
@@ -10917,7 +11046,7 @@ test_133g() {
                        -not -name force_lbug \
                        -not -name changelog_mask \
                        -exec badarea_io '{}' \\\; ||
-                               error "$facet find $facet_proc_dirs failed"
+                               error_133 "$facet find $facet_proc_dirs failed"
        done
 
        # remount the FS in case writes/reads /proc break the FS
@@ -12193,18 +12322,21 @@ test_160e() {
 run_test 160e "changelog negative testing (should return errors)"
 
 test_160f() {
-       remote_mds_nodsh && skip "remote MDS with nodsh"
+       remote_mds_nodsh && skip "remote MDS with nodsh" && return
        [[ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.10.56) ]] ||
-               skip "Need MDS version at least 2.10.56"
+               { skip "Need MDS version at least 2.10.56"; return 0; }
 
        local mdts=$(comma_list $(mdts_nodes))
 
        # Create a user
        changelog_register || error "first changelog_register failed"
        changelog_register || error "second changelog_register failed"
-       local cl_users=(${CL_USERS[$SINGLEMDS]})
-       local cl_user1="${cl_users[0]}"
-       local cl_user2="${cl_users[1]}"
+       local cl_users
+       declare -A cl_user1
+       declare -A cl_user2
+       local user_rec1
+       local user_rec2
+       local i
 
        # generate some changelog records to accumulate on each MDT
        test_mkdir -c $MDSCOUNT $DIR/$tdir || error "test_mkdir $tdir failed"
@@ -12212,11 +12344,11 @@ test_160f() {
                error "create $DIR/$tdir/$tfile failed"
 
        # check changelogs have been generated
-       nbcl=$(changelog_dump | wc -l)
+       local nbcl=$(changelog_dump | wc -l)
        [[ $nbcl -eq 0 ]] && error "no changelogs found"
 
-       # changelog_gc=1 should be set by default
        for param in "changelog_max_idle_time=10" \
+                    "changelog_gc=1" \
                     "changelog_min_gc_interval=2" \
                     "changelog_min_free_cat_entries=3"; do
                local MDT0=$(facet_svc $SINGLEMDS)
@@ -12227,44 +12359,79 @@ test_160f() {
                do_nodes $mdts $LCTL set_param mdd.*.$param
        done
 
+       # force cl_user2 to be idle (1st part)
+       sleep 9
+
        # simulate changelog catalog almost full
        #define OBD_FAIL_CAT_FREE_RECORDS       0x1313
        do_nodes $mdts $LCTL set_param fail_loc=0x1313 fail_val=3
 
-       sleep 6
-       local user_rec1=$(changelog_user_rec $SINGLEMDS $cl_user1)
-       [ -n "$user_rec1" ] ||
-               error "User $cl_user1 not found in changelog_users"
-       __changelog_clear $SINGLEMDS $cl_user1 +2
-       local user_rec2=$(changelog_user_rec $SINGLEMDS $cl_user1)
-       [ -n "$user_rec2" ] ||
-               error "User $cl_user1 not found in changelog_users"
-       echo "verifying user clear: $user_rec1 + 2 == $user_rec2"
-       [ $((user_rec1 + 2)) == $user_rec2 ] ||
-               error "user index expected $user_rec1 + 2, but is $user_rec2"
-       sleep 5
+       for i in $(seq $MDSCOUNT); do
+               cl_users=(${CL_USERS[mds$i]})
+               cl_user1[mds$i]="${cl_users[0]}"
+               cl_user2[mds$i]="${cl_users[1]}"
+
+               [ -n "${cl_user1[mds$i]}" ] ||
+                       error "mds$i: no user registered"
+               [ -n "${cl_user2[mds$i]}" ] ||
+                       error "mds$i: only ${cl_user2[mds$i]} is registered"
+
+               user_rec1=$(changelog_user_rec mds$i ${cl_user1[mds$i]})
+               [ -n "$user_rec1" ] ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               __changelog_clear mds$i ${cl_user1[mds$i]} +2
+               user_rec2=$(changelog_user_rec mds$i ${cl_user1[mds$i]})
+               [ -n "$user_rec2" ] ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               echo "mds$i: verifying user ${cl_user1[mds$i]} clear: " \
+                    "$user_rec1 + 2 == $user_rec2"
+               [ $((user_rec1 + 2)) == $user_rec2 ] ||
+                       error "mds$i: user ${cl_user1[mds$i]} index expected " \
+                             "$user_rec1 + 2, but is $user_rec2"
+               user_rec2=$(changelog_user_rec mds$i ${cl_user2[mds$i]})
+               [ -n "$user_rec2" ] ||
+                       error "mds$i: User ${cl_user2[mds$i]} not registered"
+               [ $user_rec1 == $user_rec2 ] ||
+                       error "mds$i: user ${cl_user2[mds$i]} index expected " \
+                             "$user_rec1, but is $user_rec2"
+       done
+
+       # force cl_user2 to be idle (2nd part) and to reach
+       # changelog_max_idle_time
+       sleep 2
 
        # generate one more changelog to trigger fail_loc
-       rm -rf $DIR/$tdir || error "rm -rf $tdir failed"
+       createmany -m $DIR/$tdir/${tfile}bis $((MDSCOUNT * 2)) ||
+               error "create $DIR/$tdir/${tfile}bis failed"
 
        # ensure gc thread is done
-       wait_update_facet $SINGLEMDS \
-                         "ps -e -o comm= | grep chlg_gc_thread" "" 20
-
-       # check user still registered
-       changelog_users $SINGLEMDS | grep -q "$cl_user1" ||
-               error "User $cl_user1 not found in changelog_users"
-       # check user2 unregistered
-       changelog_users $SINGLEMDS | grep -q "$cl_user2" &&
-               error "User $cl_user2 still found in changelog_users"
-
-       # check changelogs are present and starting at $user_rec2 + 1
-       local first_rec=$($LFS changelog $(facet_svc $SINGLEMDS) |
-                         awk '{ print $1; exit; }')
+       for i in $(mdts_nodes); do
+               wait_update $i \
+                       "ps -e -o comm= | grep chlg_gc_thread" "" 20 ||
+                       error "$i: GC-thread not done"
+       done
 
-       echo "verifying min purge: $user_rec2 + 1 == $first_rec"
-       [ $((user_rec2 + 1)) == $first_rec ] ||
-               error "first index should be $user_rec2 + 1, but is $first_rec"
+       local first_rec
+       for i in $(seq $MDSCOUNT); do
+               # check cl_user1 still registered
+               changelog_users mds$i | grep -q "${cl_user1[mds$i]}" ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               # check cl_user2 unregistered
+               changelog_users mds$i | grep -q "${cl_user2[mds$i]}" &&
+                       error "mds$i: User ${cl_user2[mds$i]} still registered"
+
+               # check changelogs are present and starting at $user_rec1 + 1
+               user_rec1=$(changelog_user_rec mds$i ${cl_user1[mds$i]})
+               [ -n "$user_rec1" ] ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               first_rec=$($LFS changelog $(facet_svc mds$i) |
+                           awk '{ print $1; exit; }')
+
+               echo "mds$i: verifying first index $user_rec1 + 1 == $first_rec"
+               [ $((user_rec1 + 1)) == $first_rec ] ||
+                       error "mds$i: first index should be $user_rec1 + 1, " \
+                             "but is $first_rec"
+       done
 }
 run_test 160f "changelog garbage collect (timestamped users)"
 
@@ -12281,9 +12448,12 @@ test_160g() {
        # Create a user
        changelog_register || error "first changelog_register failed"
        changelog_register || error "second changelog_register failed"
-       local cl_users=(${CL_USERS[$SINGLEMDS]})
-       local cl_user1="${cl_users[0]}"
-       local cl_user2="${cl_users[1]}"
+       local cl_users
+       declare -A cl_user1
+       declare -A cl_user2
+       local user_rec1
+       local user_rec2
+       local i
 
        # generate some changelog records to accumulate on each MDT
        test_mkdir -c $MDSCOUNT $DIR/$tdir || error "mkdir $tdir failed"
@@ -12291,11 +12461,11 @@ test_160g() {
                error "create $DIR/$tdir/$tfile failed"
 
        # check changelogs have been generated
-       nbcl=$(changelog_dump | wc -l)
+       local nbcl=$(changelog_dump | wc -l)
        [[ $nbcl -eq 0 ]] && error "no changelogs found"
 
-       # changelog_gc=1 should be set by default
        for param in "changelog_max_idle_indexes=$((nbcl / 2))" \
+                    "changelog_gc=1" \
                     "changelog_min_gc_interval=2" \
                     "changelog_min_free_cat_entries=3"; do
                local MDT0=$(facet_svc $SINGLEMDS)
@@ -12311,39 +12481,293 @@ test_160g() {
        #define OBD_FAIL_CAT_FREE_RECORDS       0x1313
        do_nodes $mdts $LCTL set_param fail_loc=0x1313 fail_val=3
 
-       local user_rec1=$(changelog_user_rec $SINGLEMDS $cl_user1)
-
-       __changelog_clear $SINGLEMDS $cl_user1 +3
-
-       local user_rec2=$(changelog_user_rec $SINGLEMDS $cl_user1)
+       for i in $(seq $MDSCOUNT); do
+               cl_users=(${CL_USERS[mds$i]})
+               cl_user1[mds$i]="${cl_users[0]}"
+               cl_user2[mds$i]="${cl_users[1]}"
+
+               [ -n "${cl_user1[mds$i]}" ] ||
+                       error "mds$i: no user registered"
+               [ -n "${cl_user2[mds$i]}" ] ||
+                       error "mds$i: only ${cl_user1[mds$i]} is registered"
+
+               user_rec1=$(changelog_user_rec mds$i ${cl_user1[mds$i]})
+               [ -n "$user_rec1" ] ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               __changelog_clear mds$i ${cl_user1[mds$i]} +2
+               user_rec2=$(changelog_user_rec mds$i ${cl_user1[mds$i]})
+               [ -n "$user_rec2" ] ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               echo "mds$i: verifying user ${cl_user1[mds$i]} clear: " \
+                    "$user_rec1 + 2 == $user_rec2"
+               [ $((user_rec1 + 2)) == $user_rec2 ] ||
+                       error "mds$i: user ${cl_user1[mds$i]} index expected " \
+                             "$user_rec1 + 2, but is $user_rec2"
+               user_rec2=$(changelog_user_rec mds$i ${cl_user2[mds$i]})
+               [ -n "$user_rec2" ] ||
+                       error "mds$i: User ${cl_user2[mds$i]} not registered"
+               [ $user_rec1 == $user_rec2 ] ||
+                       error "mds$i: user ${cl_user2[mds$i]} index expected " \
+                             "$user_rec1, but is $user_rec2"
+       done
 
-       echo "verifying user clear: $user_rec1 + 3 == $user_rec2"
-       [ $((user_rec1 + 3)) == $user_rec2 ] ||
-               error "user index expected $user_rec1 + 3, but is $user_rec2"
+       # ensure we are past the previous changelog_min_gc_interval set above
+       sleep 2
 
        # generate one more changelog to trigger fail_loc
-       rm -rf $DIR/$tdir || error "rm -rf $tdir failed"
+       createmany -m $DIR/$tdir/${tfile}bis $((MDSCOUNT * 2)) ||
+               error "create $DIR/$tdir/${tfile}bis failed"
 
        # ensure gc thread is done
-       wait_update_facet $SINGLEMDS \
-                         "ps -e -o comm= | grep chlg_gc_thread" "" 20
+       for i in $(mdts_nodes); do
+               wait_update $i \
+                       "ps -e -o comm= | grep chlg_gc_thread" "" 20 ||
+                       error "$i: GC-thread not done"
+       done
 
-       # check user still registered
-       [ -n "$(changelog_user_rec $SINGLEMDS $cl_user1)" ] ||
-               error "User $cl_user1 not found in changelog_users"
-       # check user2 unregistered
-       [ -z "$(changelog_user_rec $SINGLEMDS $cl_user2)" ] ||
-               error "User $cl_user2 still found in changelog_users"
+       local first_rec
+       for i in $(seq $MDSCOUNT); do
+               # check cl_user1 still registered
+               changelog_users mds$i | grep -q "${cl_user1[mds$i]}" ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               # check cl_user2 unregistered
+               changelog_users mds$i | grep -q "${cl_user2[mds$i]}" &&
+                       error "mds$i: User ${cl_user2[mds$i]} still registered"
+
+               # check changelogs are present and starting at $user_rec1 + 1
+               user_rec1=$(changelog_user_rec mds$i ${cl_user1[mds$i]})
+               [ -n "$user_rec1" ] ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               first_rec=$($LFS changelog $(facet_svc mds$i) |
+                           awk '{ print $1; exit; }')
+
+               echo "mds$i: verifying first index $user_rec1 + 1 == $first_rec"
+               [ $((user_rec1 + 1)) == $first_rec ] ||
+                       error "mds$i: first index should be $user_rec1 + 1, " \
+                             "but is $first_rec"
+       done
+}
+run_test 160g "changelog garbage collect (old users)"
 
-       # check changelogs are present and starting at $user_rec2 + 1
-       local first_rec=$($LFS changelog $(facet_svc $SINGLEMDS) |
-                         awk '{ print $1; exit; }')
+test_160h() {
+       remote_mds_nodsh && skip "remote MDS with nodsh" && return
+       [[ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.10.56) ]] ||
+               { skip "Need MDS version at least 2.10.56"; return 0; }
+
+       local mdts=$(comma_list $(mdts_nodes))
+
+       # Create a user
+       changelog_register || error "first changelog_register failed"
+       changelog_register || error "second changelog_register failed"
+       local cl_users
+       declare -A cl_user1
+       declare -A cl_user2
+       local user_rec1
+       local user_rec2
+       local i
+
+       # generate some changelog records to accumulate on each MDT
+       test_mkdir -c $MDSCOUNT $DIR/$tdir || error "test_mkdir $tdir failed"
+       createmany -m $DIR/$tdir/$tfile $((MDSCOUNT * 2)) ||
+               error "create $DIR/$tdir/$tfile failed"
+
+       # check changelogs have been generated
+       local nbcl=$(changelog_dump | wc -l)
+       [[ $nbcl -eq 0 ]] && error "no changelogs found"
+
+       for param in "changelog_max_idle_time=10" \
+                    "changelog_gc=1" \
+                    "changelog_min_gc_interval=2"; do
+               local MDT0=$(facet_svc $SINGLEMDS)
+               local var="${param%=*}"
+               local old=$(do_facet mds1 "$LCTL get_param -n mdd.$MDT0.$var")
+
+               stack_trap "do_nodes $mdts $LCTL set_param mdd.*.$var=$old" EXIT
+               do_nodes $mdts $LCTL set_param mdd.*.$param
+       done
+
+       # force cl_user2 to be idle (1st part)
+       sleep 9
+
+       for i in $(seq $MDSCOUNT); do
+               cl_users=(${CL_USERS[mds$i]})
+               cl_user1[mds$i]="${cl_users[0]}"
+               cl_user2[mds$i]="${cl_users[1]}"
+
+               [ -n "${cl_user1[mds$i]}" ] ||
+                       error "mds$i: no user registered"
+               [ -n "${cl_user2[mds$i]}" ] ||
+                       error "mds$i: only ${cl_user2[mds$i]} is registered"
+
+               user_rec1=$(changelog_user_rec mds$i ${cl_user1[mds$i]})
+               [ -n "$user_rec1" ] ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               __changelog_clear mds$i ${cl_user1[mds$i]} +2
+               user_rec2=$(changelog_user_rec mds$i ${cl_user1[mds$i]})
+               [ -n "$user_rec2" ] ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               echo "mds$i: verifying user ${cl_user1[mds$i]} clear: " \
+                    "$user_rec1 + 2 == $user_rec2"
+               [ $((user_rec1 + 2)) == $user_rec2 ] ||
+                       error "mds$i: user ${cl_user1[mds$i]} index expected " \
+                             "$user_rec1 + 2, but is $user_rec2"
+               user_rec2=$(changelog_user_rec mds$i ${cl_user2[mds$i]})
+               [ -n "$user_rec2" ] ||
+                       error "mds$i: User ${cl_user2[mds$i]} not registered"
+               [ $user_rec1 == $user_rec2 ] ||
+                       error "mds$i: user ${cl_user2[mds$i]} index expected " \
+                             "$user_rec1, but is $user_rec2"
+       done
+
+       # force cl_user2 to be idle (2nd part) and to reach
+       # changelog_max_idle_time
+       sleep 2
 
-       echo "verifying min purge: $user_rec2 + 1 == $first_rec"
-       [ $((user_rec2 + 1)) == $first_rec ] ||
-               error "first index should be $user_rec2 + 1, but is $first_rec"
+       # force each GC-thread start and block then
+       # one per MDT/MDD, set fail_val accordingly
+       #define OBD_FAIL_FORCE_GC_THREAD 0x1316
+       do_nodes $mdts $LCTL set_param fail_loc=0x1316
+
+       # generate more changelogs to trigger fail_loc
+       createmany -m $DIR/$tdir/${tfile}bis $((MDSCOUNT * 2)) ||
+               error "create $DIR/$tdir/${tfile}bis failed"
+
+       # stop MDT to stop GC-thread, should be done in back-ground as it will
+       # block waiting for the thread to be released and exit
+       declare -A stop_pids
+       for i in $(seq $MDSCOUNT); do
+               stop mds$i &
+               stop_pids[mds$i]=$!
+       done
+
+       for i in $(mdts_nodes); do
+               local facet
+               local nb=0
+               local facets=$(facets_up_on_host $i)
+
+               for facet in ${facets//,/ }; do
+                       if [[ $facet == mds* ]]; then
+                               nb=$((nb + 1))
+                       fi
+               done
+               # ensure each MDS's gc threads are still present and all in "R"
+               # state (OBD_FAIL_FORCE_GC_THREAD effect!)
+               [[ $(do_node $i pgrep chlg_gc_thread | wc -l) -eq $nb ]] ||
+                       error "$i: expected $nb GC-thread"
+               wait_update $i \
+                       "ps -C chlg_gc_thread -o state --no-headers | uniq" \
+                       "R" 20 ||
+                       error "$i: GC-thread not found in R-state"
+               # check umounts of each MDT on MDS have reached kthread_stop()
+               [[ $(do_node $i pgrep umount | wc -l) -eq $nb ]] ||
+                       error "$i: expected $nb umount"
+               wait_update $i \
+                       "ps -C umount -o state --no-headers | uniq" "D" 20 ||
+                       error "$i: umount not found in D-state"
+       done
+
+       # release all GC-threads
+       do_nodes $mdts $LCTL set_param fail_loc=0
+
+       # wait for MDT stop to complete
+       for i in $(seq $MDSCOUNT); do
+               wait ${stop_pids[mds$i]} || error "mds$i: stop failed"
+       done
+
+       # XXX
+       # may try to check if any orphan changelog records are present
+       # via ldiskfs/zfs and llog_reader...
+
+       # re-start/mount MDTs
+       for i in $(seq $MDSCOUNT); do
+               start mds$i $(mdsdevname $i) $MDS_MOUNT_OPTS ||
+                       error "Fail to start mds$i"
+       done
+
+       local first_rec
+       for i in $(seq $MDSCOUNT); do
+               # check cl_user1 still registered
+               changelog_users mds$i | grep -q "${cl_user1[mds$i]}" ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               # check cl_user2 unregistered
+               changelog_users mds$i | grep -q "${cl_user2[mds$i]}" &&
+                       error "mds$i: User ${cl_user2[mds$i]} still registered"
+
+               # check changelogs are present and starting at $user_rec1 + 1
+               user_rec1=$(changelog_user_rec mds$i ${cl_user1[mds$i]})
+               [ -n "$user_rec1" ] ||
+                       error "mds$i: User ${cl_user1[mds$i]} not registered"
+               first_rec=$($LFS changelog $(facet_svc mds$i) |
+                           awk '{ print $1; exit; }')
+
+               echo "mds$i: verifying first index $user_rec1 + 1 == $first_rec"
+               [ $((user_rec1 + 1)) == $first_rec ] ||
+                       error "mds$i: first index should be $user_rec1 + 1, " \
+                             "but is $first_rec"
+       done
 }
-run_test 160g "changelog garbage collect (old users)"
+run_test 160h "changelog gc thread stop upon umount, orphan records delete " \
+             "during mount"
+
+test_160i() {
+
+       local mdts=$(comma_list $(mdts_nodes))
+
+       changelog_register || error "first changelog_register failed"
+
+       # generate some changelog records to accumulate on each MDT
+       test_mkdir -c $MDSCOUNT $DIR/$tdir || error "mkdir $tdir failed"
+       createmany -m $DIR/$tdir/$tfile $((MDSCOUNT * 2)) ||
+               error "create $DIR/$tdir/$tfile failed"
+
+       # check changelogs have been generated
+       local nbcl=$(changelog_dump | wc -l)
+       [[ $nbcl -eq 0 ]] && error "no changelogs found"
+
+       # simulate race between register and unregister
+       # XXX as fail_loc is set per-MDS, with DNE configs the race
+       # simulation will only occur for one MDT per MDS and for the
+       # others the normal race scenario will take place
+       #define CFS_FAIL_CHLOG_USER_REG_UNREG_RACE          0x1315
+       do_nodes $mdts $LCTL set_param fail_loc=0x10001315
+       do_nodes $mdts $LCTL set_param fail_val=1
+
+       # unregister 1st user
+       changelog_deregister &
+       local pid1=$!
+       # wait some time for deregister work to reach race rdv
+       sleep 2
+       # register 2nd user
+       changelog_register || error "2nd user register failed"
+
+       wait $pid1 || error "1st user deregister failed"
+
+       local i
+       local last_rec
+       declare -A LAST_REC
+       for i in $(seq $MDSCOUNT); do
+               if changelog_users mds$i | grep "^cl"; then
+                       # make sure new records are added with one user present
+                       LAST_REC[mds$i]=$(changelog_users $SINGLEMDS |
+                                         awk '/^current.index:/ { print $NF }')
+               else
+                       error "mds$i has no user registered"
+               fi
+       done
+
+       # generate more changelog records to accumulate on each MDT
+       createmany -m $DIR/$tdir/${tfile}bis $((MDSCOUNT * 2)) ||
+               error "create $DIR/$tdir/${tfile}bis failed"
+
+       for i in $(seq $MDSCOUNT); do
+               last_rec=$(changelog_users $SINGLEMDS |
+                          awk '/^current.index:/ { print $NF }')
+               echo "verify changelogs are on: $last_rec != ${LAST_REC[mds$i]}"
+               [ $last_rec != ${LAST_REC[mds$i]} ] ||
+                       error "changelogs are off on mds$i"
+       done
+}
+run_test 160i "changelog user register/unregister race"
 
 test_161a() {
        [ $PARALLEL == "yes" ] && skip "skip parallel run"
@@ -12824,28 +13248,31 @@ obdecho_test() {
 
 test_180a() {
        [ $PARALLEL == "yes" ] && skip "skip parallel run"
-       remote_ost_nodsh && skip "remote OST with nodsh"
-
-       local rc=0
-       local rmmod_local=0
 
        if ! module_loaded obdecho; then
-           load_module obdecho/obdecho
-           rmmod_local=1
+               load_module obdecho/obdecho &&
+                       stack_trap "rmmod obdecho" EXIT ||
+                       error "unable to load obdecho on client"
        fi
 
        local osc=$($LCTL dl | grep -v mdt | awk '$3 == "osc" {print $4; exit}')
-       local host=$(lctl get_param -n osc.$osc.import |
-                            awk '/current_connection:/ {print $2}' )
-       local target=$(lctl get_param -n osc.$osc.import |
-                            awk '/target:/ {print $2}' )
+       local host=$($LCTL get_param -n osc.$osc.import |
+                    awk '/current_connection:/ { print $2 }' )
+       local target=$($LCTL get_param -n osc.$osc.import |
+                      awk '/target:/ { print $2 }' )
        target=${target%_UUID}
 
-       [[ -n $target ]]  && { setup_obdecho_osc $host $target || rc=1; } || rc=1
-       [ $rc -eq 0 ] && { obdecho_test ${target}_osc client || rc=2; }
-       [[ -n $target ]] && cleanup_obdecho_osc $target
-       [ $rmmod_local -eq 1 ] && rmmod obdecho
-       return $rc
+       if [ -n "$target" ]; then
+               setup_obdecho_osc $host $target &&
+                       stack_trap "cleanup_obdecho_osc $target" EXIT ||
+                       { error "obdecho setup failed with $?"; return; }
+
+               obdecho_test ${target}_osc client ||
+                       error "obdecho_test failed on ${target}_osc"
+       else
+               $LCTL get_param osc.$osc.import
+               error "there is no osc.$osc.import target"
+       fi
 }
 run_test 180a "test obdecho on osc"
 
@@ -12853,15 +13280,19 @@ test_180b() {
        [ $PARALLEL == "yes" ] && skip "skip parallel run"
        remote_ost_nodsh && skip "remote OST with nodsh"
 
-       local rc=0
-       local rmmod_remote=0
-
        do_rpc_nodes $(facet_active_host ost1) load_module obdecho/obdecho &&
-               rmmod_remote=true || error "failed to load module obdecho"
-       target=$(do_facet ost1 $LCTL dl | awk '/obdfilter/ {print $4;exit}')
-       [[ -n $target ]] && { obdecho_test $target ost1 || rc=1; }
-       $rmmod_remote && do_facet ost1 "rmmod obdecho"
-       return $rc
+               stack_trap "do_facet ost1 rmmod obdecho" EXIT ||
+               error "failed to load module obdecho"
+
+       local target=$(do_facet ost1 $LCTL dl |
+                      awk '/obdfilter/ { print $4; exit; }')
+
+       if [ -n "$target" ]; then
+               obdecho_test $target ost1 || error "obdecho_test failed with $?"
+       else
+               do_facet ost1 $LCTL dl
+               error "there is no obdfilter target on ost1"
+       fi
 }
 run_test 180b "test obdecho directly on obdfilter"
 
@@ -12871,23 +13302,22 @@ test_180c() { # LU-2598
        [[ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.4.0) ]] &&
                skip "Need MDS version at least 2.4.0"
 
-       local rc=0
-       local rmmod_remote=false
-       local pages=16384 # 64MB bulk I/O RPC size
-       local target
-
        do_rpc_nodes $(facet_active_host ost1) load_module obdecho/obdecho &&
-               rmmod_remote=true || error "failed to load module obdecho"
+               stack_trap "do_facet ost1 rmmod obdecho" EXIT ||
+               error "failed to load module obdecho"
+
+       local target=$(do_facet ost1 $LCTL dl |
+                      awk '/obdfilter/ { print $4; exit; }')
 
-       target=$(do_facet ost1 $LCTL dl | awk '/obdfilter/ { print $4; exit; }')
        if [ -n "$target" ]; then
-               obdecho_test "$target" ost1 "$pages" || rc=${PIPESTATUS[0]}
+               local pages=16384 # 64MB bulk I/O RPC size
+
+               obdecho_test "$target" ost1 "$pages" ||
+                       error "obdecho_test with pages=$pages failed with $?"
        else
-               echo "there is no obdfilter target on ost1"
-               rc=2
+               do_facet ost1 $LCTL dl
+               error "there is no obdfilter target on ost1"
        fi
-       $rmmod_remote && do_facet ost1 "rmmod obdecho" || true
-       return $rc
 }
 run_test 180c "test huge bulk I/O size on obdfilter, don't LASSERT"
 
@@ -14449,19 +14879,19 @@ test_230a() {
 
        test_mkdir $DIR/$tdir
        test_mkdir -i0 -c1 $DIR/$tdir/test_230_local
-       local mdt_idx=$($GETSTRIPE -M $DIR/$tdir/test_230_local)
+       local mdt_idx=$($LFS getstripe -m $DIR/$tdir/test_230_local)
        [ $mdt_idx -ne 0 ] &&
                error "create local directory on wrong MDT $mdt_idx"
 
        $LFS mkdir -i $MDTIDX $DIR/$tdir/test_230 ||
                        error "create remote directory failed"
-       local mdt_idx=$($GETSTRIPE -M $DIR/$tdir/test_230)
+       local mdt_idx=$($LFS getstripe -m $DIR/$tdir/test_230)
        [ $mdt_idx -ne $MDTIDX ] &&
                error "create remote directory on wrong MDT $mdt_idx"
 
        createmany -o $DIR/$tdir/test_230/t- 10 ||
                error "create files on remote directory failed"
-       mdt_idx=$($GETSTRIPE -M $DIR/$tdir/test_230/t-0)
+       mdt_idx=$($LFS getstripe -m $DIR/$tdir/test_230/t-0)
        [ $mdt_idx -ne $MDTIDX ] && error "create files on wrong MDT $mdt_idx"
        rm -r $DIR/$tdir || error "unlink remote directory failed"
 }
@@ -14517,14 +14947,14 @@ test_230b() {
        echo "migratate to MDT1, then checking.."
        for ((i = 0; i < 10; i++)); do
                for file in $(find $migrate_dir/dir_${i}); do
-                       mdt_index=$($LFS getstripe -M $file)
+                       mdt_index=$($LFS getstripe -m $file)
                        [ $mdt_index == $MDTIDX ] ||
                                error "$file is not on MDT${MDTIDX}"
                done
        done
 
        # the multiple link file should still in MDT0
-       mdt_index=$($LFS getstripe -M $migrate_dir/$tfile)
+       mdt_index=$($LFS getstripe -m $migrate_dir/$tfile)
        [ $mdt_index == 0 ] ||
                error "$file is not on MDT${MDTIDX}"
 
@@ -14581,7 +15011,7 @@ test_230b() {
 
        echo "migrate back to MDT0, checking.."
        for file in $(find $migrate_dir); do
-               mdt_index=$($LFS getstripe -M $file)
+               mdt_index=$($LFS getstripe -m $file)
                [ $mdt_index == $MDTIDX ] ||
                        error "$file is not on MDT${MDTIDX}"
        done
@@ -14678,7 +15108,7 @@ test_230c() {
 
        echo "Finish migration, then checking.."
        for file in $(find $migrate_dir); do
-               mdt_index=$($LFS getstripe -M $file)
+               mdt_index=$($LFS getstripe -m $file)
                [ $mdt_index == $MDTIDX ] ||
                        error "$file is not on MDT${MDTIDX}"
        done
@@ -14711,7 +15141,7 @@ test_230d() {
 
        echo "Finish migration, then checking.."
        for file in $(find $migrate_dir); do
-               mdt_index=$($LFS getstripe -M $file)
+               mdt_index=$($LFS getstripe -m $file)
                [ $mdt_index == $MDTIDX ] ||
                        error "$file is not on MDT${MDTIDX}"
        done
@@ -14739,22 +15169,22 @@ test_230e() {
        $LFS migrate -m 1 $DIR/$tdir/migrate_dir ||
                error "migrate dir fails"
 
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/migrate_dir)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/migrate_dir)
        [ $mdt_index == 1 ] || error "migrate_dir is not on MDT1"
 
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/migrate_dir/a)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/migrate_dir/a)
        [ $mdt_index == 0 ] || error "a is not on MDT0"
 
        $LFS migrate -m 1 $DIR/$tdir/other_dir ||
                error "migrate dir fails"
 
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/other_dir)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/other_dir)
        [ $mdt_index == 1 ] || error "other_dir is not on MDT1"
 
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/migrate_dir/a)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/migrate_dir/a)
        [ $mdt_index == 1 ] || error "a is not on MDT1"
 
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/other_dir/b)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/other_dir/b)
        [ $mdt_index == 1 ] || error "b is not on MDT1"
 
        a_fid=$($LFS path2fid $DIR/$tdir/migrate_dir/a)
@@ -14784,15 +15214,15 @@ test_230f() {
        # a should be migrated to MDT1, since no other links on MDT0
        $LFS migrate -m 1 $DIR/$tdir/migrate_dir ||
                error "#1 migrate dir fails"
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/migrate_dir)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/migrate_dir)
        [ $mdt_index == 1 ] || error "migrate_dir is not on MDT1"
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/migrate_dir/a)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/migrate_dir/a)
        [ $mdt_index == 1 ] || error "a is not on MDT1"
 
        # a should stay on MDT1, because it is a mulitple link file
        $LFS migrate -m 0 $DIR/$tdir/migrate_dir ||
                error "#2 migrate dir fails"
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/migrate_dir/a)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/migrate_dir/a)
        [ $mdt_index == 1 ] || error "a is not on MDT1"
 
        $LFS migrate -m 1 $DIR/$tdir/migrate_dir ||
@@ -14808,7 +15238,7 @@ test_230f() {
        # a should be migrated to MDT0, since no other links on MDT1
        $LFS migrate -m 0 $DIR/$tdir/migrate_dir ||
                error "#4 migrate dir fails"
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/migrate_dir/a)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/migrate_dir/a)
        [ $mdt_index == 0 ] || error "a is not on MDT0"
 
        rm -rf $DIR/$tdir || error "rm dir failed after migration"
@@ -14846,10 +15276,10 @@ test_230h() {
        $LFS migrate -m1 $DIR/$tdir/migrate_dir/.. ||
                error "migrating $tdir fail"
 
-       mdt_index=$($LFS getstripe -M $DIR/$tdir)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir)
        [ $mdt_index == 1 ] || error "$mdt_index != 1 after migration"
 
-       mdt_index=$($LFS getstripe -M $DIR/$tdir/migrate_dir)
+       mdt_index=$($LFS getstripe -m $DIR/$tdir/migrate_dir)
        [ $mdt_index == 1 ] || error "$mdt_index != 1 after migration"
 
 }
@@ -15901,6 +16331,9 @@ test_255b() {
        dd if=/dev/zero of=$DIR/$tfile bs=1048576 count=$size_mb ||
                error "dd to $DIR/$tfile failed"
 
+       #force write to complete before dropping OST cache & checking memory
+       sync
+
        local total=$(facet_meminfo ost1 MemTotal)
        echo "Total memory: $total KiB"
 
@@ -16087,7 +16520,7 @@ test_257() {
        stat $DIR/$tdir
 
 #define OBD_FAIL_MDS_XATTR_REP                 0x161
-       local mdtidx=$($LFS getstripe -M $DIR/$tdir)
+       local mdtidx=$($LFS getstripe -m $DIR/$tdir)
        local facet=mds$((mdtidx + 1))
        set_nodes_failloc $(facet_active_host $facet) 0x80000161
        getfattr -n trusted.name1 $DIR/$tdir 2> /dev/null
@@ -16131,6 +16564,45 @@ test_258b() {
 }
 run_test 258b "verify i_mutex security behavior"
 
+test_259() {
+       local file=$DIR/$tfile
+       local before
+       local after
+
+       [ "$(facet_fstype mds1)" != "ldiskfs" ] &&
+               skip "ldiskfs only test" && return
+
+       stack_trap "rm -f $file" EXIT
+
+       wait_delete_completed
+       before=$(do_facet ost1 "$LCTL get_param -n osd-*.*OST0000.kbytesfree")
+       echo "before: $before"
+
+       $LFS setstripe -i 0 -c 1 $file
+       dd if=/dev/zero of=$file bs=1M count=10 || error "couldn't write"
+       sync_all_data
+       after=$(do_facet ost1 "$LCTL get_param -n osd-*.*OST0000.kbytesfree")
+       echo "after write: $after"
+
+#define OBD_FAIL_OSD_FAIL_AT_TRUNCATE          0x2301
+       do_facet ost1 $LCTL set_param fail_loc=0x2301
+       $TRUNCATE $file 0
+       after=$(do_facet ost1 "$LCTL get_param -n osd-*.*OST0000.kbytesfree")
+       echo "after truncate: $after"
+
+       stop ost1
+       do_facet ost1 $LCTL set_param fail_loc=0
+       start ost1 $(ostdevname 1) $OST_MOUNT_OPTS || error "cannot start ost1"
+       sleep 2
+       after=$(do_facet ost1 "$LCTL get_param -n osd-*.*OST0000.kbytesfree")
+       echo "after restart: $after"
+       [ $((after - before)) -ge $(fs_log_size ost1) ] &&
+               error "missing truncate?"
+
+       return 0
+}
+run_test 259 "crash at delayed truncate"
+
 test_260() {
 #define OBD_FAIL_MDC_CLOSE               0x806
        $LCTL set_param fail_loc=0x80000806
@@ -16164,7 +16636,7 @@ test_270a() {
        [ $($LFS getstripe -c $dom) == 0 ] || error "bad stripe count"
        [ $($LFS getstripe -S $dom) == 1048576 ] || error "bad stripe size"
 
-       local mdtidx=$($GETSTRIPE -M $dom)
+       local mdtidx=$($LFS getstripe -m $dom)
        local mdtname=MDT$(printf %04x $mdtidx)
        local facet=mds$((mdtidx + 1))
        local space_check=1
@@ -16377,7 +16849,9 @@ test_270f() {
                error "Can't set directory default striping"
 
        # exceed maximum stripe size
-       $LFS setstripe -E $(($dom_limit * 2)) -L mdt $dom &&
+       $LFS setstripe -E $((dom_limit * 2)) -L mdt $dom ||
+               error "Can't create file with $((dom_limit * 2)) DoM stripe"
+       [ $($LFS getstripe -S $dom) -eq $((dom_limit * 2)) ] &&
                error "Able to create DoM component size more than LOD limit"
 
        do_facet mds1 $LCTL set_param -n lod.$mdtname.dom_stripesize=0
@@ -16385,6 +16859,19 @@ test_270f() {
                                                lod.$mdtname.dom_stripesize)
        [ 0 -eq ${dom_current} ] ||
                error "Can't set zero DoM stripe limit"
+       rm $dom
+
+       # attempt to create DoM file on server with disabled DoM should
+       # remove DoM entry from layout and be succeed
+       $LFS setstripe -E $dom_limit -L mdt -E -1 $dom ||
+               error "Can't create DoM file (DoM is disabled)"
+       [ $($LFS getstripe -L $dom) == "mdt" ] &&
+               error "File has DoM component while DoM is disabled"
+       rm $dom
+
+       # attempt to create DoM file with only DoM stripe should return error
+       $LFS setstripe -E $dom_limit -L mdt $dom &&
+               error "Able to create DoM-only file while DoM is disabled"
 
        # too low values to be aligned with smallest stripe size 64K
        do_facet mds1 $LCTL set_param -n lod.$mdtname.dom_stripesize=30000
@@ -16393,6 +16880,10 @@ test_270f() {
        [ 30000 -eq ${dom_current} ] &&
                error "Can set too small DoM stripe limit"
 
+       # 64K is a minimal stripe size in Lustre, expect limit of that size
+       [ 65536 -eq ${dom_current} ] ||
+               error "Limit is not set to 64K but ${dom_current}"
+
        do_facet mds1 $LCTL set_param -n lod.$mdtname.dom_stripesize=2147483648
        dom_current=$(do_facet mds1 $LCTL get_param -n \
                                                lod.$mdtname.dom_stripesize)
@@ -16406,7 +16897,9 @@ test_270f() {
                error "Can't create DoM component size after limit change"
        do_facet mds1 $LCTL set_param -n \
                                lod.$mdtname.dom_stripesize=$((dom_limit / 2))
-       $LFS setstripe -E $dom_limit -L mdt ${dom}_big &&
+       $LFS setstripe -E $dom_limit -L mdt ${dom}_big ||
+               error "Can't create DoM file after limit decrease"
+       [ $($LFS getstripe -S ${dom}_big) -eq $((dom_limit / 2)) ] ||
                error "Can create big DoM component after limit decrease"
        touch ${dom}_def ||
                error "Can't create file with old default layout"
@@ -16488,9 +16981,6 @@ test_271ba() {
 run_test 271ba "DoM: no glimpse RPC for stat (combined file)"
 
 test_271c() {
-       # test to be enabled with lock_convert
-       skip "skipped until lock convert will be implemented"
-
        [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.10.55) ] &&
                skip "Need MDS version at least 2.10.55"
 
@@ -16500,7 +16990,7 @@ test_271c() {
 
        $LFS setstripe -E 1024K -L mdt $DIR/$tdir
 
-       local mdtidx=$($LFS getstripe -M $DIR/$tdir)
+       local mdtidx=$($LFS getstripe -m $DIR/$tdir)
        local facet=mds$((mdtidx + 1))
 
        cancel_lru_locks mdc
@@ -16533,6 +17023,197 @@ test_271c() {
 }
 run_test 271c "DoM: IO lock at open saves enqueue RPCs"
 
+cleanup_271def_tests() {
+       trap 0
+       rm -f $1
+}
+
+test_271d() {
+       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.10.57) ] &&
+               skip "Need MDS version at least 2.10.57" && return
+
+       local dom=$DIR/$tdir/dom
+       local tmp=$TMP/$tfile
+       trap "cleanup_271def_tests $tmp" EXIT
+
+       mkdir -p $DIR/$tdir
+
+       $LFS setstripe -E 1024K -L mdt $DIR/$tdir
+
+       local mdtidx=$($GETSTRIPE -M $DIR/$tdir)
+       local facet=mds$((mdtidx + 1))
+
+       cancel_lru_locks mdc
+       dd if=/dev/urandom of=$tmp bs=1000 count=1
+       dd if=$tmp of=$dom bs=1000 count=1
+       cancel_lru_locks mdc
+
+       cat /etc/hosts >> $tmp
+       lctl set_param -n mdc.*.stats=clear
+
+       # append data to the same file it should update local page
+       echo "Append to the same page"
+       cat /etc/hosts >> $dom
+       local num=$(lctl get_param -n mdc.*.stats |
+               awk '/ost_read/ {print $2}')
+       local ra=$(lctl get_param -n mdc.*.stats |
+               awk '/req_active/ {print $2}')
+       local rw=$(lctl get_param -n mdc.*.stats |
+               awk '/req_waittime/ {print $2}')
+
+       [ -z $num ] || error "$num READ RPC occured"
+       [ $ra == $rw ] || error "$((ra - rw)) resend occured"
+       echo "... DONE"
+
+       # compare content
+       cmp $tmp $dom || error "file miscompare"
+
+       cancel_lru_locks mdc
+       lctl set_param -n mdc.*.stats=clear
+
+       echo "Open and read file"
+       cat $dom > /dev/null
+       local num=$(lctl get_param -n mdc.*.stats |
+               awk '/ost_read/ {print $2}')
+       local ra=$(lctl get_param -n mdc.*.stats |
+               awk '/req_active/ {print $2}')
+       local rw=$(lctl get_param -n mdc.*.stats |
+               awk '/req_waittime/ {print $2}')
+
+       [ -z $num ] || error "$num READ RPC occured"
+       [ $ra == $rw ] || error "$((ra - rw)) resend occured"
+       echo "... DONE"
+
+       # compare content
+       cmp $tmp $dom || error "file miscompare"
+
+       return 0
+}
+run_test 271d "DoM: read on open (1K file in reply buffer)"
+
+test_271e() {
+       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.10.57) ] &&
+               skip "Need MDS version at least 2.10.57" && return
+
+       local dom=$DIR/$tdir/dom
+       local tmp=$TMP/${tfile}.data
+       trap "cleanup_271def_tests $tmp" EXIT
+
+       mkdir -p $DIR/$tdir
+
+       $LFS setstripe -E 1024K -L mdt $DIR/$tdir
+
+       local mdtidx=$($GETSTRIPE -M $DIR/$tdir)
+       local facet=mds$((mdtidx + 1))
+
+       cancel_lru_locks mdc
+       dd if=/dev/urandom of=$tmp bs=30K count=1
+       dd if=$tmp of=$dom bs=30K count=1
+       cancel_lru_locks mdc
+       cat /etc/hosts >> $tmp
+       lctl set_param -n mdc.*.stats=clear
+
+       echo "Append to the same page"
+       cat /etc/hosts >> $dom
+
+       local num=$(lctl get_param -n mdc.*.stats | \
+               awk '/ost_read/ {print $2}')
+       local ra=$(lctl get_param -n mdc.*.stats | \
+               awk '/req_active/ {print $2}')
+       local rw=$(lctl get_param -n mdc.*.stats | \
+               awk '/req_waittime/ {print $2}')
+
+       [ -z $num ] || error "$num READ RPC occured"
+       # Reply buffer can be adjusted for larger buffer by resend
+       echo "... DONE with $((ra - rw)) resends"
+
+       # compare content
+       cmp $tmp $dom || error "file miscompare"
+
+       cancel_lru_locks mdc
+       lctl set_param -n mdc.*.stats=clear
+
+       echo "Open and read file"
+       cat $dom > /dev/null
+       local num=$(lctl get_param -n mdc.*.stats | \
+               awk '/ost_read/ {print $2}')
+       local ra=$(lctl get_param -n mdc.*.stats | \
+               awk '/req_active/ {print $2}')
+       local rw=$(lctl get_param -n mdc.*.stats | \
+               awk '/req_waittime/ {print $2}')
+
+       [ -z $num ] || error "$num READ RPC occured"
+       # Reply buffer can be adjusted for larger buffer by resend
+       echo "... DONE with $((ra - rw)) resends"
+
+       # compare content
+       cmp $tmp $dom || error "file miscompare"
+
+       return 0
+}
+run_test 271e "DoM: read on open (30K file with reply buffer adjusting)"
+
+test_271f() {
+       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.10.57) ] &&
+               skip "Need MDS version at least 2.10.57" && return
+
+       local dom=$DIR/$tdir/dom
+       local tmp=$TMP/$tfile
+       trap "cleanup_271def_tests $tmp" EXIT
+
+       mkdir -p $DIR/$tdir
+
+       $LFS setstripe -E 1024K -L mdt $DIR/$tdir
+
+       local mdtidx=$($GETSTRIPE -M $DIR/$tdir)
+       local facet=mds$((mdtidx + 1))
+
+       cancel_lru_locks mdc
+       dd if=/dev/urandom of=$tmp bs=200000 count=1
+       dd if=$tmp of=$dom bs=200000 count=1
+       cancel_lru_locks mdc
+       cat /etc/hosts >> $tmp
+       lctl set_param -n mdc.*.stats=clear
+
+       echo "Append to the same page"
+       cat /etc/hosts >> $dom
+       local num=$(lctl get_param -n mdc.*.stats | \
+               awk '/ost_read/ {print $2}')
+       local ra=$(lctl get_param -n mdc.*.stats | \
+               awk '/req_active/ {print $2}')
+       local rw=$(lctl get_param -n mdc.*.stats | \
+               awk '/req_waittime/ {print $2}')
+
+       [ -z $num ] || error "$num READ RPC occured"
+       [ $ra == $rw ] || error "$((ra - rw)) resend occured"
+       echo "... DONE"
+
+       # compare content
+       cmp $tmp $dom || error "file miscompare"
+
+       cancel_lru_locks mdc
+       lctl set_param -n mdc.*.stats=clear
+
+       echo "Open and read file"
+       cat $dom > /dev/null
+       local num=$(lctl get_param -n mdc.*.stats | \
+               awk '/ost_read/ {print $2}')
+       local ra=$(lctl get_param -n mdc.*.stats | \
+               awk '/req_active/ {print $2}')
+       local rw=$(lctl get_param -n mdc.*.stats | \
+               awk '/req_waittime/ {print $2}')
+
+       [ $num -eq 1 ] || error "expect 1 READ RPC, $num occured"
+       [ $ra == $rw ] || error "$((ra - rw)) resend occured"
+       echo "... DONE"
+
+       # compare content
+       cmp $tmp $dom || error "file miscompare"
+
+       return 0
+}
+run_test 271f "DoM: read on open (200K file and read tail)"
+
 test_275() {
        remote_ost_nodsh && skip "remote OST with nodsh"
        [ $(lustre_version_code ost1) -lt $(version_code 2.10.57) ] &&
@@ -16748,7 +17429,7 @@ test_300d() {
                error "create 10 files failed"
 
        for file in $(find $DIR/$tdir); do
-               stripe_count=$($GETSTRIPE -c $file)
+               stripe_count=$($LFS getstripe -c $file)
                [ $stripe_count -eq 2 ] ||
                        error "wrong stripe $stripe_count for $file"
        done
@@ -17550,7 +18231,7 @@ run_test 315 "read should be accounted"
 
 test_316() {
        [ $MDSCOUNT -lt 2 ] && skip "needs >= 2 MDTs"
-       large_xattr_enabled || skip_env "large_xattr disabled"
+       large_xattr_enabled || skip_env "ea_inode feature disabled"
 
        rm -rf $DIR/$tdir/d
        mkdir -p $DIR/$tdir/d
@@ -17561,6 +18242,73 @@ test_316() {
 }
 run_test 316 "lfs mv"
 
+test_317() {
+       local trunc_sz
+       local grant_blk_size
+
+       if [ "$(facet_fstype $facet)" == "zfs" ]; then
+               skip "LU-10370: no implementation for ZFS" && return
+       fi
+
+       stack_trap "rm -f $DIR/$tfile" EXIT
+       grant_blk_size=$($LCTL get_param osc.$FSNAME*.import |
+                       awk '/grant_block_size:/ { print $2; exit; }')
+       #
+       # Create File of size 5M. Truncate it to below size's and verify
+       # blocks count.
+       #
+       dd if=/dev/zero of=$DIR/$tfile bs=5M count=1 conv=fsync ||
+               error "Create file : $DIR/$tfile"
+
+       for trunc_sz in 2097152 4097 4000 509 0; do
+               $TRUNCATE $DIR/$tfile $trunc_sz ||
+                       error "truncate $tfile to $trunc_sz failed"
+               local sz=$(stat --format=%s $DIR/$tfile)
+               local blk=$(stat --format=%b $DIR/$tfile)
+               local trunc_blk=$((((trunc_sz + (grant_blk_size - 1) ) /
+                                    grant_blk_size) * 8))
+
+               if [[ $blk -ne $trunc_blk ]]; then
+                       $(which stat) $DIR/$tfile
+                       error "Expected Block $trunc_blk got $blk for $tfile"
+               fi
+
+               $CHECKSTAT -s $trunc_sz $DIR/$tfile ||
+                       error "Expected Size $trunc_sz got $sz for $tfile"
+       done
+
+       #
+       # sparse file test
+       # Create file with a hole and write actual two blocks. Block count
+       # must be 16.
+       #
+       dd if=/dev/zero of=$DIR/$tfile bs=$grant_blk_size count=2 seek=5 \
+               conv=fsync || error "Create file : $DIR/$tfile"
+
+       # Calculate the final truncate size.
+       trunc_sz=$(($(stat --format=%s $DIR/$tfile) - (grant_blk_size + 1)))
+
+       #
+       # truncate to size $trunc_sz bytes. Strip the last block
+       # The block count must drop to 8
+       #
+       $TRUNCATE $DIR/$tfile $trunc_sz ||
+               error "truncate $tfile to $trunc_sz failed"
+
+       local trunc_bsz=$((grant_blk_size / $(stat --format=%B $DIR/$tfile)))
+       sz=$(stat --format=%s $DIR/$tfile)
+       blk=$(stat --format=%b $DIR/$tfile)
+
+       if [[ $blk -ne $trunc_bsz ]]; then
+               $(which stat) $DIR/$tfile
+               error "Expected Block $trunc_bsz got $blk for $tfile"
+       fi
+
+       $CHECKSTAT -s $trunc_sz $DIR/$tfile ||
+               error "Expected Size $trunc_sz got $sz for $tfile"
+}
+run_test 317 "Verify blocks get correctly update after truncate"
+
 test_fake_rw() {
        local read_write=$1
        if [ "$read_write" = "write" ]; then
@@ -18141,6 +18889,49 @@ test_414() {
 }
 run_test 414 "simulate ENOMEM in ptlrpc_register_bulk()"
 
+test_415() {
+       [ $PARALLEL == "yes" ] && skip "skip parallel run"
+       [ $(lustre_version_code mds1) -lt $(version_code 2.11.52) ] &&
+               skip "Need server version at least 2.11.52"
+
+       # LU-11102
+       local total
+       local setattr_pid
+       local start_time
+       local end_time
+       local duration
+
+       total=500
+       # this test may be slow on ZFS
+       [ "$(facet_fstype mds1)" == "zfs" ] && total=100
+
+       # though this test is designed for striped directory, let's test normal
+       # directory too since lock is always saved as CoS lock.
+       test_mkdir $DIR/$tdir || error "mkdir $tdir"
+       createmany -o $DIR/$tdir/$tfile. $total || error "createmany"
+
+       (
+               while true; do
+                       touch $DIR/$tdir
+               done
+       ) &
+       setattr_pid=$!
+
+       start_time=$(date +%s)
+       for i in $(seq $total); do
+               mrename $DIR/$tdir/$tfile.$i $DIR/$tdir/$tfile-new.$i \
+                       > /dev/null
+       done
+       end_time=$(date +%s)
+       duration=$((end_time - start_time))
+
+       kill -9 $setattr_pid
+
+       echo "rename $total files took $duration sec"
+       [ $duration -lt 100 ] || error "rename took $duration sec"
+}
+run_test 415 "lock revoke is not missing"
+
 prep_801() {
        [[ $(lustre_version_code mds1) -lt $(version_code 2.9.55) ]] ||
        [[ $(lustre_version_code ost1) -lt $(version_code 2.9.55) ]] &&
@@ -18372,6 +19163,8 @@ test_802() {
        [[ $(lustre_version_code ost1) -lt $(version_code 2.9.55) ]] &&
                skip "Need server version at least 2.9.55"
 
+       [[ $ENABLE_QUOTA ]] && skip "Quota enabled for read-only test"
+
        mkdir $DIR/$tdir || error "(1) fail to mkdir"
 
        cp $LUSTRE/tests/test-framework.sh $DIR/$tdir/ ||
@@ -18587,6 +19380,182 @@ test_805() {
 }
 run_test 805 "ZFS can remove from full fs"
 
+# Size-on-MDS test
+check_lsom_data()
+{
+       local file=$1
+       local size=$($LFS getsom -s $file)
+       local expect=$(stat -c %s $file)
+
+       [[ $size == $expect ]] ||
+               error "$file expected size: $expect, got: $size"
+
+       local blocks=$($LFS getsom -b $file)
+       expect=$(stat -c %b $file)
+       [[ $blocks == $expect ]] ||
+               error "$file expected blocks: $expect, got: $blocks"
+}
+
+check_lsom_size()
+{
+       local size=$($LFS getsom -s $1)
+       local expect=$2
+
+       [[ $size == $expect ]] ||
+               error "$file expected size: $expect, got: $size"
+}
+
+test_806() {
+       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.11.52) ] &&
+               skip "Need MDS version at least 2.11.52" && return
+
+       local bs=1048576
+
+       touch $DIR/$tfile || error "touch $tfile failed"
+
+       local save="$TMP/$TESTSUITE-$TESTNAME.parameters"
+       save_lustre_params client "llite.*.xattr_cache" > $save
+       lctl set_param llite.*.xattr_cache=0
+       stack_trap "restore_lustre_params < $save" EXIT
+
+       # single-threaded write
+       echo "Test SOM for single-threaded write"
+       dd if=/dev/zero of=$DIR/$tfile bs=$bs count=1 ||
+               error "write $tfile failed"
+       check_lsom_size $DIR/$tfile $bs
+
+       local num=32
+       local size=$(($num * $bs))
+       local offset=0
+       local i
+
+       echo "Test SOM for single client muti-threaded($num) write"
+       $TRUNCATE $DIR/$tfile 0
+       for ((i = 0; i < $num; i++)); do
+               $MULTIOP $DIR/$tfile Oz${offset}w${bs}c &
+               local pids[$i]=$!
+               offset=$((offset + $bs))
+       done
+       for (( i=0; i < $num; i++ )); do
+               wait ${pids[$i]}
+       done
+       check_lsom_size $DIR/$tfile $size
+
+       $TRUNCATE $DIR/$tfile 0
+       for ((i = 0; i < $num; i++)); do
+               offset=$((offset - $bs))
+               $MULTIOP $DIR/$tfile Oz${offset}w${bs}c &
+               local pids[$i]=$!
+       done
+       for (( i=0; i < $num; i++ )); do
+               wait ${pids[$i]}
+       done
+       check_lsom_size $DIR/$tfile $size
+
+       # multi-client wirtes
+       num=$(get_node_count ${CLIENTS//,/ })
+       size=$(($num * $bs))
+       offset=0
+       i=0
+
+       echo "Test SOM for muti-client ($num) writes"
+       $TRUNCATE $DIR/$tfile 0
+       for client in ${CLIENTS//,/ }; do
+               do_node $client $MULTIOP $DIR/$tfile Oz${offset}w${bs}c &
+               local pids[$i]=$!
+               i=$((i + 1))
+               offset=$((offset + $bs))
+       done
+       for (( i=0; i < $num; i++ )); do
+               wait ${pids[$i]}
+       done
+       check_lsom_size $DIR/$tfile $offset
+
+       i=0
+       $TRUNCATE $DIR/$tfile 0
+       for client in ${CLIENTS//,/ }; do
+               offset=$((offset - $bs))
+               do_node $client $MULTIOP $DIR/$tfile Oz${offset}w${bs}c &
+               local pids[$i]=$!
+               i=$((i + 1))
+       done
+       for (( i=0; i < $num; i++ )); do
+               wait ${pids[$i]}
+       done
+       check_lsom_size $DIR/$tfile $size
+
+       # verify truncate
+       echo "Test SOM for truncate"
+       $TRUNCATE $DIR/$tfile 1048576
+       check_lsom_size $DIR/$tfile 1048576
+       $TRUNCATE $DIR/$tfile 1234
+       check_lsom_size $DIR/$tfile 1234
+
+       # verify SOM blocks count
+       echo "Verify SOM block count"
+       $TRUNCATE $DIR/$tfile 0
+       $MULTIOP $DIR/$tfile oO_TRUNC:O_RDWR:w1048576YSc ||
+               error "failed to write file $tfile"
+       check_lsom_data $DIR/$tfile
+}
+run_test 806 "Verify Lazy Size on MDS"
+
+test_807() {
+       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.11.52) ] &&
+               skip "Need MDS version at least 2.11.52" && return
+
+       # Registration step
+       changelog_register || error "changelog_register failed"
+       local cl_user="${CL_USERS[$SINGLEMDS]%% *}"
+       changelog_users $SINGLEMDS | grep -q $cl_user ||
+               error "User $cl_user not found in changelog_users"
+
+       local save="$TMP/$TESTSUITE-$TESTNAME.parameters"
+       save_lustre_params client "llite.*.xattr_cache" > $save
+       lctl set_param llite.*.xattr_cache=0
+       stack_trap "restore_lustre_params < $save" EXIT
+
+       rm -rf $DIR/$tdir || error "rm $tdir failed"
+       mkdir -p $DIR/$tdir || error "mkdir $tdir failed"
+       touch $DIR/$tdir/trunc || error "touch $tdir/trunc failed"
+       $TRUNCATE $DIR/$tdir/trunc 1024 || error "truncate $tdir/trunc failed"
+       $TRUNCATE $DIR/$tdir/trunc 1048576 ||
+               error "truncate $tdir/trunc failed"
+
+       local bs=1048576
+       dd if=/dev/zero of=$DIR/$tdir/single_dd bs=$bs count=1 ||
+               error "write $tfile failed"
+
+       # multi-client wirtes
+       local num=$(get_node_count ${CLIENTS//,/ })
+       local offset=0
+       local i=0
+
+       echo "Test SOM for muti-client ($num) writes"
+       touch $DIR/$tfile || error "touch $tfile failed"
+       $TRUNCATE $DIR/$tfile 0
+       for client in ${CLIENTS//,/ }; do
+               do_node $client $MULTIOP $DIR/$tfile Oz${offset}w${bs}c &
+               local pids[$i]=$!
+               i=$((i + 1))
+               offset=$((offset + $bs))
+       done
+       for (( i=0; i < $num; i++ )); do
+               wait ${pids[$i]}
+       done
+
+       sleep 5
+       $LSOM_SYNC -u $cl_user -m $FSNAME-MDT0000 $MOUNT
+       check_lsom_data $DIR/$tdir/trunc
+       check_lsom_data $DIR/$tdir/single_dd
+       check_lsom_data $DIR/$tfile
+
+       rm -rf $DIR/$tdir
+       # Deregistration step
+       changelog_deregister || error "changelog_deregister failed"
+}
+run_test 807 "verify LSOM syncing tool"
+
 #
 # tests that do cleanup/setup should be run at the end
 #