diff options
Diffstat (limited to 'drivers/md/kcopyd.c')
-rw-r--r-- | drivers/md/kcopyd.c | 122 |
1 files changed, 24 insertions, 98 deletions
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 | *---------------------------------------------------------------*/ |
33 | struct dm_kcopyd_client { | 33 | struct 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 | ||
225 | static struct kmem_cache *_job_cache; | 223 | static struct kmem_cache *_job_cache; |
226 | 224 | ||
227 | static int jobs_init(void) | 225 | int __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 | ||
236 | static void jobs_exit(void) | 234 | void 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 | *---------------------------------------------------------------*/ |
586 | static DEFINE_MUTEX(_client_lock); | ||
587 | static LIST_HEAD(_clients); | ||
588 | |||
589 | static 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 | |||
596 | static 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 | |||
603 | static DEFINE_MUTEX(kcopyd_init_lock); | ||
604 | static int kcopyd_clients = 0; | ||
605 | |||
606 | static 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 | |||
630 | static 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 | |||
640 | int dm_kcopyd_client_create(unsigned int nr_pages, | 584 | int 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 | |||
627 | bad_io_client: | ||
628 | client_free_pages(kc); | ||
629 | bad_client_pages: | ||
630 | destroy_workqueue(kc->kcopyd_wq); | ||
631 | bad_workqueue: | ||
632 | mempool_destroy(kc->job_pool); | ||
633 | bad_slab: | ||
634 | kfree(kc); | ||
635 | |||
636 | return r; | ||
709 | } | 637 | } |
710 | EXPORT_SYMBOL(dm_kcopyd_client_create); | 638 | EXPORT_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 | } |
728 | EXPORT_SYMBOL(dm_kcopyd_client_destroy); | 654 | EXPORT_SYMBOL(dm_kcopyd_client_destroy); |