2 # Common btrfs specific functions
12 $BTRFS_UTIL_PROG sub list $mnt | egrep "\s$name$" | $AWK_PROG '{ print $2 }'
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()
27 _require_command "$BTRFS_UTIL_PROG" btrfs
31 $BTRFS_UTIL_PROG $cmd --help &> /dev/null
32 [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd)"
34 test -z "$param" && return
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)"
44 $BTRFS_UTIL_PROG $cmd $param --help &> /dev/null
45 [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd $param)"
47 test -z "$param_arg" && return
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)"
55 # Require extra check on btrfs qgroup numbers
56 _require_btrfs_qgroup_report()
58 _require_btrfs_command check --qgroup-report
59 touch ${RESULT_DIR}/require_scratch.require_qgroup_report
62 _require_btrfs_dump_super()
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"
69 BTRFS_SHOW_SUPER_PROG="$BTRFS_UTIL_PROG inspect-internal dump-super"
73 _run_btrfs_util_prog()
75 run_check $BTRFS_UTIL_PROG $*
78 _require_btrfs_mkfs_feature()
81 echo "Missing feature name argument for _require_btrfs_mkfs_feature"
85 $MKFS_BTRFS_PROG -O list-all 2>&1 | \
86 grep '^[ \t]*'"$feat"'\b' > /dev/null 2>&1
88 _notrun "Feature $feat not supported in the available version of mkfs.btrfs"
91 _require_btrfs_fs_feature()
94 echo "Missing feature name argument for _require_btrfs_fs_feature"
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"
102 if [ $feat = "raid56" ]; then
103 # Zoned btrfs only supports SINGLE profile
104 _require_non_zoned_device "${SCRATCH_DEV}"
108 _require_btrfs_fs_sysfs()
110 modprobe btrfs > /dev/null 2>&1
111 [ -e /sys/fs/btrfs/features ] || \
112 _notrun "Sysfs not supported by the available btrfs version"
116 _require_btrfs_no_compress()
118 if _normalize_mount_options "$MOUNT_OPTIONS" | grep -q "compress"; then
119 _notrun "This test requires no compression enabled"
123 _check_btrfs_filesystem()
127 # If type is set, we're mounted
128 type=`_fs_type $device`
131 if [ "$type" = "$FSTYP" ]; then
133 mountpoint=`_umount_or_remount_ro $device`
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
144 rm -f $tmp.qgroup_report
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
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
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
169 _mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
173 if [ $ok -eq 0 ]; then
175 if [ "$iam" != "check" ]; then
184 _require_btrfs_dev_del_by_devid()
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>')"
191 # get btrfs profile configs being tested
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()
200 if [ "$FSTYP" != "btrfs" ]; then
204 if [ -z "$BTRFS_PROFILE_CONFIGS" ]; then
205 # Default configurations to test.
217 # User-provided configurations.
218 local configs=(${BTRFS_PROFILE_CONFIGS[@]})
221 _btrfs_profile_configs=()
222 for cfg in "${configs[@]}"; do
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.
233 elif [ "$1" == "replace-missing" ]; then
234 # We can't replace missing devices with these profiles
235 # because there isn't enough redundancy.
245 if _scratch_btrfs_is_zoned; then
246 # Zoned btrfs only supports SINGLE profile
259 for unsupp in "${unsupported[@]}"; do
260 if [ "${profiles[0]}" == "$unsupp" -o "${profiles[1]}" == "$unsupp" ]; then
264 if "$supported"; then
265 _btrfs_profile_configs+=("-m ${profiles[0]} -d ${profiles[1]}")
268 export _btrfs_profile_configs
271 # stress btrfs by running balance operation in a loop
272 _btrfs_stress_balance()
276 _run_btrfs_balance_start $options >> $seqres.full
280 # stress btrfs by creating/mounting/umounting/deleting subvolume in a loop
281 _btrfs_stress_subvolume()
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
298 # stress btrfs by running scrub in a loop
299 _btrfs_stress_scrub()
303 $BTRFS_UTIL_PROG scrub start -B $btrfs_mnt
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()
315 if [ "$compress" == "nocompress" ]; then
316 find $btrfs_mnt \( -type f -o -type d \) -exec \
317 $BTRFS_UTIL_PROG filesystem defrag {} \;
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 {} \;
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
331 _btrfs_stress_remount_compress()
335 for algo in no zlib lzo; do
336 $MOUNT_PROG -o remount,compress=$algo $btrfs_mnt
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()
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"
356 # take the last device as the first free_dev
357 local free_dev="`echo $SCRATCH_DEV_POOL | $AWK_PROG '{print $NF}'`"
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"
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 *##"`
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}'`
374 echo "dev_pool=$dev_pool"
375 echo "free_dev=$free_dev, src_dev=$src_dev"
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
383 dev_pool="$dev_pool $free_dev"
384 dev_pool=`echo $dev_pool | sed -e "s# *$src_dev *##"`
386 src_dev=`echo $dev_pool | $AWK_PROG '{print $1}'`
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()
394 $BTRFS_UTIL_PROG qgroup show --help 2>&1 | grep -q -- --raw && echo "--raw"
397 _btrfs_compression_algos()
400 for feature in /sys/fs/btrfs/features/compress_*; do
401 echo "${feature#/sys/fs/btrfs/features/compress_}"
405 # run btrfs balance start with required --full-balance if available.
406 _run_btrfs_balance_start()
410 $BTRFS_UTIL_PROG balance start --help | grep -q "full-balance"
411 (( $? == 0 )) && bal_opt="--full-balance"
413 $BTRFS_UTIL_PROG balance start $bal_opt $*
416 #return the sector size of the btrfs scratch fs
417 _scratch_btrfs_sectorsize()
419 $BTRFS_UTIL_PROG inspect-internal dump-super $SCRATCH_DEV |\
420 grep sectorsize | $AWK_PROG '{print $2}'
423 _btrfs_supports_forget()
425 $BTRFS_UTIL_PROG device scan --help | grep -wq forget && \
426 $BTRFS_UTIL_PROG device scan --forget > /dev/null 2>&1
429 _require_btrfs_forget_or_module_loadable()
431 _btrfs_supports_forget && return
433 _require_loadable_fs_module "btrfs"
436 _btrfs_forget_or_module_reload()
438 _btrfs_supports_forget && return
440 _reload_fs_module "btrfs"
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()
448 $BTRFS_UTIL_PROG device scan &> /dev/null
451 _scratch_btrfs_is_zoned()
453 [ `_zone_type ${SCRATCH_DEV}` != "none" ] && return 0
457 _require_btrfs_sysfs_fsid()
461 fsid=$($BTRFS_UTIL_PROG filesystem show $TEST_DIR |grep uuid: |\
462 $AWK_PROG '{print $NF}')
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"
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()
476 if $BTRFS_UTIL_PROG inspect-internal dump-tree $SCRATCH_DEV |\
477 grep -q "FREE_SPACE_TREE"; then
480 echo -n "-onospace_cache"
483 # Require certain sectorsize support
484 _require_btrfs_support_sectorsize()
488 # PAGE_SIZE as sectorsize is always supported
489 if [ $sectorsize -eq $(get_page_size) ]; then
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"
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
509 # Return the btrfs logical address for the first block in a file
510 _btrfs_get_first_logical()
513 _require_command "$FILEFRAG_PROG" filefrag
515 ${FILEFRAG_PROG} -v $file >> $seqres.full
516 ${FILEFRAG_PROG} -v $file | _filter_filefrag | cut -d '#' -f 1
519 # Find the device path for a btrfs logical offset
520 _btrfs_get_device_path()
525 _require_command "$BTRFS_MAP_LOGICAL_PROG" btrfs-map-logical
527 $BTRFS_MAP_LOGICAL_PROG -l $logical $SCRATCH_DEV | \
528 $AWK_PROG "(\$1 ~ /mirror/ && \$2 ~ /$stripe/) { print \$8 }"
532 # Find the device physical sector for a btrfs logical offset
533 _btrfs_get_physical()
538 _require_command "$BTRFS_MAP_LOGICAL_PROG" btrfs-map-logical
540 $BTRFS_MAP_LOGICAL_PROG -b -l $logical $SCRATCH_DEV >> $seqres.full 2>&1
541 $BTRFS_MAP_LOGICAL_PROG -l $logical $SCRATCH_DEV | \
542 $AWK_PROG "(\$1 ~ /mirror/ && \$2 ~ /$stripe/) { print \$6 }"
545 # Read from a specific stripe to test read recovery that corrupted a specific
546 # stripe. Btrfs uses the PID to select the mirror, so keep reading until the
547 # xfs_io process that performed the read was executed with a PID that ends up
548 # on the intended mirror.
549 _btrfs_direct_read_on_mirror()
557 while [[ -z $( (( BASHPID % nr_mirrors == mirror )) &&
558 exec $XFS_IO_PROG -d \
559 -c "pread -b $size $offset $size" $file) ]]; do
564 # Read from a specific stripe to test read recovery that corrupted a specific
565 # stripe. Btrfs uses the PID to select the mirror, so keep reading until the
566 # xfs_io process that performed the read was executed with a PID that ends up
567 # on the intended mirror.
568 _btrfs_buffered_read_on_mirror()
576 echo 3 > /proc/sys/vm/drop_caches
577 while [[ -z $( (( BASHPID % nr_mirrors == mirror )) &&
579 -c "pread -b $size $offset $size" $file) ]]; do