]> git.hungrycats.org Git - linux/commit
btrfs: use kvmalloc() for b-tree split_item()
authorQu Wenruo <wqu@suse.com>
Mon, 7 Sep 2026 22:17:39 +0000 (07:47 +0930)
committerDavid Sterba <dsterba@suse.com>
Mon, 14 Sep 2026 11:23:37 +0000 (13:23 +0200)
commit2969ddfd6aacf6628e50001d9fd535a196d28c66
tree45469456fe89cfb8109093db98197c07371bb5b7
parentf07031a890eef45f702cde01e5d5d007883ac857
btrfs: use kvmalloc() for b-tree split_item()

[BUG]
There is a bug report that the kmalloc() call inside split_item() failed
with the following call trace, and triggered a transaction abort:

  kworker/u69:8: page allocation failure: order:4, mode:0x40c40(GFP_NOFS|__GFP_COMP), nodemask=(null)
  CPU: 3 UID: 0 PID: 1154528 Comm: kworker/u69:8 Not tainted 7.0.2 #1 PREEMPTLAZY
  Workqueue: events_unbound btrfs_async_reclaim_metadata_space
  Call Trace:
   <TASK>
   dump_stack_lvl+0x47/0x60
   warn_alloc.cold+0x67/0xec
   __alloc_pages_slowpath.constprop.0+0x9bf/0xed0
   __alloc_frozen_pages_noprof+0x1ac/0x1c0
   ___kmalloc_large_node+0x9d/0xc0
   __kmalloc_noprof+0x17b/0x1f0
   split_item+0x9e/0x2e0
   btrfs_del_csums+0x285/0x400
   __btrfs_free_extent.isra.0+0x6de/0x12b0
   __btrfs_run_delayed_refs+0x522/0x10c0
   btrfs_run_delayed_refs+0x4d/0x1d0
   flush_space+0x34d/0x4e0
   do_async_reclaim_metadata_space+0x89/0x1d0
   btrfs_async_reclaim_metadata_space+0x44/0x60
   process_one_work+0x145/0x230
   worker_thread+0x185/0x2e0
   kthread+0xca/0x100
   ret_from_fork+0x14e/0x200
   ret_from_fork_asm+0x11/0x20
   </TASK>
  BTRFS error (device dm-3 state A): Transaction aborted (error -12)
  BTRFS: error (device dm-3 state A) in btrfs_del_csums:1053: errno=-12 Out of memory
  BTRFS info (device dm-3 state EA): forced readonly
  BTRFS: error (device dm-3 state EA) in do_free_extent_accounting:3168: errno=-12 Out of memory
  BTRFS error (device dm-3 state EA): failed to run delayed ref for logical 1202913873920 num_bytes 274432 type 184 action 2 ref_mod 1: -12
  BTRFS: error (device dm-3 state EA) in btrfs_run_delayed_refs:2247: errno=-12 Out of memory

[CAUSE]
The kmalloc() call is to allocate a buffer to store the full item.
However as shown in the above call trace, the order can be high (4), and
since we're using GFP_NOFS, it's impossible to reclaim memory by writing
back dirty pages.

When there is no physically contiguous memory left, such high order
allocation can easily fail, and if such kmalloc() happens in a critical
path we can trigger a transaction abort.

[FIX]
Instead of kmalloc(), which requires physically contiguous pages, use
kvmalloc().

There is no special requirement for physically contiguous pages here, we
just want virtually contiguous memory as a buffer.

Reported-by: xavierbachmeyer182 <xavierbachmeyer182@protonmail.com>
Link: https://lore.kernel.org/linux-btrfs/250decb0-d940-4fe6-9b54-d06e1b293a1b@suse.com/
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Daniel Vacek <neelx@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ctree.c