diff options
author | Chris Mason <chris.mason@oracle.com> | 2009-09-16 01:57:42 +0200 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-09-16 02:20:16 +0200 |
commit | 3e99d8eb347c93a5d38081380b8c9e69b203212e (patch) | |
tree | 1fde8df76b399c12827c2e2bd989e29e83d9994f /fs/btrfs/async-thread.c | |
parent | Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/... (diff) | |
download | linux-3e99d8eb347c93a5d38081380b8c9e69b203212e.tar.xz linux-3e99d8eb347c93a5d38081380b8c9e69b203212e.zip |
Btrfs: fix async worker startup race
After a new worker thread starts, it is placed into the
list of idle threads. But, this may race with a
check for idle done by the worker thread itself, resulting
in a double list_add operation.
This fix adds a check to make sure the idle thread addition
is done properly.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/async-thread.c')
-rw-r--r-- | fs/btrfs/async-thread.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 6ea5cd0a595f..73df627ab8ab 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -74,7 +74,12 @@ static void check_idle_worker(struct btrfs_worker_thread *worker) unsigned long flags; spin_lock_irqsave(&worker->workers->lock, flags); worker->idle = 1; - list_move(&worker->worker_list, &worker->workers->idle_list); + + /* the list may be empty if the worker is just starting */ + if (!list_empty(&worker->worker_list)) { + list_move(&worker->worker_list, + &worker->workers->idle_list); + } spin_unlock_irqrestore(&worker->workers->lock, flags); } } @@ -90,8 +95,11 @@ static void check_busy_worker(struct btrfs_worker_thread *worker) unsigned long flags; spin_lock_irqsave(&worker->workers->lock, flags); worker->idle = 0; - list_move_tail(&worker->worker_list, - &worker->workers->worker_list); + + if (!list_empty(&worker->worker_list)) { + list_move_tail(&worker->worker_list, + &worker->workers->worker_list); + } spin_unlock_irqrestore(&worker->workers->lock, flags); } } |