* [PATCH] iomap: follow the alignment requirement for iomap_dio_hole_iter()
@ 2026-07-30 1:22 Qu Wenruo
2026-07-30 7:45 ` Christoph Hellwig
2026-07-31 11:41 ` [syzbot ci] " syzbot ci
0 siblings, 2 replies; 7+ messages in thread
From: Qu Wenruo @ 2026-07-30 1:22 UTC (permalink / raw)
To: linux-btrfs, linux-fsdevel, linux-xfs
[BUG]
On the latest development branch, btrfs with 8K block size on 4K page
sized systems will fail the following fsstress workload:
# $fsstress -n 4 -d $mnt -s 1785675805 -v
0/0: dwrite - no filename
0/1: creat f0 x:0 0 0
0/1: creat add id=0,parent=-1
0/2: write dontcache f0[259 1 0 0 0 0] [816411,3620] 0
0/3: dread - xfsctl(XFS_IOC_DIOINFO) f0[259 1 0 0 32 820031] return 25, fallback to stat()
0/3: dread f0[259 1 0 0 32 820031] [483328,81920] 0
Which triggered the following ASSERT():
assertion failed: IS_ALIGNED(state->start, blocksize) && IS_ALIGNED(state->end + 1, blocksize), in fs/btrfs/extent-io-tree.c:346 (unaligned extent state, blocksize=8192 start=487424 end=565247 state=0x0)
------------[ cut here ]------------
kernel BUG at fs/btrfs/extent-io-tree.c:346!
Oops: invalid opcode: 0000 [#1] SMP
CPU: 4 UID: 0 PID: 648 Comm: fsstress Tainted: G E 7.2.0-rc5-custom+ #431 PREEMPT(full) 7c507bd40d65e4d871e698b22d80f1306bbec543
Tainted: [E]=UNSIGNED_MODULE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022
RIP: 0010:validate_extent_state.part.0.isra.0.cold+0x24/0x26 [btrfs]
Call Trace:
<TASK>
insert_state+0x34/0x1a0 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
set_extent_bit+0x440/0x8d0 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
btrfs_lock_extent_bits+0x58/0x380 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
btrfs_dio_iomap_begin+0x319/0xb70 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
iomap_iter+0x1a2/0x370
__iomap_dio_rw+0x236/0x8d0
iomap_dio_rw+0x12/0x30
btrfs_direct_read+0x15f/0x290 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
btrfs_file_read_iter+0x42/0x90 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
vfs_read+0x25e/0x380
ksys_read+0x73/0xe0
do_syscall_64+0xe1/0x790
entry_SYSCALL_64_after_hwframe+0x4b/0x53
RIP: 0033:0x7fc3f129318e
</TASK>
[CAUSE]
Btrfs has recently introduced more strict extent_state alignment checks,
which means functions like btrfs_lock_extent() will require the range
to be block size aligned.
But in the above workload, iomap_dio_hole_iter() only zeroed 4K, then
hit a page fault. In that case the iov_iter is still advanced 4K bytes,
then btrfs_dio_iomap_begin() is called for the remaining range, which is
no longer block size (8K) aligned, triggering the ASSERT().
This shows that, although iomap_dio_bio_iter() is properly respecting
the alignment requirement, iomap_dio_hole_iter() is not doing the same
thing.
[FIX]
Extract a helper, iomap_dio_alignment(), to calculate the alignment first.
Then for iomap_dio_hole_iter() round down the copied length, and revert
any excessive range that is beyond the aligned copied length.
Also use @aligned_copied for the size increment and iter advancement.
Fixes: 001397f5ef49 ("iomap: add IOMAP_DIO_FSBLOCK_ALIGNED flag")
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/iomap/direct-io.c | 34 ++++++++++++++++++++--------------
1 file changed, 20 insertions(+), 14 deletions(-)
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index e2cd5f92babe..94747963cb1f 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -403,6 +403,18 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter,
return ret;
}
+/*
+ * File systems that write out of place and always allocate new blocks
+ * need each bio to be block aligned as that's the unit of allocation.
+ */
+static unsigned int iomap_dio_alignment(const struct iomap_iter *iter,
+ const struct iomap_dio *dio)
+{
+ if (dio->flags & IOMAP_DIO_FSBLOCK_ALIGNED)
+ return i_blocksize(iter->inode);
+ return bdev_logical_block_size(iter->iomap.bdev);
+}
+
static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
{
const struct iomap *iomap = &iter->iomap;
@@ -414,18 +426,9 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
bool need_zeroout = false;
u64 copied = 0;
size_t orig_count;
- unsigned int alignment;
+ const unsigned int alignment = iomap_dio_alignment(iter, dio);
ssize_t ret = 0;
- /*
- * File systems that write out of place and always allocate new blocks
- * need each bio to be block aligned as that's the unit of allocation.
- */
- if (dio->flags & IOMAP_DIO_FSBLOCK_ALIGNED)
- alignment = fs_block_size;
- else
- alignment = bdev_logical_block_size(iomap->bdev);
-
if ((pos | length) & (alignment - 1))
return -EINVAL;
@@ -588,12 +591,15 @@ 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 length = iov_iter_zero(iomap_length(iter), dio->submit.iter);
+ loff_t copied = iov_iter_zero(iomap_length(iter), dio->submit.iter);
+ const unsigned int alignment = iomap_dio_alignment(iter, dio);
+ const loff_t aligned_copied = round_down(copied, alignment);
- dio->size += length;
- if (!length)
+ iov_iter_revert(dio->submit.iter, copied - aligned_copied);
+ dio->size += aligned_copied;
+ if (!aligned_copied)
return -EFAULT;
- return iomap_iter_advance(iter, length);
+ return iomap_iter_advance(iter, aligned_copied);
}
static int iomap_dio_inline_iter(struct iomap_iter *iomi, struct iomap_dio *dio)
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH] iomap: follow the alignment requirement for iomap_dio_hole_iter()
2026-07-30 1:22 [PATCH] iomap: follow the alignment requirement for iomap_dio_hole_iter() Qu Wenruo
@ 2026-07-30 7:45 ` Christoph Hellwig
2026-07-30 8:36 ` Qu Wenruo
2026-07-31 11:41 ` [syzbot ci] " syzbot ci
1 sibling, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2026-07-30 7:45 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs, linux-fsdevel, linux-xfs
On Thu, Jul 30, 2026 at 10:52:10AM +0930, Qu Wenruo wrote:
> [BUG]
> On the latest development branch, btrfs with 8K block size on 4K page
> sized systems will fail the following fsstress workload:
>
> # $fsstress -n 4 -d $mnt -s 1785675805 -v
Please add this to xfstests.
> +/*
> + * File systems that write out of place and always allocate new blocks
> + * need each bio to be block aligned as that's the unit of allocation.
> + */
> +static unsigned int iomap_dio_alignment(const struct iomap_iter *iter,
> + const struct iomap_dio *dio)
> +{
> + if (dio->flags & IOMAP_DIO_FSBLOCK_ALIGNED)
> + return i_blocksize(iter->inode);
> + return bdev_logical_block_size(iter->iomap.bdev);
> +}
This already exists in the VFS iomap tree (with a slightly different
prototype).
> static int iomap_dio_hole_iter(struct iomap_iter *iter, struct iomap_dio *dio)
> {
> - loff_t length = iov_iter_zero(iomap_length(iter), dio->submit.iter);
> + loff_t copied = iov_iter_zero(iomap_length(iter), dio->submit.iter);
> + const unsigned int alignment = iomap_dio_alignment(iter, dio);
> + const loff_t aligned_copied = round_down(copied, alignment);
>
> - dio->size += length;
> - if (!length)
> + iov_iter_revert(dio->submit.iter, copied - aligned_copied);
> + dio->size += aligned_copied;
> + if (!aligned_copied)
> return -EFAULT;
> - return iomap_iter_advance(iter, length);
> + return iomap_iter_advance(iter, aligned_copied);
> }
iomap generall expects extents to be block aligned, how do you end up
with non-aligned reporting here?
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] iomap: follow the alignment requirement for iomap_dio_hole_iter()
2026-07-30 7:45 ` Christoph Hellwig
@ 2026-07-30 8:36 ` Qu Wenruo
2026-07-30 12:01 ` Christoph Hellwig
0 siblings, 1 reply; 7+ messages in thread
From: Qu Wenruo @ 2026-07-30 8:36 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linux-btrfs, linux-fsdevel, linux-xfs
在 2026/7/30 17:15, Christoph Hellwig 写道:
> On Thu, Jul 30, 2026 at 10:52:10AM +0930, Qu Wenruo wrote:
>> [BUG]
>> On the latest development branch, btrfs with 8K block size on 4K page
>> sized systems will fail the following fsstress workload:
>>
>> # $fsstress -n 4 -d $mnt -s 1785675805 -v
>
> Please add this to xfstests.
In that case I'll create a more dedicated reproducer.
>
>> +/*
>> + * File systems that write out of place and always allocate new blocks
>> + * need each bio to be block aligned as that's the unit of allocation.
>> + */
>> +static unsigned int iomap_dio_alignment(const struct iomap_iter *iter,
>> + const struct iomap_dio *dio)
>> +{
>> + if (dio->flags & IOMAP_DIO_FSBLOCK_ALIGNED)
>> + return i_blocksize(iter->inode);
>> + return bdev_logical_block_size(iter->iomap.bdev);
>> +}
>
> This already exists in the VFS iomap tree (with a slightly different
> prototype).
>
>> static int iomap_dio_hole_iter(struct iomap_iter *iter, struct iomap_dio *dio)
>> {
>> - loff_t length = iov_iter_zero(iomap_length(iter), dio->submit.iter);
>> + loff_t copied = iov_iter_zero(iomap_length(iter), dio->submit.iter);
>> + const unsigned int alignment = iomap_dio_alignment(iter, dio);
>> + const loff_t aligned_copied = round_down(copied, alignment);
>>
>> - dio->size += length;
>> - if (!length)
>> + iov_iter_revert(dio->submit.iter, copied - aligned_copied);
>> + dio->size += aligned_copied;
>> + if (!aligned_copied)
>> return -EFAULT;
>> - return iomap_iter_advance(iter, length);
>> + return iomap_iter_advance(iter, aligned_copied);
>> }
>
> iomap generall expects extents to be block aligned, how do you end up
> with non-aligned reporting here?
The dio read buffer is 2 pages (matching the 8K alignment), but only the
first page is faulted in.
Furthermore btrfs has disabled page fault during dio read, so the 2nd
page will not be faulted in.
Thus iov_iter_zero() only got to zero the first page.
Btrfs always returned a hole that is properly aligned, but as long as bs
> ps, the page fault can always break in the middle, causing unaligned
range.
Thanks,
Qu
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] iomap: follow the alignment requirement for iomap_dio_hole_iter()
2026-07-30 8:36 ` Qu Wenruo
@ 2026-07-30 12:01 ` Christoph Hellwig
0 siblings, 0 replies; 7+ messages in thread
From: Christoph Hellwig @ 2026-07-30 12:01 UTC (permalink / raw)
To: Qu Wenruo; +Cc: Christoph Hellwig, linux-btrfs, linux-fsdevel, linux-xfs
On Thu, Jul 30, 2026 at 06:06:17PM +0930, Qu Wenruo wrote:
> > iomap generall expects extents to be block aligned, how do you end up
> > with non-aligned reporting here?
>
> The dio read buffer is 2 pages (matching the 8K alignment), but only the
> first page is faulted in.
>
> Furthermore btrfs has disabled page fault during dio read, so the 2nd page
> will not be faulted in.
>
> Thus iov_iter_zero() only got to zero the first page.
>
> Btrfs always returned a hole that is properly aligned, but as long as bs >
> ps, the page fault can always break in the middle, causing unaligned range.
Urgg, we really need to get rid of this nofault behavior rather sooner
than later. But I think the iomap should always be fsblock alignment.
While we can support smaller I/O, the mapping should always be block
aligned.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [syzbot ci] Re: iomap: follow the alignment requirement for iomap_dio_hole_iter()
2026-07-30 1:22 [PATCH] iomap: follow the alignment requirement for iomap_dio_hole_iter() Qu Wenruo
2026-07-30 7:45 ` Christoph Hellwig
@ 2026-07-31 11:41 ` syzbot ci
2026-07-31 21:29 ` Qu Wenruo
1 sibling, 1 reply; 7+ messages in thread
From: syzbot ci @ 2026-07-31 11:41 UTC (permalink / raw)
To: linux-btrfs, linux-fsdevel, linux-xfs, wqu; +Cc: syzbot, syzkaller-bugs
syzbot ci has tested the following series
[v1] iomap: follow the alignment requirement for iomap_dio_hole_iter()
https://lore.kernel.org/all/e69cc8a4a9c3f641b97872b50f04c397880077cd.1785374485.git.wqu@suse.com
* [PATCH] iomap: follow the alignment requirement for iomap_dio_hole_iter()
and found the following issue:
general protection fault in __iomap_dio_rw
Full report is available here:
https://ci.syzbot.org/series/81e0fbae-4715-4d62-8e9e-bcd19e46b164
***
general protection fault in __iomap_dio_rw
tree: vfs
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/vfs/vfs.git
base: 70c2cbf8600c7d3a622b77e31136b83d6ac7d86c
arch: amd64
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
config: https://ci.syzbot.org/builds/8d5fee65-291c-46a2-9f9a-d512f8fad82b/config
syz repro: https://ci.syzbot.org/findings/c9f79a18-3316-44ec-b805-b805b1c49325/syz_repro
loop0: rw=2049, sector=53248, nr_sectors = 976 limit=40427
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000003: 0000 [#1] SMP KASAN PTI
KASAN: null-ptr-deref in range [0x0000000000000018-0x000000000000001f]
CPU: 0 UID: 0 PID: 5842 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
RIP: 0010:bdev_get_queue include/linux/blkdev.h:1058 [inline]
RIP: 0010:bdev_logical_block_size include/linux/blkdev.h:1403 [inline]
RIP: 0010:iomap_dio_alignment fs/iomap/direct-io.c:415 [inline]
RIP: 0010:iomap_dio_hole_iter fs/iomap/direct-io.c:595 [inline]
RIP: 0010:iomap_dio_iter fs/iomap/direct-io.c:643 [inline]
RIP: 0010:__iomap_dio_rw+0x1142/0x2130 fs/iomap/direct-io.c:815
Code: e2 5a ff 83 e3 08 75 5c e8 ab de 5a ff 48 8b 9c 24 68 01 00 00 48 83 c3 18 48 89 d8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 48 89 df e8 d0 75 c8 ff 48 8b 1b b8 58 01 00 00
RSP: 0018:ffffc90003fef560 EFLAGS: 00010206
RAX: 0000000000000003 RBX: 0000000000000018 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffffc90003fef860 R08: ffff8881148d8fff R09: 0000000000000000
R10: ffff8881148d8000 R11: ffffed102291b200 R12: 1ffff920007fdecc
R13: 0000000000000000 R14: ffff888166b45340 R15: 0000000000001000
FS: 00007fd77743d6c0(0000) GS:ffff88818d951000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000200000078000 CR3: 000000011606a000 CR4: 00000000000006f0
Call Trace:
<TASK>
f2fs_dio_read_iter fs/f2fs/file.c:4887 [inline]
f2fs_file_read_iter+0x60b/0x940 fs/f2fs/file.c:4950
copy_splice_read+0x5ff/0xaa0 fs/splice.c:362
do_splice_read fs/splice.c:979 [inline]
splice_direct_to_actor+0x4b6/0xcb0 fs/splice.c:1084
do_splice_direct_actor fs/splice.c:1202 [inline]
do_splice_direct+0x195/0x290 fs/splice.c:1228
do_sendfile+0x52e/0x7c0 fs/read_write.c:1371
__do_sys_sendfile64 fs/read_write.c:1432 [inline]
__se_sys_sendfile64+0x144/0x1a0 fs/read_write.c:1418
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fd77659df99
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fd77743d028 EFLAGS: 00000246 ORIG_RAX: 0000000000000028
RAX: ffffffffffffffda RBX: 00007fd776825fa0 RCX: 00007fd77659df99
RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000000000000004
RBP: 00007fd776634ec4 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000800000009 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fd776826038 R14: 00007fd776825fa0 R15: 00007fff168f4a18
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:bdev_get_queue include/linux/blkdev.h:1058 [inline]
RIP: 0010:bdev_logical_block_size include/linux/blkdev.h:1403 [inline]
RIP: 0010:iomap_dio_alignment fs/iomap/direct-io.c:415 [inline]
RIP: 0010:iomap_dio_hole_iter fs/iomap/direct-io.c:595 [inline]
RIP: 0010:iomap_dio_iter fs/iomap/direct-io.c:643 [inline]
RIP: 0010:__iomap_dio_rw+0x1142/0x2130 fs/iomap/direct-io.c:815
Code: e2 5a ff 83 e3 08 75 5c e8 ab de 5a ff 48 8b 9c 24 68 01 00 00 48 83 c3 18 48 89 d8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 48 89 df e8 d0 75 c8 ff 48 8b 1b b8 58 01 00 00
RSP: 0018:ffffc90003fef560 EFLAGS: 00010206
RAX: 0000000000000003 RBX: 0000000000000018 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffffc90003fef860 R08: ffff8881148d8fff R09: 0000000000000000
R10: ffff8881148d8000 R11: ffffed102291b200 R12: 1ffff920007fdecc
R13: 0000000000000000 R14: ffff888166b45340 R15: 0000000000001000
FS: 00007fd77743d6c0(0000) GS:ffff8882a8f51000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007faa8f64dc80 CR3: 000000011606a000 CR4: 00000000000006f0
----------------
Code disassembly (best guess):
0: e2 5a loop 0x5c
2: ff 83 e3 08 75 5c incl 0x5c7508e3(%rbx)
8: e8 ab de 5a ff call 0xff5adeb8
d: 48 8b 9c 24 68 01 00 mov 0x168(%rsp),%rbx
14: 00
15: 48 83 c3 18 add $0x18,%rbx
19: 48 89 d8 mov %rbx,%rax
1c: 48 c1 e8 03 shr $0x3,%rax
20: 48 b9 00 00 00 00 00 movabs $0xdffffc0000000000,%rcx
27: fc ff df
* 2a: 80 3c 08 00 cmpb $0x0,(%rax,%rcx,1) <-- trapping instruction
2e: 74 08 je 0x38
30: 48 89 df mov %rbx,%rdi
33: e8 d0 75 c8 ff call 0xffc87608
38: 48 8b 1b mov (%rbx),%rbx
3b: b8 58 01 00 00 mov $0x158,%eax
***
If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syzbot@syzkaller.appspotmail.com
---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.
To test a patch for this bug, please reply with `#syz test`
(should be on a separate line).
The patch should be attached to the email.
Note: arguments like custom git repos and branches are not supported.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [syzbot ci] Re: iomap: follow the alignment requirement for iomap_dio_hole_iter()
2026-07-31 11:41 ` [syzbot ci] " syzbot ci
@ 2026-07-31 21:29 ` Qu Wenruo
0 siblings, 0 replies; 7+ messages in thread
From: Qu Wenruo @ 2026-07-31 21:29 UTC (permalink / raw)
To: syzbot ci, linux-btrfs, linux-fsdevel, linux-xfs, wqu
Cc: syzbot, syzkaller-bugs
在 2026/7/31 21:11, syzbot ci 写道:
> syzbot ci has tested the following series
>
> [v1] iomap: follow the alignment requirement for iomap_dio_hole_iter()
> https://lore.kernel.org/all/e69cc8a4a9c3f641b97872b50f04c397880077cd.1785374485.git.wqu@suse.com
> * [PATCH] iomap: follow the alignment requirement for iomap_dio_hole_iter()
>
> and found the following issue:
> general protection fault in __iomap_dio_rw
>
> Full report is available here:
> https://ci.syzbot.org/series/81e0fbae-4715-4d62-8e9e-bcd19e46b164
>
> ***
>
> general protection fault in __iomap_dio_rw
>
> tree: vfs
> URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/vfs/vfs.git
> base: 70c2cbf8600c7d3a622b77e31136b83d6ac7d86c
> arch: amd64
> compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
> config: https://ci.syzbot.org/builds/8d5fee65-291c-46a2-9f9a-d512f8fad82b/config
> syz repro: https://ci.syzbot.org/findings/c9f79a18-3316-44ec-b805-b805b1c49325/syz_repro
>
> loop0: rw=2049, sector=53248, nr_sectors = 976 limit=40427
> Oops: general protection fault, probably for non-canonical address 0xdffffc0000000003: 0000 [#1] SMP KASAN PTI
> KASAN: null-ptr-deref in range [0x0000000000000018-0x000000000000001f]
> CPU: 0 UID: 0 PID: 5842 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
> Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
> RIP: 0010:bdev_get_queue include/linux/blkdev.h:1058 [inline]
> RIP: 0010:bdev_logical_block_size include/linux/blkdev.h:1403 [inline]
> RIP: 0010:iomap_dio_alignment fs/iomap/direct-io.c:415 [inline]
> RIP: 0010:iomap_dio_hole_iter fs/iomap/direct-io.c:595 [inline]
> RIP: 0010:iomap_dio_iter fs/iomap/direct-io.c:643 [inline]
> RIP: 0010:__iomap_dio_rw+0x1142/0x2130 fs/iomap/direct-io.c:815
> Code: e2 5a ff 83 e3 08 75 5c e8 ab de 5a ff 48 8b 9c 24 68 01 00 00 48 83 c3 18 48 89 d8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 48 89 df e8 d0 75 c8 ff 48 8b 1b b8 58 01 00 00
> RSP: 0018:ffffc90003fef560 EFLAGS: 00010206
> RAX: 0000000000000003 RBX: 0000000000000018 RCX: dffffc0000000000
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
> RBP: ffffc90003fef860 R08: ffff8881148d8fff R09: 0000000000000000
> R10: ffff8881148d8000 R11: ffffed102291b200 R12: 1ffff920007fdecc
> R13: 0000000000000000 R14: ffff888166b45340 R15: 0000000000001000
> FS: 00007fd77743d6c0(0000) GS:ffff88818d951000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 0000200000078000 CR3: 000000011606a000 CR4: 00000000000006f0
> Call Trace:
> <TASK>
> f2fs_dio_read_iter fs/f2fs/file.c:4887 [inline]
This looks like f2fs is not populating iomap->bdev for holes, which is
not unreasonable for a hole.
So I need to update iomap_dio_alignment() for @bdev == NULL cases.
Thanks for the report,
Qu
> f2fs_file_read_iter+0x60b/0x940 fs/f2fs/file.c:4950
> copy_splice_read+0x5ff/0xaa0 fs/splice.c:362
> do_splice_read fs/splice.c:979 [inline]
> splice_direct_to_actor+0x4b6/0xcb0 fs/splice.c:1084
> do_splice_direct_actor fs/splice.c:1202 [inline]
> do_splice_direct+0x195/0x290 fs/splice.c:1228
> do_sendfile+0x52e/0x7c0 fs/read_write.c:1371
> __do_sys_sendfile64 fs/read_write.c:1432 [inline]
> __se_sys_sendfile64+0x144/0x1a0 fs/read_write.c:1418
> do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
> RIP: 0033:0x7fd77659df99
> Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
> RSP: 002b:00007fd77743d028 EFLAGS: 00000246 ORIG_RAX: 0000000000000028
> RAX: ffffffffffffffda RBX: 00007fd776825fa0 RCX: 00007fd77659df99
> RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000000000000004
> RBP: 00007fd776634ec4 R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000800000009 R11: 0000000000000246 R12: 0000000000000000
> R13: 00007fd776826038 R14: 00007fd776825fa0 R15: 00007fff168f4a18
> </TASK>
> Modules linked in:
> ---[ end trace 0000000000000000 ]---
> RIP: 0010:bdev_get_queue include/linux/blkdev.h:1058 [inline]
> RIP: 0010:bdev_logical_block_size include/linux/blkdev.h:1403 [inline]
> RIP: 0010:iomap_dio_alignment fs/iomap/direct-io.c:415 [inline]
> RIP: 0010:iomap_dio_hole_iter fs/iomap/direct-io.c:595 [inline]
> RIP: 0010:iomap_dio_iter fs/iomap/direct-io.c:643 [inline]
> RIP: 0010:__iomap_dio_rw+0x1142/0x2130 fs/iomap/direct-io.c:815
> Code: e2 5a ff 83 e3 08 75 5c e8 ab de 5a ff 48 8b 9c 24 68 01 00 00 48 83 c3 18 48 89 d8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 48 89 df e8 d0 75 c8 ff 48 8b 1b b8 58 01 00 00
> RSP: 0018:ffffc90003fef560 EFLAGS: 00010206
> RAX: 0000000000000003 RBX: 0000000000000018 RCX: dffffc0000000000
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
> RBP: ffffc90003fef860 R08: ffff8881148d8fff R09: 0000000000000000
> R10: ffff8881148d8000 R11: ffffed102291b200 R12: 1ffff920007fdecc
> R13: 0000000000000000 R14: ffff888166b45340 R15: 0000000000001000
> FS: 00007fd77743d6c0(0000) GS:ffff8882a8f51000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00007faa8f64dc80 CR3: 000000011606a000 CR4: 00000000000006f0
> ----------------
> Code disassembly (best guess):
> 0: e2 5a loop 0x5c
> 2: ff 83 e3 08 75 5c incl 0x5c7508e3(%rbx)
> 8: e8 ab de 5a ff call 0xff5adeb8
> d: 48 8b 9c 24 68 01 00 mov 0x168(%rsp),%rbx
> 14: 00
> 15: 48 83 c3 18 add $0x18,%rbx
> 19: 48 89 d8 mov %rbx,%rax
> 1c: 48 c1 e8 03 shr $0x3,%rax
> 20: 48 b9 00 00 00 00 00 movabs $0xdffffc0000000000,%rcx
> 27: fc ff df
> * 2a: 80 3c 08 00 cmpb $0x0,(%rax,%rcx,1) <-- trapping instruction
> 2e: 74 08 je 0x38
> 30: 48 89 df mov %rbx,%rdi
> 33: e8 d0 75 c8 ff call 0xffc87608
> 38: 48 8b 1b mov (%rbx),%rbx
> 3b: b8 58 01 00 00 mov $0x158,%eax
>
>
> ***
>
> If these findings have caused you to resend the series or submit a
> separate fix, please add the following tag to your commit message:
> Tested-by: syzbot@syzkaller.appspotmail.com
>
> ---
> This report is generated by a bot. It may contain errors.
> syzbot ci engineers can be reached at syzkaller@googlegroups.com.
>
> To test a patch for this bug, please reply with `#syz test`
> (should be on a separate line).
>
> The patch should be attached to the email.
> Note: arguments like custom git repos and branches are not supported.
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2] iomap: follow the alignment requirement for iomap_dio_hole_iter()
@ 2026-07-31 9:11 Qu Wenruo
2026-08-02 19:14 ` [syzbot ci] " syzbot ci
0 siblings, 1 reply; 7+ messages in thread
From: Qu Wenruo @ 2026-07-31 9:11 UTC (permalink / raw)
To: linux-btrfs, linux-fsdevel, linux-xfs
[BUG]
On the latest development branch, btrfs with 8K block size on 4K page
sized systems will fail all test cases that run fsstress.
One very short example would be:
# $fsstress -n 4 -d $mnt -s 1785675805 -v
0/0: dwrite - no filename
0/1: creat f0 x:0 0 0
0/1: creat add id=0,parent=-1
0/2: write dontcache f0[259 1 0 0 0 0] [816411,3620] 0
0/3: dread - xfsctl(XFS_IOC_DIOINFO) f0[259 1 0 0 32 820031] return 25, fallback to stat()
0/3: dread f0[259 1 0 0 32 820031] [483328,81920] 0
Which triggered the following ASSERT():
assertion failed: IS_ALIGNED(state->start, blocksize) && IS_ALIGNED(state->end + 1, blocksize), in fs/btrfs/extent-io-tree.c:346 (unaligned extent state, blocksize=8192 start=487424 end=565247 state=0x0)
------------[ cut here ]------------
kernel BUG at fs/btrfs/extent-io-tree.c:346!
Oops: invalid opcode: 0000 [#1] SMP
CPU: 4 UID: 0 PID: 648 Comm: fsstress Tainted: G E 7.2.0-rc5-custom+ #431 PREEMPT(full) 7c507bd40d65e4d871e698b22d80f1306bbec543
Tainted: [E]=UNSIGNED_MODULE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS unknown 02/02/2022
RIP: 0010:validate_extent_state.part.0.isra.0.cold+0x24/0x26 [btrfs]
Call Trace:
<TASK>
insert_state+0x34/0x1a0 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
set_extent_bit+0x440/0x8d0 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
btrfs_lock_extent_bits+0x58/0x380 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
btrfs_dio_iomap_begin+0x319/0xb70 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
iomap_iter+0x1a2/0x370
__iomap_dio_rw+0x236/0x8d0
iomap_dio_rw+0x12/0x30
btrfs_direct_read+0x15f/0x290 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
btrfs_file_read_iter+0x42/0x90 [btrfs 6924944583e4bc91a7c5183a1e7908e745a9b0c8]
vfs_read+0x25e/0x380
ksys_read+0x73/0xe0
do_syscall_64+0xe1/0x790
entry_SYSCALL_64_after_hwframe+0x4b/0x53
RIP: 0033:0x7fc3f129318e
</TASK>
[CAUSE]
iomap_dio_hole_iter() is responsible for zeroing out the buffer for a
hole, which calls iov_iter_zero() to zero the range.
However btrfs disables page fault during its __iomap_dio_rw() call, so
iov_iter_zero() can fail at any page boundary.
When the fs block size is larger than page size, iov_iter_zero() may
only have zeroed one page, which is not aligned to the fs block size.
Such one page long range is passed back to btrfs, which triggers the
above ASSERT().
[FIX]
For iomap_dio_hole_iter() round down the copied length, and revert
any excessive range that is beyond the aligned copied length.
Also use @aligned_copied for the size increment and iter advancement.
This should only affect btrfs, which is the only fs utilizing iomap dio
with page fault disabled.
Fixes: 001397f5ef49 ("iomap: add IOMAP_DIO_FSBLOCK_ALIGNED flag")
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
Changelog:
v2:
- Rebased to the latest vfs tree
- Slightly rewords the reproducer
In fact no special reproducer needed, any test case running fsstress
can easily trigger it.
The example provided is just the shortest sequence I used to debug the
crash.
---
fs/iomap/direct-io.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index 64c6b7286c20..f170976d9de0 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -594,12 +594,20 @@ 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 length = iov_iter_zero(iomap_length(iter), dio->submit.iter);
+ loff_t copied = iov_iter_zero(iomap_length(iter), dio->submit.iter);
+ unsigned int bs = iomap_dio_alignment(iter->inode, iter->iomap.bdev,
+ dio->flags);
+ loff_t aligned_copied = round_down(copied, bs);
- dio->size += length;
- if (!length)
+ /*
+ * 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)
return -EFAULT;
- return iomap_iter_advance(iter, length);
+ return iomap_iter_advance(iter, aligned_copied);
}
static int iomap_dio_inline_iter(struct iomap_iter *iomi, struct iomap_dio *dio)
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [syzbot ci] Re: iomap: follow the alignment requirement for iomap_dio_hole_iter()
2026-07-31 9:11 [PATCH v2] " Qu Wenruo
@ 2026-08-02 19:14 ` syzbot ci
0 siblings, 0 replies; 7+ messages in thread
From: syzbot ci @ 2026-08-02 19:14 UTC (permalink / raw)
To: linux-btrfs, linux-fsdevel, linux-xfs, wqu; +Cc: syzbot, syzkaller-bugs
syzbot ci has tested the following series
[v2] iomap: follow the alignment requirement for iomap_dio_hole_iter()
https://lore.kernel.org/all/9209e7204fc6b7b60c28f196750084be8a2faba8.1785489008.git.wqu@suse.com
* [PATCH v2] iomap: follow the alignment requirement for iomap_dio_hole_iter()
and found the following issue:
general protection fault in iomap_dio_hole_iter
Full report is available here:
https://ci.syzbot.org/series/9d98023b-4249-4697-ab21-ea7cf83805c8
***
general protection fault in iomap_dio_hole_iter
tree: vfs
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/vfs/vfs.git
base: fa20f6cb6063f7f1a6a56693d4a8713f19058d23
arch: amd64
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
config: https://ci.syzbot.org/builds/a53b891c-9ac3-484a-a77e-61c04d35157f/config
syz repro: https://ci.syzbot.org/findings/8ed3b1e3-7e4e-4c2c-b0f6-934cfea6e536/syz_repro
syz.0.17: attempt to access beyond end of device
loop0: rw=2049, sector=53248, nr_sectors = 976 limit=40427
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000003: 0000 [#1] SMP KASAN PTI
KASAN: null-ptr-deref in range [0x0000000000000018-0x000000000000001f]
CPU: 1 UID: 0 PID: 6257 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
RIP: 0010:bdev_get_queue include/linux/blkdev.h:1056 [inline]
RIP: 0010:bdev_logical_block_size include/linux/blkdev.h:1401 [inline]
RIP: 0010:iomap_dio_alignment fs/iomap/direct-io.c:412 [inline]
RIP: 0010:iomap_dio_hole_iter+0x1bf/0x390 fs/iomap/direct-io.c:598
Code: fc ff df 80 3c 08 00 74 08 4c 89 ef e8 aa d7 c7 ff 49 8b 6d 00 48 83 c5 18 48 89 e8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 48 89 ef e8 83 d7 c7 ff 41 bd 58 01 00 00 4c 03
RSP: 0018:ffffc90003eff500 EFLAGS: 00010206
RAX: 0000000000000003 RBX: ffffc90003eff680 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000018 R08: ffff88816dc38fff R09: 0000000000000000
R10: ffff88816dc38000 R11: ffffed102db87200 R12: 0000000000001000
R13: ffffc90003eff6c8 R14: ffff88816b839c00 R15: 1ffff1102d707388
FS: 00007ffb1678d6c0(0000) GS:ffff8882a8f4b000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000563ae8dcd0a8 CR3: 0000000110cf4000 CR4: 00000000000006f0
Call Trace:
<TASK>
iomap_dio_iter fs/iomap/direct-io.c:-1 [inline]
__iomap_dio_rw+0xe56/0x1ac0 fs/iomap/direct-io.c:823
f2fs_dio_read_iter fs/f2fs/file.c:4887 [inline]
f2fs_file_read_iter+0x60b/0x940 fs/f2fs/file.c:4950
copy_splice_read+0x5ff/0xaa0 fs/splice.c:362
do_splice_read fs/splice.c:979 [inline]
splice_direct_to_actor+0x4b6/0xcb0 fs/splice.c:1084
do_splice_direct_actor fs/splice.c:1202 [inline]
do_splice_direct+0x195/0x290 fs/splice.c:1228
do_sendfile+0x52e/0x7c0 fs/read_write.c:1371
__do_sys_sendfile64 fs/read_write.c:1432 [inline]
__se_sys_sendfile64+0x144/0x1a0 fs/read_write.c:1418
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ffb1599e019
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffb1678d028 EFLAGS: 00000246 ORIG_RAX: 0000000000000028
RAX: ffffffffffffffda RBX: 00007ffb15c25fa0 RCX: 00007ffb1599e019
RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000000000000004
RBP: 00007ffb15a3500c R08: 0000000000000000 R09: 0000000000000000
R10: 0000000800000009 R11: 0000000000000246 R12: 0000000000000000
R13: 00007ffb15c26038 R14: 00007ffb15c25fa0 R15: 00007ffc15b4ab58
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:bdev_get_queue include/linux/blkdev.h:1056 [inline]
RIP: 0010:bdev_logical_block_size include/linux/blkdev.h:1401 [inline]
RIP: 0010:iomap_dio_alignment fs/iomap/direct-io.c:412 [inline]
RIP: 0010:iomap_dio_hole_iter+0x1bf/0x390 fs/iomap/direct-io.c:598
Code: fc ff df 80 3c 08 00 74 08 4c 89 ef e8 aa d7 c7 ff 49 8b 6d 00 48 83 c5 18 48 89 e8 48 c1 e8 03 48 b9 00 00 00 00 00 fc ff df <80> 3c 08 00 74 08 48 89 ef e8 83 d7 c7 ff 41 bd 58 01 00 00 4c 03
RSP: 0018:ffffc90003eff500 EFLAGS: 00010206
RAX: 0000000000000003 RBX: ffffc90003eff680 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000018 R08: ffff88816dc38fff R09: 0000000000000000
R10: ffff88816dc38000 R11: ffffed102db87200 R12: 0000000000001000
R13: ffffc90003eff6c8 R14: ffff88816b839c00 R15: 1ffff1102d707388
FS: 00007ffb1678d6c0(0000) GS:ffff8882a8f4b000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000558d8b221b40 CR3: 0000000110cf4000 CR4: 00000000000006f0
----------------
Code disassembly (best guess), 2 bytes skipped:
0: df 80 3c 08 00 74 filds 0x7400083c(%rax)
6: 08 4c 89 ef or %cl,-0x11(%rcx,%rcx,4)
a: e8 aa d7 c7 ff call 0xffc7d7b9
f: 49 8b 6d 00 mov 0x0(%r13),%rbp
13: 48 83 c5 18 add $0x18,%rbp
17: 48 89 e8 mov %rbp,%rax
1a: 48 c1 e8 03 shr $0x3,%rax
1e: 48 b9 00 00 00 00 00 movabs $0xdffffc0000000000,%rcx
25: fc ff df
* 28: 80 3c 08 00 cmpb $0x0,(%rax,%rcx,1) <-- trapping instruction
2c: 74 08 je 0x36
2e: 48 89 ef mov %rbp,%rdi
31: e8 83 d7 c7 ff call 0xffc7d7b9
36: 41 bd 58 01 00 00 mov $0x158,%r13d
3c: 4c rex.WR
3d: 03 .byte 0x3
***
If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syzbot@syzkaller.appspotmail.com
---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.
To test a patch for this bug, please reply with `#syz test`
(should be on a separate line).
The patch should be attached to the email.
Note: arguments like custom git repos and branches are not supported.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-02 19:14 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 1:22 [PATCH] iomap: follow the alignment requirement for iomap_dio_hole_iter() Qu Wenruo
2026-07-30 7:45 ` Christoph Hellwig
2026-07-30 8:36 ` Qu Wenruo
2026-07-30 12:01 ` Christoph Hellwig
2026-07-31 11:41 ` [syzbot ci] " syzbot ci
2026-07-31 21:29 ` Qu Wenruo
-- strict thread matches above, loose matches on Subject: below --
2026-07-31 9:11 [PATCH v2] " Qu Wenruo
2026-08-02 19:14 ` [syzbot ci] " syzbot ci
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox