From be7c99b47ff0c162f991c6eb6de4c0435dc1edea Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Mon, 27 Mar 2006 01:17:50 -0800 Subject: [PATCH] --- yaml --- r: 24391 b: refs/heads/master c: 138728dc96529f20dfe970c470e51885a60e329f h: refs/heads/master i: 24389: b0c2f61096eddad08f8d6413a647ec5fb55b50b2 24387: 07e50a780b2dceb006cb4b11819a5fe727ebc903 24383: 570ed27c6181c68502f142bc64cd24f5201bc002 v: v3 --- [refs] | 2 +- trunk/drivers/md/dm-snap.c | 6 +++++- trunk/drivers/md/kcopyd.c | 17 ++++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/[refs] b/[refs] index 4ac5477ad4c9..d6125c33cb12 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 969429b504ae866d3f8b1cafd68a2c099e305093 +refs/heads/master: 138728dc96529f20dfe970c470e51885a60e329f diff --git a/trunk/drivers/md/dm-snap.c b/trunk/drivers/md/dm-snap.c index a5765f9fbe02..08312b46463a 100644 --- a/trunk/drivers/md/dm-snap.c +++ b/trunk/drivers/md/dm-snap.c @@ -559,8 +559,12 @@ static void snapshot_dtr(struct dm_target *ti) { struct dm_snapshot *s = (struct dm_snapshot *) ti->private; + /* Prevent further origin writes from using this snapshot. */ + /* After this returns there can be no new kcopyd jobs. */ unregister_snapshot(s); + kcopyd_client_destroy(s->kcopyd_client); + exit_exception_table(&s->pending, pending_cache); exit_exception_table(&s->complete, exception_cache); @@ -569,7 +573,7 @@ static void snapshot_dtr(struct dm_target *ti) dm_put_device(ti, s->origin); dm_put_device(ti, s->cow); - kcopyd_client_destroy(s->kcopyd_client); + kfree(s); } diff --git a/trunk/drivers/md/kcopyd.c b/trunk/drivers/md/kcopyd.c index 9dcb2c8a3853..ed71f3f94620 100644 --- a/trunk/drivers/md/kcopyd.c +++ b/trunk/drivers/md/kcopyd.c @@ -44,6 +44,9 @@ struct kcopyd_client { struct page_list *pages; unsigned int nr_pages; unsigned int nr_free_pages; + + wait_queue_head_t destroyq; + atomic_t nr_jobs; }; static struct page_list *alloc_pl(void) @@ -292,10 +295,15 @@ static int run_complete_job(struct kcopyd_job *job) int read_err = job->read_err; unsigned int write_err = job->write_err; kcopyd_notify_fn fn = job->fn; + struct kcopyd_client *kc = job->kc; - kcopyd_put_pages(job->kc, job->pages); + kcopyd_put_pages(kc, job->pages); mempool_free(job, _job_pool); fn(read_err, write_err, context); + + if (atomic_dec_and_test(&kc->nr_jobs)) + wake_up(&kc->destroyq); + return 0; } @@ -430,6 +438,7 @@ static void do_work(void *ignored) */ static void dispatch_job(struct kcopyd_job *job) { + atomic_inc(&job->kc->nr_jobs); push(&_pages_jobs, job); wake(); } @@ -669,6 +678,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) return r; } + init_waitqueue_head(&kc->destroyq); + atomic_set(&kc->nr_jobs, 0); + client_add(kc); *result = kc; return 0; @@ -676,6 +688,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) void kcopyd_client_destroy(struct kcopyd_client *kc) { + /* Wait for completion of all jobs submitted by this client. */ + wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs)); + dm_io_put(kc->nr_pages); client_free_pages(kc); client_del(kc);