blob: e7df825ed45491f9918b22b128a6eb912c3fa0f7 [file] [log] [blame]
#
# Common btrfs specific functions
#
. common/module
_btrfs_get_subvolid()
{
local mnt=$1
local name=$2
$BTRFS_UTIL_PROG subvolume list $mnt | grep -E "\s$name$" | $AWK_PROG '{ print $2 }'
}
# _require_btrfs_command <command> [<subcommand>|<option>]
# We check for btrfs and (optionally) features of the btrfs command
# This function support both subfunction like "inspect-internal dump-tree" and
# options like "check --qgroup-report", and also subfunction options like
# "subvolume delete --subvolid"
_require_btrfs_command()
{
local cmd=$1
local param=$2
local param_arg=$3
local safe_param
_require_command "$BTRFS_UTIL_PROG" btrfs
if [ -z "$1" ]; then
return 1;
fi
$BTRFS_UTIL_PROG $cmd --help &> /dev/null
[ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd)"
test -z "$param" && return
# If $param is an option, replace leading "-"s for grep
if [ ${param:0:1} == "-" ]; then
safe_param=$(echo $param | sed 's/^-*//')
$BTRFS_UTIL_PROG $cmd --help | grep -wq $safe_param || \
_notrun "$BTRFS_UTIL_PROG too old (must support $cmd $param)"
return
fi
$BTRFS_UTIL_PROG $cmd $param --help &> /dev/null
[ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd $param)"
test -z "$param_arg" && return
# replace leading "-"s for grep
safe_param=$(echo $param_arg | sed 's/^-*//')
$BTRFS_UTIL_PROG $cmd $param --help | grep -wq $safe_param || \
_notrun "$BTRFS_UTIL_PROG too old (must support $cmd $param $param_arg)"
}
# Require extra check on btrfs qgroup numbers
_require_btrfs_qgroup_report()
{
_require_btrfs_command check --qgroup-report
touch ${RESULT_DIR}/require_scratch.require_qgroup_report
}
_require_btrfs_dump_super()
{
if [ ! -x "$BTRFS_SHOW_SUPER_PROG" ]; then
_require_command "$BTRFS_UTIL_PROG" btrfs
if ! $BTRFS_UTIL_PROG inspect-internal dump-super --help >& /dev/null; then
_notrun "Missing btrfs-show-super or inspect-internal dump-super"
fi
BTRFS_SHOW_SUPER_PROG="$BTRFS_UTIL_PROG inspect-internal dump-super"
fi
}
_run_btrfs_util_prog()
{
run_check $BTRFS_UTIL_PROG $*
}
_require_btrfs_mkfs_feature()
{
if [ -z $1 ]; then
echo "Missing feature name argument for _require_btrfs_mkfs_feature"
exit 1
fi
feat=$1
$MKFS_BTRFS_PROG -O list-all 2>&1 | \
grep '^[ \t]*'"$feat"'\b' > /dev/null 2>&1
[ $? -eq 0 ] || \
_notrun "Feature $feat not supported in the available version of mkfs.btrfs"
}
_require_btrfs_mkfs_uuid_option()
{
local cnt
cnt=$($MKFS_BTRFS_PROG --help 2>&1 | \
grep -E --count -- "--uuid|--device-uuid")
if [ $cnt != 2 ]; then
_notrun "Require $MKFS_BTRFS_PROG with --uuid and --device-uuid options"
fi
}
_require_btrfs_fs_feature()
{
if [ -z $1 ]; then
echo "Missing feature name argument for _require_btrfs_fs_feature"
exit 1
fi
feat=$1
modprobe btrfs > /dev/null 2>&1
[ -e /sys/fs/btrfs/features/$feat ] || \
_notrun "Feature $feat not supported by the available btrfs version"
if [ $feat = "raid56" ]; then
# Zoned btrfs only supports SINGLE profile
_require_non_zoned_device "${SCRATCH_DEV}"
fi
}
_require_btrfs_fs_sysfs()
{
modprobe btrfs > /dev/null 2>&1
[ -e /sys/fs/btrfs/features ] || \
_notrun "Sysfs not supported by the available btrfs version"
}
_require_btrfs_no_compress()
{
if _normalize_mount_options "$MOUNT_OPTIONS" | grep -q "compress"; then
_notrun "This test requires no compression enabled"
fi
}
_require_btrfs_no_nodatacow()
{
if _normalize_mount_options "$MOUNT_OPTIONS" | grep -q "nodatacow"; then
_notrun "This test requires no nodatacow enabled"
fi
}
_require_btrfs_free_space_tree()
{
_scratch_mkfs > /dev/null 2>&1
if ! $BTRFS_UTIL_PROG inspect-internal dump-super $SCRATCH_DEV | \
grep -q "FREE_SPACE_TREE"
then
_notrun "This test requires a free-space-tree"
fi
}
_require_btrfs_no_block_group_tree()
{
_scratch_mkfs > /dev/null 2>&1
if $BTRFS_UTIL_PROG inspect-internal dump-super $SCRATCH_DEV | \
grep -q "BLOCK_GROUP_TREE"
then
_notrun "This test requires no block-group-tree"
fi
}
_check_btrfs_filesystem()
{
device=$1
# If type is set, we're mounted
type=`_fs_type $device`
ok=1
if [ "$type" = "$FSTYP" ]; then
# mounted ...
mountpoint=`_umount_or_remount_ro $device`
fi
if [ -f ${RESULT_DIR}/require_scratch.require_qgroup_report ]; then
$BTRFS_UTIL_PROG check $device --qgroup-report > $tmp.qgroup_report 2>&1
if grep -qE "Counts for qgroup.*are different" $tmp.qgroup_report ; then
_log_err "_check_btrfs_filesystem: filesystem on $device has wrong qgroup numbers"
echo "*** qgroup_report.$FSTYP output ***" >>$seqres.full
cat $tmp.qgroup_report >>$seqres.full
echo "*** qgroup_report.$FSTYP output ***" >>$seqres.full
fi
rm -f $tmp.qgroup_report
fi
$BTRFS_UTIL_PROG check $device >$tmp.fsck 2>&1
if [ $? -ne 0 ]; then
_log_err "_check_btrfs_filesystem: filesystem on $device is inconsistent"
echo "*** fsck.$FSTYP output ***" >>$seqres.full
cat $tmp.fsck >>$seqres.full
echo "*** end fsck.$FSTYP output" >>$seqres.full
ok=0
fi
rm -f $tmp.fsck
if [ $ok -eq 0 ] && [ "$DUMP_CORRUPT_FS" = "1" ]; then
local flatdev="$(basename "$device")"
_btrfs_metadump "$device" "$seqres.$flatdev.check.md" >>$seqres.full
fi
if [ $ok -eq 0 ]; then
echo "*** mount output ***" >>$seqres.full
_mount >>$seqres.full
echo "*** end mount output" >>$seqres.full
elif [ "$type" = "$FSTYP" ]; then
# was mounted ...
_mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
ok=$?
fi
if [ $ok -eq 0 ]; then
status=1
if [ "$iam" != "check" ]; then
exit 1
fi
return 1
fi
return 0
}
_require_btrfs_dev_del_by_devid()
{
$BTRFS_UTIL_PROG device delete --help | grep -E devid > /dev/null 2>&1
[ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old "\
"(must support 'btrfs device delete <devid> /<mnt>')"
}
# get btrfs profile configs being tested
#
# A set of pre-set profile configs are exported via _btrfs_profile_configs
# array. Default configs can be overridden by setting BTRFS_PROFILE_CONFIGS
# var in the format "metadata_profile:data_profile", multiple configs can be
# seperated by space, e.g.
# export BTRFS_PROFILE_CONFIGS="raid0:raid0 raid1:raid1 dup:single"
_btrfs_get_profile_configs()
{
if [ "$FSTYP" != "btrfs" ]; then
return
fi
local unsupported=()
if [ "$1" == "replace" ]; then
# We can't do replace with these profiles because they
# imply only one device ($SCRATCH_DEV), and we need to
# keep $SCRATCH_DEV around for _scratch_mount
# and _check_scratch_fs.
unsupported+=(
"dup"
)
elif [ "$1" == "replace-missing" ]; then
# We can't replace missing devices with these profiles
# because there isn't enough redundancy.
unsupported+=(
"single"
"dup"
"raid0"
)
fi
if _scratch_btrfs_is_zoned; then
# Zoned btrfs only supports SINGLE profile
unsupported+=(
"dup"
"raid0"
"raid1"
"raid1c3"
"raid1c4"
"raid10"
"raid5"
"raid6"
)
fi
if [ -z "$BTRFS_PROFILE_CONFIGS" ]; then
# Default configurations to test.
local configs=(
"single:single"
"dup:single"
"raid0:raid0"
"raid1:raid0"
"raid1:raid1"
"raid10:raid10"
"raid5:raid5"
"raid6:raid6"
)
if [ "$1" == "dup" ]; then
configs+=("dup:dup")
fi
else
# User-provided configurations.
local configs=(${BTRFS_PROFILE_CONFIGS[@]})
fi
_btrfs_profile_configs=()
for cfg in "${configs[@]}"; do
local supported=true
local profiles=(${cfg/:/ })
for unsupp in "${unsupported[@]}"; do
if [ "${profiles[0]}" == "$unsupp" -o "${profiles[1]}" == "$unsupp" ]; then
supported=false
fi
done
if "$supported"; then
_btrfs_profile_configs+=("-m ${profiles[0]} -d ${profiles[1]}")
fi
done
export _btrfs_profile_configs
}
# stress btrfs by running balance operation in a loop
_btrfs_stress_balance()
{
local options=$@
while true; do
_run_btrfs_balance_start $options >> $seqres.full
done
}
# Kill a background process running _btrfs_stress_balance()
_btrfs_kill_stress_balance_pid()
{
local balance_pid=$1
# Ignore if process already died.
kill $balance_pid &> /dev/null
wait $balance_pid &> /dev/null
# Wait for the balance operation to finish.
while ps aux | grep "balance start" | grep -qv grep; do
sleep 1
done
}
# stress btrfs by creating/mounting/umounting/deleting subvolume in a loop
_btrfs_stress_subvolume()
{
local btrfs_dev=$1
local btrfs_mnt=$2
local subvol_name=$3
local subvol_mnt=$4
local stop_file=$5
mkdir -p $subvol_mnt
while [ ! -e $stop_file ]; do
$BTRFS_UTIL_PROG subvolume create $btrfs_mnt/$subvol_name
$MOUNT_PROG -o subvol=$subvol_name $btrfs_dev $subvol_mnt
$UMOUNT_PROG $subvol_mnt
$BTRFS_UTIL_PROG subvolume delete $btrfs_mnt/$subvol_name
done
}
# stress btrfs by running scrub in a loop
_btrfs_stress_scrub()
{
local btrfs_mnt=$1
while true; do
$BTRFS_UTIL_PROG scrub start -B $btrfs_mnt
done
}
# Kill a background process running _btrfs_stress_scrub()
_btrfs_kill_stress_scrub_pid()
{
local scrub_pid=$1
# Ignore if process already died.
kill $scrub_pid &> /dev/null
wait $scrub_pid &> /dev/null
# Wait for the scrub operation to finish.
while ps aux | grep "scrub start" | grep -qv grep; do
sleep 1
done
}
# stress btrfs by defragmenting every file/dir in a loop and compress file
# contents while defragmenting if second argument is not "nocompress"
_btrfs_stress_defrag()
{
local btrfs_mnt=$1
local compress=$2
while true; do
if [ "$compress" == "nocompress" ]; then
find $btrfs_mnt \( -type f -o -type d \) -exec \
$BTRFS_UTIL_PROG filesystem defrag {} \;
else
find $btrfs_mnt \( -type f -o -type d \) -exec \
$BTRFS_UTIL_PROG filesystem defrag -clzo {} \;
find $btrfs_mnt \( -type f -o -type d \) -exec \
$BTRFS_UTIL_PROG filesystem defrag -czlib {} \;
fi
done
}
# Kill a background process running _btrfs_stress_defrag()
_btrfs_kill_stress_defrag_pid()
{
local defrag_pid=$1
# Ignore if process already died.
kill $defrag_pid &> /dev/null
wait $defrag_pid &> /dev/null
# Wait for the defrag operation to finish.
while ps aux | grep "btrfs filesystem defrag" | grep -qv grep; do
sleep 1
done
}
# stress btrfs by remounting it with different compression algorithms in a loop
# run this with fsstress running at background could exercise the compression
# code path and ensure no race when switching compression algorithm with constant
# I/O activity.
_btrfs_stress_remount_compress()
{
local btrfs_mnt=$1
while true; do
for algo in no zlib lzo; do
$MOUNT_PROG -o remount,compress=$algo $btrfs_mnt
done
done
}
# Kill a background process running _btrfs_stress_remount_compress()
_btrfs_kill_stress_remount_compress_pid()
{
local remount_pid=$1
local btrfs_mnt=$2
# Ignore if process already died.
kill $remount_pid &> /dev/null
wait $remount_pid &> /dev/null
# Wait for the remount loop to finish.
while ps aux | grep "mount.*${btrfs_mnt}" | grep -qv grep; do
sleep 1
done
}
# stress btrfs by replacing devices in a loop
# Note that at least 3 devices are needed in SCRATCH_DEV_POOL and the last
# device should be free(not used by btrfs)
_btrfs_stress_replace()
{
local btrfs_mnt=$1
# The device number in SCRATCH_DEV_POOL should be at least 3,
# one is SCRATCH_DEV, one is to be replaced, one is free device
# we won't replace SCRATCH_DEV, see below for reason
if [ "`echo $SCRATCH_DEV_POOL | wc -w`" -lt 3 ]; then
echo "_btrfs_stress_replace requires at least 3 devices in SCRATCH_DEV_POOL"
return
fi
# take the last device as the first free_dev
local free_dev="`echo $SCRATCH_DEV_POOL | $AWK_PROG '{print $NF}'`"
# free_dev should be really free
if $BTRFS_UTIL_PROG filesystem show $btrfs_mnt | grep -q "$free_dev"; then
echo "_btrfs_stress_replace: $free_dev is used by btrfs"
return
fi
# dev_pool is device list being currently used by btrfs (excluding SCRATCH_DEV)
# and can be replaced. We don't replace SCRATCH_DEV because it will be used in
# _scratch_mount and _check_scratch_fs etc.
local dev_pool=`echo $SCRATCH_DEV_POOL | sed -e "s# *$SCRATCH_DEV *##" \
-e "s# *$free_dev *##"`
# set the first device in dev_pool as the first src_dev to be replaced
local src_dev=`echo $dev_pool | $AWK_PROG '{print $1}'`
echo "dev_pool=$dev_pool"
echo "free_dev=$free_dev, src_dev=$src_dev"
while true; do
echo "Replacing $src_dev with $free_dev"
$BTRFS_UTIL_PROG replace start -fB $src_dev $free_dev $btrfs_mnt
if [ $? -ne 0 ]; then
# don't update src_dev and free_dev if replace failed
continue
fi
dev_pool="$dev_pool $free_dev"
dev_pool=`echo $dev_pool | sed -e "s# *$src_dev *##"`
free_dev=$src_dev
src_dev=`echo $dev_pool | $AWK_PROG '{print $1}'`
done
}
# find the right option to force output in bytes, older versions of btrfs-progs
# print that by default, newer print human readable numbers with unit suffix
_btrfs_qgroup_units()
{
$BTRFS_UTIL_PROG qgroup show --help 2>&1 | grep -q -- --raw && echo "--raw"
}
_btrfs_compression_algos()
{
echo zlib
for feature in /sys/fs/btrfs/features/compress_*; do
echo "${feature#/sys/fs/btrfs/features/compress_}"
done
}
# run btrfs balance start with required --full-balance if available.
_run_btrfs_balance_start()
{
local bal_opt=""
$BTRFS_UTIL_PROG balance start --help | grep -q "full-balance"
(( $? == 0 )) && bal_opt="--full-balance"
$BTRFS_UTIL_PROG balance start $bal_opt $*
}
#return the sector size of the btrfs scratch fs
_scratch_btrfs_sectorsize()
{
$BTRFS_UTIL_PROG inspect-internal dump-super $SCRATCH_DEV |\
grep sectorsize | $AWK_PROG '{print $2}'
}
_btrfs_supports_forget()
{
$BTRFS_UTIL_PROG device scan --help | grep -wq forget && \
$BTRFS_UTIL_PROG device scan --forget > /dev/null 2>&1
}
_require_btrfs_forget_or_module_loadable()
{
_btrfs_supports_forget && return
_require_loadable_fs_module "btrfs"
}
_btrfs_forget_or_module_reload()
{
_btrfs_supports_forget && return
_reload_fs_module "btrfs"
}
# Test cases which utilized _btrfs_forget_or_module_reload() must call this
# to make sure TEST_DEV can still be mounted. As TEST_DEV can be part of a
# multi-device btrfs.
_btrfs_rescan_devices()
{
$BTRFS_UTIL_PROG device scan &> /dev/null
}
_scratch_btrfs_is_zoned()
{
[ `_zone_type ${SCRATCH_DEV}` != "none" ] && return 0
return 1
}
_btrfs_get_fsid()
{
local fsid
local mnt=$1
fsid=$($BTRFS_UTIL_PROG filesystem show $mnt |grep uuid: |\
$AWK_PROG '{print $NF}')
echo $fsid
}
_require_btrfs_sysfs_fsid()
{
local fsid
fsid=$(_btrfs_get_fsid $TEST_DIR)
# Check if the kernel has sysfs fsid support.
# Following kernel patch adds it:
# btrfs: sysfs add devinfo/fsid to retrieve fsid from the device
test -f /sys/fs/btrfs/$fsid/devinfo/1/fsid ||\
_notrun "Need btrfs sysfs fsid support"
}
# If test doesn't want v1 cache to take up data space, there's no longer need
# the "nospace_cache" mount option if the filesystem is already using v2 cache.
# Since v2 cache is using metadata space, it will no longer take up data space.
_btrfs_no_v1_cache_opt()
{
if $BTRFS_UTIL_PROG inspect-internal dump-tree $SCRATCH_DEV |\
grep -q "FREE_SPACE_TREE"; then
return
fi
echo -n "-onospace_cache"
}
# Require certain sectorsize support
_require_btrfs_support_sectorsize()
{
local sectorsize=$1
# PAGE_SIZE as sectorsize is always supported
if [ $sectorsize -eq $(_get_page_size) ]; then
return
fi
test -f /sys/fs/btrfs/features/supported_sectorsizes || \
_notrun "no subpage support found"
grep -wq $sectorsize /sys/fs/btrfs/features/supported_sectorsizes || \
_notrun "sectorsize $sectorsize is not supported"
}
_require_btrfs_inline_extents_creation()
{
local ino
_require_xfs_io_command fiemap
_require_scratch
_scratch_mkfs &> /dev/null
_scratch_mount -o max_inline=2048,compress=none
_pwrite_byte 0x00 0 1024 $SCRATCH_MNT/inline &> /dev/null
sync
$XFS_IO_PROG -c "fiemap -v" $SCRATCH_MNT/inline | tail -n 1 > $tmp.fiemap
_scratch_unmount
# 0x200 means inlined, 0x100 means not block aligned, 0x1 means
# the last extent.
if ! grep -q "0x301" $tmp.fiemap; then
rm -f -- $tmp.fiemap
_notrun "No inline extent creation support, maybe subpage?"
fi
rm -f -- $tmp.fiemap
}
_btrfs_metadump()
{
local device="$1"
local dumpfile="$2"
test -n "$BTRFS_IMAGE_PROG" || _fail "btrfs-image not installed"
$BTRFS_IMAGE_PROG "$device" "$dumpfile"
[ -n "$DUMP_COMPRESSOR" ] && $DUMP_COMPRESSOR -f "$dumpfile" &> /dev/null
}
# Return the btrfs logical address for the first block in a file
_btrfs_get_first_logical()
{
local file=$1
_require_command "$FILEFRAG_PROG" filefrag
${FILEFRAG_PROG} -v $file >> $seqres.full
${FILEFRAG_PROG} -v $file | _filter_filefrag | cut -d '#' -f 1
}
# Find the device path for a btrfs logical offset
_btrfs_get_device_path()
{
local logical=$1
local stripe=$2
_require_command "$BTRFS_MAP_LOGICAL_PROG" btrfs-map-logical
$BTRFS_MAP_LOGICAL_PROG -l $logical $SCRATCH_DEV | \
$AWK_PROG "(\$1 ~ /mirror/ && \$2 ~ /$stripe/) { print \$8 }"
}
# Find the device physical sector for a btrfs logical offset
_btrfs_get_physical()
{
local logical=$1
local stripe=$2
_require_command "$BTRFS_MAP_LOGICAL_PROG" btrfs-map-logical
$BTRFS_MAP_LOGICAL_PROG -l $logical $SCRATCH_DEV >> $seqres.full 2>&1
$BTRFS_MAP_LOGICAL_PROG -l $logical $SCRATCH_DEV | \
$AWK_PROG "(\$1 ~ /mirror/ && \$2 ~ /$stripe/) { print \$6 }"
}
# Read from a specific stripe to test read recovery that corrupted a specific
# stripe. Btrfs uses the PID to select the mirror, so keep reading until the
# xfs_io process that performed the read was executed with a PID that ends up
# on the intended mirror.
_btrfs_direct_read_on_mirror()
{
local mirror=$1
local nr_mirrors=$2
local file=$3
local offset=$4
local size=$5
while [[ -z $( (( BASHPID % nr_mirrors == mirror )) &&
exec $XFS_IO_PROG -d \
-c "pread -b $size $offset $size" $file) ]]; do
:
done
}
# Read from a specific stripe to test read recovery that corrupted a specific
# stripe. Btrfs uses the PID to select the mirror, so keep reading until the
# xfs_io process that performed the read was executed with a PID that ends up
# on the intended mirror.
_btrfs_buffered_read_on_mirror()
{
local mirror=$1
local nr_mirrors=$2
local file=$3
local offset=$4
local size=$5
# The drop_caches doesn't seem to drop every pages on aarch64 with
# 64K page size.
# So here as another workaround, cycle mount the SCRATCH_MNT to ensure
# the cache are dropped, but we can not use _scratch_cycle_mount, as
# we may mount whatever dm device at SCRATCH_MNT.
# So here we grab the mounted block device and its mount options, then
# unmount and re-mount with the same device and options.
local dev=$(findmnt -n -T $SCRATCH_MNT -o SOURCE)
local opts=$(findmnt -n -T $SCRATCH_MNT -o OPTIONS)
if [ -z "$dev" -o -z "$opts" ]; then
_fail "failed to grab mount info of $SCRATCH_MNT"
fi
_scratch_unmount
_mount $dev -o $opts $SCRATCH_MNT
while [[ -z $( (( BASHPID % nr_mirrors == mirror )) &&
exec $XFS_IO_PROG \
-c "pread -b $size $offset $size" $file) ]]; do
:
done
}
_require_btrfs_corrupt_block()
{
_require_command "$BTRFS_CORRUPT_BLOCK_PROG" btrfs-corrupt-block
}
_require_btrfs_send_version()
{
local version=$1
# Check first if btrfs-progs supports the v2 stream.
_require_btrfs_command send --compressed-data
# Now check the kernel support. If send_stream_version does not exists,
# then it's a kernel that only supports v1.
[ -f /sys/fs/btrfs/features/send_stream_version ] || \
_notrun "kernel does not support send stream $version"
[ $(cat /sys/fs/btrfs/features/send_stream_version) -ge $version ] || \
_notrun "kernel does not support send stream $version"
}
# Get the bytenr associated to a file extent item at a given file offset.
#
# NOTE: At the moment this only works if the file is on a filesystem on top of
# the scratch device and the file is in the default subvolume (tree id 5).
_btrfs_get_file_extent_item_bytenr()
{
local file="$1"
local offset="$2"
local ino=$(stat -c "%i" "$file")
local file_extent_key="($ino EXTENT_DATA $offset)"
_require_btrfs_command inspect-internal dump-tree
# The tree dump command below works on committed roots, by reading from
# a device directly, so we have to sync the filesystem to commit any
# open transaction.
$BTRFS_UTIL_PROG filesystem sync $SCRATCH_MNT
$BTRFS_UTIL_PROG inspect-internal dump-tree -t 5 $SCRATCH_DEV | \
grep -A4 "$file_extent_key" | grep "disk byte" | \
$AWK_PROG '{ print $5 }'
}
# Check that btrfs-progs has support for the logical-resolve command, with the
# -o option, and that the kernel supports the logical to ino ioctl v2 (which
# adds the ignore offset parameter).
_require_btrfs_scratch_logical_resolve_v2()
{
local bytenr
# First check if we have support for calling the v2 logical resolve
# ioctl in btrfs-progs. Check if the -o options exists, which makes
# btrfs-progs call v2 of the ioctl (because the flag
# BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET is only supported in v2).
_require_btrfs_command inspect-internal logical-resolve -o
_require_scratch
_scratch_mkfs > /dev/null || \
_fail "_require_btrfs_scratch_logical_resolve_v2: mkfs failed"
_scratch_mount
$XFS_IO_PROG -f -c "pwrite -q 0 128K" "$SCRATCH_MNT/file1"
bytenr=$(_btrfs_get_file_extent_item_bytenr "$SCRATCH_MNT/file1" 0)
$BTRFS_UTIL_PROG inspect-internal logical-resolve -o $bytenr \
$SCRATCH_MNT > /dev/null
if [ $? -ne 0 ]; then
_scratch_unmount
_notrun "Logical resolve ioctl v2 not supported in the kernel"
fi
_scratch_unmount
}
_qgroup_mode()
{
local dev=$1
if [ ! -b "$dev" ]; then
_fail "Usage: _qgroup_mode <mounted_device>"
fi
if _has_fs_sysfs_attr $dev /qgroups/mode; then
_get_fs_sysfs_attr $dev qgroups/mode
else
echo "qgroup"
fi
}
_check_regular_qgroup()
{
_qgroup_mode "$@" | grep -q 'qgroup'
}
_qgroup_rescan()
{
local mnt=$1
local dev=$(findmnt -n -o SOURCE $mnt)
_check_regular_qgroup $dev || return 1
_run_btrfs_util_prog quota rescan -w $mnt
}
_require_qgroup_rescan()
{
_scratch_mkfs >>$seqres.full 2>&1
_scratch_mount
_run_btrfs_util_prog quota enable $SCRATCH_MNT
# Wait for the first rescan.
$BTRFS_UTIL_PROG quota rescan -W $SCRATCH_MNT || \
_notrun "not able to wait on a quota rescan"
# Make sure we can start a rescan.
$BTRFS_UTIL_PROG quota rescan -w $SCRATCH_MNT >> $seqres.full || \
_notrun "not able to run quota rescan"
_scratch_unmount
}
_require_scratch_qgroup()
{
_scratch_mkfs >>$seqres.full 2>&1
_scratch_mount
$BTRFS_UTIL_PROG quota enable $SCRATCH_MNT
_check_regular_qgroup $SCRATCH_DEV || \
_notrun "not running normal qgroups"
_scratch_unmount
}
_require_scratch_enable_simple_quota()
{
_scratch_mkfs >>$seqres.full 2>&1
_scratch_mount
_qgroup_mode $SCRATCH_DEV | grep 'squota' && \
_notrun "cannot enable simple quota; on by default"
$BTRFS_UTIL_PROG quota enable --simple $SCRATCH_MNT || \
_notrun "simple quotas not available"
_scratch_unmount
}
_has_btrfs_sysfs_feature_attr()
{
local feature_attr=$1
[ -z $feature_attr ] && \
_fail "Missing feature name argument for _has_btrfs_sysfs_attr"
modprobe btrfs &> /dev/null
test -e /sys/fs/btrfs/features/$feature_attr
}
# Print the fsid and metadata uuid replaced with constant strings FSID and
# METADATA_UUID. Compare temp_fsid with fsid and metadata_uuid, then echo what
# it matches to or TEMP_FSID. This helps in comparing with the golden output.
check_fsid()
{
local dev1=$1
local fsid
local metadata_uuid
_require_btrfs_fs_sysfs
_require_btrfs_fs_feature temp_fsid
_require_btrfs_fs_feature metadata_uuid
_require_btrfs_command inspect-internal dump-super
# on disk fsid
fsid=$($BTRFS_UTIL_PROG inspect-internal dump-super $dev1 | \
grep ^fsid | $AWK_PROG -d" " '{print $2}')
echo -e "On disk fsid:\t\t$fsid" | sed -e "s/$fsid/FSID/g"
# Print FSID even if it is not the same as metadata_uuid because it has
# to match in the golden output.
metadata_uuid=$(cat /sys/fs/btrfs/$fsid/metadata_uuid)
echo -e "Metadata uuid:\t\tFSID"
# This returns the temp_fsid if set
tempfsid=$(_btrfs_get_fsid $dev1)
if [[ $tempfsid == $fsid ]]; then
echo -e "Temp fsid:\t\tFSID"
elif [[ $tempfsid == $metadata_uuid ]]; then
# If we are here, it means there is a bug; let it not match with
# the golden output.
echo -e "Temp fsid:\t\t$metadata_uuid"
else
echo -e "Temp fsid:\t\tTEMPFSID"
fi
echo -e -n "Tempfsid status:\t"
cat /sys/fs/btrfs/$tempfsid/temp_fsid
}
mkfs_clone()
{
local fsid
local uuid
local dev1=$1
local dev2=$2
_require_btrfs_command inspect-internal dump-super
_require_btrfs_mkfs_uuid_option
[[ -z $dev1 || -z $dev2 ]] && \
_fail "mkfs_clone requires two devices as arguments"
_mkfs_dev -fq $dev1
fsid=$($BTRFS_UTIL_PROG inspect-internal dump-super $dev1 | \
grep -E ^fsid | $AWK_PROG '{print $2}')
uuid=$($BTRFS_UTIL_PROG inspect-internal dump-super $dev1 | \
grep -E ^dev_item.uuid | $AWK_PROG '{print $2}')
_mkfs_dev -fq --uuid $fsid --device-uuid $uuid $dev2
}