Whamcloud - gitweb
LU-7108 test: Remove sanityn tests from ALWAYS_EXCEPT list
[fs/lustre-release.git] / lustre / tests / sanityn.sh
old mode 100644 (file)
new mode 100755 (executable)
index 7f99537..a0bfb32
@@ -3,8 +3,8 @@
 set -e
 
 ONLY=${ONLY:-"$*"}
-# bug number for skipped test: 3192 LU-1205 15528/3811 9977 15528/11549 18080
-ALWAYS_EXCEPT="                14b  18c     19         28   29          35    $SANITYN_EXCEPT"
+# bug number for skipped test: LU-1205 9977/LU-7105 LU-9452
+ALWAYS_EXCEPT="                18c     28           29      $SANITYN_EXCEPT"
 # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
 
 SRCDIR=$(dirname $0)
@@ -61,9 +61,6 @@ check_runas_id $RUNAS_ID $RUNAS_GID $RUNAS
 
 build_test_filter
 
-mkdir -p $MOUNT2
-mount_client $MOUNT2
-
 test_1a() {
        touch $DIR1/f1
        [ -f $DIR2/f1 ] || error
@@ -748,42 +745,42 @@ enable_lockless_truncate() {
 test_32a() { # bug 11270
        local p="$TMP/$TESTSUITE-$TESTNAME.parameters"
        save_lustre_params client "osc.*.lockless_truncate" > $p
-        cancel_lru_locks osc
-        enable_lockless_truncate 1
-        rm -f $DIR1/$tfile
-        lfs setstripe -c -1 $DIR1/$tfile
-        dd if=/dev/zero of=$DIR1/$tfile count=$OSTCOUNT bs=$STRIPE_BYTES > \
-                /dev/null 2>&1
-        clear_osc_stats
-
-        log "checking cached lockless truncate"
-        $TRUNCATE $DIR1/$tfile 8000000
-        $CHECKSTAT -s 8000000 $DIR2/$tfile || error "wrong file size"
-       [ $(calc_osc_stats lockless_truncate) -ne 0 ] ||
+       cancel_lru_locks osc
+       enable_lockless_truncate 1
+       rm -f $DIR1/$tfile
+       lfs setstripe -c -1 $DIR1/$tfile
+       dd if=/dev/zero of=$DIR1/$tfile count=$OSTCOUNT bs=$STRIPE_BYTES > \
+               /dev/null 2>&1
+       clear_stats osc.*.osc_stats
+
+       log "checking cached lockless truncate"
+       $TRUNCATE $DIR1/$tfile 8000000
+       $CHECKSTAT -s 8000000 $DIR2/$tfile || error "wrong file size"
+       [ $(calc_stats osc.*.osc_stats lockless_truncate) -ne 0 ] ||
                error "cached truncate isn't lockless"
 
-        log "checking not cached lockless truncate"
-        $TRUNCATE $DIR2/$tfile 5000000
-        $CHECKSTAT -s 5000000 $DIR1/$tfile || error "wrong file size"
-       [ $(calc_osc_stats lockless_truncate) -ne 0 ] ||
+       log "checking not cached lockless truncate"
+       $TRUNCATE $DIR2/$tfile 5000000
+       $CHECKSTAT -s 5000000 $DIR1/$tfile || error "wrong file size"
+       [ $(calc_stats osc.*.osc_stats lockless_truncate) -ne 0 ] ||
                error "not cached truncate isn't lockless"
 
-        log "disabled lockless truncate"
-        enable_lockless_truncate 0
-        clear_osc_stats
-        $TRUNCATE $DIR2/$tfile 3000000
-        $CHECKSTAT -s 3000000 $DIR1/$tfile || error "wrong file size"
-        [ $(calc_osc_stats lockless_truncate) -eq 0 ] ||
-                error "lockless truncate disabling failed"
-        rm $DIR1/$tfile
-        # restore lockless_truncate default values
-        restore_lustre_params < $p
-        rm -f $p
+       log "disabled lockless truncate"
+       enable_lockless_truncate 0
+       clear_stats osc.*.osc_stats
+       $TRUNCATE $DIR2/$tfile 3000000
+       $CHECKSTAT -s 3000000 $DIR1/$tfile || error "wrong file size"
+       [ $(calc_stats osc.*.osc_stats lockless_truncate) -eq 0 ] ||
+               error "lockless truncate disabling failed"
+       rm $DIR1/$tfile
+       # restore lockless_truncate default values
+       restore_lustre_params < $p
+       rm -f $p
 }
 run_test 32a "lockless truncate"
 
 test_32b() { # bug 11270
-        remote_ost_nodsh && skip "remote OST with nodsh" && return
+       remote_ost_nodsh && skip "remote OST with nodsh" && return
 
        local node
        local facets=$(get_facets OST)
@@ -796,35 +793,42 @@ test_32b() { # bug 11270
                "ldlm.namespaces.filter-*.contended_locks" >> $p
        save_lustre_params $facets \
                "ldlm.namespaces.filter-*.contention_seconds" >> $p
-       clear_osc_stats
+       clear_stats osc.*.osc_stats
 
-        # agressive lockless i/o settings
-        for node in $(osts_nodes); do
-                do_node $node 'lctl set_param -n ldlm.namespaces.filter-*.max_nolock_bytes 2000000; lctl set_param -n ldlm.namespaces.filter-*.contended_locks 0; lctl set_param -n ldlm.namespaces.filter-*.contention_seconds 60'
-        done
-        lctl set_param -n osc.*.contention_seconds 60
-        for i in $(seq 5); do
-                dd if=/dev/zero of=$DIR1/$tfile bs=4k count=1 conv=notrunc > /dev/null 2>&1
-                dd if=/dev/zero of=$DIR2/$tfile bs=4k count=1 conv=notrunc > /dev/null 2>&1
-        done
-        [ $(calc_osc_stats lockless_write_bytes) -ne 0 ] || error "lockless i/o was not triggered"
-        # disable lockless i/o (it is disabled by default)
-        for node in $(osts_nodes); do
-                do_node $node 'lctl set_param -n ldlm.namespaces.filter-*.max_nolock_bytes 0; lctl set_param -n ldlm.namespaces.filter-*.contended_locks 32; lctl set_param -n ldlm.namespaces.filter-*.contention_seconds 0'
-        done
-        # set contention_seconds to 0 at client too, otherwise Lustre still
-        # remembers lock contention
-        lctl set_param -n osc.*.contention_seconds 0
-        clear_osc_stats
-        for i in $(seq 1); do
-                dd if=/dev/zero of=$DIR1/$tfile bs=4k count=1 conv=notrunc > /dev/null 2>&1
-                dd if=/dev/zero of=$DIR2/$tfile bs=4k count=1 conv=notrunc > /dev/null 2>&1
-        done
-        [ $(calc_osc_stats lockless_write_bytes) -eq 0 ] ||
-                error "lockless i/o works when disabled"
-        rm -f $DIR1/$tfile
-        restore_lustre_params <$p
-        rm -f $p
+       # agressive lockless i/o settings
+       do_nodes $(comma_list $(osts_nodes)) \
+               "lctl set_param -n ldlm.namespaces.*.max_nolock_bytes=2000000 \
+                       ldlm.namespaces.filter-*.contended_locks=0 \
+                       ldlm.namespaces.filter-*.contention_seconds=60"
+       lctl set_param -n osc.*.contention_seconds=60
+       for i in {1..5}; do
+               dd if=/dev/zero of=$DIR1/$tfile bs=4k count=1 conv=notrunc > \
+                       /dev/null 2>&1
+               dd if=/dev/zero of=$DIR2/$tfile bs=4k count=1 conv=notrunc > \
+                       /dev/null 2>&1
+       done
+       [ $(calc_stats osc.*.osc_stats lockless_write_bytes) -ne 0 ] ||
+               error "lockless i/o was not triggered"
+       # disable lockless i/o (it is disabled by default)
+       do_nodes $(comma_list $(osts_nodes)) \
+               "lctl set_param -n ldlm.namespaces.filter-*.max_nolock_bytes=0 \
+                       ldlm.namespaces.filter-*.contended_locks=32 \
+                       ldlm.namespaces.filter-*.contention_seconds=0"
+       # set contention_seconds to 0 at client too, otherwise Lustre still
+       # remembers lock contention
+       lctl set_param -n osc.*.contention_seconds=0
+       clear_stats osc.*.osc_stats
+       for i in {1..1}; do
+               dd if=/dev/zero of=$DIR1/$tfile bs=4k count=1 conv=notrunc > \
+                       /dev/null 2>&1
+               dd if=/dev/zero of=$DIR2/$tfile bs=4k count=1 conv=notrunc > \
+                       /dev/null 2>&1
+       done
+       [ $(calc_stats osc.*.osc_stats lockless_write_bytes) -eq 0 ] ||
+               error "lockless i/o works when disabled"
+       rm -f $DIR1/$tfile
+       restore_lustre_params <$p
+       rm -f $p
 }
 run_test 32b "lockless i/o"
 
@@ -876,7 +880,7 @@ test_33a() {
 
             [ $fstype = ldiskfs ] && jbdold=$(print_jbd_stat)
             echo "=== START createmany old: $jbdold transaction"
-            local elapsed=$(do_and_time "do_nodes $CLIENT1,$CLIENT2 createmany -o $DIR1/$tdir-\\\$(hostname)-$i/f- -r $DIR2/$tdir-\\\$(hostname)-$i/f- $nfiles > /dev/null 2>&1")
+            local elapsed=$(do_and_time "do_nodes $CLIENT1,$CLIENT2 createmany -o $DIR1/$tdir-\\\$(hostname)-$i/f- -r$DIR2/$tdir-\\\$(hostname)-$i/f- $nfiles > /dev/null 2>&1")
             [ $fstype = ldiskfs ] && jbdnew=$(print_jbd_stat)
             [ $fstype = ldiskfs ] && jbd=$(( jbdnew - jbdold ))
             echo "=== END   createmany new: $jbdnew transaction :  $jbd transactions  nfiles $nfiles time $elapsed COS=$COS"
@@ -932,7 +936,7 @@ test_33b() {
                        echo "=== START createmany old: $jbdold transaction"
                        local elapsed=$(do_and_time "do_nodes $CLIENT1,$CLIENT2\
                                createmany -o $DIR1/$tdir-\\\$(hostname)-$i/f- \
-                               -r $DIR2/$tdir-\\\$(hostname)-$i/f- $nfiles > \
+                               -r$DIR2/$tdir-\\\$(hostname)-$i/f- $nfiles > \
                                                                /dev/null 2>&1")
                        jbdnew=$(print_jbd_stat)
                        jbd=$(( jbdnew - jbdold ))
@@ -2410,13 +2414,13 @@ test_51a() {
        local filesize
        local origfile=/etc/hosts
 
-       filesize=`stat -c %s $origfile`
+       filesize=$(stat -c %s $origfile)
 
        # create an empty file
-       $MCREATE $DIR1/$tfile
+       $MCREATE $DIR1/$tfile || error "can't create $DIR1/$tfile"
        # cache layout lock on both mount point
-       stat $DIR1/$tfile > /dev/null
-       stat $DIR2/$tfile > /dev/null
+       stat $DIR1/$tfile > /dev/null || error "stat $DIR1/$tfile failed"
+       stat $DIR2/$tfile > /dev/null || error "stat $DIR2/$tfile failed"
 
        # open and sleep 2 seconds then read
        $MULTIOP $DIR2/$tfile o_2r${filesize}c &
@@ -2424,12 +2428,13 @@ test_51a() {
        sleep 1
 
        # create the layout of testing file
-       dd if=$origfile of=$DIR1/$tfile conv=notrunc > /dev/null
+       dd if=$origfile of=$DIR1/$tfile conv=notrunc > /dev/null ||
+               error "dd $DIR1/$tfile failed"
 
        # MULTIOP proc should be able to read enough bytes and exit
        sleep 2
-       kill -0 $pid && error "multiop is still there"
-       cmp $origfile $DIR2/$tfile || error "$MCREATE and $DIR2/$tfile differs"
+       kill -0 $pid 2> /dev/null && error "multiop is still there"
+       cmp $origfile $DIR2/$tfile || error "$origfile and $DIR2/$tfile differs"
 
        rm -f $DIR1/$tfile
 }
@@ -2442,7 +2447,7 @@ test_51b() {
        local tmpfile=`mktemp`
 
        # create an empty file
-       $MCREATE $DIR1/$tfile
+       $MCREATE $DIR1/$tfile || error "mcreate $DIR1/$tfile failed"
 
        # delay glimpse so that layout has changed when glimpse finish
 #define OBD_FAIL_GLIMPSE_DELAY 0x1404
@@ -2452,10 +2457,11 @@ test_51b() {
        sleep 1
 
        # create layout of testing file
-       dd if=/dev/zero of=$DIR1/$tfile bs=1k count=1 conv=notrunc > /dev/null
+       dd if=/dev/zero of=$DIR1/$tfile bs=1k count=1 conv=notrunc >/dev/null ||
+               error "dd $DIR1/$tfile failed"
 
        wait $pid
-       local fsize=`cat $tmpfile`
+       local fsize=$(cat $tmpfile)
 
        [ x$fsize = x1024 ] || error "file size is $fsize, should be 1024"
 
@@ -2467,11 +2473,12 @@ test_51c() {
        [ $OSTCOUNT -ge 2 ] || { skip "need at least 2 osts"; return; }
 
        # set default layout to have 1 stripe
-       mkdir -p $DIR1/$tdir
+       mkdir $DIR1/$tdir
        $LFS setstripe -c 1 $DIR1/$tdir
 
        # create a file with empty layout
-       $MCREATE $DIR1/$tdir/$tfile
+       $MCREATE $DIR1/$tdir/$tfile ||
+               error "$MCREATE $DIR1/$tdir/$tfile failed"
 
 #define OBD_FAIL_MDS_LL_BLOCK 0x172
        do_facet $SINGLEMDS $LCTL set_param fail_loc=0x172
@@ -2484,8 +2491,14 @@ test_51c() {
 
        # write something to the file, it should be blocked on fetching layout
        dd if=/dev/zero of=$DIR2/$tdir/$tfile bs=1k count=1 conv=notrunc
-       local cnt=$($LFS getstripe -c $DIR2/$tdir/$tfile)
-       [ $cnt -eq $OSTCOUNT ] || error "have $cnt stripes, expected $OSTCOUNT"
+       local stripecnt=$($LFS getstripe -c $DIR2/$tdir/$tfile)
+       wait $pid
+
+       # lod_qos.c::min_stripe_count() allows setstripe with a default stripe
+       # count to succeed with only 3/4 of the number of stripes (rounded up),
+       # so creating striped files does not fail if an OST is offline or full
+       [ $stripecnt -ge $((OSTCOUNT - $OSTCOUNT / 4)) ] ||
+               error "layout wrong: getstripe -c $stripecnt < $OSTCOUNT * 3/4"
 
        rm -fr $DIR1/$tdir
 }
@@ -2757,7 +2770,7 @@ test_70b() { # LU-2781
 }
 run_test 70b "remove files after calling rm_entry"
 
-test_71() {
+test_71a() {
        local server_version=$(lustre_version_code $SINGLEMDS)
 
        [[ $server_version -lt $(version_code 2.1.6) ]] &&
@@ -2766,7 +2779,8 @@ test_71() {
        # Patch not applied to 2.2 and 2.3 branches
        [[ $server_version -ge $(version_code 2.2.0) ]] &&
        [[ $server_version -lt $(version_code 2.4.0) ]] &&
-               skip "Need MDS version at least 2.4.0" && return
+               skip "Need MDS version earlier than 2.2.0 or at least 2.4.0" &&
+                       return
 
        checkfiemap --test ||
                { skip "checkfiemap not runnable: $?" && return; }
@@ -2798,7 +2812,34 @@ test_71() {
        echo $can2
        [ $can3 -eq $can4 ] || error $((can2-can1)) "cancel RPC occured."
 }
-run_test 71 "correct file map just after write operation is finished"
+run_test 71a "correct file map just after write operation is finished"
+
+test_71b() {
+       local server_version=$(lustre_version_code $SINGLEMDS)
+
+       [[ $server_version -lt $(version_code 2.1.6) ]] &&
+               skip "Need MDS version at least 2.1.6" && return
+
+       # Patch not applied to 2.2 and 2.3 branches
+       [[ $server_version -ge $(version_code 2.2.0) ]] &&
+       [[ $server_version -lt $(version_code 2.4.0) ]] &&
+               skip "Need MDS version earlier than 2.2.0 or at least 2.4.0" &&
+                       return
+       [[ $OSTCOUNT -ge 2 ]] || { skip "need at least 2 osts"; return; }
+
+       checkfiemap --test ||
+               { skip "error $?: checkfiemap failed" && return; }
+
+       mkdir -p $DIR1/$tdir
+
+       $LFS setstripe -c -1 $DIR1/$tdir || error "setstripe failed"
+       dd if=/dev/urandom of=$DIR1/$tdir/$tfile bs=40K count=1
+       [ "$(facet_fstype ost$(($($GETSTRIPE -i $DIR1/$tdir/$tfile) + 1)))" = \
+               "zfs" ] &&
+               skip "ORI-366/LU-1941: FIEMAP unimplemented on ZFS" && return 0
+       checkfiemap $DIR1/$tdir/$tfile 40960 || error "checkfiemap failed"
+}
+run_test 71b "check fiemap support for stripecount > 1"
 
 test_72() {
        local p="$TMP/sanityN-$TESTNAME.parameters"
@@ -2843,14 +2884,16 @@ test_73() {
                error "setfattr1 failed"
        getfattr -n user.attr1 $DIR2/$tfile || error "getfattr1 failed"
        getfattr -n user.attr1 $DIR1/$tfile || error "getfattr2 failed"
-       clear_llite_stats
+       clear_stats llite.*.stats
        # PR lock should be cached by now on both clients
        getfattr -n user.attr1 $DIR1/$tfile || error "getfattr3 failed"
        # 2 hits for getfattr(0)+getfattr(size)
-       [ $(calc_llite_stats getxattr_hits) -eq 2 ] || error "not cached in $DIR1"
+       [ $(calc_stats llite.*.stats getxattr_hits) -eq 2 ] ||
+               error "not cached in $DIR1"
        getfattr -n user.attr1 $DIR2/$tfile || error "getfattr4 failed"
        # 4 hits for more getfattr(0)+getfattr(size)
-       [ $(calc_llite_stats getxattr_hits) -eq 4 ] || error "not cached in $DIR2"
+       [ $(calc_stats llite.*.stats getxattr_hits) -eq 4 ] ||
+               error "not cached in $DIR2"
        rm -f $DIR2/$tfile
 
        restore_lustre_params < $p
@@ -2895,7 +2938,7 @@ test_76() { #LU-946
                skip "Need MDS version at least 2.5.53" && return
 
        remote_mds_nodsh && skip "remote MDS with nodsh" && return
-       local fcount=2048
+       local fcount=$((MDSCOUNT * 256))
        declare -a fd_list
        declare -a fid_list
 
@@ -2911,20 +2954,28 @@ test_76() { #LU-946
        # drop all open locks and close any cached "open" files on the client
        cancel_lru_locks mdc
 
-       echo -n "open files "
-       ulimit -n 8096
+       local open_fids_cmd="$LCTL get_param -n mdt.*.exports.'$nid'.open_files"
+       local fid_list=($(do_nodes $(comma_list $(mdts_nodes)) $open_fids_cmd))
+       local already=${#fid_list[@]}
+       for (( i = 0; i < $already; i++ )) ; do
+               log "already open[$i]: $($LFS fid2path $DIR2 ${fid_list[i]})"
+       done
+
+       echo -n "opening files: "
+       ulimit -n $((fcount + 50))
        for ((i = 0; i < $fcount; i++)); do
                touch $DIR/$tdir/f_$i
-               local fd=$(free_fd)
-               local cmd="exec $fd<$DIR/$tdir/f_$i"
-               eval $cmd
+               local fd=$(free_fd ${fd_list[i]})
+               local open_cmd="exec $fd<$DIR/$tdir/f_$i"
+               eval $open_cmd
+
                fd_list[i]=$fd
-               echo -n "."
+
+               (( $i % 32 == 0 )) && echo -n "."
        done
        echo
 
-       local get_open_fids="$LCTL get_param -n mdt.*.exports.'$nid'.open_files"
-       local fid_list=($(do_nodes $(comma_list $(mdts_nodes)) $get_open_fids))
+       fid_list=($(do_nodes $(comma_list $(mdts_nodes)) $open_fids_cmd))
 
        # Possible errors in openfiles FID list.
        # 1. Missing FIDs. Check 1
@@ -2934,19 +2985,28 @@ test_76() { #LU-946
        # 5. Valid FID, points to some other file. Check 3
 
        # Check 1
-       [ ${#fid_list[@]} -ne $fcount ] &&
-               error "${#fid_list[@]} != $fcount open files"
-
-       for (( i = 0; i < $fcount; i++ )) ; do
-               cmd="exec ${fd_list[i]}</dev/null"
-               eval $cmd
-               filename=$($LFS fid2path $DIR2 ${fid_list[i]})
+       [ ${#fid_list[@]} -ne $((fcount + already)) ] &&
+               error "${#fid_list[@]} != $fcount (+$already old) open files"
+
+       echo -n "closing files: "
+       for (( fd = 0, fid = 0; fd < $fcount; fd++, fid++ )) ; do
+               local close_cmd="exec ${fd_list[fd]}<&-"
+               eval $close_cmd
+               filename=$($LFS fid2path $DIR2 ${fid_list[fid]})
+
+               while [[ ! "$filename" =~ "$DIR2/$tdir/f_" ]]; do
+                       echo "skip old open file $filename"
+                       ((fid++))
+                       filename=$($LFS fid2path $DIR2 ${fid_list[fid]})
+               done
 
                # Check 2
                rm --interactive=no $filename
                [ $? -ne 0 ] &&
-                       error "Nonexisting fid ${fid_list[i]} listed."
+                       error "Nonexisting fid ${fid_list[fid]} listed."
+               (( $fd % 32 == 0 )) && echo -n "."
        done
+       echo
 
        # Check 3
        ls_op=$(ls $DIR2/$tdir | wc -l)
@@ -2955,7 +3015,7 @@ test_76() { #LU-946
 
        rm -rf $DIR/$tdir
 }
-run_test 76 "Verify open file for 2048 files"
+run_test 76 "Verify MDT open_files listing"
 
 nrs_write_read() {
        local n=16
@@ -2982,7 +3042,7 @@ nrs_write_read() {
        for ((i = 0; i < $n; i++)); do
                do_nodes $CLIENTS $myRUNAS dd if="$dir/nrs_w_$HOSTNAME" \
                        of=/dev/zero bs=1M seek=$i count=1 > /dev/null ||
-                       error "dd at ${i}MB on client failed (3)"
+                       error "dd at ${i}MB on client failed (3)" &
                local pids_r[$i]=$!
        done
        cancel_lru_locks osc
@@ -3077,7 +3137,7 @@ tbf_rule_operate()
 
 tbf_verify() {
        local dir=$DIR/$tdir
-       local client1=${CLIENT1:-`hostname`}
+       local client1=${CLIENT1:-$(hostname)}
        local myRUNAS="$3"
 
        mkdir $dir || error "mkdir $dir failed"
@@ -3092,7 +3152,7 @@ tbf_verify() {
 
        # verify the write rate does not exceed 110% of TBF limited rate
        [ $(bc <<< "$rate < 1.1 * $1") -eq 1 ] ||
-               error "The write rate ($rate) exceeds 110% of preset rate ($1)"
+               error_ignore LU-9140 "The write rate ($rate) exceeds 110% of preset rate ($1)"
 
        cancel_lru_locks osc
 
@@ -3103,8 +3163,9 @@ tbf_verify() {
 
        # verify the read rate does not exceed 110% of TBF limited rate
        [ $(bc <<< "$rate < 1.1 * $2") -eq 1 ] ||
-               error "The read rate ($rate) exceeds 110% of preset rate ($2)"
+               error_ignore LU-9140 "The read rate ($rate) exceeds 110% of preset rate ($2)"
 
+       cancel_lru_locks osc
        rm -rf $dir || error "rm -rf $dir failed"
 }
 
@@ -3261,10 +3322,6 @@ test_77h() {
        [ $? -eq 0 ] && error "should return error"
 
        do_facet ost1 lctl set_param \
-               ost.OSS.ost_io.nrs_policies="tbf\ reg"
-       [ $? -eq 0 ] && error "should return error"
-
-       do_facet ost1 lctl set_param \
                ost.OSS.ost_io.nrs_policies="tbf\ reg\ abc"
        [ $? -eq 0 ] && error "should return error"
 
@@ -3369,6 +3426,7 @@ test_77j() {
                        ost.OSS.ost_io.nrs_policies="tbf\ opcode" \
                        ost.OSS.ost_io.nrs_tbf_rule="start\ ost_r\ ${idis}{ost_read}\ ${rateis}5" \
                        ost.OSS.ost_io.nrs_tbf_rule="start\ ost_w\ ${idis}{ost_write}\ ${rateis}20"
+       [ $? -ne 0 ] && error "failed to set TBF OPCode policy"
 
        nrs_write_read
        tbf_verify 20 5
@@ -3385,6 +3443,109 @@ test_77j() {
 }
 run_test 77j "check TBF-OPCode NRS policy"
 
+test_77k() {
+       [[ $(lustre_version_code ost1) -ge $(version_code 2.9.53) ]] ||
+               { skip "Need OST version at least 2.9.53"; return 0; }
+
+       do_nodes $(comma_list $(osts_nodes)) \
+               lctl set_param ost.OSS.ost_io.nrs_policies="tbf" \
+                       ost.OSS.ost_io.nrs_tbf_rule="start\ ext_w\ jobid={dd.$RUNAS_ID}\&opcode={ost_write}\ rate=20" \
+                       ost.OSS.ost_io.nrs_tbf_rule="start\ ext_r\ jobid={dd.$RUNAS_ID}\&opcode={ost_read}\ rate=10"
+
+       nrs_write_read "$RUNAS"
+       tbf_verify 20 10 "$RUNAS"
+
+       local address=$(comma_list "$(host_nids_address $CLIENTS $NETTYPE)")
+       local client_nids=$(nids_list $address "\\")
+       do_nodes $(comma_list $(osts_nodes)) \
+               lctl set_param ost.OSS.ost_io.nrs_tbf_rule="stop\ ext_w" \
+                       ost.OSS.ost_io.nrs_tbf_rule="stop\ ext_r" \
+                       ost.OSS.ost_io.nrs_tbf_rule="start\ ext_w\ nid={0@lo\ $client_nids}\&opcode={ost_write}\ rate=20" \
+                       ost.OSS.ost_io.nrs_tbf_rule="start\ ext_r\ nid={0@lo\ $client_nids}\&opcode={ost_read}\ rate=10"
+
+       nrs_write_read
+       tbf_verify 20 10
+
+       do_nodes $(comma_list $(osts_nodes)) \
+               lctl set_param ost.OSS.ost_io.nrs_tbf_rule="stop\ ext_w" \
+                       ost.OSS.ost_io.nrs_tbf_rule="stop\ ext_r" \
+                       ost.OSS.ost_io.nrs_tbf_rule="start\ ext\ nid={0@lo\ $client_nids}\&jobid={dd.$RUNAS_ID}\ rate=20"
+
+       nrs_write_read "$RUNAS"
+       tbf_verify 20 20 "$RUNAS"
+
+       do_nodes $(comma_list $(osts_nodes)) \
+               lctl set_param ost.OSS.ost_io.nrs_tbf_rule="stop\ ext" \
+                       ost.OSS.ost_io.nrs_tbf_rule="start\ ext_a\ jobid={dd.$RUNAS_ID},opcode={ost_write}\ rate=20" \
+                       ost.OSS.ost_io.nrs_tbf_rule="start\ ext_b\ jobid={dd.$RUNAS_ID},opcode={ost_read}\ rate=10"
+
+       nrs_write_read "$RUNAS"
+       # with parameter "RUNAS", it will match the latest rule
+       # "ext_b" first, so the limited write rate is 10.
+       tbf_verify 10 10 "$RUNAS"
+       tbf_verify 20 10
+
+       do_nodes $(comma_list $(osts_nodes)) \
+               lctl set_param ost.OSS.ost_io.nrs_tbf_rule="stop\ ext_a" \
+                       ost.OSS.ost_io.nrs_tbf_rule="stop\ ext_b" \
+                       ost.OSS.ost_io.nrs_policies="fifo"
+
+       sleep 3
+}
+run_test 77k "check the extended TBF policy with NID/JobID/OPCode expression"
+
+test_77l() {
+       if [ $(lustre_version_code ost1) -lt $(version_code 2.9.54) ]; then
+               skip "Need OST version at least 2.9.54"
+               return 0
+       fi
+
+       local dir=$DIR/$tdir
+
+       mkdir $dir || error "mkdir $dir failed"
+       $LFS setstripe -c $OSTCOUNT $dir || error "setstripe to $dir failed"
+       chmod 777 $dir
+
+       local nodes=$(comma_list $(osts_nodes))
+       do_nodes $nodes lctl set_param ost.OSS.ost_io.nrs_policies=delay \
+                                      ost.OSS.ost_io.nrs_delay_min=4 \
+                                      ost.OSS.ost_io.nrs_delay_max=4 \
+                                      ost.OSS.ost_io.nrs_delay_pct=100
+       [ $? -ne 0 ] && error "Failed to set delay policy"
+
+       local start=$SECONDS
+       do_nodes "${SINGLECLIENT:-$HOSTNAME}" "$RUNAS" \
+                dd if=/dev/zero of="$dir/nrs_delay_$HOSTNAME" bs=1M count=1 \
+                  oflag=direct conv=fdatasync ||
+               { do_nodes $nodes lctl set_param ost.OSS.ost_io.nrs_policies="fifo";
+                 error "dd on client failed (1)"; }
+       local elapsed=$((SECONDS - start))
+
+       # NRS delay doesn't do sub-second timing, so a request enqueued at
+       # 0.9 seconds can be dequeued at 4.0
+       [ $elapsed -lt 3 ] &&
+               { do_nodes $nodes lctl set_param ost.OSS.ost_io.nrs_policies="fifo";
+                 error "Single 1M write should take at least 3 seconds"; }
+
+       start=$SECONDS
+       do_nodes "${SINGLECLIENT:-$HOSTNAME}" "$RUNAS" \
+                dd if=/dev/zero of="$dir/nrs_delay_$HOSTNAME" bs=1M count=10 \
+                  oflag=direct conv=fdatasync ||
+               { do_nodes $nodes lctl set_param ost.OSS.ost_io.nrs_policies="fifo";
+                 error "dd on client failed (2)"; }
+       elapsed=$((SECONDS - start))
+
+       [ $elapsed -lt 30 ] &&
+               { do_nodes $nodes lctl set_param ost.OSS.ost_io.nrs_policies="fifo";
+                 error "Ten 1M writes should take at least 30 seconds"; }
+
+       do_nodes $nodes lctl set_param ost.OSS.ost_io.nrs_policies="fifo"
+       [ $? -ne 0 ] && error "failed to set policy back to fifo"
+
+       return 0
+}
+run_test 77l "check NRS Delay slows write RPC processing"
+
 test_78() { #LU-6673
        local server_version=$(lustre_version_code ost1)
        [[ $server_version -ge $(version_code 2.7.58) ]] ||
@@ -3827,9 +3988,8 @@ log "cleanup: ======================================================"
 # kill and wait in each test only guarentee script finish, but command in script
 # like 'rm' 'chmod' may still be running, wait for all commands to finish
 # otherwise umount below will fail
-wait_update $HOSTNAME "fuser -m $MOUNT2" "" || true
-
-[ "$(mount | grep $MOUNT2)" ] && umount $MOUNT2
+[ "$(mount | grep $MOUNT2)" ] && wait_update $HOSTNAME "fuser -m $MOUNT2" "" ||
+       true
 
 complete $SECONDS
 rm -f $SAMPLE_FILE