aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md')
-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 = {
204 dm_target_init, 204 dm_target_init,
205 dm_linear_init, 205 dm_linear_init,
206 dm_stripe_init, 206 dm_stripe_init,
207 dm_kcopyd_init,
207 dm_interface_init, 208 dm_interface_init,
208}; 209};
209 210
@@ -212,6 +213,7 @@ static void (*_exits[])(void) = {
212 dm_target_exit, 213 dm_target_exit,
213 dm_linear_exit, 214 dm_linear_exit,
214 dm_stripe_exit, 215 dm_stripe_exit,
216 dm_kcopyd_exit,
215 dm_interface_exit, 217 dm_interface_exit,
216}; 218};
217 219
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);
195int dm_dirty_log_init(void); 195int dm_dirty_log_init(void);
196void dm_dirty_log_exit(void); 196void dm_dirty_log_exit(void);
197 197
198int dm_kcopyd_init(void);
199void dm_kcopyd_exit(void);
200
198#endif 201#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 @@
31 * pages for kcopyd io. 31 * pages for kcopyd io.
32 *---------------------------------------------------------------*/ 32 *---------------------------------------------------------------*/
33struct dm_kcopyd_client { 33struct dm_kcopyd_client {
34 struct list_head list;
35
36 spinlock_t lock; 34 spinlock_t lock;
37 struct page_list *pages; 35 struct page_list *pages;
38 unsigned int nr_pages; 36 unsigned int nr_pages;
@@ -224,7 +222,7 @@ struct kcopyd_job {
224 222
225static struct kmem_cache *_job_cache; 223static struct kmem_cache *_job_cache;
226 224
227static int jobs_init(void) 225int __init dm_kcopyd_init(void)
228{ 226{
229 _job_cache = KMEM_CACHE(kcopyd_job, 0); 227 _job_cache = KMEM_CACHE(kcopyd_job, 0);
230 if (!_job_cache) 228 if (!_job_cache)
@@ -233,7 +231,7 @@ static int jobs_init(void)
233 return 0; 231 return 0;
234} 232}
235 233
236static void jobs_exit(void) 234void dm_kcopyd_exit(void)
237{ 235{
238 kmem_cache_destroy(_job_cache); 236 kmem_cache_destroy(_job_cache);
239 _job_cache = NULL; 237 _job_cache = NULL;
@@ -581,78 +579,17 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
581#endif /* 0 */ 579#endif /* 0 */
582 580
583/*----------------------------------------------------------------- 581/*-----------------------------------------------------------------
584 * Unit setup 582 * Client setup
585 *---------------------------------------------------------------*/ 583 *---------------------------------------------------------------*/
586static DEFINE_MUTEX(_client_lock);
587static LIST_HEAD(_clients);
588
589static void client_add(struct dm_kcopyd_client *kc)
590{
591 mutex_lock(&_client_lock);
592 list_add(&kc->list, &_clients);
593 mutex_unlock(&_client_lock);
594}
595
596static void client_del(struct dm_kcopyd_client *kc)
597{
598 mutex_lock(&_client_lock);
599 list_del(&kc->list);
600 mutex_unlock(&_client_lock);
601}
602
603static DEFINE_MUTEX(kcopyd_init_lock);
604static int kcopyd_clients = 0;
605
606static int kcopyd_init(void)
607{
608 int r;
609
610 mutex_lock(&kcopyd_init_lock);
611
612 if (kcopyd_clients) {
613 /* Already initialized. */
614 kcopyd_clients++;
615 mutex_unlock(&kcopyd_init_lock);
616 return 0;
617 }
618
619 r = jobs_init();
620 if (r) {
621 mutex_unlock(&kcopyd_init_lock);
622 return r;
623 }
624
625 kcopyd_clients++;
626 mutex_unlock(&kcopyd_init_lock);
627 return 0;
628}
629
630static void kcopyd_exit(void)
631{
632 mutex_lock(&kcopyd_init_lock);
633 kcopyd_clients--;
634 if (!kcopyd_clients) {
635 jobs_exit();
636 }
637 mutex_unlock(&kcopyd_init_lock);
638}
639
640int dm_kcopyd_client_create(unsigned int nr_pages, 584int dm_kcopyd_client_create(unsigned int nr_pages,
641 struct dm_kcopyd_client **result) 585 struct dm_kcopyd_client **result)
642{ 586{
643 int r = 0; 587 int r = -ENOMEM;
644 struct dm_kcopyd_client *kc; 588 struct dm_kcopyd_client *kc;
645 589
646 r = kcopyd_init();
647 if (r)
648 return r;
649
650 kc = kmalloc(sizeof(*kc), GFP_KERNEL); 590 kc = kmalloc(sizeof(*kc), GFP_KERNEL);
651 if (!kc) { 591 if (!kc)
652 r = -ENOMEM; 592 return -ENOMEM;
653 kcopyd_exit();
654 return r;
655 }
656 593
657 spin_lock_init(&kc->lock); 594 spin_lock_init(&kc->lock);
658 spin_lock_init(&kc->job_lock); 595 spin_lock_init(&kc->job_lock);
@@ -661,51 +598,42 @@ int dm_kcopyd_client_create(unsigned int nr_pages,
661 INIT_LIST_HEAD(&kc->pages_jobs); 598 INIT_LIST_HEAD(&kc->pages_jobs);
662 599
663 kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache); 600 kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
664 if (!kc->job_pool) { 601 if (!kc->job_pool)
665 r = -ENOMEM; 602 goto bad_slab;
666 kfree(kc);
667 kcopyd_exit();
668 return r;
669 }
670 603
671 INIT_WORK(&kc->kcopyd_work, do_work); 604 INIT_WORK(&kc->kcopyd_work, do_work);
672 kc->kcopyd_wq = create_singlethread_workqueue("kcopyd"); 605 kc->kcopyd_wq = create_singlethread_workqueue("kcopyd");
673 if (!kc->kcopyd_wq) { 606 if (!kc->kcopyd_wq)
674 r = -ENOMEM; 607 goto bad_workqueue;
675 mempool_destroy(kc->job_pool);
676 kfree(kc);
677 kcopyd_exit();
678 return r;
679 }
680 608
681 kc->pages = NULL; 609 kc->pages = NULL;
682 kc->nr_pages = kc->nr_free_pages = 0; 610 kc->nr_pages = kc->nr_free_pages = 0;
683 r = client_alloc_pages(kc, nr_pages); 611 r = client_alloc_pages(kc, nr_pages);
684 if (r) { 612 if (r)
685 destroy_workqueue(kc->kcopyd_wq); 613 goto bad_client_pages;
686 mempool_destroy(kc->job_pool);
687 kfree(kc);
688 kcopyd_exit();
689 return r;
690 }
691 614
692 kc->io_client = dm_io_client_create(nr_pages); 615 kc->io_client = dm_io_client_create(nr_pages);
693 if (IS_ERR(kc->io_client)) { 616 if (IS_ERR(kc->io_client)) {
694 r = PTR_ERR(kc->io_client); 617 r = PTR_ERR(kc->io_client);
695 client_free_pages(kc); 618 goto bad_io_client;
696 destroy_workqueue(kc->kcopyd_wq);
697 mempool_destroy(kc->job_pool);
698 kfree(kc);
699 kcopyd_exit();
700 return r;
701 } 619 }
702 620
703 init_waitqueue_head(&kc->destroyq); 621 init_waitqueue_head(&kc->destroyq);
704 atomic_set(&kc->nr_jobs, 0); 622 atomic_set(&kc->nr_jobs, 0);
705 623
706 client_add(kc);
707 *result = kc; 624 *result = kc;
708 return 0; 625 return 0;
626
627bad_io_client:
628 client_free_pages(kc);
629bad_client_pages:
630 destroy_workqueue(kc->kcopyd_wq);
631bad_workqueue:
632 mempool_destroy(kc->job_pool);
633bad_slab:
634 kfree(kc);
635
636 return r;
709} 637}
710EXPORT_SYMBOL(dm_kcopyd_client_create); 638EXPORT_SYMBOL(dm_kcopyd_client_create);
711 639
@@ -720,9 +648,7 @@ void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc)
720 destroy_workqueue(kc->kcopyd_wq); 648 destroy_workqueue(kc->kcopyd_wq);
721 dm_io_client_destroy(kc->io_client); 649 dm_io_client_destroy(kc->io_client);
722 client_free_pages(kc); 650 client_free_pages(kc);
723 client_del(kc);
724 mempool_destroy(kc->job_pool); 651 mempool_destroy(kc->job_pool);
725 kfree(kc); 652 kfree(kc);
726 kcopyd_exit();
727} 653}
728EXPORT_SYMBOL(dm_kcopyd_client_destroy); 654EXPORT_SYMBOL(dm_kcopyd_client_destroy);