diff options
author | Joe Thornber <ejt@redhat.com> | 2016-09-22 06:15:21 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2017-02-16 13:12:47 -0500 |
commit | 629d0a8a1a104187db8fbf966e4cc5cfb6aa9a3c (patch) | |
tree | df900a59355073aca34dd8de83d4ca631428cd6e /drivers/md/dm-cache-metadata.c | |
parent | ae4a46a1f60942263d6fd119fe1da49bb16d2bd5 (diff) |
dm cache metadata: add "metadata2" feature
If "metadata2" is provided as a table argument when creating/loading a
cache target a more compact metadata format, with separate dirty bits,
is used. "metadata2" improves speed of shutting down a cache target.
Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md/dm-cache-metadata.c')
-rw-r--r-- | drivers/md/dm-cache-metadata.c | 278 |
1 files changed, 245 insertions, 33 deletions
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index 9364a02e1646..0610be7846dc 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c | |||
@@ -25,7 +25,7 @@ | |||
25 | * defines a range of metadata versions that this module can handle. | 25 | * defines a range of metadata versions that this module can handle. |
26 | */ | 26 | */ |
27 | #define MIN_CACHE_VERSION 1 | 27 | #define MIN_CACHE_VERSION 1 |
28 | #define MAX_CACHE_VERSION 1 | 28 | #define MAX_CACHE_VERSION 2 |
29 | 29 | ||
30 | #define CACHE_METADATA_CACHE_SIZE 64 | 30 | #define CACHE_METADATA_CACHE_SIZE 64 |
31 | 31 | ||
@@ -55,6 +55,7 @@ enum mapping_bits { | |||
55 | 55 | ||
56 | /* | 56 | /* |
57 | * The data on the cache is different from that on the origin. | 57 | * The data on the cache is different from that on the origin. |
58 | * This flag is only used by metadata format 1. | ||
58 | */ | 59 | */ |
59 | M_DIRTY = 2 | 60 | M_DIRTY = 2 |
60 | }; | 61 | }; |
@@ -93,12 +94,18 @@ struct cache_disk_superblock { | |||
93 | __le32 write_misses; | 94 | __le32 write_misses; |
94 | 95 | ||
95 | __le32 policy_version[CACHE_POLICY_VERSION_SIZE]; | 96 | __le32 policy_version[CACHE_POLICY_VERSION_SIZE]; |
97 | |||
98 | /* | ||
99 | * Metadata format 2 fields. | ||
100 | */ | ||
101 | __le64 dirty_root; | ||
96 | } __packed; | 102 | } __packed; |
97 | 103 | ||
98 | struct dm_cache_metadata { | 104 | struct dm_cache_metadata { |
99 | atomic_t ref_count; | 105 | atomic_t ref_count; |
100 | struct list_head list; | 106 | struct list_head list; |
101 | 107 | ||
108 | unsigned version; | ||
102 | struct block_device *bdev; | 109 | struct block_device *bdev; |
103 | struct dm_block_manager *bm; | 110 | struct dm_block_manager *bm; |
104 | struct dm_space_map *metadata_sm; | 111 | struct dm_space_map *metadata_sm; |
@@ -142,11 +149,18 @@ struct dm_cache_metadata { | |||
142 | bool fail_io:1; | 149 | bool fail_io:1; |
143 | 150 | ||
144 | /* | 151 | /* |
152 | * Metadata format 2 fields. | ||
153 | */ | ||
154 | dm_block_t dirty_root; | ||
155 | struct dm_disk_bitset dirty_info; | ||
156 | |||
157 | /* | ||
145 | * These structures are used when loading metadata. They're too | 158 | * These structures are used when loading metadata. They're too |
146 | * big to put on the stack. | 159 | * big to put on the stack. |
147 | */ | 160 | */ |
148 | struct dm_array_cursor mapping_cursor; | 161 | struct dm_array_cursor mapping_cursor; |
149 | struct dm_array_cursor hint_cursor; | 162 | struct dm_array_cursor hint_cursor; |
163 | struct dm_bitset_cursor dirty_cursor; | ||
150 | }; | 164 | }; |
151 | 165 | ||
152 | /*------------------------------------------------------------------- | 166 | /*------------------------------------------------------------------- |
@@ -170,6 +184,7 @@ static void sb_prepare_for_write(struct dm_block_validator *v, | |||
170 | static int check_metadata_version(struct cache_disk_superblock *disk_super) | 184 | static int check_metadata_version(struct cache_disk_superblock *disk_super) |
171 | { | 185 | { |
172 | uint32_t metadata_version = le32_to_cpu(disk_super->version); | 186 | uint32_t metadata_version = le32_to_cpu(disk_super->version); |
187 | |||
173 | if (metadata_version < MIN_CACHE_VERSION || metadata_version > MAX_CACHE_VERSION) { | 188 | if (metadata_version < MIN_CACHE_VERSION || metadata_version > MAX_CACHE_VERSION) { |
174 | DMERR("Cache metadata version %u found, but only versions between %u and %u supported.", | 189 | DMERR("Cache metadata version %u found, but only versions between %u and %u supported.", |
175 | metadata_version, MIN_CACHE_VERSION, MAX_CACHE_VERSION); | 190 | metadata_version, MIN_CACHE_VERSION, MAX_CACHE_VERSION); |
@@ -310,6 +325,11 @@ static void __copy_sm_root(struct dm_cache_metadata *cmd, | |||
310 | sizeof(cmd->metadata_space_map_root)); | 325 | sizeof(cmd->metadata_space_map_root)); |
311 | } | 326 | } |
312 | 327 | ||
328 | static bool separate_dirty_bits(struct dm_cache_metadata *cmd) | ||
329 | { | ||
330 | return cmd->version >= 2; | ||
331 | } | ||
332 | |||
313 | static int __write_initial_superblock(struct dm_cache_metadata *cmd) | 333 | static int __write_initial_superblock(struct dm_cache_metadata *cmd) |
314 | { | 334 | { |
315 | int r; | 335 | int r; |
@@ -341,7 +361,7 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd) | |||
341 | disk_super->flags = 0; | 361 | disk_super->flags = 0; |
342 | memset(disk_super->uuid, 0, sizeof(disk_super->uuid)); | 362 | memset(disk_super->uuid, 0, sizeof(disk_super->uuid)); |
343 | disk_super->magic = cpu_to_le64(CACHE_SUPERBLOCK_MAGIC); | 363 | disk_super->magic = cpu_to_le64(CACHE_SUPERBLOCK_MAGIC); |
344 | disk_super->version = cpu_to_le32(MAX_CACHE_VERSION); | 364 | disk_super->version = cpu_to_le32(cmd->version); |
345 | memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name)); | 365 | memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name)); |
346 | memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); | 366 | memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); |
347 | disk_super->policy_hint_size = 0; | 367 | disk_super->policy_hint_size = 0; |
@@ -362,6 +382,9 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd) | |||
362 | disk_super->write_hits = cpu_to_le32(0); | 382 | disk_super->write_hits = cpu_to_le32(0); |
363 | disk_super->write_misses = cpu_to_le32(0); | 383 | disk_super->write_misses = cpu_to_le32(0); |
364 | 384 | ||
385 | if (separate_dirty_bits(cmd)) | ||
386 | disk_super->dirty_root = cpu_to_le64(cmd->dirty_root); | ||
387 | |||
365 | return dm_tm_commit(cmd->tm, sblock); | 388 | return dm_tm_commit(cmd->tm, sblock); |
366 | } | 389 | } |
367 | 390 | ||
@@ -382,6 +405,13 @@ static int __format_metadata(struct dm_cache_metadata *cmd) | |||
382 | if (r < 0) | 405 | if (r < 0) |
383 | goto bad; | 406 | goto bad; |
384 | 407 | ||
408 | if (separate_dirty_bits(cmd)) { | ||
409 | dm_disk_bitset_init(cmd->tm, &cmd->dirty_info); | ||
410 | r = dm_bitset_empty(&cmd->dirty_info, &cmd->dirty_root); | ||
411 | if (r < 0) | ||
412 | goto bad; | ||
413 | } | ||
414 | |||
385 | dm_disk_bitset_init(cmd->tm, &cmd->discard_info); | 415 | dm_disk_bitset_init(cmd->tm, &cmd->discard_info); |
386 | r = dm_bitset_empty(&cmd->discard_info, &cmd->discard_root); | 416 | r = dm_bitset_empty(&cmd->discard_info, &cmd->discard_root); |
387 | if (r < 0) | 417 | if (r < 0) |
@@ -407,9 +437,10 @@ bad: | |||
407 | static int __check_incompat_features(struct cache_disk_superblock *disk_super, | 437 | static int __check_incompat_features(struct cache_disk_superblock *disk_super, |
408 | struct dm_cache_metadata *cmd) | 438 | struct dm_cache_metadata *cmd) |
409 | { | 439 | { |
410 | uint32_t features; | 440 | uint32_t incompat_flags, features; |
411 | 441 | ||
412 | features = le32_to_cpu(disk_super->incompat_flags) & ~DM_CACHE_FEATURE_INCOMPAT_SUPP; | 442 | incompat_flags = le32_to_cpu(disk_super->incompat_flags); |
443 | features = incompat_flags & ~DM_CACHE_FEATURE_INCOMPAT_SUPP; | ||
413 | if (features) { | 444 | if (features) { |
414 | DMERR("could not access metadata due to unsupported optional features (%lx).", | 445 | DMERR("could not access metadata due to unsupported optional features (%lx).", |
415 | (unsigned long)features); | 446 | (unsigned long)features); |
@@ -470,6 +501,7 @@ static int __open_metadata(struct dm_cache_metadata *cmd) | |||
470 | } | 501 | } |
471 | 502 | ||
472 | __setup_mapping_info(cmd); | 503 | __setup_mapping_info(cmd); |
504 | dm_disk_bitset_init(cmd->tm, &cmd->dirty_info); | ||
473 | dm_disk_bitset_init(cmd->tm, &cmd->discard_info); | 505 | dm_disk_bitset_init(cmd->tm, &cmd->discard_info); |
474 | sb_flags = le32_to_cpu(disk_super->flags); | 506 | sb_flags = le32_to_cpu(disk_super->flags); |
475 | cmd->clean_when_opened = test_bit(CLEAN_SHUTDOWN, &sb_flags); | 507 | cmd->clean_when_opened = test_bit(CLEAN_SHUTDOWN, &sb_flags); |
@@ -548,6 +580,7 @@ static unsigned long clear_clean_shutdown(unsigned long flags) | |||
548 | static void read_superblock_fields(struct dm_cache_metadata *cmd, | 580 | static void read_superblock_fields(struct dm_cache_metadata *cmd, |
549 | struct cache_disk_superblock *disk_super) | 581 | struct cache_disk_superblock *disk_super) |
550 | { | 582 | { |
583 | cmd->version = le32_to_cpu(disk_super->version); | ||
551 | cmd->flags = le32_to_cpu(disk_super->flags); | 584 | cmd->flags = le32_to_cpu(disk_super->flags); |
552 | cmd->root = le64_to_cpu(disk_super->mapping_root); | 585 | cmd->root = le64_to_cpu(disk_super->mapping_root); |
553 | cmd->hint_root = le64_to_cpu(disk_super->hint_root); | 586 | cmd->hint_root = le64_to_cpu(disk_super->hint_root); |
@@ -567,6 +600,9 @@ static void read_superblock_fields(struct dm_cache_metadata *cmd, | |||
567 | cmd->stats.write_hits = le32_to_cpu(disk_super->write_hits); | 600 | cmd->stats.write_hits = le32_to_cpu(disk_super->write_hits); |
568 | cmd->stats.write_misses = le32_to_cpu(disk_super->write_misses); | 601 | cmd->stats.write_misses = le32_to_cpu(disk_super->write_misses); |
569 | 602 | ||
603 | if (separate_dirty_bits(cmd)) | ||
604 | cmd->dirty_root = le64_to_cpu(disk_super->dirty_root); | ||
605 | |||
570 | cmd->changed = false; | 606 | cmd->changed = false; |
571 | } | 607 | } |
572 | 608 | ||
@@ -625,6 +661,13 @@ static int __commit_transaction(struct dm_cache_metadata *cmd, | |||
625 | */ | 661 | */ |
626 | BUILD_BUG_ON(sizeof(struct cache_disk_superblock) > 512); | 662 | BUILD_BUG_ON(sizeof(struct cache_disk_superblock) > 512); |
627 | 663 | ||
664 | if (separate_dirty_bits(cmd)) { | ||
665 | r = dm_bitset_flush(&cmd->dirty_info, cmd->dirty_root, | ||
666 | &cmd->dirty_root); | ||
667 | if (r) | ||
668 | return r; | ||
669 | } | ||
670 | |||
628 | r = dm_bitset_flush(&cmd->discard_info, cmd->discard_root, | 671 | r = dm_bitset_flush(&cmd->discard_info, cmd->discard_root, |
629 | &cmd->discard_root); | 672 | &cmd->discard_root); |
630 | if (r) | 673 | if (r) |
@@ -649,6 +692,8 @@ static int __commit_transaction(struct dm_cache_metadata *cmd, | |||
649 | update_flags(disk_super, mutator); | 692 | update_flags(disk_super, mutator); |
650 | 693 | ||
651 | disk_super->mapping_root = cpu_to_le64(cmd->root); | 694 | disk_super->mapping_root = cpu_to_le64(cmd->root); |
695 | if (separate_dirty_bits(cmd)) | ||
696 | disk_super->dirty_root = cpu_to_le64(cmd->dirty_root); | ||
652 | disk_super->hint_root = cpu_to_le64(cmd->hint_root); | 697 | disk_super->hint_root = cpu_to_le64(cmd->hint_root); |
653 | disk_super->discard_root = cpu_to_le64(cmd->discard_root); | 698 | disk_super->discard_root = cpu_to_le64(cmd->discard_root); |
654 | disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size); | 699 | disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size); |
@@ -698,7 +743,8 @@ static void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned *flags) | |||
698 | static struct dm_cache_metadata *metadata_open(struct block_device *bdev, | 743 | static struct dm_cache_metadata *metadata_open(struct block_device *bdev, |
699 | sector_t data_block_size, | 744 | sector_t data_block_size, |
700 | bool may_format_device, | 745 | bool may_format_device, |
701 | size_t policy_hint_size) | 746 | size_t policy_hint_size, |
747 | unsigned metadata_version) | ||
702 | { | 748 | { |
703 | int r; | 749 | int r; |
704 | struct dm_cache_metadata *cmd; | 750 | struct dm_cache_metadata *cmd; |
@@ -709,6 +755,7 @@ static struct dm_cache_metadata *metadata_open(struct block_device *bdev, | |||
709 | return ERR_PTR(-ENOMEM); | 755 | return ERR_PTR(-ENOMEM); |
710 | } | 756 | } |
711 | 757 | ||
758 | cmd->version = metadata_version; | ||
712 | atomic_set(&cmd->ref_count, 1); | 759 | atomic_set(&cmd->ref_count, 1); |
713 | init_rwsem(&cmd->root_lock); | 760 | init_rwsem(&cmd->root_lock); |
714 | cmd->bdev = bdev; | 761 | cmd->bdev = bdev; |
@@ -757,7 +804,8 @@ static struct dm_cache_metadata *lookup(struct block_device *bdev) | |||
757 | static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev, | 804 | static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev, |
758 | sector_t data_block_size, | 805 | sector_t data_block_size, |
759 | bool may_format_device, | 806 | bool may_format_device, |
760 | size_t policy_hint_size) | 807 | size_t policy_hint_size, |
808 | unsigned metadata_version) | ||
761 | { | 809 | { |
762 | struct dm_cache_metadata *cmd, *cmd2; | 810 | struct dm_cache_metadata *cmd, *cmd2; |
763 | 811 | ||
@@ -768,7 +816,8 @@ static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev, | |||
768 | if (cmd) | 816 | if (cmd) |
769 | return cmd; | 817 | return cmd; |
770 | 818 | ||
771 | cmd = metadata_open(bdev, data_block_size, may_format_device, policy_hint_size); | 819 | cmd = metadata_open(bdev, data_block_size, may_format_device, |
820 | policy_hint_size, metadata_version); | ||
772 | if (!IS_ERR(cmd)) { | 821 | if (!IS_ERR(cmd)) { |
773 | mutex_lock(&table_lock); | 822 | mutex_lock(&table_lock); |
774 | cmd2 = lookup(bdev); | 823 | cmd2 = lookup(bdev); |
@@ -800,10 +849,11 @@ static bool same_params(struct dm_cache_metadata *cmd, sector_t data_block_size) | |||
800 | struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, | 849 | struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, |
801 | sector_t data_block_size, | 850 | sector_t data_block_size, |
802 | bool may_format_device, | 851 | bool may_format_device, |
803 | size_t policy_hint_size) | 852 | size_t policy_hint_size, |
853 | unsigned metadata_version) | ||
804 | { | 854 | { |
805 | struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size, | 855 | struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size, may_format_device, |
806 | may_format_device, policy_hint_size); | 856 | policy_hint_size, metadata_version); |
807 | 857 | ||
808 | if (!IS_ERR(cmd) && !same_params(cmd, data_block_size)) { | 858 | if (!IS_ERR(cmd) && !same_params(cmd, data_block_size)) { |
809 | dm_cache_metadata_close(cmd); | 859 | dm_cache_metadata_close(cmd); |
@@ -829,8 +879,8 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd) | |||
829 | /* | 879 | /* |
830 | * Checks that the given cache block is either unmapped or clean. | 880 | * Checks that the given cache block is either unmapped or clean. |
831 | */ | 881 | */ |
832 | static int block_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t b, | 882 | static int block_clean_combined_dirty(struct dm_cache_metadata *cmd, dm_cblock_t b, |
833 | bool *result) | 883 | bool *result) |
834 | { | 884 | { |
835 | int r; | 885 | int r; |
836 | __le64 value; | 886 | __le64 value; |
@@ -838,10 +888,8 @@ static int block_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t b, | |||
838 | unsigned flags; | 888 | unsigned flags; |
839 | 889 | ||
840 | r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(b), &value); | 890 | r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(b), &value); |
841 | if (r) { | 891 | if (r) |
842 | DMERR("block_unmapped_or_clean failed"); | ||
843 | return r; | 892 | return r; |
844 | } | ||
845 | 893 | ||
846 | unpack_value(value, &ob, &flags); | 894 | unpack_value(value, &ob, &flags); |
847 | *result = !((flags & M_VALID) && (flags & M_DIRTY)); | 895 | *result = !((flags & M_VALID) && (flags & M_DIRTY)); |
@@ -849,17 +897,19 @@ static int block_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t b, | |||
849 | return 0; | 897 | return 0; |
850 | } | 898 | } |
851 | 899 | ||
852 | static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd, | 900 | static int blocks_are_clean_combined_dirty(struct dm_cache_metadata *cmd, |
853 | dm_cblock_t begin, dm_cblock_t end, | 901 | dm_cblock_t begin, dm_cblock_t end, |
854 | bool *result) | 902 | bool *result) |
855 | { | 903 | { |
856 | int r; | 904 | int r; |
857 | *result = true; | 905 | *result = true; |
858 | 906 | ||
859 | while (begin != end) { | 907 | while (begin != end) { |
860 | r = block_unmapped_or_clean(cmd, begin, result); | 908 | r = block_clean_combined_dirty(cmd, begin, result); |
861 | if (r) | 909 | if (r) { |
910 | DMERR("block_clean_combined_dirty failed"); | ||
862 | return r; | 911 | return r; |
912 | } | ||
863 | 913 | ||
864 | if (!*result) { | 914 | if (!*result) { |
865 | DMERR("cache block %llu is dirty", | 915 | DMERR("cache block %llu is dirty", |
@@ -873,6 +923,48 @@ static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd, | |||
873 | return 0; | 923 | return 0; |
874 | } | 924 | } |
875 | 925 | ||
926 | static int blocks_are_clean_separate_dirty(struct dm_cache_metadata *cmd, | ||
927 | dm_cblock_t begin, dm_cblock_t end, | ||
928 | bool *result) | ||
929 | { | ||
930 | int r; | ||
931 | bool dirty_flag; | ||
932 | *result = true; | ||
933 | |||
934 | // FIXME: use a cursor so we can benefit from preloading metadata. | ||
935 | while (begin != end) { | ||
936 | /* | ||
937 | * We assume that unmapped blocks have their dirty bit | ||
938 | * cleared. | ||
939 | */ | ||
940 | r = dm_bitset_test_bit(&cmd->dirty_info, cmd->dirty_root, | ||
941 | from_cblock(begin), &cmd->dirty_root, &dirty_flag); | ||
942 | if (r) | ||
943 | return r; | ||
944 | |||
945 | if (dirty_flag) { | ||
946 | DMERR("cache block %llu is dirty", | ||
947 | (unsigned long long) from_cblock(begin)); | ||
948 | *result = false; | ||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | begin = to_cblock(from_cblock(begin) + 1); | ||
953 | } | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd, | ||
959 | dm_cblock_t begin, dm_cblock_t end, | ||
960 | bool *result) | ||
961 | { | ||
962 | if (separate_dirty_bits(cmd)) | ||
963 | return blocks_are_clean_separate_dirty(cmd, begin, end, result); | ||
964 | else | ||
965 | return blocks_are_clean_combined_dirty(cmd, begin, end, result); | ||
966 | } | ||
967 | |||
876 | static bool cmd_write_lock(struct dm_cache_metadata *cmd) | 968 | static bool cmd_write_lock(struct dm_cache_metadata *cmd) |
877 | { | 969 | { |
878 | down_write(&cmd->root_lock); | 970 | down_write(&cmd->root_lock); |
@@ -950,8 +1042,18 @@ int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) | |||
950 | r = dm_array_resize(&cmd->info, cmd->root, from_cblock(cmd->cache_blocks), | 1042 | r = dm_array_resize(&cmd->info, cmd->root, from_cblock(cmd->cache_blocks), |
951 | from_cblock(new_cache_size), | 1043 | from_cblock(new_cache_size), |
952 | &null_mapping, &cmd->root); | 1044 | &null_mapping, &cmd->root); |
953 | if (!r) | 1045 | if (r) |
954 | cmd->cache_blocks = new_cache_size; | 1046 | goto out; |
1047 | |||
1048 | if (separate_dirty_bits(cmd)) { | ||
1049 | r = dm_bitset_resize(&cmd->dirty_info, cmd->dirty_root, | ||
1050 | from_cblock(cmd->cache_blocks), from_cblock(new_cache_size), | ||
1051 | false, &cmd->dirty_root); | ||
1052 | if (r) | ||
1053 | goto out; | ||
1054 | } | ||
1055 | |||
1056 | cmd->cache_blocks = new_cache_size; | ||
955 | cmd->changed = true; | 1057 | cmd->changed = true; |
956 | 1058 | ||
957 | out: | 1059 | out: |
@@ -1185,11 +1287,11 @@ static bool hints_array_available(struct dm_cache_metadata *cmd, | |||
1185 | hints_array_initialized(cmd); | 1287 | hints_array_initialized(cmd); |
1186 | } | 1288 | } |
1187 | 1289 | ||
1188 | static int __load_mapping(struct dm_cache_metadata *cmd, | 1290 | static int __load_mapping_v1(struct dm_cache_metadata *cmd, |
1189 | uint64_t cb, bool hints_valid, | 1291 | uint64_t cb, bool hints_valid, |
1190 | struct dm_array_cursor *mapping_cursor, | 1292 | struct dm_array_cursor *mapping_cursor, |
1191 | struct dm_array_cursor *hint_cursor, | 1293 | struct dm_array_cursor *hint_cursor, |
1192 | load_mapping_fn fn, void *context) | 1294 | load_mapping_fn fn, void *context) |
1193 | { | 1295 | { |
1194 | int r = 0; | 1296 | int r = 0; |
1195 | 1297 | ||
@@ -1221,6 +1323,45 @@ static int __load_mapping(struct dm_cache_metadata *cmd, | |||
1221 | return r; | 1323 | return r; |
1222 | } | 1324 | } |
1223 | 1325 | ||
1326 | static int __load_mapping_v2(struct dm_cache_metadata *cmd, | ||
1327 | uint64_t cb, bool hints_valid, | ||
1328 | struct dm_array_cursor *mapping_cursor, | ||
1329 | struct dm_array_cursor *hint_cursor, | ||
1330 | struct dm_bitset_cursor *dirty_cursor, | ||
1331 | load_mapping_fn fn, void *context) | ||
1332 | { | ||
1333 | int r = 0; | ||
1334 | |||
1335 | __le64 mapping; | ||
1336 | __le32 hint = 0; | ||
1337 | |||
1338 | __le64 *mapping_value_le; | ||
1339 | __le32 *hint_value_le; | ||
1340 | |||
1341 | dm_oblock_t oblock; | ||
1342 | unsigned flags; | ||
1343 | bool dirty; | ||
1344 | |||
1345 | dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le); | ||
1346 | memcpy(&mapping, mapping_value_le, sizeof(mapping)); | ||
1347 | unpack_value(mapping, &oblock, &flags); | ||
1348 | |||
1349 | if (flags & M_VALID) { | ||
1350 | if (hints_valid) { | ||
1351 | dm_array_cursor_get_value(hint_cursor, (void **) &hint_value_le); | ||
1352 | memcpy(&hint, hint_value_le, sizeof(hint)); | ||
1353 | } | ||
1354 | |||
1355 | dirty = dm_bitset_cursor_get_value(dirty_cursor); | ||
1356 | r = fn(context, oblock, to_cblock(cb), dirty, | ||
1357 | le32_to_cpu(hint), hints_valid); | ||
1358 | if (r) | ||
1359 | DMERR("policy couldn't load cblock"); | ||
1360 | } | ||
1361 | |||
1362 | return r; | ||
1363 | } | ||
1364 | |||
1224 | static int __load_mappings(struct dm_cache_metadata *cmd, | 1365 | static int __load_mappings(struct dm_cache_metadata *cmd, |
1225 | struct dm_cache_policy *policy, | 1366 | struct dm_cache_policy *policy, |
1226 | load_mapping_fn fn, void *context) | 1367 | load_mapping_fn fn, void *context) |
@@ -1246,10 +1387,28 @@ static int __load_mappings(struct dm_cache_metadata *cmd, | |||
1246 | } | 1387 | } |
1247 | } | 1388 | } |
1248 | 1389 | ||
1390 | if (separate_dirty_bits(cmd)) { | ||
1391 | r = dm_bitset_cursor_begin(&cmd->dirty_info, cmd->dirty_root, | ||
1392 | from_cblock(cmd->cache_blocks), | ||
1393 | &cmd->dirty_cursor); | ||
1394 | if (r) { | ||
1395 | dm_array_cursor_end(&cmd->hint_cursor); | ||
1396 | dm_array_cursor_end(&cmd->mapping_cursor); | ||
1397 | return r; | ||
1398 | } | ||
1399 | } | ||
1400 | |||
1249 | for (cb = 0; ; cb++) { | 1401 | for (cb = 0; ; cb++) { |
1250 | r = __load_mapping(cmd, cb, hints_valid, | 1402 | if (separate_dirty_bits(cmd)) |
1251 | &cmd->mapping_cursor, &cmd->hint_cursor, | 1403 | r = __load_mapping_v2(cmd, cb, hints_valid, |
1252 | fn, context); | 1404 | &cmd->mapping_cursor, |
1405 | &cmd->hint_cursor, | ||
1406 | &cmd->dirty_cursor, | ||
1407 | fn, context); | ||
1408 | else | ||
1409 | r = __load_mapping_v1(cmd, cb, hints_valid, | ||
1410 | &cmd->mapping_cursor, &cmd->hint_cursor, | ||
1411 | fn, context); | ||
1253 | if (r) | 1412 | if (r) |
1254 | goto out; | 1413 | goto out; |
1255 | 1414 | ||
@@ -1272,12 +1431,23 @@ static int __load_mappings(struct dm_cache_metadata *cmd, | |||
1272 | goto out; | 1431 | goto out; |
1273 | } | 1432 | } |
1274 | } | 1433 | } |
1434 | |||
1435 | if (separate_dirty_bits(cmd)) { | ||
1436 | r = dm_bitset_cursor_next(&cmd->dirty_cursor); | ||
1437 | if (r) { | ||
1438 | DMERR("dm_bitset_cursor_next for dirty failed"); | ||
1439 | goto out; | ||
1440 | } | ||
1441 | } | ||
1275 | } | 1442 | } |
1276 | out: | 1443 | out: |
1277 | dm_array_cursor_end(&cmd->mapping_cursor); | 1444 | dm_array_cursor_end(&cmd->mapping_cursor); |
1278 | if (hints_valid) | 1445 | if (hints_valid) |
1279 | dm_array_cursor_end(&cmd->hint_cursor); | 1446 | dm_array_cursor_end(&cmd->hint_cursor); |
1280 | 1447 | ||
1448 | if (separate_dirty_bits(cmd)) | ||
1449 | dm_bitset_cursor_end(&cmd->dirty_cursor); | ||
1450 | |||
1281 | return r; | 1451 | return r; |
1282 | } | 1452 | } |
1283 | 1453 | ||
@@ -1360,13 +1530,55 @@ static int __dirty(struct dm_cache_metadata *cmd, dm_cblock_t cblock, bool dirty | |||
1360 | 1530 | ||
1361 | } | 1531 | } |
1362 | 1532 | ||
1363 | int dm_cache_set_dirty(struct dm_cache_metadata *cmd, | 1533 | static int __set_dirty_bits_v1(struct dm_cache_metadata *cmd, unsigned nr_bits, unsigned long *bits) |
1364 | dm_cblock_t cblock, bool dirty) | 1534 | { |
1535 | int r; | ||
1536 | unsigned i; | ||
1537 | for (i = 0; i < nr_bits; i++) { | ||
1538 | r = __dirty(cmd, to_cblock(i), test_bit(i, bits)); | ||
1539 | if (r) | ||
1540 | return r; | ||
1541 | } | ||
1542 | |||
1543 | return 0; | ||
1544 | } | ||
1545 | |||
1546 | static int __set_dirty_bits_v2(struct dm_cache_metadata *cmd, unsigned nr_bits, unsigned long *bits) | ||
1547 | { | ||
1548 | int r = 0; | ||
1549 | unsigned i; | ||
1550 | |||
1551 | /* nr_bits is really just a sanity check */ | ||
1552 | if (nr_bits != from_cblock(cmd->cache_blocks)) { | ||
1553 | DMERR("dirty bitset is wrong size"); | ||
1554 | return -EINVAL; | ||
1555 | } | ||
1556 | |||
1557 | for (i = 0; i < nr_bits; i++) { | ||
1558 | if (test_bit(i, bits)) | ||
1559 | r = dm_bitset_set_bit(&cmd->dirty_info, cmd->dirty_root, i, &cmd->dirty_root); | ||
1560 | else | ||
1561 | r = dm_bitset_clear_bit(&cmd->dirty_info, cmd->dirty_root, i, &cmd->dirty_root); | ||
1562 | |||
1563 | if (r) | ||
1564 | return r; | ||
1565 | } | ||
1566 | |||
1567 | cmd->changed = true; | ||
1568 | return dm_bitset_flush(&cmd->dirty_info, cmd->dirty_root, &cmd->dirty_root); | ||
1569 | } | ||
1570 | |||
1571 | int dm_cache_set_dirty_bits(struct dm_cache_metadata *cmd, | ||
1572 | unsigned nr_bits, | ||
1573 | unsigned long *bits) | ||
1365 | { | 1574 | { |
1366 | int r; | 1575 | int r; |
1367 | 1576 | ||
1368 | WRITE_LOCK(cmd); | 1577 | WRITE_LOCK(cmd); |
1369 | r = __dirty(cmd, cblock, dirty); | 1578 | if (separate_dirty_bits(cmd)) |
1579 | r = __set_dirty_bits_v2(cmd, nr_bits, bits); | ||
1580 | else | ||
1581 | r = __set_dirty_bits_v1(cmd, nr_bits, bits); | ||
1370 | WRITE_UNLOCK(cmd); | 1582 | WRITE_UNLOCK(cmd); |
1371 | 1583 | ||
1372 | return r; | 1584 | return r; |