aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Brassow <jbrassow@redhat.com>2009-04-02 14:55:34 -0400
committerAlasdair G Kergon <agk@redhat.com>2009-04-02 14:55:34 -0400
commitfee1998e9c690f9920671e1e0ef187a48cfbbde4 (patch)
treea217e9bc2142350d9e8065c6e581be0524636498
parent2e4a31df2b10cbcaf43c333112f6f7440a035c69 (diff)
dm snapshot: move ctr parsing to exception store
First step of having the exception stores parse their own arguments - generalizing the interface. Signed-off-by: Jonathan Brassow <jbrassow@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
-rw-r--r--drivers/md/dm-exception-store.c109
-rw-r--r--drivers/md/dm-exception-store.h5
-rw-r--r--drivers/md/dm-snap.c147
3 files changed, 132 insertions, 129 deletions
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 2078b92470a1..a2e26c242141 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -7,6 +7,7 @@
7 7
8#include "dm-exception-store.h" 8#include "dm-exception-store.h"
9 9
10#include <linux/ctype.h>
10#include <linux/mm.h> 11#include <linux/mm.h>
11#include <linux/pagemap.h> 12#include <linux/pagemap.h>
12#include <linux/vmalloc.h> 13#include <linux/vmalloc.h>
@@ -137,49 +138,129 @@ int dm_exception_store_type_unregister(struct dm_exception_store_type *type)
137} 138}
138EXPORT_SYMBOL(dm_exception_store_type_unregister); 139EXPORT_SYMBOL(dm_exception_store_type_unregister);
139 140
140int dm_exception_store_create(const char *type_name, struct dm_target *ti, 141/*
141 chunk_t chunk_size, chunk_t chunk_mask, 142 * Round a number up to the nearest 'size' boundary. size must
142 chunk_t chunk_shift, struct dm_dev *cow, 143 * be a power of 2.
144 */
145static ulong round_up(ulong n, ulong size)
146{
147 size--;
148 return (n + size) & ~size;
149}
150
151static int set_chunk_size(struct dm_exception_store *store,
152 const char *chunk_size_arg, char **error)
153{
154 unsigned long chunk_size_ulong;
155 char *value;
156
157 chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10);
158 if (*chunk_size_arg == '\0' || *value != '\0') {
159 *error = "Invalid chunk size";
160 return -EINVAL;
161 }
162
163 if (!chunk_size_ulong) {
164 store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
165 return 0;
166 }
167
168 /*
169 * Chunk size must be multiple of page size. Silently
170 * round up if it's not.
171 */
172 chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9);
173
174 /* Check chunk_size is a power of 2 */
175 if (!is_power_of_2(chunk_size_ulong)) {
176 *error = "Chunk size is not a power of 2";
177 return -EINVAL;
178 }
179
180 /* Validate the chunk size against the device block size */
181 if (chunk_size_ulong % (bdev_hardsect_size(store->cow->bdev) >> 9)) {
182 *error = "Chunk size is not a multiple of device blocksize";
183 return -EINVAL;
184 }
185
186 store->chunk_size = chunk_size_ulong;
187 store->chunk_mask = chunk_size_ulong - 1;
188 store->chunk_shift = ffs(chunk_size_ulong) - 1;
189
190 return 0;
191}
192
193int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
194 unsigned *args_used,
143 struct dm_exception_store **store) 195 struct dm_exception_store **store)
144{ 196{
145 int r = 0; 197 int r = 0;
146 struct dm_exception_store_type *type; 198 struct dm_exception_store_type *type;
147 struct dm_exception_store *tmp_store; 199 struct dm_exception_store *tmp_store;
200 char persistent;
201
202 if (argc < 3) {
203 ti->error = "Insufficient exception store arguments";
204 return -EINVAL;
205 }
148 206
149 tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL); 207 tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
150 if (!tmp_store) 208 if (!tmp_store) {
209 ti->error = "Exception store allocation failed";
151 return -ENOMEM; 210 return -ENOMEM;
211 }
152 212
153 type = get_type(type_name); 213 persistent = toupper(*argv[1]);
154 if (!type) { 214 if (persistent != 'P' && persistent != 'N') {
155 kfree(tmp_store); 215 ti->error = "Persistent flag is not P or N";
156 return -EINVAL; 216 return -EINVAL;
157 } 217 }
158 218
219 type = get_type(argv[1]);
220 if (!type) {
221 ti->error = "Exception store type not recognised";
222 r = -EINVAL;
223 goto bad_type;
224 }
225
159 tmp_store->type = type; 226 tmp_store->type = type;
160 tmp_store->ti = ti; 227 tmp_store->ti = ti;
161 228
162 tmp_store->chunk_size = chunk_size; 229 r = dm_get_device(ti, argv[0], 0, 0,
163 tmp_store->chunk_mask = chunk_mask; 230 FMODE_READ | FMODE_WRITE, &tmp_store->cow);
164 tmp_store->chunk_shift = chunk_shift; 231 if (r) {
232 ti->error = "Cannot get COW device";
233 goto bad_cow;
234 }
165 235
166 tmp_store->cow = cow; 236 r = set_chunk_size(tmp_store, argv[2], &ti->error);
237 if (r)
238 goto bad_cow;
167 239
168 r = type->ctr(tmp_store, 0, NULL); 240 r = type->ctr(tmp_store, 0, NULL);
169 if (r) { 241 if (r) {
170 put_type(type); 242 ti->error = "Exception store type constructor failed";
171 kfree(tmp_store); 243 goto bad_ctr;
172 return r;
173 } 244 }
174 245
246 *args_used = 3;
175 *store = tmp_store; 247 *store = tmp_store;
176 return 0; 248 return 0;
249
250bad_ctr:
251 dm_put_device(ti, tmp_store->cow);
252bad_cow:
253 put_type(type);
254bad_type:
255 kfree(tmp_store);
256 return r;
177} 257}
178EXPORT_SYMBOL(dm_exception_store_create); 258EXPORT_SYMBOL(dm_exception_store_create);
179 259
180void dm_exception_store_destroy(struct dm_exception_store *store) 260void dm_exception_store_destroy(struct dm_exception_store *store)
181{ 261{
182 store->type->dtr(store); 262 store->type->dtr(store);
263 dm_put_device(store->ti, store->cow);
183 put_type(store->type); 264 put_type(store->type);
184 kfree(store); 265 kfree(store);
185} 266}
diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h
index 835f402d9470..023a707503c4 100644
--- a/drivers/md/dm-exception-store.h
+++ b/drivers/md/dm-exception-store.h
@@ -167,9 +167,8 @@ static inline chunk_t sector_to_chunk(struct dm_exception_store *store,
167int dm_exception_store_type_register(struct dm_exception_store_type *type); 167int dm_exception_store_type_register(struct dm_exception_store_type *type);
168int dm_exception_store_type_unregister(struct dm_exception_store_type *type); 168int dm_exception_store_type_unregister(struct dm_exception_store_type *type);
169 169
170int dm_exception_store_create(const char *type_name, struct dm_target *ti, 170int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
171 chunk_t chunk_size, chunk_t chunk_mask, 171 unsigned *args_used,
172 chunk_t chunk_shift, struct dm_dev *cow,
173 struct dm_exception_store **store); 172 struct dm_exception_store **store);
174void dm_exception_store_destroy(struct dm_exception_store *store); 173void dm_exception_store_destroy(struct dm_exception_store *store);
175 174
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}