aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-09-15 19:57:42 -0400
committerChris Mason <chris.mason@oracle.com>2009-09-15 20:20:16 -0400
commit3e99d8eb347c93a5d38081380b8c9e69b203212e (patch)
tree1fde8df76b399c12827c2e2bd989e29e83d9994f
parent83ebade34bc1a90d0c3f77b87b940f336d075fda (diff)
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>
-rw-r--r--fs/btrfs/async-thread.c14
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)
74 unsigned long flags; 74 unsigned long flags;
75 spin_lock_irqsave(&worker->workers->lock, flags); 75 spin_lock_irqsave(&worker->workers->lock, flags);
76 worker->idle = 1; 76 worker->idle = 1;
77 list_move(&worker->worker_list, &worker->workers->idle_list); 77
78 /* the list may be empty if the worker is just starting */
79 if (!list_empty(&worker->worker_list)) {
80 list_move(&worker->worker_list,
81 &worker->workers->idle_list);
82 }
78 spin_unlock_irqrestore(&worker->workers->lock, flags); 83 spin_unlock_irqrestore(&worker->workers->lock, flags);
79 } 84 }
80} 85}
@@ -90,8 +95,11 @@ static void check_busy_worker(struct btrfs_worker_thread *worker)
90 unsigned long flags; 95 unsigned long flags;
91 spin_lock_irqsave(&worker->workers->lock, flags); 96 spin_lock_irqsave(&worker->workers->lock, flags);
92 worker->idle = 0; 97 worker->idle = 0;
93 list_move_tail(&worker->worker_list, 98
94 &worker->workers->worker_list); 99 if (!list_empty(&worker->worker_list)) {
100 list_move_tail(&worker->worker_list,
101 &worker->workers->worker_list);
102 }
95 spin_unlock_irqrestore(&worker->workers->lock, flags); 103 spin_unlock_irqrestore(&worker->workers->lock, flags);
96 } 104 }
97} 105}