Files
apfstests/tests/btrfs/220
T
Josef Bacik a0bcdb6cbf btrfs/220: fix how we tests for mount options
Filipe noticed that btrfs/220 started failing with some mount option
changes I made recently, but upon closer inspection this test actually
fails in a lot of different ways normally, specifically if you specify
MOUNT_OPTIONS, or if you make an fs with the free space tree.

Address all these issues by reworking how we test that the mount options
are what we expect.  First get what the default mount options are for a
plain mount of SCRATCH_DEV.  This is used as the baseline, so no matter
how the mount options change in the future it will always work properly.

Secondly instead of specifying a rigid order of the mount options we're
testing, which breaks if we adjust the order in /proc/self/mounts,
simply specify the options we're actually interested in checking.  Then
in the test function combine the common options with the new options
we're testing, and then combine that with our actual options and use
some sort magic to see if there's any difference.  If there's no
difference then we know we have everything set as expected, if not we
fail.

This patch addresses the initial issue that Filipe noticed, but also
fixes the failures when you specified MOUNT_OPTIONS, or if you made the
fs with the free space tree.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
2020-11-08 13:51:20 +08:00

332 lines
10 KiB
Bash
Executable File

#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2020 SUSE Linux Products GmbH. All Rights Reserved.
#
# FS QA Test 220
#
# Test all existent mount options of btrfs
# * device= argument is already being test by btrfs/125
# * space cache test already covered by test btrfs/131
seq=`basename $0`
seqres=$RESULT_DIR/$seq
echo "QA output created by $seq"
here=`pwd`
tmp=/tmp/$$
status=1 # failure is the default!
trap "cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common/rc
. ./common/filter
# remove previous $seqres.full before test
rm -f $seqres.full
_supported_fs btrfs
_require_scratch
cleanup()
{
cd /
rm -f $tmp.*
}
# Compare the mounted flags with $opt_check. When the comparison fails, $opt is
# echoed to help to track which option was used to trigger the unexpected
# results.
test_mount_flags()
{
local opt
local opt_check
local stripped
opt="$1"
opt_check="$2"
active_opt=$(cat /proc/self/mounts | grep $SCRATCH_MNT | \
$AWK_PROG '{ print $4 }')
if [ "$opt_check" != "$DEFAULT_OPTS" ]; then
# We only care about the common things between defaults and the
# active set, so strip out the uniq lines between the two, and
# then we'll add this to our $opt_check which should equal
# $active_opt. We also strip 'rw' as we may be checking 'ro',
# so we need to adjust that accordingly
stripped=$(echo "$DEFAULT_OPTS,$active_opt" | tr ',' '\n' | \
sort | grep -v 'rw' | uniq -d | tr '\n' ',' | \
sed 's/.$//')
opt_check="$opt_check,$stripped"
fi
# We diff by putting our wanted opts together with the current opts,
# turning it into one option per line, sort'ing, and then printing out
# any uniq lines left. This will catch anything that is set that we're
# not expecting, or anything that wasn't set that we wanted.
#
# We strip 'rw' because some tests flip ro, so just ignore rw.
diff=$(echo "$opt_check,$active_opt" | tr ',' '\n' | \
sort | grep -v 'rw' | uniq -u)
if [ -n "$diff" ]; then
echo "Unexepcted mount options, checking for '$opt_check' in '$active_opt' using '$opt'"
fi
}
# Mounts using opt ($1), remounts using remount_opt ($2), and remounts again
# using opt again (1), checking if the mount opts are being enabled/disabled by
# using _check arguments ($3 and $4)
test_enable_disable_mount_opt()
{
local opt
local opt_check
local remount_opt
local remount_opt_check
opt="$1"
opt_check="$2"
remount_opt="$3"
remount_opt_check="$4"
_scratch_mount "-o $opt"
test_mount_flags $opt $opt_check
_scratch_remount $remount_opt
test_mount_flags $remount_opt $remount_opt_check
_scratch_remount $opt
test_mount_flags $opt $opt_check
_scratch_unmount
}
# Checks if mount options are applied and reverted correctly.
# By using options to mount ($1) and remount ($2), this function will mount,
# remount, and the mount with the original args, checking if the mount options
# match the _check args ($3 and $4).
# Later, opt and remount_opt are swapped, testing the counterpart option if used
# to first mount the fs.
test_roundtrip_mount()
{
local opt
local opt_check
local remount_opt
local remount_opt_check
opt="$1"
opt_check="$2"
remount_opt="$3"
remount_opt_check="$4"
# invert the args to make sure that both options work at mount and
# remount time
test_enable_disable_mount_opt $opt $opt_check $remount_opt $remount_opt_check
test_enable_disable_mount_opt $remount_opt $remount_opt_check $opt $opt_check
}
# Just mount and check if the options were mounted correctly by comparing the
# results with $opt_check
test_mount_opt()
{
local opt
local opt_check
local active_opt
opt="$1"
opt_check="$2"
_scratch_mount "-o $opt"
test_mount_flags $opt $opt_check
_scratch_unmount
}
# Test mount options that should fail, usually by wrong arguments to options
test_should_fail()
{
local opt
opt="$1"
# wrong $opt on purpose, should fail
_try_scratch_mount "-o $opt" >/dev/null 2>&1
if [ $? -ne 0 ]; then
return
fi
echo "Option $opt should fail to mount"
_scratch_unmount
}
# Try to mount using $opt, and bail our if the mount fails without errors. If
# the mount succeeds, then compare the mount options with $opt_check
test_optional_mount_opts()
{
local opt
local opt_check
opt="$1"
opt_check="$2"
# $opt not enabled, return without running any tests
_try_scratch_mount "-o $opt" >/dev/null 2>&1 || return
_scratch_unmount
# option enabled, run the test
test_mount_opt $opt $opt_check
}
# Testes related to subvolumes, from subvol and subvolid options.
test_subvol()
{
test_should_fail "subvol=vol2"
_scratch_mount "-o subvol=vol1"
if [ ! -f "$SCRATCH_MNT/file.txt" ]; then
echo "file.txt not found inside vol1 using subvol=vol1 mount option"
fi
_scratch_unmount
test_should_fail "subvolid=222"
_scratch_mount "-o subvolid=256"
if [ ! -f "$SCRATCH_MNT/file.txt" ]; then
echo "file.txt not found inside vol1 using subvolid=256 mount option"
fi
_scratch_unmount
# subvol and subvolid should point to the same subvolume
test_should_fail "-o subvol=vol1,subvolid=1234132"
test_mount_opt "subvol=vol1,subvolid=256" "subvolid=256,subvol=/vol1"
test_roundtrip_mount "subvol=vol1" "subvolid=256,subvol=/vol1" "subvolid=256" "subvolid=256,subvol=/vol1"
}
# These options are enable at kernel compile time, so no bother if they fail
test_optional_kernel_features()
{
# Test options that are enabled by kernel config, and so can fail safely
test_optional_mount_opts "check_int" "check_int"
test_optional_mount_opts "check_int_data" "check_int_data"
test_optional_mount_opts "check_int_print_mask=123" "check_int_print_mask=123"
test_should_fail "fragment=invalid"
test_optional_mount_opts "fragment=all" "fragment=data,fragment=metadata"
test_optional_mount_opts "fragment=data" "fragment=data"
test_optional_mount_opts "fragment=metadata" "fragment=metadata"
}
test_non_revertible_options()
{
test_mount_opt "clear_cache" "clear_cache"
test_mount_opt "degraded" "degraded"
test_mount_opt "inode_cache" "inode_cache"
# nologreplay should be used only with
test_should_fail "nologreplay"
test_mount_opt "nologreplay,ro" "ro,rescue=nologreplay"
# norecovery should be used only with. This options is an alias to nologreplay
test_should_fail "norecovery"
test_mount_opt "norecovery,ro" "ro,rescue=nologreplay"
test_mount_opt "rescan_uuid_tree" "rescan_uuid_tree"
test_mount_opt "skip_balance" "skip_balance"
test_mount_opt "user_subvol_rm_allowed" "user_subvol_rm_allowed"
test_should_fail "rescue=invalid"
# nologreplay requires readonly
test_should_fail "rescue=nologreplay"
test_mount_opt "rescue=nologreplay,ro" "ro,rescue=nologreplay"
}
# All these options can be reverted (with their "no" counterpart), or can have
# their values set to default on remount
test_revertible_options()
{
test_roundtrip_mount "acl" "$DEFAULT_OPTS" "noacl" "noacl"
test_roundtrip_mount "autodefrag" "autodefrag" "noautodefrag" "$DEFAULT_OPTS"
test_roundtrip_mount "barrier" "$DEFAULT_OPTS" "nobarrier" "nobarrier"
test_should_fail "commit=-10"
# commit=0 sets the default, so btrfs hides this mount opt
test_roundtrip_mount "commit=35" "commit=35" "commit=0" "$DEFAULT_OPTS"
test_should_fail "compress=invalid"
test_should_fail "compress-force=invalid"
test_roundtrip_mount "compress" "compress=zlib:3" "compress=lzo" "compress=lzo"
test_roundtrip_mount "compress=zstd" "compress=zstd:3" "compress=no" "$DEFAULT_OPTS"
test_roundtrip_mount "compress-force=no" "$DEFAULT_OPTS" "compress-force=zstd" "compress-force=zstd:3"
# zlib's max level is 9 and zstd's max level is 15
test_roundtrip_mount "compress=zlib:20" "compress=zlib:9" "compress=zstd:16" "compress=zstd:15"
test_roundtrip_mount "compress-force=lzo" "compress-force=lzo" "compress-force=zlib:4" "compress-force=zlib:4"
# on remount, if we only pass datacow after nodatacow was used it will remain with nodatasum
test_roundtrip_mount "nodatacow" "nodatasum,nodatacow" "datacow,datasum" "$DEFAULT_OPTS"
# nodatacow disabled compression
test_roundtrip_mount "compress-force" "compress-force=zlib:3" "nodatacow" "nodatasum,nodatacow"
# nodatacow disabled both datacow and datasum, and datasum enabled datacow and datasum
test_roundtrip_mount "nodatacow" "nodatasum,nodatacow" "datasum" "$DEFAULT_OPTS"
test_roundtrip_mount "nodatasum" "nodatasum" "datasum" "$DEFAULT_OPTS"
test_should_fail "discard=invalid"
test_roundtrip_mount "discard" "discard" "discard=sync" "discard"
test_roundtrip_mount "discard=async" "discard=async" "discard=sync" "discard"
test_roundtrip_mount "discard=sync" "discard" "nodiscard" "$DEFAULT_OPTS"
test_roundtrip_mount "enospc_debug" "enospc_debug" "noenospc_debug" "$DEFAULT_OPTS"
test_should_fail "fatal_errors=pani"
# fatal_errors=bug is the default
test_roundtrip_mount "fatal_errors=panic" "fatal_errors=panic" "fatal_errors=bug" "$DEFAULT_OPTS"
test_roundtrip_mount "flushoncommit" "flushoncommit" "noflushoncommit" "$DEFAULT_OPTS"
# 2048 is the max_inline default value
test_roundtrip_mount "max_inline=1024" "max_inline=1024" "max_inline=2048" "$DEFAULT_OPTS"
test_roundtrip_mount "metadata_ratio=0" "$DEFAULT_OPTS" "metadata_ratio=10" "metadata_ratio=10"
# ssd_spread implies ssd, while nossd_spread only disables ssd_spread
test_roundtrip_mount "ssd_spread" "ssd_spread" "nossd" "nossd"
test_roundtrip_mount "ssd" "ssd" "nossd" "nossd"
test_mount_opt "ssd" "ssd"
test_should_fail "thread_pool=-10"
test_should_fail "thread_pool=0"
test_roundtrip_mount "thread_pool=10" "thread_pool=10" "thread_pool=50" "thread_pool=50"
test_roundtrip_mount "notreelog" "notreelog" "treelog" "$DEFAULT_OPTS"
}
# real QA test starts here
_scratch_mkfs >/dev/null
# This test checks mount options, so having random MOUNT_OPTIONS set could
# affect the results of a few of these tests.
MOUNT_OPTIONS=
# create a subvolume that will be used later
_scratch_mount
# We need to save the current default options so we can validate our changes
# from one mount option to the next one.
DEFAULT_OPTS=$(cat /proc/self/mounts | grep $SCRATCH_MNT | \
$AWK_PROG '{ print $4 }')
$BTRFS_UTIL_PROG subvolume create "$SCRATCH_MNT/vol1" > /dev/null
touch "$SCRATCH_MNT/vol1/file.txt"
_scratch_unmount
test_optional_kernel_features
test_non_revertible_options
test_revertible_options
test_subvol
echo "Silence is golden"
status=0
exit