diff options
| author | Qu Wenruo <wqu@suse.com> | 2026-10-30 07:21:23 +1030 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-10-30 15:53:01 +0100 |
| commit | 87d02f3e98a86abf70441b0a0418e01cb1d64b44 (patch) | |
| tree | e1e3824cdd59018b8e0dba7418da8f7fc1d21eab | |
| parent | 99f7d39384d6f1967f3dddf27aca47280f63d8d7 (diff) | |
| download | linux-87d02f3e98a86abf70441b0a0418e01cb1d64b44.tar.gz linux-87d02f3e98a86abf70441b0a0418e01cb1d64b44.zip | |
iomap: only follow dio alignment requirement if specified
After commit 4025185cf953 ("iomap: follow the alignment requirement for
iomap_dio_hole_iter()"), generic/091 fails on both xfs and ext4.
The reason is that ext4 and xfs (except COW write) do not require full
block alignment for direct IO. They are totally fine reading a sub-block
range.
That commit fails any direct read of sub-block holes/prealloc, even those
filesystems can handle it without any problem.
Fix the regression by only follow the block alignment if the
IOMAP_DIO_FSBLOCK_ALIGNED flag is set.
Fixes: 4025185cf953 ("iomap: follow the alignment requirement for iomap_dio_hole_iter()")
Reviewed-by: Pankaj Raghav(Samsung) <pankaj.raghav@linux.dev>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Link: https://patch.msgid.link/0e89c49b6f7804081f4041007b81ac620a153830.1793307063.git.wqu@suse.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
| -rw-r--r-- | fs/iomap/direct-io.c | 26 | ||||
| -rw-r--r-- | include/linux/iomap.h | 3 |
2 files changed, 18 insertions, 11 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 @@ out: 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) diff --git a/include/linux/iomap.h b/include/linux/iomap.h index 59718f73c15a..5254430844b2 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -693,7 +693,8 @@ struct iomap_dio_ops { #define IOMAP_DIO_PARTIAL (1 << 2) /* - * Ensure each bio is aligned to fs block size. + * Ensure every operation, including bio and hole zeroing, is aligned to fs + * block size. * * For filesystems which need to calculate/verify the checksum of each fs * block. Otherwise they may not be able to handle unaligned bios. |
