diff options
Diffstat (limited to 'drivers/md/kcopyd.c')
-rw-r--r-- | drivers/md/kcopyd.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c index 9dcb2c8a3853..ed71f3f94620 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/kcopyd.c | |||
@@ -44,6 +44,9 @@ struct kcopyd_client { | |||
44 | struct page_list *pages; | 44 | struct page_list *pages; |
45 | unsigned int nr_pages; | 45 | unsigned int nr_pages; |
46 | unsigned int nr_free_pages; | 46 | unsigned int nr_free_pages; |
47 | |||
48 | wait_queue_head_t destroyq; | ||
49 | atomic_t nr_jobs; | ||
47 | }; | 50 | }; |
48 | 51 | ||
49 | static struct page_list *alloc_pl(void) | 52 | static struct page_list *alloc_pl(void) |
@@ -292,10 +295,15 @@ static int run_complete_job(struct kcopyd_job *job) | |||
292 | int read_err = job->read_err; | 295 | int read_err = job->read_err; |
293 | unsigned int write_err = job->write_err; | 296 | unsigned int write_err = job->write_err; |
294 | kcopyd_notify_fn fn = job->fn; | 297 | kcopyd_notify_fn fn = job->fn; |
298 | struct kcopyd_client *kc = job->kc; | ||
295 | 299 | ||
296 | kcopyd_put_pages(job->kc, job->pages); | 300 | kcopyd_put_pages(kc, job->pages); |
297 | mempool_free(job, _job_pool); | 301 | mempool_free(job, _job_pool); |
298 | fn(read_err, write_err, context); | 302 | fn(read_err, write_err, context); |
303 | |||
304 | if (atomic_dec_and_test(&kc->nr_jobs)) | ||
305 | wake_up(&kc->destroyq); | ||
306 | |||
299 | return 0; | 307 | return 0; |
300 | } | 308 | } |
301 | 309 | ||
@@ -430,6 +438,7 @@ static void do_work(void *ignored) | |||
430 | */ | 438 | */ |
431 | static void dispatch_job(struct kcopyd_job *job) | 439 | static void dispatch_job(struct kcopyd_job *job) |
432 | { | 440 | { |
441 | atomic_inc(&job->kc->nr_jobs); | ||
433 | push(&_pages_jobs, job); | 442 | push(&_pages_jobs, job); |
434 | wake(); | 443 | wake(); |
435 | } | 444 | } |
@@ -669,6 +678,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) | |||
669 | return r; | 678 | return r; |
670 | } | 679 | } |
671 | 680 | ||
681 | init_waitqueue_head(&kc->destroyq); | ||
682 | atomic_set(&kc->nr_jobs, 0); | ||
683 | |||
672 | client_add(kc); | 684 | client_add(kc); |
673 | *result = kc; | 685 | *result = kc; |
674 | return 0; | 686 | return 0; |
@@ -676,6 +688,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) | |||
676 | 688 | ||
677 | void kcopyd_client_destroy(struct kcopyd_client *kc) | 689 | void kcopyd_client_destroy(struct kcopyd_client *kc) |
678 | { | 690 | { |
691 | /* Wait for completion of all jobs submitted by this client. */ | ||
692 | wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs)); | ||
693 | |||
679 | dm_io_put(kc->nr_pages); | 694 | dm_io_put(kc->nr_pages); |
680 | client_free_pages(kc); | 695 | client_free_pages(kc); |
681 | client_del(kc); | 696 | client_del(kc); |