From: "Paul E. McKenney" <paulmck(a)kernel.org>
[ Upstream commit 6bc6e6b27524304aadb9c04611ddb1c84dd7617a ]
The ref_scale_shutdown() kthread/function uses wait_event() to wait for
the refscale test to complete. However, although the read-side tests
are normally extremely fast, there is no law against specifying a very
large value for the refscale.loops module parameter or against having
a slow read-side primitive. Either way, this might well trigger the
hung-task timeout.
This commit therefore replaces those wait_event() calls with calls to
wait_event_idle(), which do not trigger the hung-task timeout.
Signed-off-by: Paul E. McKenney <paulmck(a)kernel.org>
Signed-off-by: Boqun Feng <boqun.feng(a)gmail.com>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
---
kernel/rcu/refscale.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/rcu/refscale.c b/kernel/rcu/refscale.c
index afa3e1a2f6902..1970ce5f22d40 100644
--- a/kernel/rcu/refscale.c
+++ b/kernel/rcu/refscale.c
@@ -1031,7 +1031,7 @@ ref_scale_cleanup(void)
static int
ref_scale_shutdown(void *arg)
{
- wait_event(shutdown_wq, shutdown_start);
+ wait_event_idle(shutdown_wq, shutdown_start);
smp_mb(); // Wake before output.
ref_scale_cleanup();
--
2.39.2
[BUG]
Syzbot reported an ASSERT() got triggered during a scrub repair along
with balance:
BTRFS info (device loop5): balance: start -d -m
BTRFS info (device loop5): relocating block group 6881280 flags data|metadata
BTRFS info (device loop5): found 3 extents, stage: move data extents
BTRFS info (device loop5): scrub: started on devid 1
BTRFS info (device loop5): relocating block group 5242880 flags data|metadata
BTRFS info (device loop5): found 6 extents, stage: move data extents
BTRFS info (device loop5): found 1 extents, stage: update data pointers
BTRFS warning (device loop5): tree block 5500928 mirror 1 has bad bytenr, has 0 want 5500928
BTRFS info (device loop5): balance: ended with status: 0
BTRFS warning (device loop5): tree block 5435392 mirror 1 has bad bytenr, has 0 want 5435392
BTRFS warning (device loop5): tree block 5423104 mirror 1 has bad bytenr, has 0 want 5423104
assertion failed: 0, in fs/btrfs/scrub.c:614
------------[ cut here ]------------
kernel BUG at fs/btrfs/messages.c:259!
invalid opcode: 0000 [#2] PREEMPT SMP KASAN
Call Trace:
<TASK>
lock_full_stripe fs/btrfs/scrub.c:614 [inline]
scrub_handle_errored_block+0x1ee1/0x4730 fs/btrfs/scrub.c:1067
scrub_bio_end_io_worker+0x9bb/0x1370 fs/btrfs/scrub.c:2559
process_one_work+0x8a0/0x10e0 kernel/workqueue.c:2390
worker_thread+0xa63/0x1210 kernel/workqueue.c:2537
kthread+0x270/0x300 kernel/kthread.c:376
ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:308
</TASK>
[CAUSE]
Btrfs can delete empty block groups either through auto-cleanup or
relcation.
Scrub normally is able to handle this situation well by doing extra
checking, and holding the block group cache pointer during the whole
scrub lifespan.
But unfortunately for lock_full_stripe() and unlock_full_stripe()
functions, due to the context restriction, they have to do an extra
search on the block group cache.
(While the main scrub threads holds a proper btrfs_block_group, but we
have no way to directly use that in repair context).
Thus it can happen that the target block group is already deleted by
relocation.
In that case, we trigger the above ASSERT().
[FIX]
Instead of triggering the ASSERT(), let's just return 0 and continue,
this would leave @locked_ret to be false, and we won't try to unlock
later.
CC: stable(a)vger.kernel.org
Signed-off-by: Qu Wenruo <wqu(a)suse.com>
---
There would be no upstream commit, as upstream has completely rewritten
the scrub code in v6.4 merge window, and gets rid of the
lock_full_stripe()/unlock_full_stripe() functions.
I hope we don't have more scrub fixes which would only apply to older
kernels.
---
fs/btrfs/scrub.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 69c93ae333f6..43d0613c0dd3 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -610,10 +610,9 @@ static int lock_full_stripe(struct btrfs_fs_info *fs_info, u64 bytenr,
*locked_ret = false;
bg_cache = btrfs_lookup_block_group(fs_info, bytenr);
- if (!bg_cache) {
- ASSERT(0);
- return -ENOENT;
- }
+ /* The block group is removed, no need to do any lock. */
+ if (!bg_cache)
+ return 0;
/* Profiles not based on parity don't need full stripe lock */
if (!(bg_cache->flags & BTRFS_BLOCK_GROUP_RAID56_MASK))
--
2.39.2