diff options
author | Joe Thornber <ejt@redhat.com> | 2016-03-10 11:20:58 -0500 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2016-03-10 17:12:12 -0500 |
commit | d14fcf3dd79c0b8a8d0ba469c44a6b04f3a1403b (patch) | |
tree | 077898b2913e1b3d330317129ac91015d01bff12 /drivers/md | |
parent | 3f0680402c2d0da58a8b06f7e55d387591b55e61 (diff) |
dm cache: make sure every metadata function checks fail_io
Otherwise operations may be attempted that will only ever go on to crash
(since the metadata device is either missing or unreliable if 'fail_io'
is set).
Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-cache-metadata.c | 98 | ||||
-rw-r--r-- | drivers/md/dm-cache-metadata.h | 4 | ||||
-rw-r--r-- | drivers/md/dm-cache-target.c | 12 |
3 files changed, 71 insertions, 43 deletions
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index f6543f3a970f..27f2ef300f8b 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c | |||
@@ -867,19 +867,40 @@ static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd, | |||
867 | return 0; | 867 | return 0; |
868 | } | 868 | } |
869 | 869 | ||
870 | #define WRITE_LOCK(cmd) \ | 870 | #define WRITE_LOCK(cmd) \ |
871 | if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \ | 871 | down_write(&cmd->root_lock); \ |
872 | if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \ | ||
873 | up_write(&cmd->root_lock); \ | ||
872 | return -EINVAL; \ | 874 | return -EINVAL; \ |
873 | down_write(&cmd->root_lock) | 875 | } |
874 | 876 | ||
875 | #define WRITE_LOCK_VOID(cmd) \ | 877 | #define WRITE_LOCK_VOID(cmd) \ |
876 | if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \ | 878 | down_write(&cmd->root_lock); \ |
879 | if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \ | ||
880 | up_write(&cmd->root_lock); \ | ||
877 | return; \ | 881 | return; \ |
878 | down_write(&cmd->root_lock) | 882 | } |
879 | 883 | ||
880 | #define WRITE_UNLOCK(cmd) \ | 884 | #define WRITE_UNLOCK(cmd) \ |
881 | up_write(&cmd->root_lock) | 885 | up_write(&cmd->root_lock) |
882 | 886 | ||
887 | #define READ_LOCK(cmd) \ | ||
888 | down_read(&cmd->root_lock); \ | ||
889 | if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \ | ||
890 | up_read(&cmd->root_lock); \ | ||
891 | return -EINVAL; \ | ||
892 | } | ||
893 | |||
894 | #define READ_LOCK_VOID(cmd) \ | ||
895 | down_read(&cmd->root_lock); \ | ||
896 | if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \ | ||
897 | up_read(&cmd->root_lock); \ | ||
898 | return; \ | ||
899 | } | ||
900 | |||
901 | #define READ_UNLOCK(cmd) \ | ||
902 | up_read(&cmd->root_lock) | ||
903 | |||
883 | int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) | 904 | int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) |
884 | { | 905 | { |
885 | int r; | 906 | int r; |
@@ -1015,22 +1036,20 @@ int dm_cache_load_discards(struct dm_cache_metadata *cmd, | |||
1015 | { | 1036 | { |
1016 | int r; | 1037 | int r; |
1017 | 1038 | ||
1018 | down_read(&cmd->root_lock); | 1039 | READ_LOCK(cmd); |
1019 | r = __load_discards(cmd, fn, context); | 1040 | r = __load_discards(cmd, fn, context); |
1020 | up_read(&cmd->root_lock); | 1041 | READ_UNLOCK(cmd); |
1021 | 1042 | ||
1022 | return r; | 1043 | return r; |
1023 | } | 1044 | } |
1024 | 1045 | ||
1025 | dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd) | 1046 | int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result) |
1026 | { | 1047 | { |
1027 | dm_cblock_t r; | 1048 | READ_LOCK(cmd); |
1049 | *result = cmd->cache_blocks; | ||
1050 | READ_UNLOCK(cmd); | ||
1028 | 1051 | ||
1029 | down_read(&cmd->root_lock); | 1052 | return 0; |
1030 | r = cmd->cache_blocks; | ||
1031 | up_read(&cmd->root_lock); | ||
1032 | |||
1033 | return r; | ||
1034 | } | 1053 | } |
1035 | 1054 | ||
1036 | static int __remove(struct dm_cache_metadata *cmd, dm_cblock_t cblock) | 1055 | static int __remove(struct dm_cache_metadata *cmd, dm_cblock_t cblock) |
@@ -1188,9 +1207,9 @@ int dm_cache_load_mappings(struct dm_cache_metadata *cmd, | |||
1188 | { | 1207 | { |
1189 | int r; | 1208 | int r; |
1190 | 1209 | ||
1191 | down_read(&cmd->root_lock); | 1210 | READ_LOCK(cmd); |
1192 | r = __load_mappings(cmd, policy, fn, context); | 1211 | r = __load_mappings(cmd, policy, fn, context); |
1193 | up_read(&cmd->root_lock); | 1212 | READ_UNLOCK(cmd); |
1194 | 1213 | ||
1195 | return r; | 1214 | return r; |
1196 | } | 1215 | } |
@@ -1215,18 +1234,18 @@ static int __dump_mappings(struct dm_cache_metadata *cmd) | |||
1215 | 1234 | ||
1216 | void dm_cache_dump(struct dm_cache_metadata *cmd) | 1235 | void dm_cache_dump(struct dm_cache_metadata *cmd) |
1217 | { | 1236 | { |
1218 | down_read(&cmd->root_lock); | 1237 | READ_LOCK_VOID(cmd); |
1219 | __dump_mappings(cmd); | 1238 | __dump_mappings(cmd); |
1220 | up_read(&cmd->root_lock); | 1239 | READ_UNLOCK(cmd); |
1221 | } | 1240 | } |
1222 | 1241 | ||
1223 | int dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd) | 1242 | int dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd) |
1224 | { | 1243 | { |
1225 | int r; | 1244 | int r; |
1226 | 1245 | ||
1227 | down_read(&cmd->root_lock); | 1246 | READ_LOCK(cmd); |
1228 | r = cmd->changed; | 1247 | r = cmd->changed; |
1229 | up_read(&cmd->root_lock); | 1248 | READ_UNLOCK(cmd); |
1230 | 1249 | ||
1231 | return r; | 1250 | return r; |
1232 | } | 1251 | } |
@@ -1276,9 +1295,9 @@ int dm_cache_set_dirty(struct dm_cache_metadata *cmd, | |||
1276 | void dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd, | 1295 | void dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd, |
1277 | struct dm_cache_statistics *stats) | 1296 | struct dm_cache_statistics *stats) |
1278 | { | 1297 | { |
1279 | down_read(&cmd->root_lock); | 1298 | READ_LOCK_VOID(cmd); |
1280 | *stats = cmd->stats; | 1299 | *stats = cmd->stats; |
1281 | up_read(&cmd->root_lock); | 1300 | READ_UNLOCK(cmd); |
1282 | } | 1301 | } |
1283 | 1302 | ||
1284 | void dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd, | 1303 | void dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd, |
@@ -1312,9 +1331,9 @@ int dm_cache_get_free_metadata_block_count(struct dm_cache_metadata *cmd, | |||
1312 | { | 1331 | { |
1313 | int r = -EINVAL; | 1332 | int r = -EINVAL; |
1314 | 1333 | ||
1315 | down_read(&cmd->root_lock); | 1334 | READ_LOCK(cmd); |
1316 | r = dm_sm_get_nr_free(cmd->metadata_sm, result); | 1335 | r = dm_sm_get_nr_free(cmd->metadata_sm, result); |
1317 | up_read(&cmd->root_lock); | 1336 | READ_UNLOCK(cmd); |
1318 | 1337 | ||
1319 | return r; | 1338 | return r; |
1320 | } | 1339 | } |
@@ -1324,9 +1343,9 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd, | |||
1324 | { | 1343 | { |
1325 | int r = -EINVAL; | 1344 | int r = -EINVAL; |
1326 | 1345 | ||
1327 | down_read(&cmd->root_lock); | 1346 | READ_LOCK(cmd); |
1328 | r = dm_sm_get_nr_blocks(cmd->metadata_sm, result); | 1347 | r = dm_sm_get_nr_blocks(cmd->metadata_sm, result); |
1329 | up_read(&cmd->root_lock); | 1348 | READ_UNLOCK(cmd); |
1330 | 1349 | ||
1331 | return r; | 1350 | return r; |
1332 | } | 1351 | } |
@@ -1417,7 +1436,13 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * | |||
1417 | 1436 | ||
1418 | int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) | 1437 | int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) |
1419 | { | 1438 | { |
1420 | return blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); | 1439 | int r; |
1440 | |||
1441 | READ_LOCK(cmd); | ||
1442 | r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); | ||
1443 | READ_UNLOCK(cmd); | ||
1444 | |||
1445 | return r; | ||
1421 | } | 1446 | } |
1422 | 1447 | ||
1423 | void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) | 1448 | void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) |
@@ -1440,10 +1465,7 @@ int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd) | |||
1440 | struct dm_block *sblock; | 1465 | struct dm_block *sblock; |
1441 | struct cache_disk_superblock *disk_super; | 1466 | struct cache_disk_superblock *disk_super; |
1442 | 1467 | ||
1443 | /* | 1468 | WRITE_LOCK(cmd); |
1444 | * We ignore fail_io for this function. | ||
1445 | */ | ||
1446 | down_write(&cmd->root_lock); | ||
1447 | set_bit(NEEDS_CHECK, &cmd->flags); | 1469 | set_bit(NEEDS_CHECK, &cmd->flags); |
1448 | 1470 | ||
1449 | r = superblock_lock(cmd, &sblock); | 1471 | r = superblock_lock(cmd, &sblock); |
@@ -1458,19 +1480,17 @@ int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd) | |||
1458 | dm_bm_unlock(sblock); | 1480 | dm_bm_unlock(sblock); |
1459 | 1481 | ||
1460 | out: | 1482 | out: |
1461 | up_write(&cmd->root_lock); | 1483 | WRITE_UNLOCK(cmd); |
1462 | return r; | 1484 | return r; |
1463 | } | 1485 | } |
1464 | 1486 | ||
1465 | bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd) | 1487 | int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result) |
1466 | { | 1488 | { |
1467 | bool needs_check; | 1489 | READ_LOCK(cmd); |
1490 | *result = !!test_bit(NEEDS_CHECK, &cmd->flags); | ||
1491 | READ_UNLOCK(cmd); | ||
1468 | 1492 | ||
1469 | down_read(&cmd->root_lock); | 1493 | return 0; |
1470 | needs_check = !!test_bit(NEEDS_CHECK, &cmd->flags); | ||
1471 | up_read(&cmd->root_lock); | ||
1472 | |||
1473 | return needs_check; | ||
1474 | } | 1494 | } |
1475 | 1495 | ||
1476 | int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) | 1496 | int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) |
diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h index 2ffee21f318d..8528744195e5 100644 --- a/drivers/md/dm-cache-metadata.h +++ b/drivers/md/dm-cache-metadata.h | |||
@@ -66,7 +66,7 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd); | |||
66 | * origin blocks to map to. | 66 | * origin blocks to map to. |
67 | */ | 67 | */ |
68 | int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size); | 68 | int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size); |
69 | dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd); | 69 | int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result); |
70 | 70 | ||
71 | int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd, | 71 | int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd, |
72 | sector_t discard_block_size, | 72 | sector_t discard_block_size, |
@@ -137,7 +137,7 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * | |||
137 | */ | 137 | */ |
138 | int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); | 138 | int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); |
139 | 139 | ||
140 | bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd); | 140 | int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result); |
141 | int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); | 141 | int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); |
142 | void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); | 142 | void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); |
143 | void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd); | 143 | void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd); |
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 2238d6f484fe..43d9e9a39f81 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c | |||
@@ -984,9 +984,14 @@ static void notify_mode_switch(struct cache *cache, enum cache_metadata_mode mod | |||
984 | 984 | ||
985 | static void set_cache_mode(struct cache *cache, enum cache_metadata_mode new_mode) | 985 | static void set_cache_mode(struct cache *cache, enum cache_metadata_mode new_mode) |
986 | { | 986 | { |
987 | bool needs_check = dm_cache_metadata_needs_check(cache->cmd); | 987 | bool needs_check; |
988 | enum cache_metadata_mode old_mode = get_cache_mode(cache); | 988 | enum cache_metadata_mode old_mode = get_cache_mode(cache); |
989 | 989 | ||
990 | if (dm_cache_metadata_needs_check(cache->cmd, &needs_check)) { | ||
991 | DMERR("unable to read needs_check flag, setting failure mode"); | ||
992 | new_mode = CM_FAIL; | ||
993 | } | ||
994 | |||
990 | if (new_mode == CM_WRITE && needs_check) { | 995 | if (new_mode == CM_WRITE && needs_check) { |
991 | DMERR("%s: unable to switch cache to write mode until repaired.", | 996 | DMERR("%s: unable to switch cache to write mode until repaired.", |
992 | cache_device_name(cache)); | 997 | cache_device_name(cache)); |
@@ -3510,6 +3515,7 @@ static void cache_status(struct dm_target *ti, status_type_t type, | |||
3510 | char buf[BDEVNAME_SIZE]; | 3515 | char buf[BDEVNAME_SIZE]; |
3511 | struct cache *cache = ti->private; | 3516 | struct cache *cache = ti->private; |
3512 | dm_cblock_t residency; | 3517 | dm_cblock_t residency; |
3518 | bool needs_check; | ||
3513 | 3519 | ||
3514 | switch (type) { | 3520 | switch (type) { |
3515 | case STATUSTYPE_INFO: | 3521 | case STATUSTYPE_INFO: |
@@ -3583,7 +3589,9 @@ static void cache_status(struct dm_target *ti, status_type_t type, | |||
3583 | else | 3589 | else |
3584 | DMEMIT("rw "); | 3590 | DMEMIT("rw "); |
3585 | 3591 | ||
3586 | if (dm_cache_metadata_needs_check(cache->cmd)) | 3592 | r = dm_cache_metadata_needs_check(cache->cmd, &needs_check); |
3593 | |||
3594 | if (r || needs_check) | ||
3587 | DMEMIT("needs_check "); | 3595 | DMEMIT("needs_check "); |
3588 | else | 3596 | else |
3589 | DMEMIT("- "); | 3597 | DMEMIT("- "); |