btrfs/187: fix test failure when using bash 5.0+ with debug enabled
[xfstests-dev.git] / tests / btrfs / 187
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (C) 2019 SUSE Linux Products GmbH. All Rights Reserved.
4 #
5 # FSQA Test No. 187
6 #
7 # Stress send running in parallel with balance and deduplication against files
8 # that belong to the snapshots used by send. The goal is to verify that these
9 # operations running in parallel do not lead to send crashing (trigger assertion
10 # failures and BUG_ONs), or send finding an inconsistent snapshot that leads to
11 # a failure (reported in dmesg/syslog). The test needs big trees (snapshots)
12 # with large differences between the parent and send snapshots in order to hit
13 # such issues with a good probability.
14 #
15 seq=`basename $0`
16 seqres=$RESULT_DIR/$seq
17 echo "QA output created by $seq"
18 tmp=/tmp/$$
19 status=1        # failure is the default!
20 trap "_cleanup; exit \$status" 0 1 2 3 15
21
22 _cleanup()
23 {
24         cd /
25         rm -f $tmp.*
26 }
27
28 # get standard environment, filters and checks
29 . ./common/rc
30 . ./common/attr
31 . ./common/filter
32 . ./common/reflink
33
34 # real QA test starts here
35 _supported_fs btrfs
36 _require_scratch_dedupe
37 _require_attrs
38
39 rm -f $seqres.full
40
41 # We at least need 8GB of free space on $SCRATCH_DEV
42 _require_scratch_size $((8 * 1024 * 1024))
43
44 _scratch_mkfs >>$seqres.full 2>&1
45 _scratch_mount
46
47 dedupe_two_files()
48 {
49         trap "wait; exit" SIGTERM
50
51         local f1=$(find $SCRATCH_MNT/snap1 -type f | shuf -n 1)
52         local f2=$(find $SCRATCH_MNT/snap2 -type f | shuf -n 1)
53
54         if (( RANDOM % 2 )); then
55                 local tmp=$f1
56                 f1=$f2
57                 f2=$tmp
58         fi
59
60         # Ignore errors from dedupe. We just want to test for crashes and
61         # deadlocks.
62         $XFS_IO_PROG -r -c "dedupe $f1 0 0 64K" $f2 &> /dev/null
63 }
64
65 dedupe_files_loop()
66 {
67         local stop=0
68
69         # Avoid executing 'wait' inside the trap, because when we receive
70         # SIGTERM we might be already executing the wait command in the while
71         # loop below. When that is the case, bash 5.0+ with debug enabled prints
72         # a warning message that makes the test fail due to a mismatch with the
73         # golden output. That warning message is the following:
74         #
75         # warning: wait_for: recursively setting old_sigint_handler to wait_sigint_handler: running_trap = 16
76         #
77         trap "stop=1" SIGTERM
78
79         while [ $stop -eq 0 ]; do
80                 for ((i = 1; i <= 5; i++)); do
81                         dedupe_two_files &
82                 done
83                 wait
84         done
85 }
86
87 balance_loop()
88 {
89         trap "wait; exit" SIGTERM
90
91         while true; do
92                 # Balance only metadata block groups, since this is makes it
93                 # easier to hit problems (crashes and errors) in send.
94                 # Ignore errors from balance. We just want to test for crashes
95                 # and deadlocks.
96                 _run_btrfs_balance_start -f -m $SCRATCH_MNT &> /dev/null
97                 sleep $((RANDOM % 3))
98         done
99 }
100
101 full_send_loop()
102 {
103         trap "wait; exit" SIGTERM
104
105         local count=$1
106
107         for ((i = 1; i <= $count; i++)); do
108                 # Ignore errors from send. We will check for errors later in
109                 # dmesg/syslog.
110                 $BTRFS_UTIL_PROG send -f /dev/null \
111                         $SCRATCH_MNT/snap1 &> /dev/null
112                 sleep $((RANDOM % 3))
113         done
114 }
115
116 inc_send_loop()
117 {
118         trap "wait; exit" SIGTERM
119
120         local count=$1
121
122         for ((i = 1; i <= $count; i++)); do
123                 # Ignore errors from send. We will check for errors later in
124                 # dmesg/syslog.
125                 $BTRFS_UTIL_PROG send -f /dev/null \
126                         -p $SCRATCH_MNT/snap1 $SCRATCH_MNT/snap2 &> /dev/null
127                 sleep $((RANDOM % 3))
128         done
129 }
130
131 write_files_loop()
132 {
133         local count=$1
134         local offset=$2
135
136         for ((i = 1; i <= $count; i++)); do
137                 $XFS_IO_PROG -f -c "pwrite -S 0xea 0 64K" \
138                         $SCRATCH_MNT/file_$((i + offset)) >/dev/null
139         done
140 }
141
142 set_xattrs_loop()
143 {
144         local count=$1
145         local offset=$2
146
147         for ((i = 1; i <= $count; i++)); do
148                 $SETFATTR_PROG -n 'user.x1' -v $xattr_value \
149                         $SCRATCH_MNT/file_$((i + offset))
150         done
151 }
152
153 # Number of files created before first snapshot. Must be divisable by 4.
154 nr_initial_files=40000
155 # Number of files created after the first snapshot. Must be divisable by 4.
156 nr_more_files=40000
157
158 # Create initial files.
159 step=$((nr_initial_files / 4))
160 for ((n = 0; n < 4; n++)); do
161         offset=$((step * $n))
162         write_files_loop $step $offset &
163         create_pids[$n]=$!
164 done
165 wait ${create_pids[@]}
166
167 $BTRFS_UTIL_PROG subvolume snapshot -r $SCRATCH_MNT $SCRATCH_MNT/snap1 \
168         | _filter_scratch
169
170 # Add some more files, so that that are substantial differences between the
171 # two test snapshots used for an incremental send later.
172
173 # Create more files.
174 step=$((nr_more_files / 4))
175 for ((n = 0; n < 4; n++)); do
176         offset=$((nr_initial_files + step * $n))
177         write_files_loop $step $offset &
178         create_pids[$n]=$!
179 done
180 wait ${create_pids[@]}
181
182 # Add some xattrs to all files, so that every leaf and node of the fs tree is
183 # COWed. Adding more files does only adds leafs and nodes to the tree's right
184 # side, since inode numbers are based on a counter and form the first part
185 # (objectid) of btree keys (we only modifying the right most leaf of the tree).
186 # Use large values for the xattrs to quickly increase the height of the tree.
187 xattr_value=$(printf '%0.sX' $(seq 1 3800))
188
189 # Split the work into 4 workers working on consecutive ranges to avoid contention
190 # on the same leafs as much as possible.
191 step=$(((nr_more_files + nr_initial_files) / 4))
192 for ((n = 0; n < 4; n++)); do
193         offset=$((step * $n))
194         set_xattrs_loop $step $offset &
195         setxattr_pids[$n]=$!
196 done
197 wait ${setxattr_pids[@]}
198
199 $BTRFS_UTIL_PROG subvolume snapshot -r $SCRATCH_MNT $SCRATCH_MNT/snap2 \
200         | _filter_scratch
201
202 full_send_loop 5 &
203 full_send_pid=$!
204
205 inc_send_loop 10 &
206 inc_send_pid=$!
207
208 dedupe_files_loop &
209 dedupe_pid=$!
210
211 balance_loop &
212 balance_pid=$!
213
214 wait $full_send_pid
215 wait $inc_send_pid
216
217 kill $dedupe_pid
218 wait $dedupe_pid
219
220 kill $balance_pid
221 wait $balance_pid
222
223 # Check for errors messages that happen due to inconsistent snapshot caused by
224 # deduplication and balance running in parallel with send, causing btree nodes
225 # and leafs to disappear and getting reused while send is using them.
226 #
227 # Example messages:
228 #
229 # BTRFS error (device sdc): did not find backref in send_root. inode=63292, \
230 #     offset=0, disk_byte=5228134400 found extent=5228134400
231 #
232 # BTRFS error (device sdc): parent transid verify failed on 32243712 wanted 24 \
233 #     found 27
234 #
235 _dmesg_since_test_start | egrep -e '\bBTRFS error \(device .*?\):'
236
237 status=0
238 exit