aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2009-09-04 15:40:43 -0400
committerAlasdair G Kergon <agk@redhat.com>2009-09-04 15:40:43 -0400
commitae0b7448e91353ea5f821601a055aca6b58042cd (patch)
treea5c5d0532c808fb1eb2c01414edfcd2d0c039a7e /drivers
parent2defcc3fb4661e7351cb2ac48d843efc4c64db13 (diff)
dm snapshot: fix on disk chunk size validation
Fix some problems seen in the chunk size processing when activating a pre-existing snapshot. For a new snapshot, the chunk size can either be supplied by the creator or a default value can be used. For an existing snapshot, the chunk size in the snapshot header on disk should always be used. If someone attempts to load an existing snapshot and has the 'default chunk size' option set, the kernel uses its default value even when it is incorrect for the snapshot being loaded. This patch ensures the correct on-disk value is always used. Secondly, when the code does use the chunk size stored on the disk it is prudent to revalidate it, so the code can exit cleanly if it got corrupted as happened in https://bugzilla.redhat.com/show_bug.cgi?id=461506 . Cc: stable@kernel.org Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm-exception-store.c5
-rw-r--r--drivers/md/dm-snap-persistent.c22
2 files changed, 19 insertions, 8 deletions
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 4c01c7535fb5..556acff3952f 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -191,6 +191,11 @@ int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
191 return -EINVAL; 191 return -EINVAL;
192 } 192 }
193 193
194 if (chunk_size_ulong > INT_MAX >> SECTOR_SHIFT) {
195 *error = "Chunk size is too high";
196 return -EINVAL;
197 }
198
194 store->chunk_size = chunk_size_ulong; 199 store->chunk_size = chunk_size_ulong;
195 store->chunk_mask = chunk_size_ulong - 1; 200 store->chunk_mask = chunk_size_ulong - 1;
196 store->chunk_shift = ffs(chunk_size_ulong) - 1; 201 store->chunk_shift = ffs(chunk_size_ulong) - 1;
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index 5d1a97580cb7..d5b2e08750d5 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -286,6 +286,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
286 struct disk_header *dh; 286 struct disk_header *dh;
287 chunk_t chunk_size; 287 chunk_t chunk_size;
288 int chunk_size_supplied = 1; 288 int chunk_size_supplied = 1;
289 char *chunk_err;
289 290
290 /* 291 /*
291 * Use default chunk size (or hardsect_size, if larger) if none supplied 292 * Use default chunk size (or hardsect_size, if larger) if none supplied
@@ -329,20 +330,25 @@ static int read_header(struct pstore *ps, int *new_snapshot)
329 ps->version = le32_to_cpu(dh->version); 330 ps->version = le32_to_cpu(dh->version);
330 chunk_size = le32_to_cpu(dh->chunk_size); 331 chunk_size = le32_to_cpu(dh->chunk_size);
331 332
332 if (!chunk_size_supplied || ps->store->chunk_size == chunk_size) 333 if (ps->store->chunk_size == chunk_size)
333 return 0; 334 return 0;
334 335
335 DMWARN("chunk size %llu in device metadata overrides " 336 if (chunk_size_supplied)
336 "table chunk size of %llu.", 337 DMWARN("chunk size %llu in device metadata overrides "
337 (unsigned long long)chunk_size, 338 "table chunk size of %llu.",
338 (unsigned long long)ps->store->chunk_size); 339 (unsigned long long)chunk_size,
340 (unsigned long long)ps->store->chunk_size);
339 341
340 /* We had a bogus chunk_size. Fix stuff up. */ 342 /* We had a bogus chunk_size. Fix stuff up. */
341 free_area(ps); 343 free_area(ps);
342 344
343 ps->store->chunk_size = chunk_size; 345 r = dm_exception_store_set_chunk_size(ps->store, chunk_size,
344 ps->store->chunk_mask = chunk_size - 1; 346 &chunk_err);
345 ps->store->chunk_shift = ffs(chunk_size) - 1; 347 if (r) {
348 DMERR("invalid on-disk chunk size %llu: %s.",
349 (unsigned long long)chunk_size, chunk_err);
350 return r;
351 }
346 352
347 r = dm_io_client_resize(sectors_to_pages(ps->store->chunk_size), 353 r = dm_io_client_resize(sectors_to_pages(ps->store->chunk_size),
348 ps->io_client); 354 ps->io_client);