diff options
Diffstat (limited to 'drivers/md/kcopyd.c')
-rw-r--r-- | drivers/md/kcopyd.c | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c index 9dcb2c8a3853..72480a48d88b 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/kcopyd.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/vmalloc.h> | 23 | #include <linux/vmalloc.h> |
24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
25 | #include <linux/mutex.h> | ||
25 | 26 | ||
26 | #include "kcopyd.h" | 27 | #include "kcopyd.h" |
27 | 28 | ||
@@ -44,6 +45,9 @@ struct kcopyd_client { | |||
44 | struct page_list *pages; | 45 | struct page_list *pages; |
45 | unsigned int nr_pages; | 46 | unsigned int nr_pages; |
46 | unsigned int nr_free_pages; | 47 | unsigned int nr_free_pages; |
48 | |||
49 | wait_queue_head_t destroyq; | ||
50 | atomic_t nr_jobs; | ||
47 | }; | 51 | }; |
48 | 52 | ||
49 | static struct page_list *alloc_pl(void) | 53 | static struct page_list *alloc_pl(void) |
@@ -292,10 +296,15 @@ static int run_complete_job(struct kcopyd_job *job) | |||
292 | int read_err = job->read_err; | 296 | int read_err = job->read_err; |
293 | unsigned int write_err = job->write_err; | 297 | unsigned int write_err = job->write_err; |
294 | kcopyd_notify_fn fn = job->fn; | 298 | kcopyd_notify_fn fn = job->fn; |
299 | struct kcopyd_client *kc = job->kc; | ||
295 | 300 | ||
296 | kcopyd_put_pages(job->kc, job->pages); | 301 | kcopyd_put_pages(kc, job->pages); |
297 | mempool_free(job, _job_pool); | 302 | mempool_free(job, _job_pool); |
298 | fn(read_err, write_err, context); | 303 | fn(read_err, write_err, context); |
304 | |||
305 | if (atomic_dec_and_test(&kc->nr_jobs)) | ||
306 | wake_up(&kc->destroyq); | ||
307 | |||
299 | return 0; | 308 | return 0; |
300 | } | 309 | } |
301 | 310 | ||
@@ -430,6 +439,7 @@ static void do_work(void *ignored) | |||
430 | */ | 439 | */ |
431 | static void dispatch_job(struct kcopyd_job *job) | 440 | static void dispatch_job(struct kcopyd_job *job) |
432 | { | 441 | { |
442 | atomic_inc(&job->kc->nr_jobs); | ||
433 | push(&_pages_jobs, job); | 443 | push(&_pages_jobs, job); |
434 | wake(); | 444 | wake(); |
435 | } | 445 | } |
@@ -572,21 +582,21 @@ int kcopyd_cancel(struct kcopyd_job *job, int block) | |||
572 | /*----------------------------------------------------------------- | 582 | /*----------------------------------------------------------------- |
573 | * Unit setup | 583 | * Unit setup |
574 | *---------------------------------------------------------------*/ | 584 | *---------------------------------------------------------------*/ |
575 | static DECLARE_MUTEX(_client_lock); | 585 | static DEFINE_MUTEX(_client_lock); |
576 | static LIST_HEAD(_clients); | 586 | static LIST_HEAD(_clients); |
577 | 587 | ||
578 | static void client_add(struct kcopyd_client *kc) | 588 | static void client_add(struct kcopyd_client *kc) |
579 | { | 589 | { |
580 | down(&_client_lock); | 590 | mutex_lock(&_client_lock); |
581 | list_add(&kc->list, &_clients); | 591 | list_add(&kc->list, &_clients); |
582 | up(&_client_lock); | 592 | mutex_unlock(&_client_lock); |
583 | } | 593 | } |
584 | 594 | ||
585 | static void client_del(struct kcopyd_client *kc) | 595 | static void client_del(struct kcopyd_client *kc) |
586 | { | 596 | { |
587 | down(&_client_lock); | 597 | mutex_lock(&_client_lock); |
588 | list_del(&kc->list); | 598 | list_del(&kc->list); |
589 | up(&_client_lock); | 599 | mutex_unlock(&_client_lock); |
590 | } | 600 | } |
591 | 601 | ||
592 | static DEFINE_MUTEX(kcopyd_init_lock); | 602 | static DEFINE_MUTEX(kcopyd_init_lock); |
@@ -669,6 +679,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) | |||
669 | return r; | 679 | return r; |
670 | } | 680 | } |
671 | 681 | ||
682 | init_waitqueue_head(&kc->destroyq); | ||
683 | atomic_set(&kc->nr_jobs, 0); | ||
684 | |||
672 | client_add(kc); | 685 | client_add(kc); |
673 | *result = kc; | 686 | *result = kc; |
674 | return 0; | 687 | return 0; |
@@ -676,6 +689,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) | |||
676 | 689 | ||
677 | void kcopyd_client_destroy(struct kcopyd_client *kc) | 690 | void kcopyd_client_destroy(struct kcopyd_client *kc) |
678 | { | 691 | { |
692 | /* Wait for completion of all jobs submitted by this client. */ | ||
693 | wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs)); | ||
694 | |||
679 | dm_io_put(kc->nr_pages); | 695 | dm_io_put(kc->nr_pages); |
680 | client_free_pages(kc); | 696 | client_free_pages(kc); |
681 | client_del(kc); | 697 | client_del(kc); |