summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/dm.c2
-rw-r--r--drivers/md/dm.h3
-rw-r--r--drivers/md/kcopyd.c122
3 files changed, 29 insertions, 98 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 6617ce4af095..11f4ffedd646 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -204,6 +204,7 @@ static int (*_inits[])(void) __initdata = {
dm_target_init,
dm_linear_init,
dm_stripe_init,
+ dm_kcopyd_init,
dm_interface_init,
};
@@ -212,6 +213,7 @@ static void (*_exits[])(void) = {
dm_target_exit,
dm_linear_exit,
dm_stripe_exit,
+ dm_kcopyd_exit,
dm_interface_exit,
};
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 17f2d6a8b124..9a6023c9bc6b 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -195,4 +195,7 @@ void dm_kobject_uevent(struct mapped_device *md);
int dm_dirty_log_init(void);
void dm_dirty_log_exit(void);
+int dm_kcopyd_init(void);
+void dm_kcopyd_exit(void);
+
#endif
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index 0b2907d59a3f..17345844b03e 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -31,8 +31,6 @@
* pages for kcopyd io.
*---------------------------------------------------------------*/
struct dm_kcopyd_client {
- struct list_head list;
-
spinlock_t lock;
struct page_list *pages;
unsigned int nr_pages;
@@ -224,7 +222,7 @@ struct kcopyd_job {
static struct kmem_cache *_job_cache;
-static int jobs_init(void)
+int __init dm_kcopyd_init(void)
{
_job_cache = KMEM_CACHE(kcopyd_job, 0);
if (!_job_cache)
@@ -233,7 +231,7 @@ static int jobs_init(void)
return 0;
}
-static void jobs_exit(void)
+void dm_kcopyd_exit(void)
{
kmem_cache_destroy(_job_cache);
_job_cache = NULL;
@@ -581,78 +579,17 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
#endif /* 0 */
/*-----------------------------------------------------------------
- * Unit setup
+ * Client setup
*---------------------------------------------------------------*/
-static DEFINE_MUTEX(_client_lock);
-static LIST_HEAD(_clients);
-
-static void client_add(struct dm_kcopyd_client *kc)
-{
- mutex_lock(&_client_lock);
- list_add(&kc->list, &_clients);
- mutex_unlock(&_client_lock);
-}
-
-static void client_del(struct dm_kcopyd_client *kc)
-{
- mutex_lock(&_client_lock);
- list_del(&kc->list);
- mutex_unlock(&_client_lock);
-}
-
-static DEFINE_MUTEX(kcopyd_init_lock);
-static int kcopyd_clients = 0;
-
-static int kcopyd_init(void)
-{
- int r;
-
- mutex_lock(&kcopyd_init_lock);
-
- if (kcopyd_clients) {
- /* Already initialized. */
- kcopyd_clients++;
- mutex_unlock(&kcopyd_init_lock);
- return 0;
- }
-
- r = jobs_init();
- if (r) {
- mutex_unlock(&kcopyd_init_lock);
- return r;
- }
-
- kcopyd_clients++;
- mutex_unlock(&kcopyd_init_lock);
- return 0;
-}
-
-static void kcopyd_exit(void)
-{
- mutex_lock(&kcopyd_init_lock);
- kcopyd_clients--;
- if (!kcopyd_clients) {
- jobs_exit();
- }
- mutex_unlock(&kcopyd_init_lock);
-}
-
int dm_kcopyd_client_create(unsigned int nr_pages,
struct dm_kcopyd_client **result)
{
- int r = 0;
+ int r = -ENOMEM;
struct dm_kcopyd_client *kc;
- r = kcopyd_init();
- if (r)
- return r;
-
kc = kmalloc(sizeof(*kc), GFP_KERNEL);
- if (!kc) {
- r = -ENOMEM;
- kcopyd_exit();
- return r;
- }
+ if (!kc)
+ return -ENOMEM;
spin_lock_init(&kc->lock);
spin_lock_init(&kc->job_lock);
@@ -661,51 +598,42 @@ int dm_kcopyd_client_create(unsigned int nr_pages,
INIT_LIST_HEAD(&kc->pages_jobs);
kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
- if (!kc->job_pool) {
- r = -ENOMEM;
- kfree(kc);
- kcopyd_exit();
- return r;
- }
+ if (!kc->job_pool)
+ goto bad_slab;
INIT_WORK(&kc->kcopyd_work, do_work);
kc->kcopyd_wq = create_singlethread_workqueue("kcopyd");
- if (!kc->kcopyd_wq) {
- r = -ENOMEM;
- mempool_destroy(kc->job_pool);
- kfree(kc);
- kcopyd_exit();
- return r;
- }
+ if (!kc->kcopyd_wq)
+ goto bad_workqueue;
kc->pages = NULL;
kc->nr_pages = kc->nr_free_pages = 0;
r = client_alloc_pages(kc, nr_pages);
- if (r) {
- destroy_workqueue(kc->kcopyd_wq);
- mempool_destroy(kc->job_pool);
- kfree(kc);
- kcopyd_exit();
- return r;
- }
+ if (r)
+ goto bad_client_pages;
kc->io_client = dm_io_client_create(nr_pages);
if (IS_ERR(kc->io_client)) {
r = PTR_ERR(kc->io_client);
- client_free_pages(kc);
- destroy_workqueue(kc->kcopyd_wq);
- mempool_destroy(kc->job_pool);
- kfree(kc);
- kcopyd_exit();
- return r;
+ goto bad_io_client;
}
init_waitqueue_head(&kc->destroyq);
atomic_set(&kc->nr_jobs, 0);
- client_add(kc);
*result = kc;
return 0;
+
+bad_io_client:
+ client_free_pages(kc);
+bad_client_pages:
+ destroy_workqueue(kc->kcopyd_wq);
+bad_workqueue:
+ mempool_destroy(kc->job_pool);
+bad_slab:
+ kfree(kc);
+
+ return r;
}
EXPORT_SYMBOL(dm_kcopyd_client_create);
@@ -720,9 +648,7 @@ void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc)
destroy_workqueue(kc->kcopyd_wq);
dm_io_client_destroy(kc->io_client);
client_free_pages(kc);
- client_del(kc);
mempool_destroy(kc->job_pool);
kfree(kc);
- kcopyd_exit();
}
EXPORT_SYMBOL(dm_kcopyd_client_destroy);