Linux filesystem development
 help / color / mirror / Atom feed
* [PATCH] iomap: only follow dio alignment requirement if specified
@ 2026-10-26  6:48 Qu Wenruo
  2026-10-26 14:21 ` Pankaj Raghav (Samsung)
  2026-10-26 19:49 ` Pankaj Raghav (Samsung)
  0 siblings, 2 replies; 8+ messages in thread
From: Qu Wenruo @ 2026-10-26  6:48 UTC (permalink / raw)
  To: linux-btrfs, linux-xfs, linux-fsdevel; +Cc: stable

[BUG]
After commit 4025185cf953 ("iomap: follow the alignment requirement for
iomap_dio_hole_iter()"), generic/091 fails on both xfs and ext4:

 FSTYP         -- ext4
 PLATFORM      -- Linux/x86_64 btrfs-vm 7.3.0-custom+ #6 SMP PREEMPT_DYNAMIC Mon Oct 26 16:04:56 ACDT 2026
 MKFS_OPTIONS  -- -F /dev/mapper/test-scratch1
 MOUNT_OPTIONS -- -o acl,user_xattr /dev/mapper/test-scratch1 /mnt/scratch

 generic/091  6s ... [failed, exit status 1]- output mismatch (see /home/adam/xfstests/results//generic/091.out.bad)
     --- /home/adam/xfstests/tests/generic/091.out	2022-05-11 11:25:30.766666664 +0930
     +++ /home/adam/xfstests/results//generic/091.out.bad	2026-10-26 16:43:49.387401669 +1030
     @@ -1,7 +1,25 @@
      QA output created by 091
      fsx -N 10000 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W
     -fsx -N 10000 -o 8192 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W
     -fsx -N 10000 -o 32768 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W
     -fsx -N 10000 -o 8192 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W
     -fsx -N 10000 -o 32768 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -R -W
     -fsx -N 10000 -o 128000 -l 500000 -r PSIZE -t BSIZE -w BSIZE -Z -W
     ...
     (Run 'diff -u /home/adam/xfstests/tests/generic/091.out /home/adam/xfstests/results//generic/091.out.bad'  to see the entire diff)
 Ran: generic/091
 Failures: generic/091
 Failed 1 of 1 tests

[CAUSE]
The failed command of fsx is COPY_RANGE:

 copy range: 0x6800 to 0xa200 at 0x3f200
 do_copy_range:: Resource temporarily unavailable
 LOG DUMP (8 total operations):
 1(  1 mod 256): SKIPPED (no operation)
 2(  2 mod 256): SKIPPED (no operation)
 3(  3 mod 256): WRITE    0x14400 thru 0x211ff	(0xce00 bytes) HOLE
 4(  4 mod 256): FALLOC   0x72bf4 thru 0x76221	(0x362d bytes) EXTENDING
 5(  5 mod 256): SKIPPED (no operation)
 6(  6 mod 256): INSERT 0x11000 thru 0x13fff	(0x3000 bytes)
 7(  7 mod 256): TRUNCATE DOWN	from 0x79221 to 0xa800
 8(  8 mod 256): COPY 0x6800 thru 0xa1ff	(0x3a00 bytes) to 0x3f200 thru 0x42bff
 Log of operations saved to "/mnt/test/junk.fsxops"; replay with --replay-ops
 Correct content saved for comparison
 (maybe hexdump "/mnt/test/junk" vs "/mnt/test/junk.fsxgood")

Both ext4 and xfs only require direct IO to be aligned to the logical
block size of the device, not the fs block size. So the 0x3a00 bytes
read at 0x6800 is allowed, and should succeed.

But that range is a hole, and that commit makes iomap_dio_hole_iter()
round the zeroed length down to the fs block size unconditionally.
The first iteration zeroes 0x3a00 bytes but only advances 0x3000 bytes,
then the next iteration zeroes the remaining 0xa00 bytes, which is
rounded down to 0, so -EFAULT is returned.

As ext4 and xfs do not pass IOMAP_DIO_PARTIAL, the whole read fails
with -EFAULT, which is then converted to -EAGAIN by copy_splice_read().
Every retry of fsx hits the same -EAGAIN, failing the run.

That commit breaks all direct reads which range is not fs block aligned
for ext4 and xfs.

[FIX]
Do not revert the range unless the dio has IOMAP_DIO_FSBLOCK_ALIGNED flag.

iomap_dio_hole_iter() is only called for reads, and for now only btrfs
reads can reach this path with the flag set. Btrfs has the proper
fallback when dio returns -EFAULT.

Fixes: 4025185cf953 ("iomap: follow the alignment requirement for iomap_dio_hole_iter()")
Cc: stable@vger.kernel.org
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/iomap/direct-io.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index 45bb24934f3d..ad041ac3252a 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -590,18 +590,24 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
 static int iomap_dio_hole_iter(struct iomap_iter *iter, struct iomap_dio *dio)
 {
 	loff_t copied = iov_iter_zero(iomap_length(iter), dio->submit.iter);
-	unsigned int bs = i_blocksize(iter->inode);
-	loff_t aligned_copied = round_down(copied, bs);
 
-	/*
-	 * If fs block size is larger than page size, page fault failure
-	 * can cause @copied to be page aligned but not fs block aligned.
-	 */
-	iov_iter_revert(dio->submit.iter, copied - aligned_copied);
-	dio->size += aligned_copied;
-	if (!aligned_copied)
+	if (dio->flags & IOMAP_DIO_FSBLOCK_ALIGNED) {
+		loff_t aligned_copied = round_down(copied,
+						   i_blocksize(iter->inode));
+
+		/*
+		 * For fs passing IOMAP_DIO_FSBLOCK_ALIGNED flag, if fs block
+		 * size is larger than page size, page fault failure
+		 * can cause @copied to be page aligned but not fs block
+		 * aligned.
+		 */
+		iov_iter_revert(dio->submit.iter, copied - aligned_copied);
+		copied = aligned_copied;
+	}
+	dio->size += copied;
+	if (!copied)
 		return -EFAULT;
-	return iomap_iter_advance(iter, aligned_copied);
+	return iomap_iter_advance(iter, copied);
 }
 
 static int iomap_dio_inline_iter(struct iomap_iter *iomi, struct iomap_dio *dio)
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-10-27 11:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-26  6:48 [PATCH] iomap: only follow dio alignment requirement if specified Qu Wenruo
2026-10-26 14:21 ` Pankaj Raghav (Samsung)
2026-10-26 19:49 ` Pankaj Raghav (Samsung)
2026-10-26 20:59   ` Qu Wenruo
2026-10-26 21:29     ` Qu Wenruo
2026-10-27 10:07     ` Pankaj Raghav
2026-10-27 10:12       ` Qu Wenruo
2026-10-27 11:14         ` Pankaj Raghav

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox