Whamcloud - gitweb
LU-12328 flr: avoid reading unhealthy mirror
[fs/lustre-release.git] / lustre / tests / sanity-flr.sh
index 443778b..3df762b 100644 (file)
@@ -20,8 +20,8 @@ ALWAYS_EXCEPT+="                  201"
 
 build_test_filter
 
-[[ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.10.56) ]] ||
-       { skip "Need MDS version at least 2.10.56"; exit 0; }
+[[ "$MDS1_VERSION" -ge $(version_code 2.10.56) ]] ||
+       skip "Need MDS version at least 2.10.56"
 
 [ $UID -eq 0 -a $RUNAS_ID -eq 0 ] &&
        error "\$RUNAS_ID set to 0, but \$UID is also 0!"
@@ -273,6 +273,16 @@ verify_comp_attrs() {
        verify_comp_attr_with_parent pool $tf $comp_id
 }
 
+verify_flr_state()
+{
+       local tf=$1
+       local expected_state=$2
+
+       local state=$($LFS getstripe -v $tf | awk '/lcm_flags/{ print $2 }')
+       [ $expected_state = $state ] ||
+               error "expected: $expected_state, actual $state"
+}
+
 # command line test cases
 test_0a() {
        local td=$DIR/$tdir
@@ -380,6 +390,15 @@ test_0b() {
        verify_comp_attr stripe-count $tf ${ids[5]} $OSTCOUNT
        verify_comp_attr_with_parent pool $tf ${ids[5]}
 
+       if [ $MDS1_VERSION -ge $(version_code 2.12.55) ]; then
+               # LU-11022 - remove mirror by pool name
+               local=cnt cnt=$($LFS getstripe $tf | grep archive | wc -l)
+               [ "$cnt" != "1" ] && error "unexpected mirror count $cnt"
+               $LFS mirror delete --pool archive $tf || error "delete mirror"
+               cnt=$($LFS getstripe $tf | grep archive | wc -l)
+               [ "$cnt" != "0" ] && error "mirror count after removal: $cnt"
+       fi
+
        # destroy OST pool
        destroy_test_pools
 }
@@ -711,6 +730,35 @@ test_0h() {
                error "error setting flag prefer"
 
        verify_comp_attr lcme_flags $tf 0x20003 prefer
+
+       $LFS setstripe --comp-set -I 0x20003 --comp-flags=^prefer $tf ||
+               error "error clearing prefer flag from component 0x20003"
+
+       # MDS disallows setting stale flag on the last non-stale mirror
+       [[ "$MDS1_VERSION" -ge $(version_code 2.12.57) ]] || return 0
+
+       cp /etc/hosts $tf || error "error writing file '$tf'"
+
+       verify_comp_attr lcme_flags $tf 0x10002 prefer
+       verify_comp_attr lcme_flags $tf 0x20003 stale
+       verify_comp_attr lcme_flags $tf 0x30004 stale
+
+       ! $LFS setstripe --comp-set -I 0x10002 --comp-flags=^prefer,stale $tf \
+               > /dev/null 2>&1 ||
+               error "setting stale flag on component 0x10002 should fail"
+
+       $LFS mirror resync $tf || error "error resync-ing file '$tf'"
+
+       $LFS setstripe --comp-set -I 0x10001 --comp-flags=stale $tf ||
+               error "error setting stale flag on component 0x10001"
+       $LFS setstripe --comp-set -I 0x20003 --comp-flags=stale $tf ||
+               error "error setting stale flag on component 0x20003"
+
+       ! $LFS setstripe --comp-set -I 0x30004 --comp-flags=stale $tf \
+               > /dev/null 2>&1 ||
+               error "setting stale flag on component 0x30004 should fail"
+
+       $LFS mirror resync $tf || error "error resync-ing file '$tf'"
 }
 run_test 0h "set, clear and test flags for FLR files"
 
@@ -1002,7 +1050,7 @@ test_32() {
 }
 run_test 32 "data should be mirrored to newly created mirror"
 
-test_33() {
+test_33a() {
        [[ $OSTCOUNT -lt 2 ]] && skip "need >= 2 OSTs" && return
 
        rm -f $DIR/$tfile $DIR/$tfile-2
@@ -1076,7 +1124,114 @@ test_33() {
 
        start_osts 2
 }
-run_test 33 "read can choose available mirror to read"
+run_test 33a "read can choose available mirror to read"
+
+test_33b() {
+       [[ $OSTCOUNT -lt 2 ]] && skip "need >= 2 OSTs" && return
+
+       rm -f $DIR/$tfile
+
+       stack_trap "rm -f $DIR/$tfile" EXIT
+
+       # create a file with two mirrors on OST0000 and OST0001
+       $LFS setstripe -N -Eeof -o0 -N -Eeof -o1 $DIR/$tfile
+
+       # make sure that $tfile has two mirrors
+       [ $($LFS getstripe -N $DIR/$tfile) -eq 2 ] ||
+               { $LFS getstripe $DIR/$tfile; error "expected count 2"; }
+
+       # write 50M
+       dd if=/dev/urandom of=$DIR/$tfile bs=2M count=25 ||
+               error "write failed for $DIR/$tfile"
+       $LFS mirror resync $DIR/$tfile || error "resync failed for $DIR/$tfile"
+       verify_flr_state $DIR/$tfile "ro"
+       drop_client_cache
+
+       ls -l $DIR/$tfile
+
+       # read file - all OSTs are available
+       echo "reading file (data can be provided by any ost)... "
+       local t1=$SECONDS
+       time cat $DIR/$tfile > /dev/null || error "read all"
+       local t2=$SECONDS
+       ra=$((t2 - t1))
+
+       # read file again with ost1 {OST0000} failed
+       stop_osts 1
+       drop_client_cache
+       echo "reading file (data should be provided by ost2)..."
+       t1=$SECONDS
+       time cat $DIR/$tfile > /dev/null || error "read ost2"
+       t2=$SECONDS
+       r1=$((t2 - t1))
+
+       # remount ost1
+       start_osts 1
+
+       # read file again with ost2 {OST0001} failed
+       stop_osts 2
+       drop_client_cache
+
+       echo "reading file (data should be provided by ost1)..."
+       t1=$SECONDS
+       time cat $DIR/$tfile > /dev/null || error "read ost1"
+       t2=$SECONDS
+       r2=$((t2 - t1))
+
+       # remount ost2
+       start_osts 2
+
+       [ $((r1 * 100)) -gt $((ra * 105)) -a $r1 -gt $((ra + 2)) ] &&
+               error "read mirror too slow without ost1, from $ra to $r1"
+       [ $((r2 * 100)) -gt $((ra * 105)) -a $r2 -gt $((ra + 2)) ] &&
+               error "read mirror too slow without ost2, from $ra to $r2"
+
+       wait_osc_import_ready client ost2
+}
+run_test 33b "avoid reading from unhealthy mirror"
+
+test_33c() {
+       [[ $OSTCOUNT -lt 3 ]] && skip "need >= 3 OSTs" && return
+
+       rm -f $DIR/$tfile
+
+       stack_trap "rm -f $DIR/$tfile" EXIT
+
+       # create a file with two mirrors
+       # mirror1: {OST0000, OST0001}
+       # mirror2: {OST0001, OST0002}
+       $LFS setstripe -N -Eeof -c2 -o0,1 -N -Eeof -c2 -o1,2 $DIR/$tfile
+
+       # make sure that $tfile has two mirrors
+       [ $($LFS getstripe -N $DIR/$tfile) -eq 2 ] ||
+               { $LFS getstripe $DIR/$tfile; error "expected count 2"; }
+
+       # write 50M
+       dd if=/dev/urandom of=$DIR/$tfile bs=2M count=25 ||
+               error "write failed for $DIR/$tfile"
+       $LFS mirror resync $DIR/$tfile || error "resync failed for $DIR/$tfile"
+       verify_flr_state $DIR/$tfile "ro"
+       drop_client_cache
+
+       ls -l $DIR/$tfile
+
+       # read file - all OSTs are available
+       echo "reading file (data can be provided by any ost)... "
+       time cat $DIR/$tfile > /dev/null || error "read all"
+
+       # read file again with ost2 (OST0001) failed
+       stop_osts 2
+       drop_client_cache
+
+       echo "reading file (data should be provided by ost1 and ost3)..."
+       time cat $DIR/$tfile > /dev/null || error "read ost1 & ost3"
+
+       # remount ost2
+       start_osts 2
+
+       wait_osc_import_ready client ost2
+}
+run_test 33c "keep reading among unhealthy mirrors"
 
 test_34a() {
        [[ $OSTCOUNT -lt 4 ]] && skip "need >= 4 OSTs" && return
@@ -1338,16 +1493,6 @@ test_37()
 }
 run_test 37 "mirror I/O API verification"
 
-verify_flr_state()
-{
-       local tf=$1
-       local expected_state=$2
-
-       local state=$($LFS getstripe -v $tf | awk '/lcm_flags/{ print $2 }')
-       [ $expected_state = $state ] ||
-               error "expected: $expected_state, actual $state"
-}
-
 test_38() {
        local tf=$DIR/$tfile
        local ref=$DIR/${tfile}-ref
@@ -1773,6 +1918,10 @@ test_44() {
 
        verify_flr_state $tf "wp"
 
+       # disallow destroying the last non-stale mirror
+       ! $LFS mirror delete --mirror-id 1 $tf > /dev/null 2>&1 ||
+               error "destroying mirror 1 should fail"
+
        # synchronize all mirrors of the file
        $LFS mirror resync $tf || error "mirror resync $tf failed"
 
@@ -1798,8 +1947,17 @@ test_44() {
        verify_mirror_count $tf 2
        verify_mirror_count $tf.mirror~2 1
 
+       $LFS setstripe --comp-set -I 0x30008 --comp-flags=stale $tf ||
+               error "setting stale flag on component 0x30008 failed"
+
+       # disallow destroying the last non-stale mirror
+       ! $LFS mirror split --mirror-id 4 -d $tf > /dev/null 2>&1 ||
+               error "destroying mirror 4 should fail"
+
+       $LFS mirror resync $tf || error "resynchronizing $tf failed"
+
        $LFS mirror split --mirror-id 3 -d $tf ||
-               error "split and delte mirror 3 failed"
+               error "destroying mirror 3 failed"
        verify_mirror_count $tf 1
 
        # verify splitted file contains the same content as the orig file does
@@ -2261,7 +2419,7 @@ test_203() {
        #create 2 mirrors
        $LFS mirror create -N2 -c1 $tf || error "create FLR file $tf"
        #delete first mirror
-       $LFS mirror split --mirror-id=1 -d $tf || error "delete first mirror"
+       $LFS mirror delete --mirror-id=1 $tf || error "delete first mirror"
 
        $LFS getstripe $tf
        local old_id=$($LFS getstripe --mirror-id=2 -I $tf)
@@ -2288,7 +2446,7 @@ run_test 203 "mirror file preserve mirror ID"
 
 # Simple test of FLR + self-extending layout, SEL in non-primary mirror
 test_204a() {
-       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+       [ "$MDS1_VERSION" -lt $(version_code $SEL_VER) ] &&
                skip "skipped for lustre < $SEL_VER"
 
        local comp_file=$DIR/$tdir/$tfile
@@ -2335,7 +2493,7 @@ run_test 204a "FLR write/stale/resync tests with self-extending mirror"
 
 # Simple test of FLR + self-extending layout, SEL in primary mirror
 test_204b() {
-       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+       [ "$MDS1_VERSION" -lt $(version_code $SEL_VER) ] &&
                skip "skipped for lustre < $SEL_VER"
 
        local comp_file=$DIR/$tdir/$tfile
@@ -2405,8 +2563,8 @@ run_test 204b "FLR write/stale/resync tests with self-extending primary"
 # FLR + SEL failed extension & component removal
 # extension space in second mirror
 test_204c() {
-       [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
-       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+       [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs"
+       [ "$MDS1_VERSION" -lt $(version_code $SEL_VER) ] &&
                skip "skipped for lustre < $SEL_VER"
 
        local comp_file=$DIR/$tdir/$tfile
@@ -2466,6 +2624,225 @@ test_204c() {
 }
 run_test 204c "FLR write/stale/resync test with component removal"
 
+# Successful repeated component in primary mirror
+test_204d() {
+       [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs"
+       [ "$MDS1_VERSION" -lt $(version_code $SEL_VER) ] &&
+               skip "skipped for lustre < $SEL_VERSION"
+
+       local comp_file=$DIR/$tdir/$tfile
+       local found=""
+
+       wait_delete_completed
+       wait_mds_ost_sync
+       test_mkdir $DIR/$tdir
+
+       # first mirror is 64M followed by extension space to -1, second mirror
+       # is 0-10M, then 10M-(-1)
+       $LFS setstripe -N -E-1 -z64M -N -E 10M -E-1 $comp_file ||
+               error "Create $comp_file failed"
+
+       local ost_idx1=$($LFS getstripe -I65537 -i $comp_file)
+       local ost_name=$(ostname_from_index $ost_idx1)
+       # degrade OST for first comp so we won't extend there
+       do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+               obdfilter.$ost_name.degraded=1
+       sleep_maxage
+
+       # Write beyond first component, causing repeat & stale second mirror
+       dd if=/dev/zero bs=1M count=1 seek=66 of=$comp_file conv=notrunc
+       RC=$?
+
+       do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+               obdfilter.$ost_name.degraded=0
+       sleep_maxage
+
+       [ $RC -eq 0 ] || error "dd to repeat & stale failed"
+
+       $LFS getstripe $comp_file
+
+       found=$($LFS find --component-start 64m --component-end 128m \
+               --component-flags init $comp_file | wc -l)
+       [ $found -eq 1 ] || error "write: Repeat comp incorrect"
+
+       local ost_idx2=$($LFS getstripe --component-start=64m           \
+                        --component-end=128m --component-flags=init    \
+                        -i $comp_file)
+       [[ $ost_idx1 -eq $ost_idx2 ]] && error "$ost_idx1 == $ost_idx2"
+       local mirror_id=$($LFS getstripe --component-start=64m          \
+                        --component-end=128m --component-flags=init    \
+                        $comp_file | grep lcme_mirror_id | awk '{ print $2 }')
+       [[ $mirror_id -eq 1 ]] ||
+               error "component not in correct mirror: $mirror_id, not 1"
+
+       $LFS mirror resync $comp_file
+
+       $LFS getstripe $comp_file
+
+       # component dimensions should not change from resync
+       found=$($LFS find --component-start 0m --component-end 64m \
+               --component-flags init $comp_file | wc -l)
+       [ $found -eq 1 ] || error "resync: first comp incorrect"
+       found=$($LFS find --component-start 64m --component-end 128m \
+               --component-flags init $comp_file | wc -l)
+       [ $found -eq 1 ] || error "resync: repeat comp incorrect"
+
+       sel_layout_sanity $comp_file 5
+
+       rm -f $comp_file
+}
+run_test 204d "FLR write/stale/resync sel test with repeated comp"
+
+# Successful repeated component, SEL in non-primary mirror
+test_204e() {
+       [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs"
+       [ "$MDS1_VERSION" -lt $(version_code $SEL_VER) ] &&
+               skip "skipped for lustre < $SEL_VERSION"
+
+       local comp_file=$DIR/$tdir/$tfile
+       local found=""
+
+       wait_delete_completed
+       wait_mds_ost_sync
+
+       test_mkdir $DIR/$tdir
+
+       # first mirror is is 0-100M, then 100M-(-1), second mirror is extension
+       # space to -1 (-z 64M, so first comp is 0-64M)
+       # Note: we have to place both 1st components on OST0, otherwise 2 OSTs
+       # will be not enough - one will be degraded, the other is used on
+       # an overlapping mirror.
+       $LFS setstripe -N -E 100M -i 0 -E-1 -N -E-1 -i 0 -z 64M $comp_file ||
+               error "Create $comp_file failed"
+
+       local ost_idx1=$($LFS getstripe --component-start=0 \
+                        --component-end=64m -i $comp_file)
+       local ost_name=$(ostname_from_index $ost_idx1)
+       # degrade OST for first comp of 2nd mirror so we won't extend there
+       do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+               obdfilter.$ost_name.degraded=1
+       sleep_maxage
+
+       $LFS getstripe $comp_file
+
+       # Write to first component, stale & instantiate second mirror components
+       # overlapping with the written component (0-100M);
+       dd if=/dev/zero bs=2M count=1 of=$comp_file conv=notrunc
+       RC=$?
+
+       do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+               obdfilter.$ost_name.degraded=0
+       sleep_maxage
+       $LFS getstripe $comp_file
+
+       [ $RC -eq 0 ] || error "dd to repeat & stale failed"
+
+       found=$($LFS find --component-start 0m --component-end 64m \
+               --component-flags init,stale $comp_file | wc -l)
+       [ $found -eq 1 ] || error "write: first comp incorrect"
+
+       # was repeated due to degraded ost
+       found=$($LFS find --component-start 64m --component-end 128m \
+               --component-flags init,stale $comp_file | wc -l)
+       [ $found -eq 1 ] || error "write: repeated comp incorrect"
+
+       local ost_idx2=$($LFS getstripe --component-start=64m           \
+                        --component-end=128m --component-flags=init    \
+                        -i $comp_file)
+       [[ $ost_idx1 -eq $ost_idx2 ]] && error "$ost_idx1 == $ost_idx2"
+       local mirror_id=$($LFS getstripe --component-start=0m           \
+                        --component-end=64m --component-flags=init     \
+                        $comp_file | grep lcme_mirror_id | awk '{ print $2 }')
+       [[ $mirror_id -eq 2 ]] ||
+               error "component not in correct mirror? $mirror_id"
+
+       $LFS mirror resync $comp_file
+
+       $LFS getstripe $comp_file
+
+       # component dimensions should not change from resync
+       found=$($LFS find --component-start 0m --component-end 64m \
+               --component-flags init,^stale $comp_file | wc -l)
+       [ $found -eq 1 ] || error "resync: first comp incorrect"
+       found=$($LFS find --component-start 64m --component-end 128m \
+               --component-flags init,^stale $comp_file | wc -l)
+       [ $found -eq 1 ] || error "resync: repeated comp incorrect"
+
+       sel_layout_sanity $comp_file 5
+
+       rm -f $comp_file
+}
+run_test 204e "FLR write/stale/resync sel test with repeated comp"
+
+# FLR + SEL: failed repeated component, SEL in non-primary mirror
+test_204f() {
+       [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs"
+       [ "$MDS1_VERSION" -lt $(version_code $SEL_VER) ] &&
+               skip "skipped for lustre < $SEL_VERSION"
+
+       local comp_file=$DIR/$tdir/$tfile
+       local found=""
+
+       wait_delete_completed
+       wait_mds_ost_sync
+       test_mkdir $DIR/$tdir
+
+       pool_add $TESTNAME || error "Pool creation failed"
+       pool_add_targets $TESTNAME 0 1 || error "Pool add targets failed"
+
+       # first mirror is is 0-100M, then 100M-(-1), second mirror is extension
+       # space to -1 (-z 64M, so first comp is 0-64M)
+       $LFS setstripe -N -E 100M -E-1 -N --pool="$TESTNAME" \
+               -E-1 -c 1 -z 64M $comp_file || error "Create $comp_file failed"
+
+       local ost_name0=$(ostname_from_index 0)
+       local ost_name1=$(ostname_from_index 1)
+
+       # degrade both OSTs in pool, so we'll try to repeat, then fail and
+       # extend original comp
+       do_facet ost1 $LCTL set_param -n obdfilter.$ost_name0.degraded=1
+       do_facet ost2 $LCTL set_param -n obdfilter.$ost_name1.degraded=1
+       sleep_maxage
+
+       # a write to the 1st component, 100M length, which will try to stale
+       # the first 100M of mirror 2, attempting to extend its 0-64M component
+       dd if=/dev/zero bs=2M count=1 of=$comp_file conv=notrunc
+       RC=$?
+
+       do_facet ost1 $LCTL set_param -n obdfilter.$ost_name0.degraded=0
+       do_facet ost2 $LCTL set_param -n obdfilter.$ost_name1.degraded=0
+       sleep_maxage
+
+       [ $RC -eq 0 ] || error "dd to extend mirror comp failed"
+
+       $LFS getstripe $comp_file
+
+       found=$($LFS find --component-start 0m --component-end 128m \
+               --component-flags init,stale $comp_file | wc -l)
+       [ $found -eq 1 ] || error "write: First mirror comp incorrect"
+
+       local mirror_id=$($LFS getstripe --component-start=0m           \
+                        --component-end=128m --component-flags=init    \
+                        $comp_file | grep lcme_mirror_id | awk '{ print $2 }')
+
+       [[ $mirror_id -eq 2 ]] ||
+               error "component not in correct mirror? $mirror_id, not 2"
+
+       $LFS mirror resync $comp_file
+
+       $LFS getstripe $comp_file
+
+       # component dimensions should not change from resync
+       found=$($LFS find --component-start 0m --component-end 128m \
+               --component-flags init,^stale $comp_file | wc -l)
+       [ $found -eq 1 ] || error "resync: First mirror comp incorrect"
+
+       sel_layout_sanity $comp_file 4
+
+       rm -f $comp_file
+}
+run_test 204f "FLR write/stale/resync sel w/forced extension"
+
 complete $SECONDS
 check_and_cleanup_lustre
 exit_status