blob: c84c7065d8c625531c7af6a6b9e76f990fb2db44 [file] [log] [blame]
#! /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