diff options
Diffstat (limited to 'fs/btrfs/async-thread.c')
| -rw-r--r-- | fs/btrfs/async-thread.c | 146 |
1 files changed, 71 insertions, 75 deletions
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 7ec14097fef1..58b7d14b08ee 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c | |||
| @@ -64,6 +64,8 @@ struct btrfs_worker_thread { | |||
| 64 | int idle; | 64 | int idle; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | static int __btrfs_start_workers(struct btrfs_workers *workers); | ||
| 68 | |||
| 67 | /* | 69 | /* |
| 68 | * btrfs_start_workers uses kthread_run, which can block waiting for memory | 70 | * btrfs_start_workers uses kthread_run, which can block waiting for memory |
| 69 | * for a very long time. It will actually throttle on page writeback, | 71 | * for a very long time. It will actually throttle on page writeback, |
| @@ -88,27 +90,10 @@ static void start_new_worker_func(struct btrfs_work *work) | |||
| 88 | { | 90 | { |
| 89 | struct worker_start *start; | 91 | struct worker_start *start; |
| 90 | start = container_of(work, struct worker_start, work); | 92 | start = container_of(work, struct worker_start, work); |
| 91 | btrfs_start_workers(start->queue, 1); | 93 | __btrfs_start_workers(start->queue); |
| 92 | kfree(start); | 94 | kfree(start); |
| 93 | } | 95 | } |
| 94 | 96 | ||
| 95 | static int start_new_worker(struct btrfs_workers *queue) | ||
| 96 | { | ||
| 97 | struct worker_start *start; | ||
| 98 | int ret; | ||
| 99 | |||
| 100 | start = kzalloc(sizeof(*start), GFP_NOFS); | ||
| 101 | if (!start) | ||
| 102 | return -ENOMEM; | ||
| 103 | |||
| 104 | start->work.func = start_new_worker_func; | ||
| 105 | start->queue = queue; | ||
| 106 | ret = btrfs_queue_worker(queue->atomic_worker_start, &start->work); | ||
| 107 | if (ret) | ||
| 108 | kfree(start); | ||
| 109 | return ret; | ||
| 110 | } | ||
| 111 | |||
| 112 | /* | 97 | /* |
| 113 | * helper function to move a thread onto the idle list after it | 98 | * helper function to move a thread onto the idle list after it |
| 114 | * has finished some requests. | 99 | * has finished some requests. |
| @@ -153,12 +138,20 @@ static void check_busy_worker(struct btrfs_worker_thread *worker) | |||
| 153 | static void check_pending_worker_creates(struct btrfs_worker_thread *worker) | 138 | static void check_pending_worker_creates(struct btrfs_worker_thread *worker) |
| 154 | { | 139 | { |
| 155 | struct btrfs_workers *workers = worker->workers; | 140 | struct btrfs_workers *workers = worker->workers; |
| 141 | struct worker_start *start; | ||
| 156 | unsigned long flags; | 142 | unsigned long flags; |
| 157 | 143 | ||
| 158 | rmb(); | 144 | rmb(); |
| 159 | if (!workers->atomic_start_pending) | 145 | if (!workers->atomic_start_pending) |
| 160 | return; | 146 | return; |
| 161 | 147 | ||
| 148 | start = kzalloc(sizeof(*start), GFP_NOFS); | ||
| 149 | if (!start) | ||
| 150 | return; | ||
| 151 | |||
| 152 | start->work.func = start_new_worker_func; | ||
| 153 | start->queue = workers; | ||
| 154 | |||
| 162 | spin_lock_irqsave(&workers->lock, flags); | 155 | spin_lock_irqsave(&workers->lock, flags); |
| 163 | if (!workers->atomic_start_pending) | 156 | if (!workers->atomic_start_pending) |
| 164 | goto out; | 157 | goto out; |
| @@ -170,18 +163,19 @@ static void check_pending_worker_creates(struct btrfs_worker_thread *worker) | |||
| 170 | 163 | ||
| 171 | workers->num_workers_starting += 1; | 164 | workers->num_workers_starting += 1; |
| 172 | spin_unlock_irqrestore(&workers->lock, flags); | 165 | spin_unlock_irqrestore(&workers->lock, flags); |
| 173 | start_new_worker(workers); | 166 | btrfs_queue_worker(workers->atomic_worker_start, &start->work); |
| 174 | return; | 167 | return; |
| 175 | 168 | ||
| 176 | out: | 169 | out: |
| 170 | kfree(start); | ||
| 177 | spin_unlock_irqrestore(&workers->lock, flags); | 171 | spin_unlock_irqrestore(&workers->lock, flags); |
| 178 | } | 172 | } |
| 179 | 173 | ||
| 180 | static noinline int run_ordered_completions(struct btrfs_workers *workers, | 174 | static noinline void run_ordered_completions(struct btrfs_workers *workers, |
| 181 | struct btrfs_work *work) | 175 | struct btrfs_work *work) |
| 182 | { | 176 | { |
| 183 | if (!workers->ordered) | 177 | if (!workers->ordered) |
| 184 | return 0; | 178 | return; |
| 185 | 179 | ||
| 186 | set_bit(WORK_DONE_BIT, &work->flags); | 180 | set_bit(WORK_DONE_BIT, &work->flags); |
| 187 | 181 | ||
| @@ -212,14 +206,20 @@ static noinline int run_ordered_completions(struct btrfs_workers *workers, | |||
| 212 | 206 | ||
| 213 | work->ordered_func(work); | 207 | work->ordered_func(work); |
| 214 | 208 | ||
| 215 | /* now take the lock again and call the freeing code */ | 209 | /* now take the lock again and drop our item from the list */ |
| 216 | spin_lock(&workers->order_lock); | 210 | spin_lock(&workers->order_lock); |
| 217 | list_del(&work->order_list); | 211 | list_del(&work->order_list); |
| 212 | spin_unlock(&workers->order_lock); | ||
| 213 | |||
| 214 | /* | ||
| 215 | * we don't want to call the ordered free functions | ||
| 216 | * with the lock held though | ||
| 217 | */ | ||
| 218 | work->ordered_free(work); | 218 | work->ordered_free(work); |
| 219 | spin_lock(&workers->order_lock); | ||
| 219 | } | 220 | } |
| 220 | 221 | ||
| 221 | spin_unlock(&workers->order_lock); | 222 | spin_unlock(&workers->order_lock); |
| 222 | return 0; | ||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | static void put_worker(struct btrfs_worker_thread *worker) | 225 | static void put_worker(struct btrfs_worker_thread *worker) |
| @@ -331,7 +331,7 @@ again: | |||
| 331 | run_ordered_completions(worker->workers, work); | 331 | run_ordered_completions(worker->workers, work); |
| 332 | 332 | ||
| 333 | check_pending_worker_creates(worker); | 333 | check_pending_worker_creates(worker); |
| 334 | 334 | cond_resched(); | |
| 335 | } | 335 | } |
| 336 | 336 | ||
| 337 | spin_lock_irq(&worker->lock); | 337 | spin_lock_irq(&worker->lock); |
| @@ -340,7 +340,7 @@ again: | |||
| 340 | if (freezing(current)) { | 340 | if (freezing(current)) { |
| 341 | worker->working = 0; | 341 | worker->working = 0; |
| 342 | spin_unlock_irq(&worker->lock); | 342 | spin_unlock_irq(&worker->lock); |
| 343 | refrigerator(); | 343 | try_to_freeze(); |
| 344 | } else { | 344 | } else { |
| 345 | spin_unlock_irq(&worker->lock); | 345 | spin_unlock_irq(&worker->lock); |
| 346 | if (!kthread_should_stop()) { | 346 | if (!kthread_should_stop()) { |
| @@ -405,7 +405,7 @@ again: | |||
| 405 | /* | 405 | /* |
| 406 | * this will wait for all the worker threads to shutdown | 406 | * this will wait for all the worker threads to shutdown |
| 407 | */ | 407 | */ |
| 408 | int btrfs_stop_workers(struct btrfs_workers *workers) | 408 | void btrfs_stop_workers(struct btrfs_workers *workers) |
| 409 | { | 409 | { |
| 410 | struct list_head *cur; | 410 | struct list_head *cur; |
| 411 | struct btrfs_worker_thread *worker; | 411 | struct btrfs_worker_thread *worker; |
| @@ -433,7 +433,6 @@ int btrfs_stop_workers(struct btrfs_workers *workers) | |||
| 433 | put_worker(worker); | 433 | put_worker(worker); |
| 434 | } | 434 | } |
| 435 | spin_unlock_irq(&workers->lock); | 435 | spin_unlock_irq(&workers->lock); |
| 436 | return 0; | ||
| 437 | } | 436 | } |
| 438 | 437 | ||
| 439 | /* | 438 | /* |
| @@ -462,56 +461,55 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max, | |||
| 462 | * starts new worker threads. This does not enforce the max worker | 461 | * starts new worker threads. This does not enforce the max worker |
| 463 | * count in case you need to temporarily go past it. | 462 | * count in case you need to temporarily go past it. |
| 464 | */ | 463 | */ |
| 465 | static int __btrfs_start_workers(struct btrfs_workers *workers, | 464 | static int __btrfs_start_workers(struct btrfs_workers *workers) |
| 466 | int num_workers) | ||
| 467 | { | 465 | { |
| 468 | struct btrfs_worker_thread *worker; | 466 | struct btrfs_worker_thread *worker; |
| 469 | int ret = 0; | 467 | int ret = 0; |
| 470 | int i; | ||
| 471 | 468 | ||
| 472 | for (i = 0; i < num_workers; i++) { | 469 | worker = kzalloc(sizeof(*worker), GFP_NOFS); |
| 473 | worker = kzalloc(sizeof(*worker), GFP_NOFS); | 470 | if (!worker) { |
| 474 | if (!worker) { | 471 | ret = -ENOMEM; |
| 475 | ret = -ENOMEM; | 472 | goto fail; |
| 476 | goto fail; | 473 | } |
| 477 | } | ||
| 478 | 474 | ||
| 479 | INIT_LIST_HEAD(&worker->pending); | 475 | INIT_LIST_HEAD(&worker->pending); |
| 480 | INIT_LIST_HEAD(&worker->prio_pending); | 476 | INIT_LIST_HEAD(&worker->prio_pending); |
| 481 | INIT_LIST_HEAD(&worker->worker_list); | 477 | INIT_LIST_HEAD(&worker->worker_list); |
| 482 | spin_lock_init(&worker->lock); | 478 | spin_lock_init(&worker->lock); |
| 483 | 479 | ||
| 484 | atomic_set(&worker->num_pending, 0); | 480 | atomic_set(&worker->num_pending, 0); |
| 485 | atomic_set(&worker->refs, 1); | 481 | atomic_set(&worker->refs, 1); |
| 486 | worker->workers = workers; | 482 | worker->workers = workers; |
| 487 | worker->task = kthread_run(worker_loop, worker, | 483 | worker->task = kthread_run(worker_loop, worker, |
| 488 | "btrfs-%s-%d", workers->name, | 484 | "btrfs-%s-%d", workers->name, |
| 489 | workers->num_workers + i); | 485 | workers->num_workers + 1); |
| 490 | if (IS_ERR(worker->task)) { | 486 | if (IS_ERR(worker->task)) { |
| 491 | ret = PTR_ERR(worker->task); | 487 | ret = PTR_ERR(worker->task); |
| 492 | kfree(worker); | 488 | kfree(worker); |
| 493 | goto fail; | 489 | goto fail; |
| 494 | } | ||
| 495 | spin_lock_irq(&workers->lock); | ||
| 496 | list_add_tail(&worker->worker_list, &workers->idle_list); | ||
| 497 | worker->idle = 1; | ||
| 498 | workers->num_workers++; | ||
| 499 | workers->num_workers_starting--; | ||
| 500 | WARN_ON(workers->num_workers_starting < 0); | ||
| 501 | spin_unlock_irq(&workers->lock); | ||
| 502 | } | 490 | } |
| 491 | spin_lock_irq(&workers->lock); | ||
| 492 | list_add_tail(&worker->worker_list, &workers->idle_list); | ||
| 493 | worker->idle = 1; | ||
| 494 | workers->num_workers++; | ||
| 495 | workers->num_workers_starting--; | ||
| 496 | WARN_ON(workers->num_workers_starting < 0); | ||
| 497 | spin_unlock_irq(&workers->lock); | ||
| 498 | |||
| 503 | return 0; | 499 | return 0; |
| 504 | fail: | 500 | fail: |
| 505 | btrfs_stop_workers(workers); | 501 | spin_lock_irq(&workers->lock); |
| 502 | workers->num_workers_starting--; | ||
| 503 | spin_unlock_irq(&workers->lock); | ||
| 506 | return ret; | 504 | return ret; |
| 507 | } | 505 | } |
| 508 | 506 | ||
| 509 | int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) | 507 | int btrfs_start_workers(struct btrfs_workers *workers) |
| 510 | { | 508 | { |
| 511 | spin_lock_irq(&workers->lock); | 509 | spin_lock_irq(&workers->lock); |
| 512 | workers->num_workers_starting += num_workers; | 510 | workers->num_workers_starting++; |
| 513 | spin_unlock_irq(&workers->lock); | 511 | spin_unlock_irq(&workers->lock); |
| 514 | return __btrfs_start_workers(workers, num_workers); | 512 | return __btrfs_start_workers(workers); |
| 515 | } | 513 | } |
| 516 | 514 | ||
| 517 | /* | 515 | /* |
| @@ -568,9 +566,10 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) | |||
| 568 | struct btrfs_worker_thread *worker; | 566 | struct btrfs_worker_thread *worker; |
| 569 | unsigned long flags; | 567 | unsigned long flags; |
| 570 | struct list_head *fallback; | 568 | struct list_head *fallback; |
| 569 | int ret; | ||
| 571 | 570 | ||
| 572 | again: | ||
| 573 | spin_lock_irqsave(&workers->lock, flags); | 571 | spin_lock_irqsave(&workers->lock, flags); |
| 572 | again: | ||
| 574 | worker = next_worker(workers); | 573 | worker = next_worker(workers); |
| 575 | 574 | ||
| 576 | if (!worker) { | 575 | if (!worker) { |
| @@ -584,7 +583,10 @@ again: | |||
| 584 | workers->num_workers_starting++; | 583 | workers->num_workers_starting++; |
| 585 | spin_unlock_irqrestore(&workers->lock, flags); | 584 | spin_unlock_irqrestore(&workers->lock, flags); |
| 586 | /* we're below the limit, start another worker */ | 585 | /* we're below the limit, start another worker */ |
| 587 | __btrfs_start_workers(workers, 1); | 586 | ret = __btrfs_start_workers(workers); |
| 587 | spin_lock_irqsave(&workers->lock, flags); | ||
| 588 | if (ret) | ||
| 589 | goto fallback; | ||
| 588 | goto again; | 590 | goto again; |
| 589 | } | 591 | } |
| 590 | } | 592 | } |
| @@ -618,14 +620,14 @@ found: | |||
| 618 | * it was taken from. It is intended for use with long running work functions | 620 | * it was taken from. It is intended for use with long running work functions |
| 619 | * that make some progress and want to give the cpu up for others. | 621 | * that make some progress and want to give the cpu up for others. |
| 620 | */ | 622 | */ |
| 621 | int btrfs_requeue_work(struct btrfs_work *work) | 623 | void btrfs_requeue_work(struct btrfs_work *work) |
| 622 | { | 624 | { |
| 623 | struct btrfs_worker_thread *worker = work->worker; | 625 | struct btrfs_worker_thread *worker = work->worker; |
| 624 | unsigned long flags; | 626 | unsigned long flags; |
| 625 | int wake = 0; | 627 | int wake = 0; |
| 626 | 628 | ||
| 627 | if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags)) | 629 | if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags)) |
| 628 | goto out; | 630 | return; |
| 629 | 631 | ||
| 630 | spin_lock_irqsave(&worker->lock, flags); | 632 | spin_lock_irqsave(&worker->lock, flags); |
| 631 | if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) | 633 | if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) |
| @@ -652,9 +654,6 @@ int btrfs_requeue_work(struct btrfs_work *work) | |||
| 652 | if (wake) | 654 | if (wake) |
| 653 | wake_up_process(worker->task); | 655 | wake_up_process(worker->task); |
| 654 | spin_unlock_irqrestore(&worker->lock, flags); | 656 | spin_unlock_irqrestore(&worker->lock, flags); |
| 655 | out: | ||
| 656 | |||
| 657 | return 0; | ||
| 658 | } | 657 | } |
| 659 | 658 | ||
| 660 | void btrfs_set_work_high_prio(struct btrfs_work *work) | 659 | void btrfs_set_work_high_prio(struct btrfs_work *work) |
| @@ -665,7 +664,7 @@ void btrfs_set_work_high_prio(struct btrfs_work *work) | |||
| 665 | /* | 664 | /* |
| 666 | * places a struct btrfs_work into the pending queue of one of the kthreads | 665 | * places a struct btrfs_work into the pending queue of one of the kthreads |
| 667 | */ | 666 | */ |
| 668 | int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) | 667 | void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) |
| 669 | { | 668 | { |
| 670 | struct btrfs_worker_thread *worker; | 669 | struct btrfs_worker_thread *worker; |
| 671 | unsigned long flags; | 670 | unsigned long flags; |
| @@ -673,7 +672,7 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) | |||
| 673 | 672 | ||
| 674 | /* don't requeue something already on a list */ | 673 | /* don't requeue something already on a list */ |
| 675 | if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags)) | 674 | if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags)) |
| 676 | goto out; | 675 | return; |
| 677 | 676 | ||
| 678 | worker = find_worker(workers); | 677 | worker = find_worker(workers); |
| 679 | if (workers->ordered) { | 678 | if (workers->ordered) { |
| @@ -712,7 +711,4 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) | |||
| 712 | if (wake) | 711 | if (wake) |
| 713 | wake_up_process(worker->task); | 712 | wake_up_process(worker->task); |
| 714 | spin_unlock_irqrestore(&worker->lock, flags); | 713 | spin_unlock_irqrestore(&worker->lock, flags); |
| 715 | |||
| 716 | out: | ||
| 717 | return 0; | ||
| 718 | } | 714 | } |
