mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 12:34:02 +02:00
btrfs: zstd: fix lost wakeup when waiting for a workspace
A writer can sleep forever in zstd_get_workspace() even though a workspace
is free. When zstd_alloc_workspace() fails, the task is queued on
zwsm->wait and schedules unconditionally, never re-testing the pool.
zstd_put_workspace() publishes the workspace and then calls cond_wake_up(),
which only wakes when a sleeper is already visible, so a workspace returned
between the failed allocation and prepare_to_wait() wakes nobody. The
window is wide: zstd_alloc_workspace() goes through kvmalloc() and may
enter reclaim.
Only a max level workspace triggers the wakeup and one is deliberately kept
allocated as the fallback every waiter waits for, so once its wakeup is
lost the writer stays in TASK_UNINTERRUPTIBLE until some other task happens
to return one. Re-check the pool after prepare_to_wait() has published the
waiter, and use the workspace if one turned up.
Fixes: 3f93aef535 ("btrfs: add zstd compression level support")
Assisted-by: Claude:claude-opus-5
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: FAN YE <fy15309206903@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
cacf358322
commit
2acb9f3d1c
|
|
@ -307,8 +307,17 @@ struct list_head *zstd_get_workspace(struct btrfs_fs_info *fs_info, int level)
|
|||
DEFINE_WAIT(wait);
|
||||
|
||||
prepare_to_wait(&zwsm->wait, &wait, TASK_UNINTERRUPTIBLE);
|
||||
schedule();
|
||||
/*
|
||||
* Re-check after being queued: zstd_put_workspace() only wakes
|
||||
* a queue that already has a sleeper, so a workspace returned
|
||||
* since the failed allocation woke nobody.
|
||||
*/
|
||||
ws = zstd_find_workspace(fs_info, level);
|
||||
if (!ws)
|
||||
schedule();
|
||||
finish_wait(&zwsm->wait, &wait);
|
||||
if (ws)
|
||||
return ws;
|
||||
|
||||
goto again;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user