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