diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 22:30:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 22:30:50 -0500 |
commit | a4ffc0a0b240a29cbe489f6db9dae112a49ef1c1 (patch) | |
tree | 9719c706444f4b720aff2bb4bdf23a4be3f4b1e3 /drivers/md/dm-snap.c | |
parent | d7511ec8115487ccea2ce93bf58d5e5cd2c1c0a3 (diff) | |
parent | af195ac82e38ba802fd86b5a014ed05ef6dd88bb (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
* git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm: (44 commits)
dm raid1: report fault status
dm raid1: handle read failures
dm raid1: fix EIO after log failure
dm raid1: handle recovery failures
dm raid1: handle write failures
dm snapshot: combine consecutive exceptions in memory
dm: stripe enhanced status return
dm: stripe trigger event on failure
dm log: auto load modules
dm: move deferred bio flushing to workqueue
dm crypt: use async crypto
dm crypt: prepare async callback fn
dm crypt: add completion for async
dm crypt: add async request mempool
dm crypt: extract scatterlist processing
dm crypt: tidy io ref counting
dm crypt: introduce crypt_write_io_loop
dm crypt: abstract crypt_write_done
dm crypt: store sector mapping in dm_crypt_io
dm crypt: move queue functions
...
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r-- | drivers/md/dm-snap.c | 95 |
1 files changed, 69 insertions, 26 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index cee16fadd9ee..ae24eab8cd81 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -213,11 +213,15 @@ static void unregister_snapshot(struct dm_snapshot *s) | |||
213 | 213 | ||
214 | /* | 214 | /* |
215 | * Implementation of the exception hash tables. | 215 | * Implementation of the exception hash tables. |
216 | * The lowest hash_shift bits of the chunk number are ignored, allowing | ||
217 | * some consecutive chunks to be grouped together. | ||
216 | */ | 218 | */ |
217 | static int init_exception_table(struct exception_table *et, uint32_t size) | 219 | static int init_exception_table(struct exception_table *et, uint32_t size, |
220 | unsigned hash_shift) | ||
218 | { | 221 | { |
219 | unsigned int i; | 222 | unsigned int i; |
220 | 223 | ||
224 | et->hash_shift = hash_shift; | ||
221 | et->hash_mask = size - 1; | 225 | et->hash_mask = size - 1; |
222 | et->table = dm_vcalloc(size, sizeof(struct list_head)); | 226 | et->table = dm_vcalloc(size, sizeof(struct list_head)); |
223 | if (!et->table) | 227 | if (!et->table) |
@@ -248,7 +252,7 @@ static void exit_exception_table(struct exception_table *et, struct kmem_cache * | |||
248 | 252 | ||
249 | static uint32_t exception_hash(struct exception_table *et, chunk_t chunk) | 253 | static uint32_t exception_hash(struct exception_table *et, chunk_t chunk) |
250 | { | 254 | { |
251 | return chunk & et->hash_mask; | 255 | return (chunk >> et->hash_shift) & et->hash_mask; |
252 | } | 256 | } |
253 | 257 | ||
254 | static void insert_exception(struct exception_table *eh, | 258 | static void insert_exception(struct exception_table *eh, |
@@ -275,7 +279,8 @@ static struct dm_snap_exception *lookup_exception(struct exception_table *et, | |||
275 | 279 | ||
276 | slot = &et->table[exception_hash(et, chunk)]; | 280 | slot = &et->table[exception_hash(et, chunk)]; |
277 | list_for_each_entry (e, slot, hash_list) | 281 | list_for_each_entry (e, slot, hash_list) |
278 | if (e->old_chunk == chunk) | 282 | if (chunk >= e->old_chunk && |
283 | chunk <= e->old_chunk + dm_consecutive_chunk_count(e)) | ||
279 | return e; | 284 | return e; |
280 | 285 | ||
281 | return NULL; | 286 | return NULL; |
@@ -307,6 +312,49 @@ static void free_pending_exception(struct dm_snap_pending_exception *pe) | |||
307 | mempool_free(pe, pending_pool); | 312 | mempool_free(pe, pending_pool); |
308 | } | 313 | } |
309 | 314 | ||
315 | static void insert_completed_exception(struct dm_snapshot *s, | ||
316 | struct dm_snap_exception *new_e) | ||
317 | { | ||
318 | struct exception_table *eh = &s->complete; | ||
319 | struct list_head *l; | ||
320 | struct dm_snap_exception *e = NULL; | ||
321 | |||
322 | l = &eh->table[exception_hash(eh, new_e->old_chunk)]; | ||
323 | |||
324 | /* Add immediately if this table doesn't support consecutive chunks */ | ||
325 | if (!eh->hash_shift) | ||
326 | goto out; | ||
327 | |||
328 | /* List is ordered by old_chunk */ | ||
329 | list_for_each_entry_reverse(e, l, hash_list) { | ||
330 | /* Insert after an existing chunk? */ | ||
331 | if (new_e->old_chunk == (e->old_chunk + | ||
332 | dm_consecutive_chunk_count(e) + 1) && | ||
333 | new_e->new_chunk == (dm_chunk_number(e->new_chunk) + | ||
334 | dm_consecutive_chunk_count(e) + 1)) { | ||
335 | dm_consecutive_chunk_count_inc(e); | ||
336 | free_exception(new_e); | ||
337 | return; | ||
338 | } | ||
339 | |||
340 | /* Insert before an existing chunk? */ | ||
341 | if (new_e->old_chunk == (e->old_chunk - 1) && | ||
342 | new_e->new_chunk == (dm_chunk_number(e->new_chunk) - 1)) { | ||
343 | dm_consecutive_chunk_count_inc(e); | ||
344 | e->old_chunk--; | ||
345 | e->new_chunk--; | ||
346 | free_exception(new_e); | ||
347 | return; | ||
348 | } | ||
349 | |||
350 | if (new_e->old_chunk > e->old_chunk) | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | out: | ||
355 | list_add(&new_e->hash_list, e ? &e->hash_list : l); | ||
356 | } | ||
357 | |||
310 | int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new) | 358 | int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new) |
311 | { | 359 | { |
312 | struct dm_snap_exception *e; | 360 | struct dm_snap_exception *e; |
@@ -316,8 +364,12 @@ int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new) | |||
316 | return -ENOMEM; | 364 | return -ENOMEM; |
317 | 365 | ||
318 | e->old_chunk = old; | 366 | e->old_chunk = old; |
367 | |||
368 | /* Consecutive_count is implicitly initialised to zero */ | ||
319 | e->new_chunk = new; | 369 | e->new_chunk = new; |
320 | insert_exception(&s->complete, e); | 370 | |
371 | insert_completed_exception(s, e); | ||
372 | |||
321 | return 0; | 373 | return 0; |
322 | } | 374 | } |
323 | 375 | ||
@@ -334,16 +386,6 @@ static int calc_max_buckets(void) | |||
334 | } | 386 | } |
335 | 387 | ||
336 | /* | 388 | /* |
337 | * Rounds a number down to a power of 2. | ||
338 | */ | ||
339 | static uint32_t round_down(uint32_t n) | ||
340 | { | ||
341 | while (n & (n - 1)) | ||
342 | n &= (n - 1); | ||
343 | return n; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * Allocate room for a suitable hash table. | 389 | * Allocate room for a suitable hash table. |
348 | */ | 390 | */ |
349 | static int init_hash_tables(struct dm_snapshot *s) | 391 | static int init_hash_tables(struct dm_snapshot *s) |
@@ -361,9 +403,9 @@ static int init_hash_tables(struct dm_snapshot *s) | |||
361 | hash_size = min(origin_dev_size, cow_dev_size) >> s->chunk_shift; | 403 | hash_size = min(origin_dev_size, cow_dev_size) >> s->chunk_shift; |
362 | hash_size = min(hash_size, max_buckets); | 404 | hash_size = min(hash_size, max_buckets); |
363 | 405 | ||
364 | /* Round it down to a power of 2 */ | 406 | hash_size = rounddown_pow_of_two(hash_size); |
365 | hash_size = round_down(hash_size); | 407 | if (init_exception_table(&s->complete, hash_size, |
366 | if (init_exception_table(&s->complete, hash_size)) | 408 | DM_CHUNK_CONSECUTIVE_BITS)) |
367 | return -ENOMEM; | 409 | return -ENOMEM; |
368 | 410 | ||
369 | /* | 411 | /* |
@@ -374,7 +416,7 @@ static int init_hash_tables(struct dm_snapshot *s) | |||
374 | if (hash_size < 64) | 416 | if (hash_size < 64) |
375 | hash_size = 64; | 417 | hash_size = 64; |
376 | 418 | ||
377 | if (init_exception_table(&s->pending, hash_size)) { | 419 | if (init_exception_table(&s->pending, hash_size, 0)) { |
378 | exit_exception_table(&s->complete, exception_cache); | 420 | exit_exception_table(&s->complete, exception_cache); |
379 | return -ENOMEM; | 421 | return -ENOMEM; |
380 | } | 422 | } |
@@ -733,7 +775,7 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) | |||
733 | * Add a proper exception, and remove the | 775 | * Add a proper exception, and remove the |
734 | * in-flight exception from the list. | 776 | * in-flight exception from the list. |
735 | */ | 777 | */ |
736 | insert_exception(&s->complete, e); | 778 | insert_completed_exception(s, e); |
737 | 779 | ||
738 | out: | 780 | out: |
739 | remove_exception(&pe->e); | 781 | remove_exception(&pe->e); |
@@ -867,11 +909,12 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) | |||
867 | } | 909 | } |
868 | 910 | ||
869 | static void remap_exception(struct dm_snapshot *s, struct dm_snap_exception *e, | 911 | static void remap_exception(struct dm_snapshot *s, struct dm_snap_exception *e, |
870 | struct bio *bio) | 912 | struct bio *bio, chunk_t chunk) |
871 | { | 913 | { |
872 | bio->bi_bdev = s->cow->bdev; | 914 | bio->bi_bdev = s->cow->bdev; |
873 | bio->bi_sector = chunk_to_sector(s, e->new_chunk) + | 915 | bio->bi_sector = chunk_to_sector(s, dm_chunk_number(e->new_chunk) + |
874 | (bio->bi_sector & s->chunk_mask); | 916 | (chunk - e->old_chunk)) + |
917 | (bio->bi_sector & s->chunk_mask); | ||
875 | } | 918 | } |
876 | 919 | ||
877 | static int snapshot_map(struct dm_target *ti, struct bio *bio, | 920 | static int snapshot_map(struct dm_target *ti, struct bio *bio, |
@@ -902,7 +945,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, | |||
902 | /* If the block is already remapped - use that, else remap it */ | 945 | /* If the block is already remapped - use that, else remap it */ |
903 | e = lookup_exception(&s->complete, chunk); | 946 | e = lookup_exception(&s->complete, chunk); |
904 | if (e) { | 947 | if (e) { |
905 | remap_exception(s, e, bio); | 948 | remap_exception(s, e, bio, chunk); |
906 | goto out_unlock; | 949 | goto out_unlock; |
907 | } | 950 | } |
908 | 951 | ||
@@ -919,7 +962,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, | |||
919 | goto out_unlock; | 962 | goto out_unlock; |
920 | } | 963 | } |
921 | 964 | ||
922 | remap_exception(s, &pe->e, bio); | 965 | remap_exception(s, &pe->e, bio, chunk); |
923 | bio_list_add(&pe->snapshot_bios, bio); | 966 | bio_list_add(&pe->snapshot_bios, bio); |
924 | 967 | ||
925 | r = DM_MAPIO_SUBMITTED; | 968 | r = DM_MAPIO_SUBMITTED; |
@@ -1207,7 +1250,7 @@ static int origin_status(struct dm_target *ti, status_type_t type, char *result, | |||
1207 | 1250 | ||
1208 | static struct target_type origin_target = { | 1251 | static struct target_type origin_target = { |
1209 | .name = "snapshot-origin", | 1252 | .name = "snapshot-origin", |
1210 | .version = {1, 5, 0}, | 1253 | .version = {1, 6, 0}, |
1211 | .module = THIS_MODULE, | 1254 | .module = THIS_MODULE, |
1212 | .ctr = origin_ctr, | 1255 | .ctr = origin_ctr, |
1213 | .dtr = origin_dtr, | 1256 | .dtr = origin_dtr, |
@@ -1218,7 +1261,7 @@ static struct target_type origin_target = { | |||
1218 | 1261 | ||
1219 | static struct target_type snapshot_target = { | 1262 | static struct target_type snapshot_target = { |
1220 | .name = "snapshot", | 1263 | .name = "snapshot", |
1221 | .version = {1, 5, 0}, | 1264 | .version = {1, 6, 0}, |
1222 | .module = THIS_MODULE, | 1265 | .module = THIS_MODULE, |
1223 | .ctr = snapshot_ctr, | 1266 | .ctr = snapshot_ctr, |
1224 | .dtr = snapshot_dtr, | 1267 | .dtr = snapshot_dtr, |