aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-snap.c
diff options
context:
space:
mode:
authorMark McLoughlin <markmc@redhat.com>2006-10-03 04:15:25 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-03 11:04:14 -0400
commit4c7e3bf44d0ae227ea1ee87c2197212e65d043d7 (patch)
tree658140b966d78f4709de10cd03e0bfdade6bc13e /drivers/md/dm-snap.c
parent92c060a692a0c3482cdfcaf346cb2f7572368895 (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.c90
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
401static 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 */
404static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) 446static 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
1206static struct target_type origin_target = { 1214static 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
1217static struct target_type snapshot_target = { 1225static 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,