diff mbox series

btrfs: fix assertion failure when splitting ordered extent after transaction abort

Message ID efe1ae546864e0f22b4e29794115e3cedb602c30.1736782338.git.fdmanana@suse.com (mailing list archive)
State New
Headers show
Series btrfs: fix assertion failure when splitting ordered extent after transaction abort | expand

Commit Message

Filipe Manana Jan. 13, 2025, 3:32 p.m. UTC
From: Filipe Manana <fdmanana@suse.com>

If while we are doing a direct IO write a transaction abort happens, we
mark all existing ordered extents with the BTRFS_ORDERED_IOERR flag (done
at btrfs_destroy_ordered_extents()), and then after that if we enter
btrfs_split_ordered_extent() and the ordered extent has bytes left
(meaning we have a bio that doesn't cover the whole ordered extent, see
details at btrfs_extract_ordered_extent()), we will fail on the following
assertion at btrfs_split_ordered_extent():

   ASSERT(!(flags & ~BTRFS_ORDERED_TYPE_FLAGS));

because the BTRFS_ORDERED_IOERR flag is set and the definition of
BTRFS_ORDERED_TYPE_FLAGS is just the union of all flags that identify the
type of write (regular, nocow, prealloc, compressed, direct IO, encoded).

Fix this by returning an error from btrfs_extract_ordered_extent() if we
find the BTRFS_ORDERED_IOERR flag in the ordered extent. The error will
be the error that resulted in the transaction abort or -EIO if no
transaction abort happened.

This was recently reported by syzbot with the following trace:

   FAULT_INJECTION: forcing a failure.
   name failslab, interval 1, probability 0, space 0, times 1
   CPU: 0 UID: 0 PID: 5321 Comm: syz.0.0 Not tainted 6.13.0-rc5-syzkaller #0
   Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
   Call Trace:
    <TASK>
    __dump_stack lib/dump_stack.c:94 [inline]
    dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120
    fail_dump lib/fault-inject.c:53 [inline]
    should_fail_ex+0x3b0/0x4e0 lib/fault-inject.c:154
    should_failslab+0xac/0x100 mm/failslab.c:46
    slab_pre_alloc_hook mm/slub.c:4072 [inline]
    slab_alloc_node mm/slub.c:4148 [inline]
    __do_kmalloc_node mm/slub.c:4297 [inline]
    __kmalloc_noprof+0xdd/0x4c0 mm/slub.c:4310
    kmalloc_noprof include/linux/slab.h:905 [inline]
    kzalloc_noprof include/linux/slab.h:1037 [inline]
    btrfs_chunk_alloc_add_chunk_item+0x244/0x1100 fs/btrfs/volumes.c:5742
    reserve_chunk_space+0x1ca/0x2c0 fs/btrfs/block-group.c:4292
    check_system_chunk fs/btrfs/block-group.c:4319 [inline]
    do_chunk_alloc fs/btrfs/block-group.c:3891 [inline]
    btrfs_chunk_alloc+0x77b/0xf80 fs/btrfs/block-group.c:4187
    find_free_extent_update_loop fs/btrfs/extent-tree.c:4166 [inline]
    find_free_extent+0x42d1/0x5810 fs/btrfs/extent-tree.c:4579
    btrfs_reserve_extent+0x422/0x810 fs/btrfs/extent-tree.c:4672
    btrfs_new_extent_direct fs/btrfs/direct-io.c:186 [inline]
    btrfs_get_blocks_direct_write+0x706/0xfa0 fs/btrfs/direct-io.c:321
    btrfs_dio_iomap_begin+0xbb7/0x1180 fs/btrfs/direct-io.c:525
    iomap_iter+0x697/0xf60 fs/iomap/iter.c:90
    __iomap_dio_rw+0xeb9/0x25b0 fs/iomap/direct-io.c:702
    btrfs_dio_write fs/btrfs/direct-io.c:775 [inline]
    btrfs_direct_write+0x610/0xa30 fs/btrfs/direct-io.c:880
    btrfs_do_write_iter+0x2a0/0x760 fs/btrfs/file.c:1397
    do_iter_readv_writev+0x600/0x880
    vfs_writev+0x376/0xba0 fs/read_write.c:1050
    do_pwritev fs/read_write.c:1146 [inline]
    __do_sys_pwritev2 fs/read_write.c:1204 [inline]
    __se_sys_pwritev2+0x196/0x2b0 fs/read_write.c:1195
    do_syscall_x64 arch/x86/entry/common.c:52 [inline]
    do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
    entry_SYSCALL_64_after_hwframe+0x77/0x7f
   RIP: 0033:0x7f1281f85d29
   Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 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 a8 ff ff ff f7 d8 64 89 01 48
   RSP: 002b:00007f12819fe038 EFLAGS: 00000246 ORIG_RAX: 0000000000000148
   RAX: ffffffffffffffda RBX: 00007f1282176080 RCX: 00007f1281f85d29
   RDX: 0000000000000001 RSI: 0000000020000240 RDI: 0000000000000005
   RBP: 00007f12819fe090 R08: 0000000000000000 R09: 0000000000000003
   R10: 0000000000007000 R11: 0000000000000246 R12: 0000000000000002
   R13: 0000000000000000 R14: 00007f1282176080 R15: 00007ffcb9e23328
    </TASK>
   BTRFS error (device loop0 state A): Transaction aborted (error -12)
   BTRFS: error (device loop0 state A) in btrfs_chunk_alloc_add_chunk_item:5745: errno=-12 Out of memory
   BTRFS info (device loop0 state EA): forced readonly
   assertion failed: !(flags & ~BTRFS_ORDERED_TYPE_FLAGS), in fs/btrfs/ordered-data.c:1234
   ------------[ cut here ]------------
   kernel BUG at fs/btrfs/ordered-data.c:1234!
   Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI
   CPU: 0 UID: 0 PID: 5321 Comm: syz.0.0 Not tainted 6.13.0-rc5-syzkaller #0
   Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
   RIP: 0010:btrfs_split_ordered_extent+0xd8d/0xe20 fs/btrfs/ordered-data.c:1234
   Code: 43 fd 90 0f 0b e8 43 c4 db fd 48 c7 c7 20 0c 4c 8c 48 c7 c6 80 0f 4c 8c 48 c7 c2 e0 0b 4c 8c b9 d2 04 00 00 e8 04 57 43 fd 90 <0f> 0b e8 1c c4 db fd eb 5b e8 15 c4 db fd 48 c7 c7 20 0c 4c 8c 48
   RSP: 0018:ffffc9000d1df2b8 EFLAGS: 00010246
   RAX: 0000000000000057 RBX: 000000000006a000 RCX: 9ce21886c4195300
   RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000
   RBP: 0000000000000091 R08: ffffffff817f0a3c R09: 1ffff92001a3bdf4
   R10: dffffc0000000000 R11: fffff52001a3bdf5 R12: 1ffff1100a45f401
   R13: ffff8880522fa018 R14: dffffc0000000000 R15: 000000000006a000
   FS:  00007f12819fe6c0(0000) GS:ffff88801fc00000(0000) knlGS:0000000000000000
   CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
   CR2: 0000557750bd7da8 CR3: 00000000400ea000 CR4: 0000000000352ef0
   DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
   DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
   Call Trace:
    <TASK>
    btrfs_extract_ordered_extent fs/btrfs/direct-io.c:702 [inline]
    btrfs_dio_submit_io+0x4be/0x6d0 fs/btrfs/direct-io.c:737
    iomap_dio_submit_bio fs/iomap/direct-io.c:85 [inline]
    iomap_dio_bio_iter+0x1022/0x1740 fs/iomap/direct-io.c:447
    __iomap_dio_rw+0x13b7/0x25b0 fs/iomap/direct-io.c:703
    btrfs_dio_write fs/btrfs/direct-io.c:775 [inline]
    btrfs_direct_write+0x610/0xa30 fs/btrfs/direct-io.c:880
    btrfs_do_write_iter+0x2a0/0x760 fs/btrfs/file.c:1397
    do_iter_readv_writev+0x600/0x880
    vfs_writev+0x376/0xba0 fs/read_write.c:1050
    do_pwritev fs/read_write.c:1146 [inline]
    __do_sys_pwritev2 fs/read_write.c:1204 [inline]
    __se_sys_pwritev2+0x196/0x2b0 fs/read_write.c:1195
    do_syscall_x64 arch/x86/entry/common.c:52 [inline]
    do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
    entry_SYSCALL_64_after_hwframe+0x77/0x7f
   RIP: 0033:0x7f1281f85d29
   Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 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 a8 ff ff ff f7 d8 64 89 01 48
   RSP: 002b:00007f12819fe038 EFLAGS: 00000246 ORIG_RAX: 0000000000000148
   RAX: ffffffffffffffda RBX: 00007f1282176080 RCX: 00007f1281f85d29
   RDX: 0000000000000001 RSI: 0000000020000240 RDI: 0000000000000005
   RBP: 00007f12819fe090 R08: 0000000000000000 R09: 0000000000000003
   R10: 0000000000007000 R11: 0000000000000246 R12: 0000000000000002
   R13: 0000000000000000 R14: 00007f1282176080 R15: 00007ffcb9e23328
    </TASK>
   Modules linked in:
   ---[ end trace 0000000000000000 ]---
   RIP: 0010:btrfs_split_ordered_extent+0xd8d/0xe20 fs/btrfs/ordered-data.c:1234
   Code: 43 fd 90 0f 0b e8 43 c4 db fd 48 c7 c7 20 0c 4c 8c 48 c7 c6 80 0f 4c 8c 48 c7 c2 e0 0b 4c 8c b9 d2 04 00 00 e8 04 57 43 fd 90 <0f> 0b e8 1c c4 db fd eb 5b e8 15 c4 db fd 48 c7 c7 20 0c 4c 8c 48
   RSP: 0018:ffffc9000d1df2b8 EFLAGS: 00010246
   RAX: 0000000000000057 RBX: 000000000006a000 RCX: 9ce21886c4195300
   RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000
   RBP: 0000000000000091 R08: ffffffff817f0a3c R09: 1ffff92001a3bdf4
   R10: dffffc0000000000 R11: fffff52001a3bdf5 R12: 1ffff1100a45f401
   R13: ffff8880522fa018 R14: dffffc0000000000 R15: 000000000006a000
   FS:  00007f12819fe6c0(0000) GS:ffff88801fc00000(0000) knlGS:0000000000000000
   CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
   CR2: 0000557750bd7da8 CR3: 00000000400ea000 CR4: 0000000000352ef0
   DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
   DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400

In this case the transaction abort was due to (an injected) memory
allocation failure when attempting to allocate a new chunk.

Reported-by: syzbot+f60d8337a5c8e8d92a77@syzkaller.appspotmail.com
Link: https://lore.kernel.org/linux-btrfs/6777f2dd.050a0220.178762.0045.GAE@google.com/
Fixes: 52b1fdca23ac ("btrfs: handle completed ordered extents in btrfs_split_ordered_extent")
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/ordered-data.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Comments

Qu Wenruo Jan. 13, 2025, 9:12 p.m. UTC | #1
在 2025/1/14 02:02, fdmanana@kernel.org 写道:
> From: Filipe Manana <fdmanana@suse.com>
>
> If while we are doing a direct IO write a transaction abort happens, we
> mark all existing ordered extents with the BTRFS_ORDERED_IOERR flag (done
> at btrfs_destroy_ordered_extents()), and then after that if we enter
> btrfs_split_ordered_extent() and the ordered extent has bytes left
> (meaning we have a bio that doesn't cover the whole ordered extent, see
> details at btrfs_extract_ordered_extent()), we will fail on the following
> assertion at btrfs_split_ordered_extent():
>
>     ASSERT(!(flags & ~BTRFS_ORDERED_TYPE_FLAGS));
>
> because the BTRFS_ORDERED_IOERR flag is set and the definition of
> BTRFS_ORDERED_TYPE_FLAGS is just the union of all flags that identify the
> type of write (regular, nocow, prealloc, compressed, direct IO, encoded).
>
> Fix this by returning an error from btrfs_extract_ordered_extent() if we
> find the BTRFS_ORDERED_IOERR flag in the ordered extent. The error will
> be the error that resulted in the transaction abort or -EIO if no
> transaction abort happened.
>
> This was recently reported by syzbot with the following trace:
>
>     FAULT_INJECTION: forcing a failure.
>     name failslab, interval 1, probability 0, space 0, times 1
>     CPU: 0 UID: 0 PID: 5321 Comm: syz.0.0 Not tainted 6.13.0-rc5-syzkaller #0
>     Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
>     Call Trace:
>      <TASK>
>      __dump_stack lib/dump_stack.c:94 [inline]
>      dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120
>      fail_dump lib/fault-inject.c:53 [inline]
>      should_fail_ex+0x3b0/0x4e0 lib/fault-inject.c:154
>      should_failslab+0xac/0x100 mm/failslab.c:46
>      slab_pre_alloc_hook mm/slub.c:4072 [inline]
>      slab_alloc_node mm/slub.c:4148 [inline]
>      __do_kmalloc_node mm/slub.c:4297 [inline]
>      __kmalloc_noprof+0xdd/0x4c0 mm/slub.c:4310
>      kmalloc_noprof include/linux/slab.h:905 [inline]
>      kzalloc_noprof include/linux/slab.h:1037 [inline]
>      btrfs_chunk_alloc_add_chunk_item+0x244/0x1100 fs/btrfs/volumes.c:5742
>      reserve_chunk_space+0x1ca/0x2c0 fs/btrfs/block-group.c:4292
>      check_system_chunk fs/btrfs/block-group.c:4319 [inline]
>      do_chunk_alloc fs/btrfs/block-group.c:3891 [inline]
>      btrfs_chunk_alloc+0x77b/0xf80 fs/btrfs/block-group.c:4187
>      find_free_extent_update_loop fs/btrfs/extent-tree.c:4166 [inline]
>      find_free_extent+0x42d1/0x5810 fs/btrfs/extent-tree.c:4579
>      btrfs_reserve_extent+0x422/0x810 fs/btrfs/extent-tree.c:4672
>      btrfs_new_extent_direct fs/btrfs/direct-io.c:186 [inline]
>      btrfs_get_blocks_direct_write+0x706/0xfa0 fs/btrfs/direct-io.c:321
>      btrfs_dio_iomap_begin+0xbb7/0x1180 fs/btrfs/direct-io.c:525
>      iomap_iter+0x697/0xf60 fs/iomap/iter.c:90
>      __iomap_dio_rw+0xeb9/0x25b0 fs/iomap/direct-io.c:702
>      btrfs_dio_write fs/btrfs/direct-io.c:775 [inline]
>      btrfs_direct_write+0x610/0xa30 fs/btrfs/direct-io.c:880
>      btrfs_do_write_iter+0x2a0/0x760 fs/btrfs/file.c:1397
>      do_iter_readv_writev+0x600/0x880
>      vfs_writev+0x376/0xba0 fs/read_write.c:1050
>      do_pwritev fs/read_write.c:1146 [inline]
>      __do_sys_pwritev2 fs/read_write.c:1204 [inline]
>      __se_sys_pwritev2+0x196/0x2b0 fs/read_write.c:1195
>      do_syscall_x64 arch/x86/entry/common.c:52 [inline]
>      do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
>      entry_SYSCALL_64_after_hwframe+0x77/0x7f
>     RIP: 0033:0x7f1281f85d29
>     Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 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 a8 ff ff ff f7 d8 64 89 01 48
>     RSP: 002b:00007f12819fe038 EFLAGS: 00000246 ORIG_RAX: 0000000000000148
>     RAX: ffffffffffffffda RBX: 00007f1282176080 RCX: 00007f1281f85d29
>     RDX: 0000000000000001 RSI: 0000000020000240 RDI: 0000000000000005
>     RBP: 00007f12819fe090 R08: 0000000000000000 R09: 0000000000000003
>     R10: 0000000000007000 R11: 0000000000000246 R12: 0000000000000002
>     R13: 0000000000000000 R14: 00007f1282176080 R15: 00007ffcb9e23328
>      </TASK>
>     BTRFS error (device loop0 state A): Transaction aborted (error -12)
>     BTRFS: error (device loop0 state A) in btrfs_chunk_alloc_add_chunk_item:5745: errno=-12 Out of memory
>     BTRFS info (device loop0 state EA): forced readonly
>     assertion failed: !(flags & ~BTRFS_ORDERED_TYPE_FLAGS), in fs/btrfs/ordered-data.c:1234
>     ------------[ cut here ]------------
>     kernel BUG at fs/btrfs/ordered-data.c:1234!
>     Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI
>     CPU: 0 UID: 0 PID: 5321 Comm: syz.0.0 Not tainted 6.13.0-rc5-syzkaller #0
>     Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
>     RIP: 0010:btrfs_split_ordered_extent+0xd8d/0xe20 fs/btrfs/ordered-data.c:1234
>     Code: 43 fd 90 0f 0b e8 43 c4 db fd 48 c7 c7 20 0c 4c 8c 48 c7 c6 80 0f 4c 8c 48 c7 c2 e0 0b 4c 8c b9 d2 04 00 00 e8 04 57 43 fd 90 <0f> 0b e8 1c c4 db fd eb 5b e8 15 c4 db fd 48 c7 c7 20 0c 4c 8c 48
>     RSP: 0018:ffffc9000d1df2b8 EFLAGS: 00010246
>     RAX: 0000000000000057 RBX: 000000000006a000 RCX: 9ce21886c4195300
>     RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000
>     RBP: 0000000000000091 R08: ffffffff817f0a3c R09: 1ffff92001a3bdf4
>     R10: dffffc0000000000 R11: fffff52001a3bdf5 R12: 1ffff1100a45f401
>     R13: ffff8880522fa018 R14: dffffc0000000000 R15: 000000000006a000
>     FS:  00007f12819fe6c0(0000) GS:ffff88801fc00000(0000) knlGS:0000000000000000
>     CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>     CR2: 0000557750bd7da8 CR3: 00000000400ea000 CR4: 0000000000352ef0
>     DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
>     DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
>     Call Trace:
>      <TASK>
>      btrfs_extract_ordered_extent fs/btrfs/direct-io.c:702 [inline]
>      btrfs_dio_submit_io+0x4be/0x6d0 fs/btrfs/direct-io.c:737
>      iomap_dio_submit_bio fs/iomap/direct-io.c:85 [inline]
>      iomap_dio_bio_iter+0x1022/0x1740 fs/iomap/direct-io.c:447
>      __iomap_dio_rw+0x13b7/0x25b0 fs/iomap/direct-io.c:703
>      btrfs_dio_write fs/btrfs/direct-io.c:775 [inline]
>      btrfs_direct_write+0x610/0xa30 fs/btrfs/direct-io.c:880
>      btrfs_do_write_iter+0x2a0/0x760 fs/btrfs/file.c:1397
>      do_iter_readv_writev+0x600/0x880
>      vfs_writev+0x376/0xba0 fs/read_write.c:1050
>      do_pwritev fs/read_write.c:1146 [inline]
>      __do_sys_pwritev2 fs/read_write.c:1204 [inline]
>      __se_sys_pwritev2+0x196/0x2b0 fs/read_write.c:1195
>      do_syscall_x64 arch/x86/entry/common.c:52 [inline]
>      do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
>      entry_SYSCALL_64_after_hwframe+0x77/0x7f
>     RIP: 0033:0x7f1281f85d29
>     Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 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 a8 ff ff ff f7 d8 64 89 01 48
>     RSP: 002b:00007f12819fe038 EFLAGS: 00000246 ORIG_RAX: 0000000000000148
>     RAX: ffffffffffffffda RBX: 00007f1282176080 RCX: 00007f1281f85d29
>     RDX: 0000000000000001 RSI: 0000000020000240 RDI: 0000000000000005
>     RBP: 00007f12819fe090 R08: 0000000000000000 R09: 0000000000000003
>     R10: 0000000000007000 R11: 0000000000000246 R12: 0000000000000002
>     R13: 0000000000000000 R14: 00007f1282176080 R15: 00007ffcb9e23328
>      </TASK>
>     Modules linked in:
>     ---[ end trace 0000000000000000 ]---
>     RIP: 0010:btrfs_split_ordered_extent+0xd8d/0xe20 fs/btrfs/ordered-data.c:1234
>     Code: 43 fd 90 0f 0b e8 43 c4 db fd 48 c7 c7 20 0c 4c 8c 48 c7 c6 80 0f 4c 8c 48 c7 c2 e0 0b 4c 8c b9 d2 04 00 00 e8 04 57 43 fd 90 <0f> 0b e8 1c c4 db fd eb 5b e8 15 c4 db fd 48 c7 c7 20 0c 4c 8c 48
>     RSP: 0018:ffffc9000d1df2b8 EFLAGS: 00010246
>     RAX: 0000000000000057 RBX: 000000000006a000 RCX: 9ce21886c4195300
>     RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000
>     RBP: 0000000000000091 R08: ffffffff817f0a3c R09: 1ffff92001a3bdf4
>     R10: dffffc0000000000 R11: fffff52001a3bdf5 R12: 1ffff1100a45f401
>     R13: ffff8880522fa018 R14: dffffc0000000000 R15: 000000000006a000
>     FS:  00007f12819fe6c0(0000) GS:ffff88801fc00000(0000) knlGS:0000000000000000
>     CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>     CR2: 0000557750bd7da8 CR3: 00000000400ea000 CR4: 0000000000352ef0
>     DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
>     DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
>
> In this case the transaction abort was due to (an injected) memory
> allocation failure when attempting to allocate a new chunk.
>
> Reported-by: syzbot+f60d8337a5c8e8d92a77@syzkaller.appspotmail.com
> Link: https://lore.kernel.org/linux-btrfs/6777f2dd.050a0220.178762.0045.GAE@google.com/
> Fixes: 52b1fdca23ac ("btrfs: handle completed ordered extents in btrfs_split_ordered_extent")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>

Reviewed-by: Qu Wenruo <wqu@suse.com>

Thanks,
Qu

> ---
>   fs/btrfs/ordered-data.c | 12 ++++++++++++
>   1 file changed, 12 insertions(+)
>
> diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
> index 30eceaf829a7..3cf95a801086 100644
> --- a/fs/btrfs/ordered-data.c
> +++ b/fs/btrfs/ordered-data.c
> @@ -1229,6 +1229,18 @@ struct btrfs_ordered_extent *btrfs_split_ordered_extent(
>   	 */
>   	if (WARN_ON_ONCE(len >= ordered->num_bytes))
>   		return ERR_PTR(-EINVAL);
> +	/*
> +	 * If our ordered extent had an error there's no point in continuing.
> +	 * The error may have come from a transaction abort done either by this
> +	 * task or some other concurrent task, and the transaction abort path
> +	 * iterates over all existing ordered extents and sets the flag
> +	 * BTRFS_ORDERED_IOERR on them.
> +	 */
> +	if (unlikely(flags & BTRFS_ORDERED_IOERR)) {
> +		const int fs_error = BTRFS_FS_ERROR(fs_info);
> +
> +		return fs_error ? ERR_PTR(fs_error) : ERR_PTR(-EIO);
> +	}
>   	/* We cannot split partially completed ordered extents. */
>   	if (ordered->bytes_left) {
>   		ASSERT(!(flags & ~BTRFS_ORDERED_TYPE_FLAGS));
Filipe Manana Jan. 14, 2025, 6:52 p.m. UTC | #2
On Mon, Jan 13, 2025 at 9:12 PM Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
>
>
>
> 在 2025/1/14 02:02, fdmanana@kernel.org 写道:
> > From: Filipe Manana <fdmanana@suse.com>
> >
> > If while we are doing a direct IO write a transaction abort happens, we
> > mark all existing ordered extents with the BTRFS_ORDERED_IOERR flag (done
> > at btrfs_destroy_ordered_extents()), and then after that if we enter
> > btrfs_split_ordered_extent() and the ordered extent has bytes left
> > (meaning we have a bio that doesn't cover the whole ordered extent, see
> > details at btrfs_extract_ordered_extent()), we will fail on the following
> > assertion at btrfs_split_ordered_extent():
> >
> >     ASSERT(!(flags & ~BTRFS_ORDERED_TYPE_FLAGS));
> >
> > because the BTRFS_ORDERED_IOERR flag is set and the definition of
> > BTRFS_ORDERED_TYPE_FLAGS is just the union of all flags that identify the
> > type of write (regular, nocow, prealloc, compressed, direct IO, encoded).
> >
> > Fix this by returning an error from btrfs_extract_ordered_extent() if we
> > find the BTRFS_ORDERED_IOERR flag in the ordered extent. The error will
> > be the error that resulted in the transaction abort or -EIO if no
> > transaction abort happened.
> >
> > This was recently reported by syzbot with the following trace:
> >
> >     FAULT_INJECTION: forcing a failure.
> >     name failslab, interval 1, probability 0, space 0, times 1
> >     CPU: 0 UID: 0 PID: 5321 Comm: syz.0.0 Not tainted 6.13.0-rc5-syzkaller #0
> >     Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
> >     Call Trace:
> >      <TASK>
> >      __dump_stack lib/dump_stack.c:94 [inline]
> >      dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120
> >      fail_dump lib/fault-inject.c:53 [inline]
> >      should_fail_ex+0x3b0/0x4e0 lib/fault-inject.c:154
> >      should_failslab+0xac/0x100 mm/failslab.c:46
> >      slab_pre_alloc_hook mm/slub.c:4072 [inline]
> >      slab_alloc_node mm/slub.c:4148 [inline]
> >      __do_kmalloc_node mm/slub.c:4297 [inline]
> >      __kmalloc_noprof+0xdd/0x4c0 mm/slub.c:4310
> >      kmalloc_noprof include/linux/slab.h:905 [inline]
> >      kzalloc_noprof include/linux/slab.h:1037 [inline]
> >      btrfs_chunk_alloc_add_chunk_item+0x244/0x1100 fs/btrfs/volumes.c:5742
> >      reserve_chunk_space+0x1ca/0x2c0 fs/btrfs/block-group.c:4292
> >      check_system_chunk fs/btrfs/block-group.c:4319 [inline]
> >      do_chunk_alloc fs/btrfs/block-group.c:3891 [inline]
> >      btrfs_chunk_alloc+0x77b/0xf80 fs/btrfs/block-group.c:4187
> >      find_free_extent_update_loop fs/btrfs/extent-tree.c:4166 [inline]
> >      find_free_extent+0x42d1/0x5810 fs/btrfs/extent-tree.c:4579
> >      btrfs_reserve_extent+0x422/0x810 fs/btrfs/extent-tree.c:4672
> >      btrfs_new_extent_direct fs/btrfs/direct-io.c:186 [inline]
> >      btrfs_get_blocks_direct_write+0x706/0xfa0 fs/btrfs/direct-io.c:321
> >      btrfs_dio_iomap_begin+0xbb7/0x1180 fs/btrfs/direct-io.c:525
> >      iomap_iter+0x697/0xf60 fs/iomap/iter.c:90
> >      __iomap_dio_rw+0xeb9/0x25b0 fs/iomap/direct-io.c:702
> >      btrfs_dio_write fs/btrfs/direct-io.c:775 [inline]
> >      btrfs_direct_write+0x610/0xa30 fs/btrfs/direct-io.c:880
> >      btrfs_do_write_iter+0x2a0/0x760 fs/btrfs/file.c:1397
> >      do_iter_readv_writev+0x600/0x880
> >      vfs_writev+0x376/0xba0 fs/read_write.c:1050
> >      do_pwritev fs/read_write.c:1146 [inline]
> >      __do_sys_pwritev2 fs/read_write.c:1204 [inline]
> >      __se_sys_pwritev2+0x196/0x2b0 fs/read_write.c:1195
> >      do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> >      do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
> >      entry_SYSCALL_64_after_hwframe+0x77/0x7f
> >     RIP: 0033:0x7f1281f85d29
> >     Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 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 a8 ff ff ff f7 d8 64 89 01 48
> >     RSP: 002b:00007f12819fe038 EFLAGS: 00000246 ORIG_RAX: 0000000000000148
> >     RAX: ffffffffffffffda RBX: 00007f1282176080 RCX: 00007f1281f85d29
> >     RDX: 0000000000000001 RSI: 0000000020000240 RDI: 0000000000000005
> >     RBP: 00007f12819fe090 R08: 0000000000000000 R09: 0000000000000003
> >     R10: 0000000000007000 R11: 0000000000000246 R12: 0000000000000002
> >     R13: 0000000000000000 R14: 00007f1282176080 R15: 00007ffcb9e23328
> >      </TASK>
> >     BTRFS error (device loop0 state A): Transaction aborted (error -12)
> >     BTRFS: error (device loop0 state A) in btrfs_chunk_alloc_add_chunk_item:5745: errno=-12 Out of memory
> >     BTRFS info (device loop0 state EA): forced readonly
> >     assertion failed: !(flags & ~BTRFS_ORDERED_TYPE_FLAGS), in fs/btrfs/ordered-data.c:1234
> >     ------------[ cut here ]------------
> >     kernel BUG at fs/btrfs/ordered-data.c:1234!
> >     Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN NOPTI
> >     CPU: 0 UID: 0 PID: 5321 Comm: syz.0.0 Not tainted 6.13.0-rc5-syzkaller #0
> >     Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
> >     RIP: 0010:btrfs_split_ordered_extent+0xd8d/0xe20 fs/btrfs/ordered-data.c:1234
> >     Code: 43 fd 90 0f 0b e8 43 c4 db fd 48 c7 c7 20 0c 4c 8c 48 c7 c6 80 0f 4c 8c 48 c7 c2 e0 0b 4c 8c b9 d2 04 00 00 e8 04 57 43 fd 90 <0f> 0b e8 1c c4 db fd eb 5b e8 15 c4 db fd 48 c7 c7 20 0c 4c 8c 48
> >     RSP: 0018:ffffc9000d1df2b8 EFLAGS: 00010246
> >     RAX: 0000000000000057 RBX: 000000000006a000 RCX: 9ce21886c4195300
> >     RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000
> >     RBP: 0000000000000091 R08: ffffffff817f0a3c R09: 1ffff92001a3bdf4
> >     R10: dffffc0000000000 R11: fffff52001a3bdf5 R12: 1ffff1100a45f401
> >     R13: ffff8880522fa018 R14: dffffc0000000000 R15: 000000000006a000
> >     FS:  00007f12819fe6c0(0000) GS:ffff88801fc00000(0000) knlGS:0000000000000000
> >     CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> >     CR2: 0000557750bd7da8 CR3: 00000000400ea000 CR4: 0000000000352ef0
> >     DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> >     DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> >     Call Trace:
> >      <TASK>
> >      btrfs_extract_ordered_extent fs/btrfs/direct-io.c:702 [inline]
> >      btrfs_dio_submit_io+0x4be/0x6d0 fs/btrfs/direct-io.c:737
> >      iomap_dio_submit_bio fs/iomap/direct-io.c:85 [inline]
> >      iomap_dio_bio_iter+0x1022/0x1740 fs/iomap/direct-io.c:447
> >      __iomap_dio_rw+0x13b7/0x25b0 fs/iomap/direct-io.c:703
> >      btrfs_dio_write fs/btrfs/direct-io.c:775 [inline]
> >      btrfs_direct_write+0x610/0xa30 fs/btrfs/direct-io.c:880
> >      btrfs_do_write_iter+0x2a0/0x760 fs/btrfs/file.c:1397
> >      do_iter_readv_writev+0x600/0x880
> >      vfs_writev+0x376/0xba0 fs/read_write.c:1050
> >      do_pwritev fs/read_write.c:1146 [inline]
> >      __do_sys_pwritev2 fs/read_write.c:1204 [inline]
> >      __se_sys_pwritev2+0x196/0x2b0 fs/read_write.c:1195
> >      do_syscall_x64 arch/x86/entry/common.c:52 [inline]
> >      do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
> >      entry_SYSCALL_64_after_hwframe+0x77/0x7f
> >     RIP: 0033:0x7f1281f85d29
> >     Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 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 a8 ff ff ff f7 d8 64 89 01 48
> >     RSP: 002b:00007f12819fe038 EFLAGS: 00000246 ORIG_RAX: 0000000000000148
> >     RAX: ffffffffffffffda RBX: 00007f1282176080 RCX: 00007f1281f85d29
> >     RDX: 0000000000000001 RSI: 0000000020000240 RDI: 0000000000000005
> >     RBP: 00007f12819fe090 R08: 0000000000000000 R09: 0000000000000003
> >     R10: 0000000000007000 R11: 0000000000000246 R12: 0000000000000002
> >     R13: 0000000000000000 R14: 00007f1282176080 R15: 00007ffcb9e23328
> >      </TASK>
> >     Modules linked in:
> >     ---[ end trace 0000000000000000 ]---
> >     RIP: 0010:btrfs_split_ordered_extent+0xd8d/0xe20 fs/btrfs/ordered-data.c:1234
> >     Code: 43 fd 90 0f 0b e8 43 c4 db fd 48 c7 c7 20 0c 4c 8c 48 c7 c6 80 0f 4c 8c 48 c7 c2 e0 0b 4c 8c b9 d2 04 00 00 e8 04 57 43 fd 90 <0f> 0b e8 1c c4 db fd eb 5b e8 15 c4 db fd 48 c7 c7 20 0c 4c 8c 48
> >     RSP: 0018:ffffc9000d1df2b8 EFLAGS: 00010246
> >     RAX: 0000000000000057 RBX: 000000000006a000 RCX: 9ce21886c4195300
> >     RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000
> >     RBP: 0000000000000091 R08: ffffffff817f0a3c R09: 1ffff92001a3bdf4
> >     R10: dffffc0000000000 R11: fffff52001a3bdf5 R12: 1ffff1100a45f401
> >     R13: ffff8880522fa018 R14: dffffc0000000000 R15: 000000000006a000
> >     FS:  00007f12819fe6c0(0000) GS:ffff88801fc00000(0000) knlGS:0000000000000000
> >     CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> >     CR2: 0000557750bd7da8 CR3: 00000000400ea000 CR4: 0000000000352ef0
> >     DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> >     DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> >
> > In this case the transaction abort was due to (an injected) memory
> > allocation failure when attempting to allocate a new chunk.
> >
> > Reported-by: syzbot+f60d8337a5c8e8d92a77@syzkaller.appspotmail.com
> > Link: https://lore.kernel.org/linux-btrfs/6777f2dd.050a0220.178762.0045.GAE@google.com/
> > Fixes: 52b1fdca23ac ("btrfs: handle completed ordered extents in btrfs_split_ordered_extent")
> > Signed-off-by: Filipe Manana <fdmanana@suse.com>
>
> Reviewed-by: Qu Wenruo <wqu@suse.com>
>
> Thanks,
> Qu
>
> > ---
> >   fs/btrfs/ordered-data.c | 12 ++++++++++++
> >   1 file changed, 12 insertions(+)
> >
> > diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
> > index 30eceaf829a7..3cf95a801086 100644
> > --- a/fs/btrfs/ordered-data.c
> > +++ b/fs/btrfs/ordered-data.c
> > @@ -1229,6 +1229,18 @@ struct btrfs_ordered_extent *btrfs_split_ordered_extent(
> >        */
> >       if (WARN_ON_ONCE(len >= ordered->num_bytes))
> >               return ERR_PTR(-EINVAL);
> > +     /*
> > +      * If our ordered extent had an error there's no point in continuing.
> > +      * The error may have come from a transaction abort done either by this
> > +      * task or some other concurrent task, and the transaction abort path
> > +      * iterates over all existing ordered extents and sets the flag
> > +      * BTRFS_ORDERED_IOERR on them.
> > +      */
> > +     if (unlikely(flags & BTRFS_ORDERED_IOERR)) {

This should be:

flags & (1U << BTRFS_ORDERED_IOERR)

I'll fix it up when committing to for-next, thanks.

> > +             const int fs_error = BTRFS_FS_ERROR(fs_info);
> > +
> > +             return fs_error ? ERR_PTR(fs_error) : ERR_PTR(-EIO);
> > +     }
> >       /* We cannot split partially completed ordered extents. */
> >       if (ordered->bytes_left) {
> >               ASSERT(!(flags & ~BTRFS_ORDERED_TYPE_FLAGS));
>
diff mbox series

Patch

diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 30eceaf829a7..3cf95a801086 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -1229,6 +1229,18 @@  struct btrfs_ordered_extent *btrfs_split_ordered_extent(
 	 */
 	if (WARN_ON_ONCE(len >= ordered->num_bytes))
 		return ERR_PTR(-EINVAL);
+	/*
+	 * If our ordered extent had an error there's no point in continuing.
+	 * The error may have come from a transaction abort done either by this
+	 * task or some other concurrent task, and the transaction abort path
+	 * iterates over all existing ordered extents and sets the flag
+	 * BTRFS_ORDERED_IOERR on them.
+	 */
+	if (unlikely(flags & BTRFS_ORDERED_IOERR)) {
+		const int fs_error = BTRFS_FS_ERROR(fs_info);
+
+		return fs_error ? ERR_PTR(fs_error) : ERR_PTR(-EIO);
+	}
 	/* We cannot split partially completed ordered extents. */
 	if (ordered->bytes_left) {
 		ASSERT(!(flags & ~BTRFS_ORDERED_TYPE_FLAGS));