diff options
author | Joe Thornber <ejt@redhat.com> | 2014-06-13 09:47:24 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2014-08-01 12:30:32 -0400 |
commit | e5aea7b49f2b1fd01f35ca7abeb76f5c56128a55 (patch) | |
tree | 02a829b3be21ed5cf51f2fe585a1a751f25a7599 /drivers/md | |
parent | 50f3c3efdd5773d90396be07a7ecaa58227ff906 (diff) |
dm thin: relax external origin size constraints
Track the size of any external origin. Previously the external origin's
size had to be a multiple of the thin-pool's block size, that is no
longer a requirement. In addition, snapshots that are larger than the
external origin are now supported.
Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-thin.c | 158 |
1 files changed, 115 insertions, 43 deletions
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 4c9a3b5f4ff1..0e844a5eca8f 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c | |||
@@ -227,6 +227,7 @@ struct thin_c { | |||
227 | struct list_head list; | 227 | struct list_head list; |
228 | struct dm_dev *pool_dev; | 228 | struct dm_dev *pool_dev; |
229 | struct dm_dev *origin_dev; | 229 | struct dm_dev *origin_dev; |
230 | sector_t origin_size; | ||
230 | dm_thin_id dev_id; | 231 | dm_thin_id dev_id; |
231 | 232 | ||
232 | struct pool *pool; | 233 | struct pool *pool; |
@@ -590,31 +591,31 @@ static void __complete_mapping_preparation(struct dm_thin_new_mapping *m) | |||
590 | } | 591 | } |
591 | } | 592 | } |
592 | 593 | ||
593 | static void copy_complete(int read_err, unsigned long write_err, void *context) | 594 | static void complete_mapping_preparation(struct dm_thin_new_mapping *m) |
594 | { | 595 | { |
595 | unsigned long flags; | 596 | unsigned long flags; |
596 | struct dm_thin_new_mapping *m = context; | ||
597 | struct pool *pool = m->tc->pool; | 597 | struct pool *pool = m->tc->pool; |
598 | 598 | ||
599 | m->err = read_err || write_err ? -EIO : 0; | ||
600 | |||
601 | spin_lock_irqsave(&pool->lock, flags); | 599 | spin_lock_irqsave(&pool->lock, flags); |
602 | __complete_mapping_preparation(m); | 600 | __complete_mapping_preparation(m); |
603 | spin_unlock_irqrestore(&pool->lock, flags); | 601 | spin_unlock_irqrestore(&pool->lock, flags); |
604 | } | 602 | } |
605 | 603 | ||
604 | static void copy_complete(int read_err, unsigned long write_err, void *context) | ||
605 | { | ||
606 | struct dm_thin_new_mapping *m = context; | ||
607 | |||
608 | m->err = read_err || write_err ? -EIO : 0; | ||
609 | complete_mapping_preparation(m); | ||
610 | } | ||
611 | |||
606 | static void overwrite_endio(struct bio *bio, int err) | 612 | static void overwrite_endio(struct bio *bio, int err) |
607 | { | 613 | { |
608 | unsigned long flags; | ||
609 | struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook)); | 614 | struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook)); |
610 | struct dm_thin_new_mapping *m = h->overwrite_mapping; | 615 | struct dm_thin_new_mapping *m = h->overwrite_mapping; |
611 | struct pool *pool = m->tc->pool; | ||
612 | 616 | ||
613 | m->err = err; | 617 | m->err = err; |
614 | 618 | complete_mapping_preparation(m); | |
615 | spin_lock_irqsave(&pool->lock, flags); | ||
616 | __complete_mapping_preparation(m); | ||
617 | spin_unlock_irqrestore(&pool->lock, flags); | ||
618 | } | 619 | } |
619 | 620 | ||
620 | /*----------------------------------------------------------------*/ | 621 | /*----------------------------------------------------------------*/ |
@@ -824,10 +825,31 @@ static struct dm_thin_new_mapping *get_next_mapping(struct pool *pool) | |||
824 | return m; | 825 | return m; |
825 | } | 826 | } |
826 | 827 | ||
828 | static void ll_zero(struct thin_c *tc, struct dm_thin_new_mapping *m, | ||
829 | sector_t begin, sector_t end) | ||
830 | { | ||
831 | int r; | ||
832 | struct dm_io_region to; | ||
833 | |||
834 | to.bdev = tc->pool_dev->bdev; | ||
835 | to.sector = begin; | ||
836 | to.count = end - begin; | ||
837 | |||
838 | r = dm_kcopyd_zero(tc->pool->copier, 1, &to, 0, copy_complete, m); | ||
839 | if (r < 0) { | ||
840 | DMERR_LIMIT("dm_kcopyd_zero() failed"); | ||
841 | copy_complete(1, 1, m); | ||
842 | } | ||
843 | } | ||
844 | |||
845 | /* | ||
846 | * A partial copy also needs to zero the uncopied region. | ||
847 | */ | ||
827 | static void schedule_copy(struct thin_c *tc, dm_block_t virt_block, | 848 | static void schedule_copy(struct thin_c *tc, dm_block_t virt_block, |
828 | struct dm_dev *origin, dm_block_t data_origin, | 849 | struct dm_dev *origin, dm_block_t data_origin, |
829 | dm_block_t data_dest, | 850 | dm_block_t data_dest, |
830 | struct dm_bio_prison_cell *cell, struct bio *bio) | 851 | struct dm_bio_prison_cell *cell, struct bio *bio, |
852 | sector_t len) | ||
831 | { | 853 | { |
832 | int r; | 854 | int r; |
833 | struct pool *pool = tc->pool; | 855 | struct pool *pool = tc->pool; |
@@ -838,10 +860,15 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block, | |||
838 | m->data_block = data_dest; | 860 | m->data_block = data_dest; |
839 | m->cell = cell; | 861 | m->cell = cell; |
840 | 862 | ||
863 | /* | ||
864 | * quiesce action + copy action + an extra reference held for the | ||
865 | * duration of this function (we may need to inc later for a | ||
866 | * partial zero). | ||
867 | */ | ||
868 | atomic_set(&m->prepare_actions, 3); | ||
869 | |||
841 | if (!dm_deferred_set_add_work(pool->shared_read_ds, &m->list)) | 870 | if (!dm_deferred_set_add_work(pool->shared_read_ds, &m->list)) |
842 | atomic_set(&m->prepare_actions, 1); /* copy only */ | 871 | complete_mapping_preparation(m); /* already quiesced */ |
843 | else | ||
844 | atomic_set(&m->prepare_actions, 2); /* quiesce + copy */ | ||
845 | 872 | ||
846 | /* | 873 | /* |
847 | * IO to pool_dev remaps to the pool target's data_dev. | 874 | * IO to pool_dev remaps to the pool target's data_dev. |
@@ -862,20 +889,38 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block, | |||
862 | 889 | ||
863 | from.bdev = origin->bdev; | 890 | from.bdev = origin->bdev; |
864 | from.sector = data_origin * pool->sectors_per_block; | 891 | from.sector = data_origin * pool->sectors_per_block; |
865 | from.count = pool->sectors_per_block; | 892 | from.count = len; |
866 | 893 | ||
867 | to.bdev = tc->pool_dev->bdev; | 894 | to.bdev = tc->pool_dev->bdev; |
868 | to.sector = data_dest * pool->sectors_per_block; | 895 | to.sector = data_dest * pool->sectors_per_block; |
869 | to.count = pool->sectors_per_block; | 896 | to.count = len; |
870 | 897 | ||
871 | r = dm_kcopyd_copy(pool->copier, &from, 1, &to, | 898 | r = dm_kcopyd_copy(pool->copier, &from, 1, &to, |
872 | 0, copy_complete, m); | 899 | 0, copy_complete, m); |
873 | if (r < 0) { | 900 | if (r < 0) { |
874 | mempool_free(m, pool->mapping_pool); | ||
875 | DMERR_LIMIT("dm_kcopyd_copy() failed"); | 901 | DMERR_LIMIT("dm_kcopyd_copy() failed"); |
876 | cell_error(pool, cell); | 902 | copy_complete(1, 1, m); |
903 | |||
904 | /* | ||
905 | * We allow the zero to be issued, to simplify the | ||
906 | * error path. Otherwise we'd need to start | ||
907 | * worrying about decrementing the prepare_actions | ||
908 | * counter. | ||
909 | */ | ||
910 | } | ||
911 | |||
912 | /* | ||
913 | * Do we need to zero a tail region? | ||
914 | */ | ||
915 | if (len < pool->sectors_per_block && pool->pf.zero_new_blocks) { | ||
916 | atomic_inc(&m->prepare_actions); | ||
917 | ll_zero(tc, m, | ||
918 | data_dest * pool->sectors_per_block + len, | ||
919 | (data_dest + 1) * pool->sectors_per_block); | ||
877 | } | 920 | } |
878 | } | 921 | } |
922 | |||
923 | complete_mapping_preparation(m); /* drop our ref */ | ||
879 | } | 924 | } |
880 | 925 | ||
881 | static void schedule_internal_copy(struct thin_c *tc, dm_block_t virt_block, | 926 | static void schedule_internal_copy(struct thin_c *tc, dm_block_t virt_block, |
@@ -883,15 +928,8 @@ static void schedule_internal_copy(struct thin_c *tc, dm_block_t virt_block, | |||
883 | struct dm_bio_prison_cell *cell, struct bio *bio) | 928 | struct dm_bio_prison_cell *cell, struct bio *bio) |
884 | { | 929 | { |
885 | schedule_copy(tc, virt_block, tc->pool_dev, | 930 | schedule_copy(tc, virt_block, tc->pool_dev, |
886 | data_origin, data_dest, cell, bio); | 931 | data_origin, data_dest, cell, bio, |
887 | } | 932 | tc->pool->sectors_per_block); |
888 | |||
889 | static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block, | ||
890 | dm_block_t data_dest, | ||
891 | struct dm_bio_prison_cell *cell, struct bio *bio) | ||
892 | { | ||
893 | schedule_copy(tc, virt_block, tc->origin_dev, | ||
894 | virt_block, data_dest, cell, bio); | ||
895 | } | 933 | } |
896 | 934 | ||
897 | static void schedule_zero(struct thin_c *tc, dm_block_t virt_block, | 935 | static void schedule_zero(struct thin_c *tc, dm_block_t virt_block, |
@@ -923,21 +961,33 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block, | |||
923 | save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio); | 961 | save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio); |
924 | inc_all_io_entry(pool, bio); | 962 | inc_all_io_entry(pool, bio); |
925 | remap_and_issue(tc, bio, data_block); | 963 | remap_and_issue(tc, bio, data_block); |
926 | } else { | ||
927 | int r; | ||
928 | struct dm_io_region to; | ||
929 | 964 | ||
930 | to.bdev = tc->pool_dev->bdev; | 965 | } else |
931 | to.sector = data_block * pool->sectors_per_block; | 966 | ll_zero(tc, m, |
932 | to.count = pool->sectors_per_block; | 967 | data_block * pool->sectors_per_block, |
968 | (data_block + 1) * pool->sectors_per_block); | ||
969 | } | ||
933 | 970 | ||
934 | r = dm_kcopyd_zero(pool->copier, 1, &to, 0, copy_complete, m); | 971 | static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block, |
935 | if (r < 0) { | 972 | dm_block_t data_dest, |
936 | mempool_free(m, pool->mapping_pool); | 973 | struct dm_bio_prison_cell *cell, struct bio *bio) |
937 | DMERR_LIMIT("dm_kcopyd_zero() failed"); | 974 | { |
938 | cell_error(pool, cell); | 975 | struct pool *pool = tc->pool; |
939 | } | 976 | sector_t virt_block_begin = virt_block * pool->sectors_per_block; |
940 | } | 977 | sector_t virt_block_end = (virt_block + 1) * pool->sectors_per_block; |
978 | |||
979 | if (virt_block_end <= tc->origin_size) | ||
980 | schedule_copy(tc, virt_block, tc->origin_dev, | ||
981 | virt_block, data_dest, cell, bio, | ||
982 | pool->sectors_per_block); | ||
983 | |||
984 | else if (virt_block_begin < tc->origin_size) | ||
985 | schedule_copy(tc, virt_block, tc->origin_dev, | ||
986 | virt_block, data_dest, cell, bio, | ||
987 | tc->origin_size - virt_block_begin); | ||
988 | |||
989 | else | ||
990 | schedule_zero(tc, virt_block, data_dest, cell, bio); | ||
941 | } | 991 | } |
942 | 992 | ||
943 | /* | 993 | /* |
@@ -1319,7 +1369,18 @@ static void process_bio(struct thin_c *tc, struct bio *bio) | |||
1319 | inc_all_io_entry(pool, bio); | 1369 | inc_all_io_entry(pool, bio); |
1320 | cell_defer_no_holder(tc, cell); | 1370 | cell_defer_no_holder(tc, cell); |
1321 | 1371 | ||
1322 | remap_to_origin_and_issue(tc, bio); | 1372 | if (bio_end_sector(bio) <= tc->origin_size) |
1373 | remap_to_origin_and_issue(tc, bio); | ||
1374 | |||
1375 | else if (bio->bi_iter.bi_sector < tc->origin_size) { | ||
1376 | zero_fill_bio(bio); | ||
1377 | bio->bi_iter.bi_size = (tc->origin_size - bio->bi_iter.bi_sector) << SECTOR_SHIFT; | ||
1378 | remap_to_origin_and_issue(tc, bio); | ||
1379 | |||
1380 | } else { | ||
1381 | zero_fill_bio(bio); | ||
1382 | bio_endio(bio, 0); | ||
1383 | } | ||
1323 | } else | 1384 | } else |
1324 | provision_block(tc, bio, block, cell); | 1385 | provision_block(tc, bio, block, cell); |
1325 | break; | 1386 | break; |
@@ -3145,7 +3206,7 @@ static struct target_type pool_target = { | |||
3145 | .name = "thin-pool", | 3206 | .name = "thin-pool", |
3146 | .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | | 3207 | .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | |
3147 | DM_TARGET_IMMUTABLE, | 3208 | DM_TARGET_IMMUTABLE, |
3148 | .version = {1, 12, 0}, | 3209 | .version = {1, 13, 0}, |
3149 | .module = THIS_MODULE, | 3210 | .module = THIS_MODULE, |
3150 | .ctr = pool_ctr, | 3211 | .ctr = pool_ctr, |
3151 | .dtr = pool_dtr, | 3212 | .dtr = pool_dtr, |
@@ -3404,6 +3465,16 @@ static void thin_postsuspend(struct dm_target *ti) | |||
3404 | noflush_work(tc, do_noflush_stop); | 3465 | noflush_work(tc, do_noflush_stop); |
3405 | } | 3466 | } |
3406 | 3467 | ||
3468 | static int thin_preresume(struct dm_target *ti) | ||
3469 | { | ||
3470 | struct thin_c *tc = ti->private; | ||
3471 | |||
3472 | if (tc->origin_dev) | ||
3473 | tc->origin_size = get_dev_size(tc->origin_dev->bdev); | ||
3474 | |||
3475 | return 0; | ||
3476 | } | ||
3477 | |||
3407 | /* | 3478 | /* |
3408 | * <nr mapped sectors> <highest mapped sector> | 3479 | * <nr mapped sectors> <highest mapped sector> |
3409 | */ | 3480 | */ |
@@ -3486,12 +3557,13 @@ static int thin_iterate_devices(struct dm_target *ti, | |||
3486 | 3557 | ||
3487 | static struct target_type thin_target = { | 3558 | static struct target_type thin_target = { |
3488 | .name = "thin", | 3559 | .name = "thin", |
3489 | .version = {1, 12, 0}, | 3560 | .version = {1, 13, 0}, |
3490 | .module = THIS_MODULE, | 3561 | .module = THIS_MODULE, |
3491 | .ctr = thin_ctr, | 3562 | .ctr = thin_ctr, |
3492 | .dtr = thin_dtr, | 3563 | .dtr = thin_dtr, |
3493 | .map = thin_map, | 3564 | .map = thin_map, |
3494 | .end_io = thin_endio, | 3565 | .end_io = thin_endio, |
3566 | .preresume = thin_preresume, | ||
3495 | .presuspend = thin_presuspend, | 3567 | .presuspend = thin_presuspend, |
3496 | .postsuspend = thin_postsuspend, | 3568 | .postsuspend = thin_postsuspend, |
3497 | .status = thin_status, | 3569 | .status = thin_status, |