In v5.11~v5.15 kernels, there is a regression in autodefrag that if a cluster (up to 256K in size) has even a single hole, the whole cluster will be rejected. This will greatly reduce the efficiency of autodefrag. The behavior is fixed in v5.16 by a full rework, although the rework itself has other problems, it at least solves the problem. Here we add a test case to reproduce the case, where we have a 128K cluster, the first half is fragmented extents which can be defragged. The second half is hole. Make sure autodefrag can defrag the 64K part. Signed-off-by: Qu Wenruo <wqu@xxxxxxxx> --- Changelog: v2: - Use the previously define _get_file_extent_sector() helper This also removed some out-of-sync error messages - Trigger autodefrag using commit=1 mount option No need for special purpose patch any more. - Use xfs_io -s to skip several sync calls - Shorten the subject of the commit --- tests/btrfs/256 | 80 +++++++++++++++++++++++++++++++++++++++++++++ tests/btrfs/256.out | 2 ++ 2 files changed, 82 insertions(+) create mode 100755 tests/btrfs/256 create mode 100644 tests/btrfs/256.out diff --git a/tests/btrfs/256 b/tests/btrfs/256 new file mode 100755 index 00000000..def83a15 --- /dev/null +++ b/tests/btrfs/256 @@ -0,0 +1,80 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2022 SUSE Linux Products GmbH. All Rights Reserved. +# +# FS QA Test 256 +# +# Make sure btrfs auto defrag can properly defrag clusters which has hole +# in the middle +# +. ./common/preamble +_begin_fstest auto defrag quick + +. ./common/btrfs +. ./common/filter + +# real QA test starts here + +# Modify as appropriate. +_supported_fs generic +_require_scratch + +# Needs 4K sectorsize, as larger sectorsize can change the file layout. +_require_btrfs_support_sectorsize 4096 + +_scratch_mkfs >> $seqres.full + +# Need datacow to show which range is defragged, and we're testing +# autodefrag +_scratch_mount -o datacow,autodefrag + +# Create a layout where we have fragmented extents at [0, 64k) (sync write in +# reserve order), then a hole at [64k, 128k) +$XFS_IO_PROG -f -s -c "pwrite 48k 16k" -c "pwrite 32k 16k" \ + -c "pwrite 16k 16k" -c "pwrite 0 16k" \ + $SCRATCH_MNT/foobar >> $seqres.full +truncate -s 128k $SCRATCH_MNT/foobar + +old_csum=$(_md5_checksum $SCRATCH_MNT/foobar) +echo "=== File extent layout before autodefrag ===" >> $seqres.full +$XFS_IO_PROG -c "fiemap -v" "$SCRATCH_MNT/foobar" >> $seqres.full +echo "old md5=$old_csum" >> $seqres.full + +old_regular=$(_get_file_extent_sector "$SCRATCH_MNT/foobar" 0) +old_hole=$(_get_file_extent_sector "$SCRATCH_MNT/foobar" 64k) + +# Now trigger autodefrag, autodefrag is triggered in the cleaner thread, +# which will be woken up by commit thread +_scratch_remount commit=1 +sleep 3 +sync + +new_csum=$(_md5_checksum $SCRATCH_MNT/foobar) +new_regular=$(_get_file_extent_sector "$SCRATCH_MNT/foobar" 0) +new_hole=$(_get_file_extent_sector "$SCRATCH_MNT/foobar" 64k) + +echo "=== File extent layout after autodefrag ===" >> $seqres.full +$XFS_IO_PROG -c "fiemap -v" "$SCRATCH_MNT/foobar" >> $seqres.full +echo "new md5=$new_csum" >> $seqres.full + +# In v5.11~v5.15 kernels, regular extents won't get defragged, and would trigger +# the following output +if [ $new_regular == $old_regular ]; then + echo "regular extents didn't get defragged" +fi + +# In v5.10 and earlier kernel, autodefrag may choose to defrag holes, +# which should be avoided. +if [ "$new_hole" != "$old_hole" ]; then + echo "hole extents got defragged" +fi + +# Defrag should not change file content +if [ "$new_csum" != "$old_csum" ]; then + echo "file content changed" +fi + +echo "Silence is golden" +# success, all done +status=0 +exit diff --git a/tests/btrfs/256.out b/tests/btrfs/256.out new file mode 100644 index 00000000..7ee8e2e5 --- /dev/null +++ b/tests/btrfs/256.out @@ -0,0 +1,2 @@ +QA output created by 256 +Silence is golden -- 2.34.1