diff options
Diffstat (limited to 'drivers/md/dm-cache-metadata.c')
| -rw-r--r-- | drivers/md/dm-cache-metadata.c | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index fbd3625f2748..83e995fece88 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c | |||
| @@ -83,6 +83,8 @@ struct cache_disk_superblock { | |||
| 83 | __le32 read_misses; | 83 | __le32 read_misses; |
| 84 | __le32 write_hits; | 84 | __le32 write_hits; |
| 85 | __le32 write_misses; | 85 | __le32 write_misses; |
| 86 | |||
| 87 | __le32 policy_version[CACHE_POLICY_VERSION_SIZE]; | ||
| 86 | } __packed; | 88 | } __packed; |
| 87 | 89 | ||
| 88 | struct dm_cache_metadata { | 90 | struct dm_cache_metadata { |
| @@ -109,6 +111,7 @@ struct dm_cache_metadata { | |||
| 109 | bool clean_when_opened:1; | 111 | bool clean_when_opened:1; |
| 110 | 112 | ||
| 111 | char policy_name[CACHE_POLICY_NAME_SIZE]; | 113 | char policy_name[CACHE_POLICY_NAME_SIZE]; |
| 114 | unsigned policy_version[CACHE_POLICY_VERSION_SIZE]; | ||
| 112 | size_t policy_hint_size; | 115 | size_t policy_hint_size; |
| 113 | struct dm_cache_statistics stats; | 116 | struct dm_cache_statistics stats; |
| 114 | }; | 117 | }; |
| @@ -268,7 +271,8 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd) | |||
| 268 | memset(disk_super->uuid, 0, sizeof(disk_super->uuid)); | 271 | memset(disk_super->uuid, 0, sizeof(disk_super->uuid)); |
| 269 | disk_super->magic = cpu_to_le64(CACHE_SUPERBLOCK_MAGIC); | 272 | disk_super->magic = cpu_to_le64(CACHE_SUPERBLOCK_MAGIC); |
| 270 | disk_super->version = cpu_to_le32(CACHE_VERSION); | 273 | disk_super->version = cpu_to_le32(CACHE_VERSION); |
| 271 | memset(disk_super->policy_name, 0, CACHE_POLICY_NAME_SIZE); | 274 | memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name)); |
| 275 | memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); | ||
| 272 | disk_super->policy_hint_size = 0; | 276 | disk_super->policy_hint_size = 0; |
| 273 | 277 | ||
| 274 | r = dm_sm_copy_root(cmd->metadata_sm, &disk_super->metadata_space_map_root, | 278 | r = dm_sm_copy_root(cmd->metadata_sm, &disk_super->metadata_space_map_root, |
| @@ -284,7 +288,6 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd) | |||
| 284 | disk_super->metadata_block_size = cpu_to_le32(DM_CACHE_METADATA_BLOCK_SIZE >> SECTOR_SHIFT); | 288 | disk_super->metadata_block_size = cpu_to_le32(DM_CACHE_METADATA_BLOCK_SIZE >> SECTOR_SHIFT); |
| 285 | disk_super->data_block_size = cpu_to_le32(cmd->data_block_size); | 289 | disk_super->data_block_size = cpu_to_le32(cmd->data_block_size); |
| 286 | disk_super->cache_blocks = cpu_to_le32(0); | 290 | disk_super->cache_blocks = cpu_to_le32(0); |
| 287 | memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name)); | ||
| 288 | 291 | ||
| 289 | disk_super->read_hits = cpu_to_le32(0); | 292 | disk_super->read_hits = cpu_to_le32(0); |
| 290 | disk_super->read_misses = cpu_to_le32(0); | 293 | disk_super->read_misses = cpu_to_le32(0); |
| @@ -478,6 +481,9 @@ static void read_superblock_fields(struct dm_cache_metadata *cmd, | |||
| 478 | cmd->data_block_size = le32_to_cpu(disk_super->data_block_size); | 481 | cmd->data_block_size = le32_to_cpu(disk_super->data_block_size); |
| 479 | cmd->cache_blocks = to_cblock(le32_to_cpu(disk_super->cache_blocks)); | 482 | cmd->cache_blocks = to_cblock(le32_to_cpu(disk_super->cache_blocks)); |
| 480 | strncpy(cmd->policy_name, disk_super->policy_name, sizeof(cmd->policy_name)); | 483 | strncpy(cmd->policy_name, disk_super->policy_name, sizeof(cmd->policy_name)); |
| 484 | cmd->policy_version[0] = le32_to_cpu(disk_super->policy_version[0]); | ||
| 485 | cmd->policy_version[1] = le32_to_cpu(disk_super->policy_version[1]); | ||
| 486 | cmd->policy_version[2] = le32_to_cpu(disk_super->policy_version[2]); | ||
| 481 | cmd->policy_hint_size = le32_to_cpu(disk_super->policy_hint_size); | 487 | cmd->policy_hint_size = le32_to_cpu(disk_super->policy_hint_size); |
| 482 | 488 | ||
| 483 | cmd->stats.read_hits = le32_to_cpu(disk_super->read_hits); | 489 | cmd->stats.read_hits = le32_to_cpu(disk_super->read_hits); |
| @@ -572,6 +578,9 @@ static int __commit_transaction(struct dm_cache_metadata *cmd, | |||
| 572 | disk_super->discard_nr_blocks = cpu_to_le64(from_dblock(cmd->discard_nr_blocks)); | 578 | disk_super->discard_nr_blocks = cpu_to_le64(from_dblock(cmd->discard_nr_blocks)); |
| 573 | disk_super->cache_blocks = cpu_to_le32(from_cblock(cmd->cache_blocks)); | 579 | disk_super->cache_blocks = cpu_to_le32(from_cblock(cmd->cache_blocks)); |
| 574 | strncpy(disk_super->policy_name, cmd->policy_name, sizeof(disk_super->policy_name)); | 580 | strncpy(disk_super->policy_name, cmd->policy_name, sizeof(disk_super->policy_name)); |
| 581 | disk_super->policy_version[0] = cpu_to_le32(cmd->policy_version[0]); | ||
| 582 | disk_super->policy_version[1] = cpu_to_le32(cmd->policy_version[1]); | ||
| 583 | disk_super->policy_version[2] = cpu_to_le32(cmd->policy_version[2]); | ||
| 575 | 584 | ||
| 576 | disk_super->read_hits = cpu_to_le32(cmd->stats.read_hits); | 585 | disk_super->read_hits = cpu_to_le32(cmd->stats.read_hits); |
| 577 | disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses); | 586 | disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses); |
| @@ -854,18 +863,43 @@ struct thunk { | |||
| 854 | bool hints_valid; | 863 | bool hints_valid; |
| 855 | }; | 864 | }; |
| 856 | 865 | ||
| 866 | static bool policy_unchanged(struct dm_cache_metadata *cmd, | ||
| 867 | struct dm_cache_policy *policy) | ||
| 868 | { | ||
| 869 | const char *policy_name = dm_cache_policy_get_name(policy); | ||
| 870 | const unsigned *policy_version = dm_cache_policy_get_version(policy); | ||
| 871 | size_t policy_hint_size = dm_cache_policy_get_hint_size(policy); | ||
| 872 | |||
| 873 | /* | ||
| 874 | * Ensure policy names match. | ||
| 875 | */ | ||
| 876 | if (strncmp(cmd->policy_name, policy_name, sizeof(cmd->policy_name))) | ||
| 877 | return false; | ||
| 878 | |||
| 879 | /* | ||
| 880 | * Ensure policy major versions match. | ||
| 881 | */ | ||
| 882 | if (cmd->policy_version[0] != policy_version[0]) | ||
| 883 | return false; | ||
| 884 | |||
| 885 | /* | ||
| 886 | * Ensure policy hint sizes match. | ||
| 887 | */ | ||
| 888 | if (cmd->policy_hint_size != policy_hint_size) | ||
| 889 | return false; | ||
| 890 | |||
| 891 | return true; | ||
| 892 | } | ||
| 893 | |||
| 857 | static bool hints_array_initialized(struct dm_cache_metadata *cmd) | 894 | static bool hints_array_initialized(struct dm_cache_metadata *cmd) |
| 858 | { | 895 | { |
| 859 | return cmd->hint_root && cmd->policy_hint_size; | 896 | return cmd->hint_root && cmd->policy_hint_size; |
| 860 | } | 897 | } |
| 861 | 898 | ||
| 862 | static bool hints_array_available(struct dm_cache_metadata *cmd, | 899 | static bool hints_array_available(struct dm_cache_metadata *cmd, |
| 863 | const char *policy_name) | 900 | struct dm_cache_policy *policy) |
| 864 | { | 901 | { |
| 865 | bool policy_names_match = !strncmp(cmd->policy_name, policy_name, | 902 | return cmd->clean_when_opened && policy_unchanged(cmd, policy) && |
| 866 | sizeof(cmd->policy_name)); | ||
| 867 | |||
| 868 | return cmd->clean_when_opened && policy_names_match && | ||
| 869 | hints_array_initialized(cmd); | 903 | hints_array_initialized(cmd); |
| 870 | } | 904 | } |
| 871 | 905 | ||
| @@ -899,7 +933,8 @@ static int __load_mapping(void *context, uint64_t cblock, void *leaf) | |||
| 899 | return r; | 933 | return r; |
| 900 | } | 934 | } |
| 901 | 935 | ||
| 902 | static int __load_mappings(struct dm_cache_metadata *cmd, const char *policy_name, | 936 | static int __load_mappings(struct dm_cache_metadata *cmd, |
| 937 | struct dm_cache_policy *policy, | ||
| 903 | load_mapping_fn fn, void *context) | 938 | load_mapping_fn fn, void *context) |
| 904 | { | 939 | { |
| 905 | struct thunk thunk; | 940 | struct thunk thunk; |
| @@ -909,18 +944,19 @@ static int __load_mappings(struct dm_cache_metadata *cmd, const char *policy_nam | |||
| 909 | 944 | ||
| 910 | thunk.cmd = cmd; | 945 | thunk.cmd = cmd; |
| 911 | thunk.respect_dirty_flags = cmd->clean_when_opened; | 946 | thunk.respect_dirty_flags = cmd->clean_when_opened; |
| 912 | thunk.hints_valid = hints_array_available(cmd, policy_name); | 947 | thunk.hints_valid = hints_array_available(cmd, policy); |
| 913 | 948 | ||
| 914 | return dm_array_walk(&cmd->info, cmd->root, __load_mapping, &thunk); | 949 | return dm_array_walk(&cmd->info, cmd->root, __load_mapping, &thunk); |
| 915 | } | 950 | } |
| 916 | 951 | ||
| 917 | int dm_cache_load_mappings(struct dm_cache_metadata *cmd, const char *policy_name, | 952 | int dm_cache_load_mappings(struct dm_cache_metadata *cmd, |
| 953 | struct dm_cache_policy *policy, | ||
| 918 | load_mapping_fn fn, void *context) | 954 | load_mapping_fn fn, void *context) |
| 919 | { | 955 | { |
| 920 | int r; | 956 | int r; |
| 921 | 957 | ||
| 922 | down_read(&cmd->root_lock); | 958 | down_read(&cmd->root_lock); |
| 923 | r = __load_mappings(cmd, policy_name, fn, context); | 959 | r = __load_mappings(cmd, policy, fn, context); |
| 924 | up_read(&cmd->root_lock); | 960 | up_read(&cmd->root_lock); |
| 925 | 961 | ||
| 926 | return r; | 962 | return r; |
| @@ -979,7 +1015,7 @@ static int __dirty(struct dm_cache_metadata *cmd, dm_cblock_t cblock, bool dirty | |||
| 979 | /* nothing to be done */ | 1015 | /* nothing to be done */ |
| 980 | return 0; | 1016 | return 0; |
| 981 | 1017 | ||
| 982 | value = pack_value(oblock, flags | (dirty ? M_DIRTY : 0)); | 1018 | value = pack_value(oblock, (flags & ~M_DIRTY) | (dirty ? M_DIRTY : 0)); |
| 983 | __dm_bless_for_disk(&value); | 1019 | __dm_bless_for_disk(&value); |
| 984 | 1020 | ||
| 985 | r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock), | 1021 | r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock), |
| @@ -1070,13 +1106,15 @@ static int begin_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *po | |||
| 1070 | __le32 value; | 1106 | __le32 value; |
| 1071 | size_t hint_size; | 1107 | size_t hint_size; |
| 1072 | const char *policy_name = dm_cache_policy_get_name(policy); | 1108 | const char *policy_name = dm_cache_policy_get_name(policy); |
| 1109 | const unsigned *policy_version = dm_cache_policy_get_version(policy); | ||
| 1073 | 1110 | ||
| 1074 | if (!policy_name[0] || | 1111 | if (!policy_name[0] || |
| 1075 | (strlen(policy_name) > sizeof(cmd->policy_name) - 1)) | 1112 | (strlen(policy_name) > sizeof(cmd->policy_name) - 1)) |
| 1076 | return -EINVAL; | 1113 | return -EINVAL; |
| 1077 | 1114 | ||
| 1078 | if (strcmp(cmd->policy_name, policy_name)) { | 1115 | if (!policy_unchanged(cmd, policy)) { |
| 1079 | strncpy(cmd->policy_name, policy_name, sizeof(cmd->policy_name)); | 1116 | strncpy(cmd->policy_name, policy_name, sizeof(cmd->policy_name)); |
| 1117 | memcpy(cmd->policy_version, policy_version, sizeof(cmd->policy_version)); | ||
| 1080 | 1118 | ||
| 1081 | hint_size = dm_cache_policy_get_hint_size(policy); | 1119 | hint_size = dm_cache_policy_get_hint_size(policy); |
| 1082 | if (!hint_size) | 1120 | if (!hint_size) |
