diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/async-thread.c | 23 | ||||
-rw-r--r-- | fs/btrfs/async-thread.h | 3 |
2 files changed, 16 insertions, 10 deletions
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index f10c895224ae..4b4372df3b6d 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c | |||
@@ -124,14 +124,12 @@ out: | |||
124 | static noinline int run_ordered_completions(struct btrfs_workers *workers, | 124 | static noinline int run_ordered_completions(struct btrfs_workers *workers, |
125 | struct btrfs_work *work) | 125 | struct btrfs_work *work) |
126 | { | 126 | { |
127 | unsigned long flags; | ||
128 | |||
129 | if (!workers->ordered) | 127 | if (!workers->ordered) |
130 | return 0; | 128 | return 0; |
131 | 129 | ||
132 | set_bit(WORK_DONE_BIT, &work->flags); | 130 | set_bit(WORK_DONE_BIT, &work->flags); |
133 | 131 | ||
134 | spin_lock_irqsave(&workers->lock, flags); | 132 | spin_lock(&workers->order_lock); |
135 | 133 | ||
136 | while (1) { | 134 | while (1) { |
137 | if (!list_empty(&workers->prio_order_list)) { | 135 | if (!list_empty(&workers->prio_order_list)) { |
@@ -154,17 +152,17 @@ static noinline int run_ordered_completions(struct btrfs_workers *workers, | |||
154 | if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags)) | 152 | if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags)) |
155 | break; | 153 | break; |
156 | 154 | ||
157 | spin_unlock_irqrestore(&workers->lock, flags); | 155 | spin_unlock(&workers->order_lock); |
158 | 156 | ||
159 | work->ordered_func(work); | 157 | work->ordered_func(work); |
160 | 158 | ||
161 | /* now take the lock again and call the freeing code */ | 159 | /* now take the lock again and call the freeing code */ |
162 | spin_lock_irqsave(&workers->lock, flags); | 160 | spin_lock(&workers->order_lock); |
163 | list_del(&work->order_list); | 161 | list_del(&work->order_list); |
164 | work->ordered_free(work); | 162 | work->ordered_free(work); |
165 | } | 163 | } |
166 | 164 | ||
167 | spin_unlock_irqrestore(&workers->lock, flags); | 165 | spin_unlock(&workers->order_lock); |
168 | return 0; | 166 | return 0; |
169 | } | 167 | } |
170 | 168 | ||
@@ -345,6 +343,7 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max) | |||
345 | INIT_LIST_HEAD(&workers->order_list); | 343 | INIT_LIST_HEAD(&workers->order_list); |
346 | INIT_LIST_HEAD(&workers->prio_order_list); | 344 | INIT_LIST_HEAD(&workers->prio_order_list); |
347 | spin_lock_init(&workers->lock); | 345 | spin_lock_init(&workers->lock); |
346 | spin_lock_init(&workers->order_lock); | ||
348 | workers->max_workers = max; | 347 | workers->max_workers = max; |
349 | workers->idle_thresh = 32; | 348 | workers->idle_thresh = 32; |
350 | workers->name = name; | 349 | workers->name = name; |
@@ -374,6 +373,7 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) | |||
374 | INIT_LIST_HEAD(&worker->prio_pending); | 373 | INIT_LIST_HEAD(&worker->prio_pending); |
375 | INIT_LIST_HEAD(&worker->worker_list); | 374 | INIT_LIST_HEAD(&worker->worker_list); |
376 | spin_lock_init(&worker->lock); | 375 | spin_lock_init(&worker->lock); |
376 | |||
377 | atomic_set(&worker->num_pending, 0); | 377 | atomic_set(&worker->num_pending, 0); |
378 | atomic_set(&worker->refs, 1); | 378 | atomic_set(&worker->refs, 1); |
379 | worker->workers = workers; | 379 | worker->workers = workers; |
@@ -453,10 +453,8 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) | |||
453 | again: | 453 | again: |
454 | spin_lock_irqsave(&workers->lock, flags); | 454 | spin_lock_irqsave(&workers->lock, flags); |
455 | worker = next_worker(workers); | 455 | worker = next_worker(workers); |
456 | spin_unlock_irqrestore(&workers->lock, flags); | ||
457 | 456 | ||
458 | if (!worker) { | 457 | if (!worker) { |
459 | spin_lock_irqsave(&workers->lock, flags); | ||
460 | if (workers->num_workers >= workers->max_workers) { | 458 | if (workers->num_workers >= workers->max_workers) { |
461 | goto fallback; | 459 | goto fallback; |
462 | } else if (workers->atomic_worker_start) { | 460 | } else if (workers->atomic_worker_start) { |
@@ -469,6 +467,7 @@ again: | |||
469 | goto again; | 467 | goto again; |
470 | } | 468 | } |
471 | } | 469 | } |
470 | spin_unlock_irqrestore(&workers->lock, flags); | ||
472 | return worker; | 471 | return worker; |
473 | 472 | ||
474 | fallback: | 473 | fallback: |
@@ -552,14 +551,18 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) | |||
552 | 551 | ||
553 | worker = find_worker(workers); | 552 | worker = find_worker(workers); |
554 | if (workers->ordered) { | 553 | if (workers->ordered) { |
555 | spin_lock_irqsave(&workers->lock, flags); | 554 | /* |
555 | * you're not allowed to do ordered queues from an | ||
556 | * interrupt handler | ||
557 | */ | ||
558 | spin_lock(&workers->order_lock); | ||
556 | if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) { | 559 | if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) { |
557 | list_add_tail(&work->order_list, | 560 | list_add_tail(&work->order_list, |
558 | &workers->prio_order_list); | 561 | &workers->prio_order_list); |
559 | } else { | 562 | } else { |
560 | list_add_tail(&work->order_list, &workers->order_list); | 563 | list_add_tail(&work->order_list, &workers->order_list); |
561 | } | 564 | } |
562 | spin_unlock_irqrestore(&workers->lock, flags); | 565 | spin_unlock(&workers->order_lock); |
563 | } else { | 566 | } else { |
564 | INIT_LIST_HEAD(&work->order_list); | 567 | INIT_LIST_HEAD(&work->order_list); |
565 | } | 568 | } |
diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index a562ad8d83aa..fc089b95ec14 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h | |||
@@ -99,6 +99,9 @@ struct btrfs_workers { | |||
99 | /* lock for finding the next worker thread to queue on */ | 99 | /* lock for finding the next worker thread to queue on */ |
100 | spinlock_t lock; | 100 | spinlock_t lock; |
101 | 101 | ||
102 | /* lock for the ordered lists */ | ||
103 | spinlock_t order_lock; | ||
104 | |||
102 | /* extra name for this worker, used for current->name */ | 105 | /* extra name for this worker, used for current->name */ |
103 | char *name; | 106 | char *name; |
104 | }; | 107 | }; |