mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
f6879e8a78
A bug in file cloning/reflinking was recently found that afftected both
Btrfs and XFS, which was caused by allowing the cloning of an eof block
into the middle of a file when the eof is not aligned to the filesystem's
block size.
The fix consists of returning the errno -EINVAL to user space when the
arguments passed to the system call lead to the scenario of data
corruption. However this overlaps with some cases where the system call,
in Btrfs, returned -EOPNOTSUPP, which means we are trying to reflink
inline extents. That is unsupported in Btrfs due to the huge complexity
of supporting it (due to copying and trimming inline extents, deal with
eventual compression, etc).
We have a few btrfs test cases that verify that attempts to clone inline
extents result in a failure, and are currently expecting an -EINVAL error
message from the output of the cloner program. So create a filter that
converts error messages related to the -EOPNOTSUPP error to messages
related to the -EINVAL error, so that the test can run both on patched
and non-patched linux kernels.
The corresponding btrfs patch for the linux kernel is titled:
"Btrfs: fix data corruption due to cloning of eof block"
And the VFS change that introduces the -EINVAL error return was introduced
by the following linux kernel commit (landed in 4.20-rc1):
07d19dc9fbe9 ("vfs: avoid problematic remapping requests into partial EOF block")
The btrfs patch is not yet in Linus' tree (it was submitted around the
same time as this change) and the VFS change was introduced in 4.10-rc1.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
119 lines
3.5 KiB
Plaintext
119 lines
3.5 KiB
Plaintext
# Filters for btrfs command output
|
|
|
|
. ./common/filter
|
|
|
|
# Some, but not all, commands emit "Btrfs <version>"
|
|
_filter_btrfs_version()
|
|
{
|
|
sed -e "s/^[Bb]trfs.*//g"
|
|
}
|
|
|
|
_filter_devid()
|
|
{
|
|
sed -e "s/\(devid\)\s\+[0-9]\+/\1 <DEVID>/g"
|
|
}
|
|
|
|
# If passed a number as first arg, filter that number of devices
|
|
# If passed a UUID as second arg, filter that exact UUID
|
|
_filter_btrfs_filesystem_show()
|
|
{
|
|
if [ ! -z $1 ]; then
|
|
NUMDEVS=$1
|
|
NUM_SUBST="<EXACTNUM>"
|
|
else
|
|
NUMDEVS="[0-9]\+"
|
|
NUM_SUBST="<NUM>"
|
|
fi
|
|
|
|
UUID=""
|
|
if [ ! -z $2 ]; then
|
|
UUID=$2
|
|
fi
|
|
|
|
# the uniq collapses all device lines into 1
|
|
_filter_uuid $UUID | _filter_scratch | _filter_scratch_pool | \
|
|
_filter_size | _filter_btrfs_version | _filter_devid | \
|
|
_filter_zero_size | \
|
|
sed -e "s/\(Total devices\) $NUMDEVS/\1 $NUM_SUBST/g" | \
|
|
uniq
|
|
}
|
|
|
|
# This eliminates all numbers, and shows only unique lines,
|
|
# to accomodate a varying nr. of devices.
|
|
# If given an argument, make sure we saw that many devices
|
|
# in total.
|
|
_filter_btrfs_device_stats()
|
|
{
|
|
if [ ! -z $1 ]; then
|
|
NUMDEVS=$1
|
|
UNIQ_OPT="-c"
|
|
else
|
|
NUMDEVS="thiswillnotmatch"
|
|
UNIQ_OPT=""
|
|
fi
|
|
|
|
_filter_scratch | _filter_scratch_pool | \
|
|
sed -e "s/[0-9]\+$/<NUM>/g" | sort | uniq $UNIQ_OPT | \
|
|
sed -e "s/ *$NUMDEVS /<NUMDEVS> /g"
|
|
}
|
|
|
|
_filter_transaction_commit() {
|
|
sed -e "/Transaction commit: none (default)/d" | \
|
|
sed -e "s/Delete subvolume (.*commit):/Delete subvolume/g"
|
|
}
|
|
|
|
_filter_btrfs_subvol_delete()
|
|
{
|
|
_filter_scratch | _filter_transaction_commit
|
|
}
|
|
|
|
_filter_btrfs_compress_property()
|
|
{
|
|
sed -e "s/compression=\(lzo\|zlib\|zstd\)/COMPRESSION=XXX/g"
|
|
}
|
|
|
|
# filter error messages from btrfs prop, optionally verify against $1
|
|
# recognized message(s):
|
|
# "object is not compatible with property: label"
|
|
# "invalid value for property:{, value}"
|
|
# "failed to {get,set} compression for $PATH[.:]: Invalid argument"
|
|
_filter_btrfs_prop_error()
|
|
{
|
|
if ! [ -z "$1" ]; then
|
|
sed -e "s#\(compatible with property\): $1#\1#" \
|
|
-e "s#^\(.*failed to [sg]et compression for $1\)[:.] \(.*\)#\1: \2#"
|
|
else
|
|
sed -e "s#^\(.*compatible with property\).*#\1#" \
|
|
-e "s#^\(.*invalid value for property\)[:.].*#\1#"
|
|
fi
|
|
}
|
|
|
|
# filter warning messages caused by "btrfs quota assign/remove" command.
|
|
# Since qgroup relationship change could cause qgroup inconsistency, it would
|
|
# either trigger a qgroup rescan, or warning message.
|
|
_filter_btrfs_qgroup_assign_warnings()
|
|
{
|
|
sed -e "/Quota data changed, rescan scheduled/d" \
|
|
-e "/quotas may be inconsistent, rescan needed/d"
|
|
}
|
|
|
|
# Long ago we found that attempting to clone inline extents resulted in hitting
|
|
# a BUG_ON() and then decided to not support such use cases by returning errno
|
|
# -EOPNOTSUPP to user space. Later on, clone/reflink became a VFS API too, since
|
|
# other filesystems (such as XFS) implemented this feature. After that we found
|
|
# one scenario of data corruption due to allowing cloning an EOF block into the
|
|
# middle of a file, and started to reject such scenario by returning the errno
|
|
# -EINVAL to user space (this affected both Btrfs and XFS). Such scenario often
|
|
# overlaps the detection of attempts to clone inline extents, since it is done
|
|
# early on based only on the arguments passed to the clone system call (and
|
|
# btrfs' specific ioctl) before processing the source file extents.
|
|
# So replace error messages related to errno -EOPNOTSUPP to be the same as the
|
|
# one we get from a -EINVAL errno.
|
|
_filter_btrfs_cloner_error()
|
|
{
|
|
sed -e "s/\(clone failed:\) Operation not supported/\1 Invalid argument/g"
|
|
}
|
|
|
|
# make sure this script returns success
|
|
/bin/true
|