aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlasdair G Kergon <agk@redhat.com>2006-06-26 03:27:18 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 12:58:34 -0400
commitc51c2752491e5e771de6c8861a85ba46752d7888 (patch)
tree9371dab2a38e1a17bf91d9bc143b47b1c58c5fb7
parentb877a96409a3a99f2ce27b3c6473c9b28298ac7c (diff)
[PATCH] dm snapshot: unify chunk_size
Persistent snapshots currently store a private copy of the chunk size. Userspace also supplies the chunk size when loading a snapshot. Ensure consistency by only storing the chunk_size in one place instead of two. Currently the two sizes will differ if the chunk size supplied by userspace does not match the chunk size an existing snapshot actually uses. Amongst other problems, this causes an incorrect 'percentage full' to be reported. The patch ensures consistency by only storing the chunk_size in one place, removing it from struct pstore. Some initialisation is delayed until the correct chunk_size is known. If read_header() discovers that the wrong chunk size was supplied, the 'area' buffer (which the header already got read into) is reinitialised to the correct size. [akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] Signed-off-by: Alasdair G Kergon <agk@redhat.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/md/dm-exception-store.c65
-rw-r--r--drivers/md/dm-snap.c6
2 files changed, 45 insertions, 26 deletions
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index cc07bbebbb16..34a75939a0ca 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -91,7 +91,6 @@ struct pstore {
91 struct dm_snapshot *snap; /* up pointer to my snapshot */ 91 struct dm_snapshot *snap; /* up pointer to my snapshot */
92 int version; 92 int version;
93 int valid; 93 int valid;
94 uint32_t chunk_size;
95 uint32_t exceptions_per_area; 94 uint32_t exceptions_per_area;
96 95
97 /* 96 /*
@@ -133,7 +132,7 @@ static int alloc_area(struct pstore *ps)
133 int r = -ENOMEM; 132 int r = -ENOMEM;
134 size_t len; 133 size_t len;
135 134
136 len = ps->chunk_size << SECTOR_SHIFT; 135 len = ps->snap->chunk_size << SECTOR_SHIFT;
137 136
138 /* 137 /*
139 * Allocate the chunk_size block of memory that will hold 138 * Allocate the chunk_size block of memory that will hold
@@ -160,8 +159,8 @@ static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
160 unsigned long bits; 159 unsigned long bits;
161 160
162 where.bdev = ps->snap->cow->bdev; 161 where.bdev = ps->snap->cow->bdev;
163 where.sector = ps->chunk_size * chunk; 162 where.sector = ps->snap->chunk_size * chunk;
164 where.count = ps->chunk_size; 163 where.count = ps->snap->chunk_size;
165 164
166 return dm_io_sync_vm(1, &where, rw, ps->area, &bits); 165 return dm_io_sync_vm(1, &where, rw, ps->area, &bits);
167} 166}
@@ -188,7 +187,7 @@ static int area_io(struct pstore *ps, uint32_t area, int rw)
188 187
189static int zero_area(struct pstore *ps, uint32_t area) 188static int zero_area(struct pstore *ps, uint32_t area)
190{ 189{
191 memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); 190 memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
192 return area_io(ps, area, WRITE); 191 return area_io(ps, area, WRITE);
193} 192}
194 193
@@ -196,6 +195,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
196{ 195{
197 int r; 196 int r;
198 struct disk_header *dh; 197 struct disk_header *dh;
198 chunk_t chunk_size;
199 199
200 r = chunk_io(ps, 0, READ); 200 r = chunk_io(ps, 0, READ);
201 if (r) 201 if (r)
@@ -210,8 +210,29 @@ static int read_header(struct pstore *ps, int *new_snapshot)
210 *new_snapshot = 0; 210 *new_snapshot = 0;
211 ps->valid = le32_to_cpu(dh->valid); 211 ps->valid = le32_to_cpu(dh->valid);
212 ps->version = le32_to_cpu(dh->version); 212 ps->version = le32_to_cpu(dh->version);
213 ps->chunk_size = le32_to_cpu(dh->chunk_size); 213 chunk_size = le32_to_cpu(dh->chunk_size);
214 214 if (ps->snap->chunk_size != chunk_size) {
215 DMWARN("chunk size %llu in device metadata overrides "
216 "table chunk size of %llu.",
217 (unsigned long long)chunk_size,
218 (unsigned long long)ps->snap->chunk_size);
219
220 /* We had a bogus chunk_size. Fix stuff up. */
221 dm_io_put(sectors_to_pages(ps->snap->chunk_size));
222 free_area(ps);
223
224 ps->snap->chunk_size = chunk_size;
225 ps->snap->chunk_mask = chunk_size - 1;
226 ps->snap->chunk_shift = ffs(chunk_size) - 1;
227
228 r = alloc_area(ps);
229 if (r)
230 return r;
231
232 r = dm_io_get(sectors_to_pages(chunk_size));
233 if (r)
234 return r;
235 }
215 } else { 236 } else {
216 DMWARN("Invalid/corrupt snapshot"); 237 DMWARN("Invalid/corrupt snapshot");
217 r = -ENXIO; 238 r = -ENXIO;
@@ -224,13 +245,13 @@ static int write_header(struct pstore *ps)
224{ 245{
225 struct disk_header *dh; 246 struct disk_header *dh;
226 247
227 memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); 248 memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
228 249
229 dh = (struct disk_header *) ps->area; 250 dh = (struct disk_header *) ps->area;
230 dh->magic = cpu_to_le32(SNAP_MAGIC); 251 dh->magic = cpu_to_le32(SNAP_MAGIC);
231 dh->valid = cpu_to_le32(ps->valid); 252 dh->valid = cpu_to_le32(ps->valid);
232 dh->version = cpu_to_le32(ps->version); 253 dh->version = cpu_to_le32(ps->version);
233 dh->chunk_size = cpu_to_le32(ps->chunk_size); 254 dh->chunk_size = cpu_to_le32(ps->snap->chunk_size);
234 255
235 return chunk_io(ps, 0, WRITE); 256 return chunk_io(ps, 0, WRITE);
236} 257}
@@ -365,7 +386,7 @@ static void persistent_destroy(struct exception_store *store)
365{ 386{
366 struct pstore *ps = get_info(store); 387 struct pstore *ps = get_info(store);
367 388
368 dm_io_put(sectors_to_pages(ps->chunk_size)); 389 dm_io_put(sectors_to_pages(ps->snap->chunk_size));
369 vfree(ps->callbacks); 390 vfree(ps->callbacks);
370 free_area(ps); 391 free_area(ps);
371 kfree(ps); 392 kfree(ps);
@@ -384,6 +405,16 @@ static int persistent_read_metadata(struct exception_store *store)
384 return r; 405 return r;
385 406
386 /* 407 /*
408 * Now we know correct chunk_size, complete the initialisation.
409 */
410 ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) /
411 sizeof(struct disk_exception);
412 ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
413 sizeof(*ps->callbacks));
414 if (!ps->callbacks)
415 return -ENOMEM;
416
417 /*
387 * Do we need to setup a new snapshot ? 418 * Do we need to setup a new snapshot ?
388 */ 419 */
389 if (new_snapshot) { 420 if (new_snapshot) {
@@ -533,9 +564,6 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
533 ps->snap = store->snap; 564 ps->snap = store->snap;
534 ps->valid = 1; 565 ps->valid = 1;
535 ps->version = SNAPSHOT_DISK_VERSION; 566 ps->version = SNAPSHOT_DISK_VERSION;
536 ps->chunk_size = chunk_size;
537 ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) /
538 sizeof(struct disk_exception);
539 ps->next_free = 2; /* skipping the header and first area */ 567 ps->next_free = 2; /* skipping the header and first area */
540 ps->current_committed = 0; 568 ps->current_committed = 0;
541 569
@@ -543,18 +571,9 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
543 if (r) 571 if (r)
544 goto bad; 572 goto bad;
545 573
546 /*
547 * Allocate space for all the callbacks.
548 */
549 ps->callback_count = 0; 574 ps->callback_count = 0;
550 atomic_set(&ps->pending_count, 0); 575 atomic_set(&ps->pending_count, 0);
551 ps->callbacks = dm_vcalloc(ps->exceptions_per_area, 576 ps->callbacks = NULL;
552 sizeof(*ps->callbacks));
553
554 if (!ps->callbacks) {
555 r = -ENOMEM;
556 goto bad;
557 }
558 577
559 store->destroy = persistent_destroy; 578 store->destroy = persistent_destroy;
560 store->read_metadata = persistent_read_metadata; 579 store->read_metadata = persistent_read_metadata;
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 08312b46463a..b84bc1aae353 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -530,7 +530,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
530 } 530 }
531 531
532 ti->private = s; 532 ti->private = s;
533 ti->split_io = chunk_size; 533 ti->split_io = s->chunk_size;
534 534
535 return 0; 535 return 0;
536 536
@@ -1204,7 +1204,7 @@ static int origin_status(struct dm_target *ti, status_type_t type, char *result,
1204 1204
1205static struct target_type origin_target = { 1205static struct target_type origin_target = {
1206 .name = "snapshot-origin", 1206 .name = "snapshot-origin",
1207 .version = {1, 1, 0}, 1207 .version = {1, 4, 0},
1208 .module = THIS_MODULE, 1208 .module = THIS_MODULE,
1209 .ctr = origin_ctr, 1209 .ctr = origin_ctr,
1210 .dtr = origin_dtr, 1210 .dtr = origin_dtr,
@@ -1215,7 +1215,7 @@ static struct target_type origin_target = {
1215 1215
1216static struct target_type snapshot_target = { 1216static struct target_type snapshot_target = {
1217 .name = "snapshot", 1217 .name = "snapshot",
1218 .version = {1, 1, 0}, 1218 .version = {1, 4, 0},
1219 .module = THIS_MODULE, 1219 .module = THIS_MODULE,
1220 .ctr = snapshot_ctr, 1220 .ctr = snapshot_ctr,
1221 .dtr = snapshot_dtr, 1221 .dtr = snapshot_dtr,