]> git.ipfire.org Git - thirdparty/kernel/linux.git/commit
btrfs: flush the fixup workers during close_ctree
authorBoris Burkov <boris@bur.io>
Thu, 30 Jul 2026 16:38:02 +0000 (09:38 -0700)
committerDavid Sterba <dsterba@suse.com>
Mon, 3 Aug 2026 22:59:16 +0000 (00:59 +0200)
commitae2567b11c3df43861d05f856bdb3434b3961aa1
tree36c68896815f62e7fa985742ca0c6c721baa3387
parent0680cbbf39ca61c70be16141b5259f822e7cdb3b
btrfs: flush the fixup workers during close_ctree

Reintroducing the COW fixup worker brought back the unmount race fixed
by commit 41fd1e94066a ("btrfs: wait for fixup workers before stopping
cleaner kthread during umount") without bringing back the fix.

A fixup work item queued by the final writeback pass can still be in flight
when close_ctree() stops the cleaner kthread and frees the fs roots.
While destroy_workqueue() drains the queue, that happens after the
cleaner thread was freed, so btrfs_add_delayed_iput() called from the
fixup worker is no longer safe (not to mention that we are already in
BTRFS_FS_STATE_NO_DELAYED_IPUT when it runs).

Therefore we need to bring back explicitly flushing the fixup workqueue
as in Filipe's original fix. The first flush will catch all the fixup
writeback queued during the final sync before umount, but some of that
might hit memory allocation errors and stay fixup in the blocks/folio,
leading any subsequent writeback triggered *inside* umount (e.g. reclaim
workers shutting down) to hit it and queue again. To fix that, and the
possibility of any really long-lived pinned folios getting marked, deny
queueing new fixup during umount. That allows us to flush twice (once
before doing a real writeback pass to get the actual data, second time
to clean up any rather unlikely stragglers right before declaring
BTRFS_FS_STATE_NO_DELAYED_IPUT) and be certain nothing got re-queued.

Reproduced by injecting a one-shot 30s sleep at the head of
btrfs_writepage_fixup_worker() on a KASAN kernel, running the normal
reproducing read dio workload before unmount and then observing:

  BUG: KASAN: slab-use-after-free in _raw_spin_lock_irqsave+0x35/0x50
  Read of size 1 at addr ffff88810b4b08f8 by task kworker/u32:5/219
  Workqueue: btrfs-fixup btrfs_writepage_fixup_worker [btrfs]
  Call Trace:
   _raw_spin_lock_irqsave+0x35/0x50
   try_to_wake_up+0xc0/0x18c0
   btrfs_writepage_fixup_worker+0x7f3/0xf20 [btrfs]
  ...

Fixes: 4be9c7da6860 ("btrfs: trigger cow fixup via dirty_folio()")
Assisted-by: LLM (reproduction, analysis)
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/disk-io.c
fs/btrfs/inode.c