From 57e68bd5c6bb93be7ef64e847ac51dc0d1e678f3 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 24 Jul 2025 13:05:59 +0100 Subject: [PATCH] generic/211: verify if the filesystem being tested supports in place writes The test currently assumes the filesystem can do in place writes (no Copy-On-Write, no allocation of new extents) when overwriting a file. While that is the case for most filesystems in most configurations, there are exceptions such as zoned xfs where overwriting results in allocating new extents for the new data. So make the test check that in place writes are supported and skip the test if they are not supported. Signed-off-by: Filipe Manana Reviewed-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Zorro Lang --- common/rc | 71 +++++++++++++++++++++++++++++++++++++++++++++++ tests/generic/211 | 9 ++---- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/common/rc b/common/rc index 96578d15..b9292a78 100644 --- a/common/rc +++ b/common/rc @@ -5873,6 +5873,77 @@ _require_program() { _have_program "$1" || _notrun "$tag required" } +_force_inplace_writes() +{ + local file=$1 + + if [ -z "$file" ]; then + _fail "Usage: _force_inplace_writes " + fi + + case "$FSTYP" in + "btrfs") + # Set the file to NOCOW mode on btrfs, which must be done while + # the file is empty, otherwise it fails with -EINVAL. + _require_chattr C + $CHATTR_PROG +C "$file" + ;; + esac +} + +# Test that a filesystem can do writes to a file in place (without allocating +# new extents, without Copy-On-Write semantics). +_require_inplace_writes() +{ + _require_xfs_io_command "fiemap" + + local target=$1 + local test_file="${target}/test_inplace_writes" + local fiemap_before + local fiemap_after + + if [ -z "$target" ]; then + _fail "Usage: _require_inplace_writes " + fi + + rm -f "$test_file" + touch "$test_file" + _force_inplace_writes "$test_file" + + $XFS_IO_PROG -c "pwrite 0 128K" -c "fsync" "$test_file" &> /dev/null + if [ $? -ne 0 ]; then + rm -f "$test_file" + _fail "_require_inplace_writes failed to write to test file" + fi + + # Grab fiemap output before overwriting. + fiemap_before=$($XFS_IO_PROG -c "fiemap" "$test_file") + if [ $? -ne 0 ]; then + rm -f "$test_file" + _fail "_require_inplace_writes first fiemap call failed" + fi + + $XFS_IO_PROG -c "pwrite 0 128K" -c "fsync" "$test_file" &> /dev/null + if [ $? -ne 0 ]; then + rm -f "$test_file" + _fail "_require_inplace_writes failed to overwrite test file" + fi + + fiemap_after=$($XFS_IO_PROG -c "fiemap" "$test_file") + if [ $? -ne 0 ]; then + rm -f "$test_file" + _fail "_require_inplace_writes second fiemap call failed" + fi + + rm -f "$test_file" + + # If the filesystem supports inplace writes, then the extent mapping is + # the same before and after overwriting. + if [ "${fiemap_after}" != "${fiemap_before}" ]; then + _notrun "in-place writes not supported" + fi +} + ################################################################################ # make sure this script returns success /bin/true diff --git a/tests/generic/211 b/tests/generic/211 index e87d1e01..6eda1608 100755 --- a/tests/generic/211 +++ b/tests/generic/211 @@ -27,15 +27,10 @@ fs_size=$(_small_fs_size_mb 512) _try_scratch_mkfs_sized $((fs_size * 1024 * 1024)) >>$seqres.full 2>&1 || \ _fail "mkfs failed" _scratch_mount +_require_inplace_writes $SCRATCH_MNT touch $SCRATCH_MNT/foobar - -# Set the file to NOCOW mode on btrfs, which must be done while the file is -# empty, otherwise it fails. -if [ $FSTYP == "btrfs" ]; then - _require_chattr C - $CHATTR_PROG +C $SCRATCH_MNT/foobar -fi +_force_inplace_writes $SCRATCH_MNT/foobar # Add initial data to the file we will later overwrite with mmap. $XFS_IO_PROG -c "pwrite -S 0xab 0 1M" $SCRATCH_MNT/foobar | _filter_xfs_io -- 2.39.5