btrfs: make sure we rescan all devices after unregistering
[xfstests-dev.git] / common / btrfs
1 #
2 # Common btrfs specific functions
3 #
4
5 _btrfs_get_subvolid()
6 {
7         mnt=$1
8         name=$2
9
10         $BTRFS_UTIL_PROG sub list $mnt | egrep "\s$name$" | awk '{ print $2 }'
11 }
12
13 # _require_btrfs_command <command> [<subcommand>|<option>]
14 # We check for btrfs and (optionally) features of the btrfs command
15 # This function support both subfunction like "inspect-internal dump-tree" and
16 # options like "check --qgroup-report", and also subfunction options like
17 # "subvolume delete --subvolid"
18 _require_btrfs_command()
19 {
20         local cmd=$1
21         local param=$2
22         local param_arg=$3
23         local safe_param
24
25         _require_command "$BTRFS_UTIL_PROG" btrfs
26         if [ -z "$1" ]; then
27                 return 1;
28         fi
29         $BTRFS_UTIL_PROG $cmd --help &> /dev/null
30         [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd)"
31
32         test -z "$param" && return
33
34         # If $param is an option, replace leading "-"s for grep
35         if [ ${param:0:1} == "-" ]; then
36                 safe_param=$(echo $param | sed 's/^-*//')
37                 $BTRFS_UTIL_PROG $cmd --help | grep -wq $safe_param || \
38                         _notrun "$BTRFS_UTIL_PROG too old (must support $cmd $param)"
39                 return
40         fi
41
42         $BTRFS_UTIL_PROG $cmd $param --help &> /dev/null
43         [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd $param)"
44
45         test -z "$param_arg" && return
46
47         # replace leading "-"s for grep
48         safe_param=$(echo $param_arg | sed 's/^-*//')
49         $BTRFS_UTIL_PROG $cmd $param --help | grep -wq $safe_param || \
50                 _notrun "$BTRFS_UTIL_PROG too old (must support $cmd $param $param_arg)"
51 }
52
53 # Require extra check on btrfs qgroup numbers
54 _require_btrfs_qgroup_report()
55 {
56         _require_btrfs_command check --qgroup-report
57         touch ${RESULT_DIR}/require_scratch.require_qgroup_report
58 }
59
60 _require_btrfs_dump_super()
61 {
62         if [ ! -x "$BTRFS_SHOW_SUPER_PROG" ]; then
63                 _require_command "$BTRFS_UTIL_PROG" btrfs
64                 if ! $BTRFS_UTIL_PROG inspect-internal dump-super --help >& /dev/null; then
65                         _notrun "Missing btrfs-show-super or inspect-internal dump-super"
66                 fi
67                 BTRFS_SHOW_SUPER_PROG="$BTRFS_UTIL_PROG inspect-internal dump-super"
68         fi
69 }
70
71 _run_btrfs_util_prog()
72 {
73         run_check $BTRFS_UTIL_PROG $*
74 }
75
76 _require_btrfs_mkfs_feature()
77 {
78         if [ -z $1 ]; then
79                 echo "Missing feature name argument for _require_btrfs_mkfs_feature"
80                 exit 1
81         fi
82         feat=$1
83         $MKFS_BTRFS_PROG -O list-all 2>&1 | \
84                 grep '^[ \t]*'"$feat"'\b' > /dev/null 2>&1
85         [ $? -eq 0 ] || \
86                 _notrun "Feature $feat not supported in the available version of mkfs.btrfs"
87 }
88
89 _require_btrfs_fs_feature()
90 {
91         if [ -z $1 ]; then
92                 echo "Missing feature name argument for _require_btrfs_fs_feature"
93                 exit 1
94         fi
95         feat=$1
96         modprobe btrfs > /dev/null 2>&1
97         [ -e /sys/fs/btrfs/features/$feat ] || \
98                 _notrun "Feature $feat not supported by the available btrfs version"
99 }
100
101 _require_btrfs_fs_sysfs()
102 {
103         modprobe btrfs > /dev/null 2>&1
104         [ -e /sys/fs/btrfs/features ] || \
105                 _notrun "Sysfs not supported by the available btrfs version"
106
107 }
108
109 _check_btrfs_filesystem()
110 {
111         device=$1
112
113         # If type is set, we're mounted
114         type=`_fs_type $device`
115         ok=1
116
117         if [ "$type" = "$FSTYP" ]; then
118                 # mounted ...
119                 mountpoint=`_umount_or_remount_ro $device`
120         fi
121
122         if [ -f ${RESULT_DIR}/require_scratch.require_qgroup_report ]; then
123                 $BTRFS_UTIL_PROG check $device --qgroup-report > $tmp.qgroup_report 2>&1
124                 if grep -qE "Counts for qgroup.*are different" $tmp.qgroup_report ; then
125                         _log_err "_check_btrfs_filesystem: filesystem on $device has wrong qgroup numbers"
126                         echo "*** qgroup_report.$FSTYP output ***"      >>$seqres.full
127                         cat $tmp.qgroup_report                          >>$seqres.full
128                         echo "*** qgroup_report.$FSTYP output ***"      >>$seqres.full
129                 fi
130                 rm -f $tmp.qgroup_report
131         fi
132
133         $BTRFS_UTIL_PROG check $device >$tmp.fsck 2>&1
134         if [ $? -ne 0 ]; then
135                 _log_err "_check_btrfs_filesystem: filesystem on $device is inconsistent"
136                 echo "*** fsck.$FSTYP output ***"       >>$seqres.full
137                 cat $tmp.fsck                           >>$seqres.full
138                 echo "*** end fsck.$FSTYP output"       >>$seqres.full
139
140                 ok=0
141         fi
142         rm -f $tmp.fsck
143
144         if [ $ok -eq 0 ]; then
145                 echo "*** mount output ***"             >>$seqres.full
146                 _mount                                  >>$seqres.full
147                 echo "*** end mount output"             >>$seqres.full
148         elif [ "$type" = "$FSTYP" ]; then
149                 # was mounted ...
150                 _mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
151                 ok=$?
152         fi
153
154         if [ $ok -eq 0 ]; then
155                 status=1
156                 if [ "$iam" != "check" ]; then
157                         exit 1
158                 fi
159                 return 1
160         fi
161
162         return 0
163 }
164
165 _require_btrfs_dev_del_by_devid()
166 {
167         $BTRFS_UTIL_PROG device delete --help | egrep devid > /dev/null 2>&1
168         [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old "\
169                         "(must support 'btrfs device delete <devid> /<mnt>')"
170 }
171
172 # get btrfs profile configs being tested
173 #
174 # A set of pre-set profile configs are exported via _btrfs_profile_configs
175 # array. Default configs can be overridden by setting BTRFS_PROFILE_CONFIGS
176 # var in the format "metadata_profile:data_profile", multiple configs can be
177 # seperated by space, e.g.
178 # export BTRFS_PROFILE_CONFIGS="raid0:raid0 raid1:raid1 dup:single"
179 _btrfs_get_profile_configs()
180 {
181         if [ "$FSTYP" != "btrfs" ]; then
182                 return
183         fi
184
185         if [ -z "$BTRFS_PROFILE_CONFIGS" ]; then
186                 # Default configurations to test.
187                 local configs=(
188                         "single:single"
189                         "dup:single"
190                         "raid0:raid0"
191                         "raid1:raid0"
192                         "raid1:raid1"
193                         "raid10:raid10"
194                         "raid5:raid5"
195                         "raid6:raid6"
196                 )
197         else
198                 # User-provided configurations.
199                 local configs=(${BTRFS_PROFILE_CONFIGS[@]})
200         fi
201
202         _btrfs_profile_configs=()
203         for cfg in "${configs[@]}"; do
204                 local supported=true
205                 local profiles=(${cfg/:/ })
206                 if [ "$1" == "replace" ]; then
207                         # We can't do replace with these profiles because they
208                         # imply only one device ($SCRATCH_DEV), and we need to
209                         # keep $SCRATCH_DEV around for _scratch_mount
210                         # and _check_scratch_fs.
211                         local unsupported=(
212                                 "dup"
213                         )
214                 elif [ "$1" == "replace-missing" ]; then
215                         # We can't replace missing devices with these profiles
216                         # because there isn't enough redundancy.
217                         local unsupported=(
218                                 "single"
219                                 "dup"
220                                 "raid0"
221                         )
222                 else
223                         local unsupported=()
224                 fi
225                 for unsupp in "${unsupported[@]}"; do
226                         if [ "${profiles[0]}" == "$unsupp" -o "${profiles[1]}" == "$unsupp" ]; then
227                              if [ -z "$BTRFS_PROFILE_CONFIGS" ]; then
228                                      # For the default config, just omit it.
229                                      supported=false
230                              else
231                                      # For user-provided config, don't run the test.
232                                      _notrun "Profile $unsupp not supported for $1"
233                              fi
234                         fi
235                 done
236                 if "$supported"; then
237                         _btrfs_profile_configs+=("-m ${profiles[0]} -d ${profiles[1]}")
238                 fi
239         done
240         export _btrfs_profile_configs
241 }
242
243 # stress btrfs by running balance operation in a loop
244 _btrfs_stress_balance()
245 {
246         local options=$@
247         while true; do
248                 _run_btrfs_balance_start $options >> $seqres.full
249         done
250 }
251
252 # stress btrfs by creating/mounting/umounting/deleting subvolume in a loop
253 _btrfs_stress_subvolume()
254 {
255         local btrfs_dev=$1
256         local btrfs_mnt=$2
257         local subvol_name=$3
258         local subvol_mnt=$4
259         local stop_file=$5
260
261         mkdir -p $subvol_mnt
262         while [ ! -e $stop_file ]; do
263                 $BTRFS_UTIL_PROG subvolume create $btrfs_mnt/$subvol_name
264                 $MOUNT_PROG -o subvol=$subvol_name $btrfs_dev $subvol_mnt
265                 $UMOUNT_PROG $subvol_mnt
266                 $BTRFS_UTIL_PROG subvolume delete $btrfs_mnt/$subvol_name
267         done
268 }
269
270 # stress btrfs by running scrub in a loop
271 _btrfs_stress_scrub()
272 {
273         local btrfs_mnt=$1
274         while true; do
275                 $BTRFS_UTIL_PROG scrub start -B $btrfs_mnt
276         done
277 }
278
279 # stress btrfs by defragmenting every file/dir in a loop and compress file
280 # contents while defragmenting if second argument is not "nocompress"
281 _btrfs_stress_defrag()
282 {
283         local btrfs_mnt=$1
284         local compress=$2
285
286         while true; do
287                 if [ "$compress" == "nocompress" ]; then
288                         find $btrfs_mnt \( -type f -o -type d \) -exec \
289                         $BTRFS_UTIL_PROG filesystem defrag {} \;
290                 else
291                         find $btrfs_mnt \( -type f -o -type d \) -exec \
292                         $BTRFS_UTIL_PROG filesystem defrag -clzo {} \;
293                         find $btrfs_mnt \( -type f -o -type d \) -exec \
294                         $BTRFS_UTIL_PROG filesystem defrag -czlib {} \;
295                 fi
296         done
297 }
298
299 # stress btrfs by remounting it with different compression algorithms in a loop
300 # run this with fsstress running at background could exercise the compression
301 # code path and ensure no race when switching compression algorithm with constant
302 # I/O activity.
303 _btrfs_stress_remount_compress()
304 {
305         local btrfs_mnt=$1
306         while true; do
307                 for algo in no zlib lzo; do
308                         $MOUNT_PROG -o remount,compress=$algo $btrfs_mnt
309                 done
310         done
311 }
312
313 # stress btrfs by replacing devices in a loop
314 # Note that at least 3 devices are needed in SCRATCH_DEV_POOL and the last
315 # device should be free(not used by btrfs)
316 _btrfs_stress_replace()
317 {
318         local btrfs_mnt=$1
319
320         # The device number in SCRATCH_DEV_POOL should be at least 3,
321         # one is SCRATCH_DEV, one is to be replaced, one is free device
322         # we won't replace SCRATCH_DEV, see below for reason
323         if [ "`echo $SCRATCH_DEV_POOL | wc -w`" -lt 3 ]; then
324                 echo "_btrfs_stress_replace requires at least 3 devices in SCRATCH_DEV_POOL"
325                 return
326         fi
327
328         # take the last device as the first free_dev
329         local free_dev="`echo $SCRATCH_DEV_POOL | $AWK_PROG '{print $NF}'`"
330
331         # free_dev should be really free
332         if $BTRFS_UTIL_PROG filesystem show $btrfs_mnt | grep -q "$free_dev"; then
333                 echo "_btrfs_stress_replace: $free_dev is used by btrfs"
334                 return
335         fi
336
337         # dev_pool is device list being currently used by btrfs (excluding SCRATCH_DEV)
338         # and can be replaced. We don't replace SCRATCH_DEV because it will be used in
339         # _scratch_mount and _check_scratch_fs etc.
340         local dev_pool=`echo $SCRATCH_DEV_POOL | sed -e "s# *$SCRATCH_DEV *##" \
341                         -e "s# *$free_dev *##"`
342
343         # set the first device in dev_pool as the first src_dev to be replaced
344         local src_dev=`echo $dev_pool | $AWK_PROG '{print $1}'`
345
346         echo "dev_pool=$dev_pool"
347         echo "free_dev=$free_dev, src_dev=$src_dev"
348         while true; do
349                 echo "Replacing $src_dev with $free_dev"
350                 $BTRFS_UTIL_PROG replace start -fB $src_dev $free_dev $btrfs_mnt
351                 if [ $? -ne 0 ]; then
352                         # don't update src_dev and free_dev if replace failed
353                         continue
354                 fi
355                 dev_pool="$dev_pool $free_dev"
356                 dev_pool=`echo $dev_pool | sed -e "s# *$src_dev *##"`
357                 free_dev=$src_dev
358                 src_dev=`echo $dev_pool | $AWK_PROG '{print $1}'`
359         done
360 }
361
362 # find the right option to force output in bytes, older versions of btrfs-progs
363 # print that by default, newer print human readable numbers with unit suffix
364 _btrfs_qgroup_units()
365 {
366         $BTRFS_UTIL_PROG qgroup show --help 2>&1 | grep -q -- --raw && echo "--raw"
367 }
368
369 _btrfs_compression_algos()
370 {
371         echo zlib
372         for feature in /sys/fs/btrfs/features/compress_*; do
373                 echo "${feature#/sys/fs/btrfs/features/compress_}"
374         done
375 }
376
377 # run btrfs balance start with required --full-balance if available.
378 _run_btrfs_balance_start()
379 {
380         local bal_opt=""
381
382         $BTRFS_UTIL_PROG balance start --help | grep -q "full-balance"
383         (( $? == 0 )) && bal_opt="--full-balance"
384
385         $BTRFS_UTIL_PROG balance start $bal_opt $*
386 }
387
388 #return the sector size of the btrfs scratch fs
389 _scratch_btrfs_sectorsize()
390 {
391         $BTRFS_UTIL_PROG inspect-internal dump-super $SCRATCH_DEV |\
392                 grep sectorsize | awk '{print $2}'
393 }
394
395 _btrfs_supports_forget()
396 {
397         $BTRFS_UTIL_PROG device scan --help | grep -wq forget && \
398                 $BTRFS_UTIL_PROG device scan --forget > /dev/null 2>&1
399 }
400
401 _require_btrfs_forget_or_module_loadable()
402 {
403         _btrfs_supports_forget && return
404
405         _require_loadable_fs_module "btrfs"
406 }
407
408 _btrfs_forget_or_module_reload()
409 {
410         _btrfs_supports_forget && return
411
412         _reload_fs_module "btrfs"
413 }
414
415 # Test cases which utilized _btrfs_forget_or_module_reload() must call this
416 # to make sure TEST_DEV can still be mounted. As TEST_DEV can be part of a
417 # multi-device btrfs.
418 _btrfs_rescan_devices()
419 {
420         $BTRFS_UTIL_PROG device scan &> /dev/null
421 }