diff options
author | Mark McLoughlin <markmc@redhat.com> | 2006-10-03 04:15:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-03 11:04:14 -0400 |
commit | 4c7e3bf44d0ae227ea1ee87c2197212e65d043d7 (patch) | |
tree | 658140b966d78f4709de10cd03e0bfdade6bc13e /drivers/md/dm-snap.c | |
parent | 92c060a692a0c3482cdfcaf346cb2f7572368895 (diff) |
[PATCH] dm snapshot: allow zero chunk_size
The chunk size of snapshots cannot be changed so it is redundant to require it
as a parameter when activating an existing snapshot. Allow a value of zero in
this case and ignore it. For a new snapshot, use a default value if zero is
specified.
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r-- | drivers/md/dm-snap.c | 90 |
1 files changed, 49 insertions, 41 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 7c14867b5903..89f8dd1bfaa0 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -398,21 +398,60 @@ static void read_snapshot_metadata(struct dm_snapshot *s) | |||
398 | } | 398 | } |
399 | } | 399 | } |
400 | 400 | ||
401 | static int set_chunk_size(struct dm_snapshot *s, const char *chunk_size_arg, | ||
402 | char **error) | ||
403 | { | ||
404 | unsigned long chunk_size; | ||
405 | char *value; | ||
406 | |||
407 | chunk_size = simple_strtoul(chunk_size_arg, &value, 10); | ||
408 | if (*chunk_size_arg == '\0' || *value != '\0') { | ||
409 | *error = "Invalid chunk size"; | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
413 | if (!chunk_size) { | ||
414 | s->chunk_size = s->chunk_mask = s->chunk_shift = 0; | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | /* | ||
419 | * Chunk size must be multiple of page size. Silently | ||
420 | * round up if it's not. | ||
421 | */ | ||
422 | chunk_size = round_up(chunk_size, PAGE_SIZE >> 9); | ||
423 | |||
424 | /* Check chunk_size is a power of 2 */ | ||
425 | if (chunk_size & (chunk_size - 1)) { | ||
426 | *error = "Chunk size is not a power of 2"; | ||
427 | return -EINVAL; | ||
428 | } | ||
429 | |||
430 | /* Validate the chunk size against the device block size */ | ||
431 | if (chunk_size % (bdev_hardsect_size(s->cow->bdev) >> 9)) { | ||
432 | *error = "Chunk size is not a multiple of device blocksize"; | ||
433 | return -EINVAL; | ||
434 | } | ||
435 | |||
436 | s->chunk_size = chunk_size; | ||
437 | s->chunk_mask = chunk_size - 1; | ||
438 | s->chunk_shift = ffs(chunk_size) - 1; | ||
439 | |||
440 | return 0; | ||
441 | } | ||
442 | |||
401 | /* | 443 | /* |
402 | * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size> | 444 | * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size> |
403 | */ | 445 | */ |
404 | static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 446 | static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
405 | { | 447 | { |
406 | struct dm_snapshot *s; | 448 | struct dm_snapshot *s; |
407 | unsigned long chunk_size; | ||
408 | int r = -EINVAL; | 449 | int r = -EINVAL; |
409 | char persistent; | 450 | char persistent; |
410 | char *origin_path; | 451 | char *origin_path; |
411 | char *cow_path; | 452 | char *cow_path; |
412 | char *value; | ||
413 | int blocksize; | ||
414 | 453 | ||
415 | if (argc < 4) { | 454 | if (argc != 4) { |
416 | ti->error = "requires exactly 4 arguments"; | 455 | ti->error = "requires exactly 4 arguments"; |
417 | r = -EINVAL; | 456 | r = -EINVAL; |
418 | goto bad1; | 457 | goto bad1; |
@@ -428,13 +467,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
428 | goto bad1; | 467 | goto bad1; |
429 | } | 468 | } |
430 | 469 | ||
431 | chunk_size = simple_strtoul(argv[3], &value, 10); | ||
432 | if (chunk_size == 0 || value == NULL) { | ||
433 | ti->error = "Invalid chunk size"; | ||
434 | r = -EINVAL; | ||
435 | goto bad1; | ||
436 | } | ||
437 | |||
438 | s = kmalloc(sizeof(*s), GFP_KERNEL); | 470 | s = kmalloc(sizeof(*s), GFP_KERNEL); |
439 | if (s == NULL) { | 471 | if (s == NULL) { |
440 | ti->error = "Cannot allocate snapshot context private " | 472 | ti->error = "Cannot allocate snapshot context private " |
@@ -457,31 +489,11 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
457 | goto bad2; | 489 | goto bad2; |
458 | } | 490 | } |
459 | 491 | ||
460 | /* | 492 | r = set_chunk_size(s, argv[3], &ti->error); |
461 | * Chunk size must be multiple of page size. Silently | 493 | if (r) |
462 | * round up if it's not. | ||
463 | */ | ||
464 | chunk_size = round_up(chunk_size, PAGE_SIZE >> 9); | ||
465 | |||
466 | /* Validate the chunk size against the device block size */ | ||
467 | blocksize = s->cow->bdev->bd_disk->queue->hardsect_size; | ||
468 | if (chunk_size % (blocksize >> 9)) { | ||
469 | ti->error = "Chunk size is not a multiple of device blocksize"; | ||
470 | r = -EINVAL; | ||
471 | goto bad3; | ||
472 | } | ||
473 | |||
474 | /* Check chunk_size is a power of 2 */ | ||
475 | if (chunk_size & (chunk_size - 1)) { | ||
476 | ti->error = "Chunk size is not a power of 2"; | ||
477 | r = -EINVAL; | ||
478 | goto bad3; | 494 | goto bad3; |
479 | } | ||
480 | 495 | ||
481 | s->chunk_size = chunk_size; | ||
482 | s->chunk_mask = chunk_size - 1; | ||
483 | s->type = persistent; | 496 | s->type = persistent; |
484 | s->chunk_shift = ffs(chunk_size) - 1; | ||
485 | 497 | ||
486 | s->valid = 1; | 498 | s->valid = 1; |
487 | s->active = 0; | 499 | s->active = 0; |
@@ -496,16 +508,12 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
496 | goto bad3; | 508 | goto bad3; |
497 | } | 509 | } |
498 | 510 | ||
499 | /* | ||
500 | * Check the persistent flag - done here because we need the iobuf | ||
501 | * to check the LV header | ||
502 | */ | ||
503 | s->store.snap = s; | 511 | s->store.snap = s; |
504 | 512 | ||
505 | if (persistent == 'P') | 513 | if (persistent == 'P') |
506 | r = dm_create_persistent(&s->store, chunk_size); | 514 | r = dm_create_persistent(&s->store); |
507 | else | 515 | else |
508 | r = dm_create_transient(&s->store, s, blocksize); | 516 | r = dm_create_transient(&s->store); |
509 | 517 | ||
510 | if (r) { | 518 | if (r) { |
511 | ti->error = "Couldn't create exception store"; | 519 | ti->error = "Couldn't create exception store"; |
@@ -1205,7 +1213,7 @@ static int origin_status(struct dm_target *ti, status_type_t type, char *result, | |||
1205 | 1213 | ||
1206 | static struct target_type origin_target = { | 1214 | static struct target_type origin_target = { |
1207 | .name = "snapshot-origin", | 1215 | .name = "snapshot-origin", |
1208 | .version = {1, 4, 0}, | 1216 | .version = {1, 5, 0}, |
1209 | .module = THIS_MODULE, | 1217 | .module = THIS_MODULE, |
1210 | .ctr = origin_ctr, | 1218 | .ctr = origin_ctr, |
1211 | .dtr = origin_dtr, | 1219 | .dtr = origin_dtr, |
@@ -1216,7 +1224,7 @@ static struct target_type origin_target = { | |||
1216 | 1224 | ||
1217 | static struct target_type snapshot_target = { | 1225 | static struct target_type snapshot_target = { |
1218 | .name = "snapshot", | 1226 | .name = "snapshot", |
1219 | .version = {1, 4, 0}, | 1227 | .version = {1, 5, 0}, |
1220 | .module = THIS_MODULE, | 1228 | .module = THIS_MODULE, |
1221 | .ctr = snapshot_ctr, | 1229 | .ctr = snapshot_ctr, |
1222 | .dtr = snapshot_dtr, | 1230 | .dtr = snapshot_dtr, |