diff options
Diffstat (limited to 'drivers/md/dm-exception-store.c')
-rw-r--r-- | drivers/md/dm-exception-store.c | 67 |
1 files changed, 44 insertions, 23 deletions
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index cc07bbebbb16..d12379b5cdb5 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | 18 | ||
19 | #define DM_MSG_PREFIX "snapshots" | ||
20 | |||
19 | /*----------------------------------------------------------------- | 21 | /*----------------------------------------------------------------- |
20 | * Persistent snapshots, by persistent we mean that the snapshot | 22 | * Persistent snapshots, by persistent we mean that the snapshot |
21 | * will survive a reboot. | 23 | * will survive a reboot. |
@@ -91,7 +93,6 @@ struct pstore { | |||
91 | struct dm_snapshot *snap; /* up pointer to my snapshot */ | 93 | struct dm_snapshot *snap; /* up pointer to my snapshot */ |
92 | int version; | 94 | int version; |
93 | int valid; | 95 | int valid; |
94 | uint32_t chunk_size; | ||
95 | uint32_t exceptions_per_area; | 96 | uint32_t exceptions_per_area; |
96 | 97 | ||
97 | /* | 98 | /* |
@@ -133,7 +134,7 @@ static int alloc_area(struct pstore *ps) | |||
133 | int r = -ENOMEM; | 134 | int r = -ENOMEM; |
134 | size_t len; | 135 | size_t len; |
135 | 136 | ||
136 | len = ps->chunk_size << SECTOR_SHIFT; | 137 | len = ps->snap->chunk_size << SECTOR_SHIFT; |
137 | 138 | ||
138 | /* | 139 | /* |
139 | * Allocate the chunk_size block of memory that will hold | 140 | * Allocate the chunk_size block of memory that will hold |
@@ -160,8 +161,8 @@ static int chunk_io(struct pstore *ps, uint32_t chunk, int rw) | |||
160 | unsigned long bits; | 161 | unsigned long bits; |
161 | 162 | ||
162 | where.bdev = ps->snap->cow->bdev; | 163 | where.bdev = ps->snap->cow->bdev; |
163 | where.sector = ps->chunk_size * chunk; | 164 | where.sector = ps->snap->chunk_size * chunk; |
164 | where.count = ps->chunk_size; | 165 | where.count = ps->snap->chunk_size; |
165 | 166 | ||
166 | return dm_io_sync_vm(1, &where, rw, ps->area, &bits); | 167 | return dm_io_sync_vm(1, &where, rw, ps->area, &bits); |
167 | } | 168 | } |
@@ -188,7 +189,7 @@ static int area_io(struct pstore *ps, uint32_t area, int rw) | |||
188 | 189 | ||
189 | static int zero_area(struct pstore *ps, uint32_t area) | 190 | static int zero_area(struct pstore *ps, uint32_t area) |
190 | { | 191 | { |
191 | memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); | 192 | memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); |
192 | return area_io(ps, area, WRITE); | 193 | return area_io(ps, area, WRITE); |
193 | } | 194 | } |
194 | 195 | ||
@@ -196,6 +197,7 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
196 | { | 197 | { |
197 | int r; | 198 | int r; |
198 | struct disk_header *dh; | 199 | struct disk_header *dh; |
200 | chunk_t chunk_size; | ||
199 | 201 | ||
200 | r = chunk_io(ps, 0, READ); | 202 | r = chunk_io(ps, 0, READ); |
201 | if (r) | 203 | if (r) |
@@ -210,8 +212,29 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
210 | *new_snapshot = 0; | 212 | *new_snapshot = 0; |
211 | ps->valid = le32_to_cpu(dh->valid); | 213 | ps->valid = le32_to_cpu(dh->valid); |
212 | ps->version = le32_to_cpu(dh->version); | 214 | ps->version = le32_to_cpu(dh->version); |
213 | ps->chunk_size = le32_to_cpu(dh->chunk_size); | 215 | chunk_size = le32_to_cpu(dh->chunk_size); |
214 | 216 | if (ps->snap->chunk_size != chunk_size) { | |
217 | DMWARN("chunk size %llu in device metadata overrides " | ||
218 | "table chunk size of %llu.", | ||
219 | (unsigned long long)chunk_size, | ||
220 | (unsigned long long)ps->snap->chunk_size); | ||
221 | |||
222 | /* We had a bogus chunk_size. Fix stuff up. */ | ||
223 | dm_io_put(sectors_to_pages(ps->snap->chunk_size)); | ||
224 | free_area(ps); | ||
225 | |||
226 | ps->snap->chunk_size = chunk_size; | ||
227 | ps->snap->chunk_mask = chunk_size - 1; | ||
228 | ps->snap->chunk_shift = ffs(chunk_size) - 1; | ||
229 | |||
230 | r = alloc_area(ps); | ||
231 | if (r) | ||
232 | return r; | ||
233 | |||
234 | r = dm_io_get(sectors_to_pages(chunk_size)); | ||
235 | if (r) | ||
236 | return r; | ||
237 | } | ||
215 | } else { | 238 | } else { |
216 | DMWARN("Invalid/corrupt snapshot"); | 239 | DMWARN("Invalid/corrupt snapshot"); |
217 | r = -ENXIO; | 240 | r = -ENXIO; |
@@ -224,13 +247,13 @@ static int write_header(struct pstore *ps) | |||
224 | { | 247 | { |
225 | struct disk_header *dh; | 248 | struct disk_header *dh; |
226 | 249 | ||
227 | memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); | 250 | memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); |
228 | 251 | ||
229 | dh = (struct disk_header *) ps->area; | 252 | dh = (struct disk_header *) ps->area; |
230 | dh->magic = cpu_to_le32(SNAP_MAGIC); | 253 | dh->magic = cpu_to_le32(SNAP_MAGIC); |
231 | dh->valid = cpu_to_le32(ps->valid); | 254 | dh->valid = cpu_to_le32(ps->valid); |
232 | dh->version = cpu_to_le32(ps->version); | 255 | dh->version = cpu_to_le32(ps->version); |
233 | dh->chunk_size = cpu_to_le32(ps->chunk_size); | 256 | dh->chunk_size = cpu_to_le32(ps->snap->chunk_size); |
234 | 257 | ||
235 | return chunk_io(ps, 0, WRITE); | 258 | return chunk_io(ps, 0, WRITE); |
236 | } | 259 | } |
@@ -365,7 +388,7 @@ static void persistent_destroy(struct exception_store *store) | |||
365 | { | 388 | { |
366 | struct pstore *ps = get_info(store); | 389 | struct pstore *ps = get_info(store); |
367 | 390 | ||
368 | dm_io_put(sectors_to_pages(ps->chunk_size)); | 391 | dm_io_put(sectors_to_pages(ps->snap->chunk_size)); |
369 | vfree(ps->callbacks); | 392 | vfree(ps->callbacks); |
370 | free_area(ps); | 393 | free_area(ps); |
371 | kfree(ps); | 394 | kfree(ps); |
@@ -384,6 +407,16 @@ static int persistent_read_metadata(struct exception_store *store) | |||
384 | return r; | 407 | return r; |
385 | 408 | ||
386 | /* | 409 | /* |
410 | * Now we know correct chunk_size, complete the initialisation. | ||
411 | */ | ||
412 | ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) / | ||
413 | sizeof(struct disk_exception); | ||
414 | ps->callbacks = dm_vcalloc(ps->exceptions_per_area, | ||
415 | sizeof(*ps->callbacks)); | ||
416 | if (!ps->callbacks) | ||
417 | return -ENOMEM; | ||
418 | |||
419 | /* | ||
387 | * Do we need to setup a new snapshot ? | 420 | * Do we need to setup a new snapshot ? |
388 | */ | 421 | */ |
389 | if (new_snapshot) { | 422 | if (new_snapshot) { |
@@ -533,9 +566,6 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size) | |||
533 | ps->snap = store->snap; | 566 | ps->snap = store->snap; |
534 | ps->valid = 1; | 567 | ps->valid = 1; |
535 | ps->version = SNAPSHOT_DISK_VERSION; | 568 | 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 */ | 569 | ps->next_free = 2; /* skipping the header and first area */ |
540 | ps->current_committed = 0; | 570 | ps->current_committed = 0; |
541 | 571 | ||
@@ -543,18 +573,9 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size) | |||
543 | if (r) | 573 | if (r) |
544 | goto bad; | 574 | goto bad; |
545 | 575 | ||
546 | /* | ||
547 | * Allocate space for all the callbacks. | ||
548 | */ | ||
549 | ps->callback_count = 0; | 576 | ps->callback_count = 0; |
550 | atomic_set(&ps->pending_count, 0); | 577 | atomic_set(&ps->pending_count, 0); |
551 | ps->callbacks = dm_vcalloc(ps->exceptions_per_area, | 578 | ps->callbacks = NULL; |
552 | sizeof(*ps->callbacks)); | ||
553 | |||
554 | if (!ps->callbacks) { | ||
555 | r = -ENOMEM; | ||
556 | goto bad; | ||
557 | } | ||
558 | 579 | ||
559 | store->destroy = persistent_destroy; | 580 | store->destroy = persistent_destroy; |
560 | store->read_metadata = persistent_read_metadata; | 581 | store->read_metadata = persistent_read_metadata; |