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