The new test case is a regression test related to the block size < page size handling of compressed read. The test case will only be triggered with 64K page size and 4K btrfs block size. I'm using aarch64 with 64K page size to trigger the regression. The test case will create the following file layout: base: [0, 64K): Single compressed data extent at bytenr X. new: [0, 32K): Reflinked from base [32K, 64K) [32K, 60K): Reflinked from base [0, 28K) [60K, 64K): New 4K write The range [0, 32K) and [32K, 64K) are pointing to the same compressed data. The last 4K write is a special workaround. It is a block aligned write, thus it will create the folio but without reading out the remaing part. This is to avoid readahead path, which has the proper fix. We want single folio read without readahead. Then output the file "new" just after the last 4K write, then cycle mount and output the content again. For patched kernel, or with 4K page sized system, the test will pass, the resulted content will not change during mount cycles. For unpatched kernel and with 64K page size, the test will fail, the content after the write will be incorrect (the range [32K, 60K) will be zero), but after a mount cycle the content is correct again. Signed-off-by: Qu Wenruo <wqu@xxxxxxxx> --- tests/btrfs/337 | 56 +++++++++++++++++++++++++++++++++++++++++++++ tests/btrfs/337.out | 23 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100755 tests/btrfs/337 create mode 100644 tests/btrfs/337.out diff --git a/tests/btrfs/337 b/tests/btrfs/337 new file mode 100755 index 00000000..9cd2ea42 --- /dev/null +++ b/tests/btrfs/337 @@ -0,0 +1,56 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2025 SUSE Linux Products GmbH. All Rights Reserved. +# +# FS QA Test 337 +# +# Test compressed read with shared extents, especially for bs < ps cases. +# +. ./common/preamble +_begin_fstest auto quick compress reflink + +_fixed_by_kernel_commit xxxxxxxxxxxx \ + "btrfs: do more strict compressed read merge check" + +. ./common/filter +. ./common/reflink + +_require_btrfs_support_sectorsize 4096 +_require_scratch_reflink + +# The layout used in the test case is all 4K based, and can only be reproduced +# with page size larger than 4K. +_scratch_mkfs -s 4k >> $seqres.full +_scratch_mount "-o compress" + +# Create the reflink source, which must be a compressed extent. +$XFS_IO_PROG -f -c "pwrite -S 0x0f 0 32K" \ + -c "pwrite -S 0xf0 32K 32K" \ + -c sync $SCRATCH_MNT/base >> $seqres.full +echo "Reflink source:" +echo "Reflink source:" >> $seqres.full +od -t x1 $SCRATCH_MNT/base | _filter_od + +# Create the reflink dest, which reverse the order of the two 32K range. +# +# And do a further aligned write into the last block. +# This write is to make sure the folio exists in filemap, so that we won't go +# through the readahead path (which has the proper handling) for the folio. +$XFS_IO_PROG -f -c "reflink $SCRATCH_MNT/base 32K 0 32K" \ + -c "reflink $SCRATCH_MNT/base 0 32K 32K" \ + -c "pwrite 60K 4K" $SCRATCH_MNT/new >> $seqres.full + +# This will result an incorrect output for unpatched kernel. +# The range [32K, 60K) will be zero due to incorrectly merged compressed read. +echo "Before mount cycle:" +od -t x1 $SCRATCH_MNT/new | _filter_od + +_scratch_cycle_mount + +# This will go through readahead path, which has the proper handling, thus give +# the correct content. +echo "After mount cycle:" +od -t x1 $SCRATCH_MNT/new | _filter_od + +status=0 +_exit 0 diff --git a/tests/btrfs/337.out b/tests/btrfs/337.out new file mode 100644 index 00000000..d3e35863 --- /dev/null +++ b/tests/btrfs/337.out @@ -0,0 +1,23 @@ +QA output created by 337 +Reflink source: +0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f +* +10 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 +* +20 +Before mount cycle: +0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 +* +10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f +* +17 cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd +* +20 +After mount cycle: +0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 +* +10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f +* +17 cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd +* +20 -- 2.49.0