aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-snap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r--drivers/md/dm-snap.c147
1 files changed, 35 insertions, 112 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index fcb1ac12119f..974916b9ea21 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -7,7 +7,6 @@
7 */ 7 */
8 8
9#include <linux/blkdev.h> 9#include <linux/blkdev.h>
10#include <linux/ctype.h>
11#include <linux/device-mapper.h> 10#include <linux/device-mapper.h>
12#include <linux/delay.h> 11#include <linux/delay.h>
13#include <linux/fs.h> 12#include <linux/fs.h>
@@ -538,8 +537,7 @@ static int calc_max_buckets(void)
538/* 537/*
539 * Allocate room for a suitable hash table. 538 * Allocate room for a suitable hash table.
540 */ 539 */
541static int init_hash_tables(struct dm_snapshot *s, chunk_t chunk_shift, 540static int init_hash_tables(struct dm_snapshot *s)
542 struct dm_dev *cow)
543{ 541{
544 sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets; 542 sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
545 543
@@ -547,11 +545,11 @@ static int init_hash_tables(struct dm_snapshot *s, chunk_t chunk_shift,
547 * Calculate based on the size of the original volume or 545 * Calculate based on the size of the original volume or
548 * the COW volume... 546 * the COW volume...
549 */ 547 */
550 cow_dev_size = get_dev_size(cow->bdev); 548 cow_dev_size = get_dev_size(s->store->cow->bdev);
551 origin_dev_size = get_dev_size(s->origin->bdev); 549 origin_dev_size = get_dev_size(s->origin->bdev);
552 max_buckets = calc_max_buckets(); 550 max_buckets = calc_max_buckets();
553 551
554 hash_size = min(origin_dev_size, cow_dev_size) >> chunk_shift; 552 hash_size = min(origin_dev_size, cow_dev_size) >> s->store->chunk_shift;
555 hash_size = min(hash_size, max_buckets); 553 hash_size = min(hash_size, max_buckets);
556 554
557 hash_size = rounddown_pow_of_two(hash_size); 555 hash_size = rounddown_pow_of_two(hash_size);
@@ -576,60 +574,6 @@ static int init_hash_tables(struct dm_snapshot *s, chunk_t chunk_shift,
576} 574}
577 575
578/* 576/*
579 * Round a number up to the nearest 'size' boundary. size must
580 * be a power of 2.
581 */
582static ulong round_up(ulong n, ulong size)
583{
584 size--;
585 return (n + size) & ~size;
586}
587
588static int set_chunk_size(struct dm_snapshot *s, const char *chunk_size_arg,
589 chunk_t *chunk_size, chunk_t *chunk_mask,
590 chunk_t *chunk_shift, struct dm_dev *cow,
591 char **error)
592{
593 unsigned long chunk_size_ulong;
594 char *value;
595
596 chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10);
597 if (*chunk_size_arg == '\0' || *value != '\0') {
598 *error = "Invalid chunk size";
599 return -EINVAL;
600 }
601
602 if (!chunk_size_ulong) {
603 *chunk_size = *chunk_mask = *chunk_shift = 0;
604 return 0;
605 }
606
607 /*
608 * Chunk size must be multiple of page size. Silently
609 * round up if it's not.
610 */
611 chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9);
612
613 /* Check chunk_size is a power of 2 */
614 if (!is_power_of_2(chunk_size_ulong)) {
615 *error = "Chunk size is not a power of 2";
616 return -EINVAL;
617 }
618
619 /* Validate the chunk size against the device block size */
620 if (chunk_size_ulong % (bdev_hardsect_size(cow->bdev) >> 9)) {
621 *error = "Chunk size is not a multiple of device blocksize";
622 return -EINVAL;
623 }
624
625 *chunk_size = chunk_size_ulong;
626 *chunk_mask = chunk_size_ulong - 1;
627 *chunk_shift = ffs(chunk_size_ulong) - 1;
628
629 return 0;
630}
631
632/*
633 * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size> 577 * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size>
634 */ 578 */
635static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) 579static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
@@ -637,55 +581,45 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
637 struct dm_snapshot *s; 581 struct dm_snapshot *s;
638 int i; 582 int i;
639 int r = -EINVAL; 583 int r = -EINVAL;
640 char persistent;
641 char *origin_path; 584 char *origin_path;
642 char *cow_path; 585 struct dm_exception_store *store;
643 chunk_t chunk_size, chunk_mask, chunk_shift; 586 unsigned args_used;
644 struct dm_dev *cow;
645 587
646 if (argc != 4) { 588 if (argc != 4) {
647 ti->error = "requires exactly 4 arguments"; 589 ti->error = "requires exactly 4 arguments";
648 r = -EINVAL; 590 r = -EINVAL;
649 goto bad1; 591 goto bad_args;
650 } 592 }
651 593
652 origin_path = argv[0]; 594 origin_path = argv[0];
653 cow_path = argv[1]; 595 argv++;
654 persistent = toupper(*argv[2]); 596 argc--;
655 597
656 if (persistent != 'P' && persistent != 'N') { 598 r = dm_exception_store_create(ti, argc, argv, &args_used, &store);
657 ti->error = "Persistent flag is not P or N"; 599 if (r) {
600 ti->error = "Couldn't create exception store";
658 r = -EINVAL; 601 r = -EINVAL;
659 goto bad1; 602 goto bad_args;
660 } 603 }
661 604
605 argv += args_used;
606 argc -= args_used;
607
662 s = kmalloc(sizeof(*s), GFP_KERNEL); 608 s = kmalloc(sizeof(*s), GFP_KERNEL);
663 if (s == NULL) { 609 if (!s) {
664 ti->error = "Cannot allocate snapshot context private " 610 ti->error = "Cannot allocate snapshot context private "
665 "structure"; 611 "structure";
666 r = -ENOMEM; 612 r = -ENOMEM;
667 goto bad1; 613 goto bad_snap;
668 } 614 }
669 615
670 r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin); 616 r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin);
671 if (r) { 617 if (r) {
672 ti->error = "Cannot get origin device"; 618 ti->error = "Cannot get origin device";
673 goto bad2; 619 goto bad_origin;
674 } 620 }
675 621
676 r = dm_get_device(ti, cow_path, 0, 0, 622 s->store = store;
677 FMODE_READ | FMODE_WRITE, &cow);
678 if (r) {
679 dm_put_device(ti, s->origin);
680 ti->error = "Cannot get COW device";
681 goto bad2;
682 }
683
684 r = set_chunk_size(s, argv[3], &chunk_size, &chunk_mask, &chunk_shift,
685 cow, &ti->error);
686 if (r)
687 goto bad3;
688
689 s->valid = 1; 623 s->valid = 1;
690 s->active = 0; 624 s->active = 0;
691 atomic_set(&s->pending_exceptions_count, 0); 625 atomic_set(&s->pending_exceptions_count, 0);
@@ -693,30 +627,22 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
693 spin_lock_init(&s->pe_lock); 627 spin_lock_init(&s->pe_lock);
694 628
695 /* Allocate hash table for COW data */ 629 /* Allocate hash table for COW data */
696 if (init_hash_tables(s, chunk_shift, cow)) { 630 if (init_hash_tables(s)) {
697 ti->error = "Unable to allocate hash table space"; 631 ti->error = "Unable to allocate hash table space";
698 r = -ENOMEM; 632 r = -ENOMEM;
699 goto bad3; 633 goto bad_hash_tables;
700 }
701
702 r = dm_exception_store_create(argv[2], ti, chunk_size, chunk_mask,
703 chunk_shift, cow, &s->store);
704 if (r) {
705 ti->error = "Couldn't create exception store";
706 r = -EINVAL;
707 goto bad4;
708 } 634 }
709 635
710 r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client); 636 r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client);
711 if (r) { 637 if (r) {
712 ti->error = "Could not create kcopyd client"; 638 ti->error = "Could not create kcopyd client";
713 goto bad5; 639 goto bad_kcopyd;
714 } 640 }
715 641
716 s->pending_pool = mempool_create_slab_pool(MIN_IOS, pending_cache); 642 s->pending_pool = mempool_create_slab_pool(MIN_IOS, pending_cache);
717 if (!s->pending_pool) { 643 if (!s->pending_pool) {
718 ti->error = "Could not allocate mempool for pending exceptions"; 644 ti->error = "Could not allocate mempool for pending exceptions";
719 goto bad6; 645 goto bad_pending_pool;
720 } 646 }
721 647
722 s->tracked_chunk_pool = mempool_create_slab_pool(MIN_IOS, 648 s->tracked_chunk_pool = mempool_create_slab_pool(MIN_IOS,
@@ -759,30 +685,29 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
759 685
760 return 0; 686 return 0;
761 687
762 bad_load_and_register: 688bad_load_and_register:
763 mempool_destroy(s->tracked_chunk_pool); 689 mempool_destroy(s->tracked_chunk_pool);
764 690
765 bad_tracked_chunk_pool: 691bad_tracked_chunk_pool:
766 mempool_destroy(s->pending_pool); 692 mempool_destroy(s->pending_pool);
767 693
768 bad6: 694bad_pending_pool:
769 dm_kcopyd_client_destroy(s->kcopyd_client); 695 dm_kcopyd_client_destroy(s->kcopyd_client);
770 696
771 bad5: 697bad_kcopyd:
772 s->store->type->dtr(s->store);
773
774 bad4:
775 exit_exception_table(&s->pending, pending_cache); 698 exit_exception_table(&s->pending, pending_cache);
776 exit_exception_table(&s->complete, exception_cache); 699 exit_exception_table(&s->complete, exception_cache);
777 700
778 bad3: 701bad_hash_tables:
779 dm_put_device(ti, cow);
780 dm_put_device(ti, s->origin); 702 dm_put_device(ti, s->origin);
781 703
782 bad2: 704bad_origin:
783 kfree(s); 705 kfree(s);
784 706
785 bad1: 707bad_snap:
708 dm_exception_store_destroy(store);
709
710bad_args:
786 return r; 711 return r;
787} 712}
788 713
@@ -793,8 +718,6 @@ static void __free_exceptions(struct dm_snapshot *s)
793 718
794 exit_exception_table(&s->pending, pending_cache); 719 exit_exception_table(&s->pending, pending_cache);
795 exit_exception_table(&s->complete, exception_cache); 720 exit_exception_table(&s->complete, exception_cache);
796
797 s->store->type->dtr(s->store);
798} 721}
799 722
800static void snapshot_dtr(struct dm_target *ti) 723static void snapshot_dtr(struct dm_target *ti)
@@ -803,7 +726,6 @@ static void snapshot_dtr(struct dm_target *ti)
803 int i; 726 int i;
804#endif 727#endif
805 struct dm_snapshot *s = ti->private; 728 struct dm_snapshot *s = ti->private;
806 struct dm_dev *cow = s->store->cow;
807 729
808 flush_workqueue(ksnapd); 730 flush_workqueue(ksnapd);
809 731
@@ -831,7 +753,8 @@ static void snapshot_dtr(struct dm_target *ti)
831 mempool_destroy(s->pending_pool); 753 mempool_destroy(s->pending_pool);
832 754
833 dm_put_device(ti, s->origin); 755 dm_put_device(ti, s->origin);
834 dm_put_device(ti, cow); 756
757 dm_exception_store_destroy(s->store);
835 758
836 kfree(s); 759 kfree(s);
837} 760}