* [PATCH] btrfs: dev-replace: fix missing barrier before waking bio counter waiters
@ 2026-08-22 14:44 FAN YE via B4 Relay
0 siblings, 0 replies; only message in thread
From: FAN YE via B4 Relay @ 2026-08-22 14:44 UTC (permalink / raw)
To: Chris Mason, David Sterba; +Cc: linux-btrfs, linux-kernel
From: FAN YE <fy15309206903@gmail.com>
btrfs_bio_counter_sub() gates the wakeup on cond_wake_up_nomb(), whose
bare waitqueue_active() requires a full barrier from the preceding code.
percpu_counter_sub() does not provide one, its fast path is a plain
per-cpu update, so the waitqueue_active() load can be hoisted over the
counter update. btrfs_rm_dev_replace_blocked() waits for
percpu_counter_sum() to reach zero and can then be left sleeping by the
very decrement that reaches it. It stays asleep until some unrelated
later decrement wakes it, with BTRFS_FS_STATE_DEV_REPLACING set the whole
time, so every bio submitter on the filesystem blocks as well.
Use cond_wake_up(), which has the barrier.
Fixes: 4245215d6a8d ("Btrfs, raid56: fix use-after-free problem in the final device replace procedure on raid56")
Assisted-by: Claude:claude-opus-5
Signed-off-by: FAN YE <fy15309206903@gmail.com>
---
Two independent checks. A litmus test of the same shape: herd7 with the LKMM
allows the interleaving and forbids it with smp_mb(); built with klitmus7 it
hits 349326 times in 64000000 iterations on x86_64, 0 times with the barrier.
With that interleaving staged in the dev-replace path in a VM (the last
in-flight bio released while the finishing waiter is queueing), the wakeup is
lost in 3/3 runs and the filesystem stalls for 24.5s until an unrelated
decrement arrives, 0/3 with this patch. Gating the barrier on
BTRFS_FS_STATE_DEV_REPLACING to keep it off the common path does not work:
that test_bit() is unordered as well, and hoisting it over the decrement drops
the wakeup in 3/3 runs. Compile-tested (W=1, x86_64 defconfig +
CONFIG_BTRFS_FS=y).
---
fs/btrfs/dev-replace.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index dc0834f920c3..b2791480e263 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -1353,7 +1353,7 @@ bool __pure btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace)
void btrfs_bio_counter_sub(struct btrfs_fs_info *fs_info, s64 amount)
{
percpu_counter_sub(&fs_info->dev_replace.bio_counter, amount);
- cond_wake_up_nomb(&fs_info->dev_replace.replace_wait);
+ cond_wake_up(&fs_info->dev_replace.replace_wait);
}
void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info)
---
base-commit: 26260251022fbc2f248a3d747a9b2b961b18d2d8
change-id: 20260822-btrfs-dev-replace-bio-counter-barrier-4a20eb35187a
Best regards,
--
FAN YE <fy15309206903@gmail.com>
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-08-22 14:44 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-22 14:44 [PATCH] btrfs: dev-replace: fix missing barrier before waking bio counter waiters FAN YE via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox