btrfs/011: continue the test if we failed to cancel the replace
[xfstests-dev.git] / tests / btrfs / 011
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (C) 2013 STRATO.  All rights reserved.
4 #
5 # FSQA Test No. btrfs/011
6 #
7 # Test of the btrfs replace operation.
8 #
9 # The amount of tests done depends on the number of devices in the
10 # SCRATCH_DEV_POOL. For full test coverage, at least 5 devices should
11 # be available (e.g. 5 partitions).
12 #
13 # The source and target devices for the replace operation are
14 # arbitrarily chosen out of SCRATCH_DEV_POOl. Since the target device
15 # mustn't be smaller than the source device, the requirement for this
16 # test is that all devices have _exactly_ the same size. If this is
17 # not the case, this test is not run.
18 #
19 # To check the filesystems after replacing a device, a scrub run is
20 # performed, a btrfsck run, and finally the filesystem is remounted.
21 #
22 . ./common/preamble
23 _begin_fstest auto replace volume
24
25 noise_pid=0
26
27 # Override the default cleanup function.
28 _cleanup()
29 {
30         if [ $noise_pid -ne 0 ] && ps -p $noise_pid | grep -q $noise_pid; then
31                 kill -TERM $noise_pid
32         fi
33         wait
34         rm -f $tmp.*
35         # we need this umount and couldn't rely on _require_scratch to umount
36         # it from next test, because we would replace SCRATCH_DEV, which is
37         # needed by _require_scratch, and make it umounted.
38         _scratch_unmount > /dev/null 2>&1
39 }
40
41 # Import common functions.
42 . ./common/filter
43
44 # real QA test starts here
45 _supported_fs btrfs
46 _require_scratch_nocheck
47 _require_scratch_dev_pool 5
48 _require_scratch_dev_pool_equal_size
49 _require_scratch_size $((10 * 1024 * 1024)) #kB
50 _require_command "$WIPEFS_PROG" wipefs
51
52 rm -f $tmp.*
53
54 echo "*** test btrfs replace"
55
56 # In seconds
57 wait_time=1
58
59 fill_scratch()
60 {
61         local fssize=$1
62         local filler_pid
63
64         # Fill inline extents.
65         for i in `seq 1 500`; do
66                 _ddt of=$SCRATCH_MNT/s$i bs=3800 count=1
67         done > /dev/null 2>&1
68
69         # Fill data extents.
70         for i in `seq 1 500`; do
71                 _ddt of=$SCRATCH_MNT/l$i bs=16385 count=1
72         done > /dev/null 2>&1
73         _ddt of=$SCRATCH_MNT/t0 bs=1M count=1 > /dev/null 2>&1
74         for i in `seq $fssize`; do
75                 cp $SCRATCH_MNT/t0 $SCRATCH_MNT/t$i || _fail "cp failed"
76         done > /dev/null 2>> $seqres.full
77
78         # Ensure we have enough data so that dev-replace would take at least
79         # 2 * $wait_time, allowing we cancel the running replace.
80         # Some extra points:
81         # - Use XFS_IO_PROG instead of dd
82         #   fstests wraps dd, making it pretty hard to kill the real dd pid
83         # - Use 64K block size with Direct IO
84         #   64K is the same stripe size used in replace/scrub. Using Direct IO
85         #   ensure the IO speed is near device limit and comparable to replace
86         #   speed.
87         $XFS_IO_PROG -f -d -c "pwrite -b 64k 0 1E" "$SCRATCH_MNT/t_filler" &>\
88                 $tmp.filler_result &
89         filler_pid=$!
90         sleep $((2 * $wait_time))
91         kill -KILL $filler_pid &> /dev/null
92         wait $filler_pid &> /dev/null
93
94         # If the system is too fast and the fs is too small, then skip the test
95         if grep -q "No space left" $tmp.filler_result; then
96                 ls -alh $SCRATCH_MNT >> $seqres.full
97                 cat $tmp.filler_result >> $seqres.full
98                 _notrun "fs too small for this test"
99         fi
100         cat $tmp.filler_result
101         sync; sync
102 }
103
104 workout()
105 {
106         local mkfs_options="$1"
107         local num_devs4raid="$2"
108         local with_cancel="$3"
109         local fssize="$4"
110         local source_dev="`echo ${SCRATCH_DEV_POOL} | awk '{print $1}'`"
111         local quick="quick"
112
113         [[ $fssize != 64 ]] && quick="thorough"
114
115         echo -e "\\n---------workout \"$1\" $2 $3 $4-----------" >> $seqres.full
116
117         $WIPEFS_PROG -a $SCRATCH_DEV_POOL > /dev/null 2>&1
118         _scratch_dev_pool_get $num_devs4raid
119         _spare_dev_get
120
121         _scratch_pool_mkfs $mkfs_options >> $seqres.full 2>&1 ||\
122                 _fail "mkfs failed"
123
124         _scratch_mount
125         _require_fs_space $SCRATCH_MNT $((2 * 512 * 1024)) #2.5G
126
127         fill_scratch $fssize
128         _run_btrfs_util_prog filesystem show -m $SCRATCH_MNT
129
130         echo -e "Replace from $source_dev to $SPARE_DEV\\n" >> $seqres.full
131         btrfs_replace_test $source_dev $SPARE_DEV "" $with_cancel $quick
132
133         _run_btrfs_util_prog filesystem show -m $SCRATCH_MNT
134
135         # Skip -r test for configs without mirror OR replace cancel
136         if echo $mkfs_options | egrep -qv "raid1|raid5|raid6|raid10" || \
137            [ "${with_cancel}Q" = "cancelQ" ]; then
138                 _scratch_unmount > /dev/null 2>&1
139                 _scratch_dev_pool_put
140                 _spare_dev_put
141                 return 0
142         fi
143
144         # Due to above replace, now SPARE_DEV is part of the FS, check that.
145         $BTRFS_UTIL_PROG filesystem show -m $SCRATCH_MNT |\
146                 grep -qs $SPARE_DEV$ ||\
147                 _fail "$SPARE_DEV is not part of SCRATCH_FS"
148
149         btrfs_replace_test $SPARE_DEV $source_dev "-r" $with_cancel $quick
150
151         _scratch_unmount > /dev/null 2>&1
152         _scratch_dev_pool_put
153         _spare_dev_put
154 }
155
156 btrfs_replace_test()
157 {
158         local source_dev="$1"
159         local target_dev="$2"
160         local replace_options="$3"
161         local with_cancel="$4"
162         local quick="$5"
163
164         # generate some (slow) background traffic in parallel to the
165         # replace operation. It is not a problem if cat fails early
166         # with ENOSPC.
167         cat /dev/urandom | od > $SCRATCH_MNT/noise 2>> $seqres.full &
168         noise_pid=$!
169
170         if [ "${with_cancel}Q" = "cancelQ" ]; then
171                 # background the replace operation (no '-B' option given)
172                 _run_btrfs_util_prog replace start -f $replace_options $source_dev $target_dev $SCRATCH_MNT
173                 sleep $wait_time
174                 $BTRFS_UTIL_PROG replace cancel $SCRATCH_MNT 2>&1 >> $seqres.full
175
176                 # 'replace status' waits for the replace operation to finish
177                 # before the status is printed
178                 $BTRFS_UTIL_PROG replace status $SCRATCH_MNT > $tmp.tmp 2>&1
179                 cat $tmp.tmp >> $seqres.full
180
181                 # If the replace is finished, we need to replace $source_dev
182                 # back with $target_dev, or later fsck will fail and abort
183                 # the test, reducing the coverage.
184                 if grep -q finished $tmp.tmp ; then
185                         $BTRFS_UTIL_PROG replace start -Bf $target_dev \
186                                 $source_dev $SCRATCH_MNT > /dev/null
187                 fi
188
189                 # For above finished case, we still output the error message
190                 # but continue the test, or later profiles won't get tested
191                 # at all.
192                 grep -q canceled $tmp.tmp || echo "btrfs replace status (canceled) failed"
193         else
194                 if [ "${quick}Q" = "thoroughQ" ]; then
195                         # The thorough test runs around 2 * $wait_time seconds.
196                         # This is a chance to force a sync in the middle of the
197                         # replace operation.
198                         (sleep $wait_time; sync) > /dev/null 2>&1 &
199                 fi
200                 _run_btrfs_util_prog replace start -Bf $replace_options $source_dev $target_dev $SCRATCH_MNT
201
202                 $BTRFS_UTIL_PROG replace status $SCRATCH_MNT > $tmp.tmp 2>&1
203                 cat $tmp.tmp >> $seqres.full
204                 grep -q finished $tmp.tmp || _fail "btrfs replace status (finished) failed"
205         fi
206
207         if ps -p $noise_pid | grep -q $noise_pid; then
208                 kill -TERM $noise_pid 2> /dev/null
209         fi
210         noise_pid=0
211         wait
212
213         # scrub tests on-disk data, that's the reason for the sync.
214         # With the '-B' option (don't background), any type of error causes
215         # exit values != 0, including detected correctable and uncorrectable
216         # errors on the device.
217         sync; sync
218         _run_btrfs_util_prog scrub start -B $SCRATCH_MNT
219
220         # Two tests are performed, the 1st is to btrfsck the filesystem,
221         # and the 2nd test is to mount the filesystem.
222         # Usually _check_btrfs_filesystem would perform the mount test,
223         # but it gets confused by the mount output that shows SCRATCH_MNT
224         # mounted but not being mounted to SCRATCH_DEV. This happens
225         # because in /proc/mounts the 2nd device of the filesystem is
226         # shown after the replace operation. Let's just do the mount
227         # test manually after _check_btrfs_filesystem is finished.
228         _scratch_unmount > /dev/null 2>&1
229         if [ "${with_cancel}Q" != "cancelQ" ]; then
230                 # after the replace operation, use the target_dev for everything
231                 echo "_check_btrfs_filesystem $target_dev" >> $seqres.full
232                 _check_btrfs_filesystem $target_dev
233                 _mount -t $FSTYP `_scratch_mount_options | sed "s&${SCRATCH_DEV}&${target_dev}&"`
234         else
235                 _check_btrfs_filesystem $source_dev
236                 _scratch_mount
237         fi
238 }
239
240 workout "-m single -d single" 1 no 64
241 # Mixed BG & RAID/DUP profiles are not supported on zoned btrfs
242 if ! _scratch_btrfs_is_zoned; then
243         workout "-m dup -d single" 1 no 64
244         workout "-m dup -d single" 1 cancel 1024
245         workout "-m raid0 -d raid0" 2 no 64
246         workout "-m raid1 -d raid1" 2 no 2048
247         workout "-m raid10 -d raid10" 4 no 64
248         workout "-m single -d single -M" 1 no 64
249         workout "-m dup -d dup -M" 1 no 64
250         workout "-m raid5 -d raid5" 2 no 64
251         workout "-m raid6 -d raid6" 3 no 64
252 fi
253
254 echo "*** done"
255 status=0
256 exit