From: Milan Broz <mbroz@redhat.com>

Add an asynchronous destruction option to kcopyd_client_destroy().
Return code indicates whether destruction was delayed.

Signed-off-by: Milan Broz <mbroz@redhat.com>
---

 drivers/md/dm-raid1.c |    2 +-
 drivers/md/dm-snap.c  |    9 +++++----
 drivers/md/kcopyd.c   |    8 +++++++-
 drivers/md/kcopyd.h   |    2 +-
 4 files changed, 14 insertions(+), 7 deletions(-)

Index: linux-2.6.21/drivers/md/dm-raid1.c
===================================================================
--- linux-2.6.21.orig/drivers/md/dm-raid1.c	2007-05-02 19:48:20.000000000 +0100
+++ linux-2.6.21/drivers/md/dm-raid1.c	2007-05-03 17:21:06.000000000 +0100
@@ -1167,7 +1167,7 @@ static void mirror_dtr(struct dm_target 
 	struct mirror_set *ms = (struct mirror_set *) ti->private;
 
 	flush_workqueue(ms->kmirrord_wq);
-	kcopyd_client_destroy(ms->kcopyd_client);
+	kcopyd_client_destroy(ms->kcopyd_client, 0);
 	destroy_workqueue(ms->kmirrord_wq);
 	free_context(ms, ti, ms->nr_mirrors);
 }
Index: linux-2.6.21/drivers/md/dm-snap.c
===================================================================
--- linux-2.6.21.orig/drivers/md/dm-snap.c	2007-05-01 17:41:13.000000000 +0100
+++ linux-2.6.21/drivers/md/dm-snap.c	2007-05-03 17:21:06.000000000 +0100
@@ -544,7 +544,7 @@ static int snapshot_ctr(struct dm_target
 	return 0;
 
  bad6:
-	kcopyd_client_destroy(s->kcopyd_client);
+	kcopyd_client_destroy(s->kcopyd_client, 0);
 
  bad5:
 	s->store.destroy(&s->store);
@@ -566,7 +566,7 @@ static int snapshot_ctr(struct dm_target
 
 static void __free_exceptions(struct dm_snapshot *s)
 {
-	kcopyd_client_destroy(s->kcopyd_client);
+	kcopyd_client_destroy(s->kcopyd_client, 0);
 	s->kcopyd_client = NULL;
 
 	exit_exception_table(&s->pending, pending_cache);
@@ -700,8 +700,9 @@ static void pending_complete(struct pend
 	struct bio *snapshot_bios = NULL;
 	int error = 0;
 
-	if (!success) {
-		/* Read/write error - snapshot is unusable */
+	if (!success || !s->valid) {
+		/* Read/write error or deferred kcopyd
+		 * on invalidated snapshot - snapshot is unusable */
 		down_write(&s->lock);
 		__invalidate_snapshot(s, -EIO);
 		error = 1;
Index: linux-2.6.21/drivers/md/kcopyd.c
===================================================================
--- linux-2.6.21.orig/drivers/md/kcopyd.c	2007-05-01 18:01:32.000000000 +0100
+++ linux-2.6.21/drivers/md/kcopyd.c	2007-05-03 17:21:06.000000000 +0100
@@ -694,8 +694,12 @@ int kcopyd_client_create(unsigned int nr
 	return 0;
 }
 
-void kcopyd_client_destroy(struct kcopyd_client *kc)
+int kcopyd_client_destroy(struct kcopyd_client *kc, unsigned async)
 {
+	/* Return immediately if there is still work in progress. */
+	if (async && atomic_read(&kc->nr_jobs))
+		return 1;
+
 	/* Wait for completion of all jobs submitted by this client. */
 	wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
 
@@ -704,6 +708,8 @@ void kcopyd_client_destroy(struct kcopyd
 	client_del(kc);
 	kfree(kc);
 	kcopyd_exit();
+
+	return 0;
 }
 
 EXPORT_SYMBOL(kcopyd_client_create);
Index: linux-2.6.21/drivers/md/kcopyd.h
===================================================================
--- linux-2.6.21.orig/drivers/md/kcopyd.h	2007-05-01 17:41:13.000000000 +0100
+++ linux-2.6.21/drivers/md/kcopyd.h	2007-05-03 17:21:06.000000000 +0100
@@ -23,7 +23,7 @@
  */
 struct kcopyd_client;
 int kcopyd_client_create(unsigned int num_pages, struct kcopyd_client **result);
-void kcopyd_client_destroy(struct kcopyd_client *kc);
+int kcopyd_client_destroy(struct kcopyd_client *kc, unsigned async);
 
 /*
  * Submit a copy job to kcopyd.  This is built on top of the