From: Filipe Manana <fdmanana@xxxxxxxx> Test that we are able to activate a swap file on a file that used to have its extents shared multiple times. This exercises a bug on btrfs' extent sharedness detection during swap file activation, which is fixed by the following kernel commit: 03018e5d8508 ("btrfs: fix swap file activation failure due to extents that used to be shared") The fails sporadically on XFS and the bug was already reported to the XFS mailing list: https://lore.kernel.org/linux-xfs/CAL3q7H7cURmnkJfUUx44HM3q=xKmqHb80eRdisErD_x8rU4+0Q@xxxxxxxxxxxxxx/ https://lore.kernel.org/fstests/dca49a16a7aacdab831b8895bdecbbb52c0e609c.1733928765.git.fdmanana@xxxxxxxx/ So for now skip the test on XFS and add comments with references to these threads. Signed-off-by: Filipe Manana <fdmanana@xxxxxxxx> --- V2: Add git commit ID now that the btrfs fix landed in Linus' tree. Skip the test on XFS and add a comment about it. tests/generic/370 | 109 ++++++++++++++++++++++++++++++++++++++++++ tests/generic/370.out | 25 ++++++++++ 2 files changed, 134 insertions(+) create mode 100755 tests/generic/370 create mode 100644 tests/generic/370.out diff --git a/tests/generic/370 b/tests/generic/370 new file mode 100755 index 00000000..67af7b6e --- /dev/null +++ b/tests/generic/370 @@ -0,0 +1,109 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2025 SUSE Linux Products GmbH. All Rights Reserved. +# +# FS QA Test 370 +# +# Test that we are able to create and activate a swap file on a file that used +# to have its extents shared multiple times. +# +. ./common/preamble +_begin_fstest auto quick clone swap + +_cleanup() +{ + cd / + rm -r -f $tmp.* + test -n "$swap_file" && swapoff $swap_file &> /dev/null +} + +. ./common/reflink + +[ "$FSTYP" = "btrfs" ] && _fixed_by_kernel_commit 03018e5d8508 \ + "btrfs: fix swap file activation failure due to extents that used to be shared" + +# Skip XFS for now because this exposes an issue that is hard to fix. +# See the following threads for details about it: +# +# https://lore.kernel.org/linux-xfs/CAL3q7H7cURmnkJfUUx44HM3q=xKmqHb80eRdisErD_x8rU4+0Q@xxxxxxxxxxxxxx/ +# https://lore.kernel.org/fstests/dca49a16a7aacdab831b8895bdecbbb52c0e609c.1733928765.git.fdmanana@xxxxxxxx/ +# +_supported_fs ^xfs + +_require_scratch_swapfile +_require_scratch_reflink +_require_cp_reflink + +run_test() +{ + local sync_after_add_reflinks=$1 + local sync_after_remove_reflinks=$2 + local first_swap_file="$SCRATCH_MNT/swap" + local swap_size=$(($(_get_page_size) * 32)) + local num_clones=50 + local swap_file="$SCRATCH_MNT/clone_${num_clones}" + + _scratch_mkfs >> $seqres.full 2>&1 || _fail "failed to mkfs" + _scratch_mount + + echo "Creating swap file..." + _format_swapfile $first_swap_file $swap_size >> $seqres.full + + echo "Cloning swap file..." + # Create a large number of clones so that on btrfs we get external ref + # items in the extent tree and not just inline refs (33 is currently the + # treshold after which external refs are created). + for ((i = 1; i <= $num_clones; i++)); do + # Create the destination file and set +C (NOCOW) on it before + # copying into it with reflink. This is because when cp needs to + # create the destination file, it first copies/clones the data + # and then sets the +C attribute, and on btrfs we can't clone a + # NOCOW file into a COW file, both must be NOCOW or both COW. + touch $SCRATCH_MNT/clone_$i + # 0600 is required for swap files, do the same as _format_swapfile. + chmod 0600 $SCRATCH_MNT/clone_$i + $CHATTR_PROG +C $SCRATCH_MNT/clone_$i > /dev/null 2>&1 + _cp_reflink $first_swap_file $SCRATCH_MNT/clone_$i + done + + if [ $sync_after_add_reflinks -ne 0 ]; then + # Force a transaction commit on btrfs to flush all delayed + # references and commit the current transaction. + _scratch_sync + fi + + echo "Deleting original file and all clones except the last..." + rm -f $first_swap_file + for ((i = 1; i < $num_clones; i++)); do + rm -f $SCRATCH_MNT/clone_$i + done + + if [ $sync_after_remove_reflinks -ne 0 ]; then + # Force a transaction commit on btrfs to flush all delayed + # references and commit the current transaction. + _scratch_sync + fi + + # Now use the last clone as a swap file. + echo "Activating swap file..." + _swapon_file $swap_file + swapoff $swap_file + + _scratch_unmount +} + +echo -e "\nTest without sync after creating and removing clones" +run_test 0 0 + +echo -e "\nTest with sync after creating clones" +run_test 1 0 + +echo -e "\nTest with sync after removing clones" +run_test 0 1 + +echo -e "\nTest with sync after creating and removing clones" +run_test 1 1 + +# success, all done +status=0 +exit diff --git a/tests/generic/370.out b/tests/generic/370.out new file mode 100644 index 00000000..36b2dc27 --- /dev/null +++ b/tests/generic/370.out @@ -0,0 +1,25 @@ +QA output created by 370 + +Test without sync after creating and removing clones +Creating swap file... +Cloning swap file... +Deleting original file and all clones except the last... +Activating swap file... + +Test with sync after creating clones +Creating swap file... +Cloning swap file... +Deleting original file and all clones except the last... +Activating swap file... + +Test with sync after removing clones +Creating swap file... +Cloning swap file... +Deleting original file and all clones except the last... +Activating swap file... + +Test with sync after creating and removing clones +Creating swap file... +Cloning swap file... +Deleting original file and all clones except the last... +Activating swap file... -- 2.45.2