Create/destroy kcopyd on demand.

--- diff/drivers/md/dm.c	2004-06-11 19:22:02.000000000 +0100
+++ source/drivers/md/dm.c	2004-06-11 19:37:40.000000000 +0100
@@ -153,7 +153,6 @@
 	xx(dm_target)
 	xx(dm_linear)
 	xx(dm_stripe)
-	xx(kcopyd)
 	xx(dm_interface)
 #undef xx
 };
--- diff/drivers/md/dm.h	2004-06-11 19:22:02.000000000 +0100
+++ source/drivers/md/dm.h	2004-06-11 19:37:40.000000000 +0100
@@ -178,9 +178,6 @@
 int dm_stripe_init(void);
 void dm_stripe_exit(void);
 
-int kcopyd_init(void);
-void kcopyd_exit(void);
-
 void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
 
 #endif
--- diff/drivers/md/kcopyd.c	2004-06-11 19:26:46.000000000 +0100
+++ source/drivers/md/kcopyd.c	2004-06-11 19:37:40.000000000 +0100
@@ -247,6 +247,8 @@
 
 	mempool_destroy(_job_pool);
 	kmem_cache_destroy(_job_cache);
+	_job_pool = NULL;
+	_job_cache = NULL;
 }
 
 /*
@@ -589,14 +591,67 @@
 	up(&_client_lock);
 }
 
+static DECLARE_MUTEX(kcopyd_init_lock);
+static int kcopyd_clients = 0;
+
+static int kcopyd_init(void)
+{
+	int r;
+
+	down(&kcopyd_init_lock);
+
+	if (kcopyd_clients) {
+		/* Already initialized. */
+		kcopyd_clients++;
+		up(&kcopyd_init_lock);
+		return 0;
+	}
+
+	r = jobs_init();
+	if (r) {
+		up(&kcopyd_init_lock);
+		return r;
+	}
+
+	_kcopyd_wq = create_singlethread_workqueue("kcopyd");
+	if (!_kcopyd_wq) {
+		jobs_exit();
+		up(&kcopyd_init_lock);
+		return -ENOMEM;
+	}
+
+	kcopyd_clients++;
+	INIT_WORK(&_kcopyd_work, do_work, NULL);
+	up(&kcopyd_init_lock);
+	return 0;
+}
+
+static void kcopyd_exit(void)
+{
+	down(&kcopyd_init_lock);
+	kcopyd_clients--;
+	if (!kcopyd_clients) {
+		jobs_exit();
+		destroy_workqueue(_kcopyd_wq);
+		_kcopyd_wq = NULL;
+	}
+	up(&kcopyd_init_lock);
+}
+
 int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
 {
 	int r = 0;
 	struct kcopyd_client *kc;
 
+	r = kcopyd_init();
+	if (r)
+		return r;
+
 	kc = kmalloc(sizeof(*kc), GFP_KERNEL);
-	if (!kc)
+	if (!kc) {
+		kcopyd_exit();
 		return -ENOMEM;
+	}
 
 	kc->lock = SPIN_LOCK_UNLOCKED;
 	kc->pages = NULL;
@@ -604,6 +659,7 @@
 	r = client_alloc_pages(kc, nr_pages);
 	if (r) {
 		kfree(kc);
+		kcopyd_exit();
 		return r;
 	}
 
@@ -611,6 +667,7 @@
 	if (r) {
 		client_free_pages(kc);
 		kfree(kc);
+		kcopyd_exit();
 		return r;
 	}
 
@@ -619,6 +676,7 @@
 		dm_io_put(nr_pages);
 		client_free_pages(kc);
 		kfree(kc);
+		kcopyd_exit();
 		return r;
 	}
 
@@ -632,31 +690,7 @@
 	client_free_pages(kc);
 	client_del(kc);
 	kfree(kc);
-}
-
-
-int __init kcopyd_init(void)
-{
-	int r;
-
-	r = jobs_init();
-	if (r)
-		return r;
-
-	_kcopyd_wq = create_singlethread_workqueue("kcopyd");
-	if (!_kcopyd_wq) {
-		jobs_exit();
-		return -ENOMEM;
-	}
-
-	INIT_WORK(&_kcopyd_work, do_work, NULL);
-	return 0;
-}
-
-void kcopyd_exit(void)
-{
-	jobs_exit();
-	destroy_workqueue(_kcopyd_wq);
+	kcopyd_exit();
 }
 
 EXPORT_SYMBOL(kcopyd_client_create);
--- diff/drivers/md/kcopyd.h	2004-06-11 19:22:02.000000000 +0100
+++ source/drivers/md/kcopyd.h	2004-06-11 19:37:40.000000000 +0100
@@ -13,9 +13,6 @@
 
 #include "dm-io.h"
 
-int kcopyd_init(void);
-void kcopyd_exit(void);
-
 /* FIXME: make this configurable */
 #define KCOPYD_MAX_REGIONS 8
 
