diff options
-rw-r--r-- | drivers/md/dm-thin-metadata.c | 207 | ||||
-rw-r--r-- | drivers/md/dm-thin-metadata.h | 12 |
2 files changed, 158 insertions, 61 deletions
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index d30bc09fd7c4..693e149e9727 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2011 Red Hat, Inc. | 2 | * Copyright (C) 2011-2012 Red Hat, Inc. |
3 | * | 3 | * |
4 | * This file is released under the GPL. | 4 | * This file is released under the GPL. |
5 | */ | 5 | */ |
@@ -185,6 +185,13 @@ struct dm_pool_metadata { | |||
185 | unsigned long flags; | 185 | unsigned long flags; |
186 | sector_t data_block_size; | 186 | sector_t data_block_size; |
187 | bool read_only:1; | 187 | bool read_only:1; |
188 | |||
189 | /* | ||
190 | * Set if a transaction has to be aborted but the attempt to roll back | ||
191 | * to the previous (good) transaction failed. The only pool metadata | ||
192 | * operation possible in this state is the closing of the device. | ||
193 | */ | ||
194 | bool fail_io:1; | ||
188 | }; | 195 | }; |
189 | 196 | ||
190 | struct dm_thin_device { | 197 | struct dm_thin_device { |
@@ -193,7 +200,8 @@ struct dm_thin_device { | |||
193 | dm_thin_id id; | 200 | dm_thin_id id; |
194 | 201 | ||
195 | int open_count; | 202 | int open_count; |
196 | int changed; | 203 | bool changed:1; |
204 | bool aborted_with_changes:1; | ||
197 | uint64_t mapped_blocks; | 205 | uint64_t mapped_blocks; |
198 | uint64_t transaction_id; | 206 | uint64_t transaction_id; |
199 | uint32_t creation_time; | 207 | uint32_t creation_time; |
@@ -731,9 +739,6 @@ static int __write_changed_details(struct dm_pool_metadata *pmd) | |||
731 | 739 | ||
732 | static int __commit_transaction(struct dm_pool_metadata *pmd) | 740 | static int __commit_transaction(struct dm_pool_metadata *pmd) |
733 | { | 741 | { |
734 | /* | ||
735 | * FIXME: Associated pool should be made read-only on failure. | ||
736 | */ | ||
737 | int r; | 742 | int r; |
738 | size_t metadata_len, data_len; | 743 | size_t metadata_len, data_len; |
739 | struct thin_disk_superblock *disk_super; | 744 | struct thin_disk_superblock *disk_super; |
@@ -809,6 +814,7 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, | |||
809 | pmd->time = 0; | 814 | pmd->time = 0; |
810 | INIT_LIST_HEAD(&pmd->thin_devices); | 815 | INIT_LIST_HEAD(&pmd->thin_devices); |
811 | pmd->read_only = false; | 816 | pmd->read_only = false; |
817 | pmd->fail_io = false; | ||
812 | pmd->bdev = bdev; | 818 | pmd->bdev = bdev; |
813 | pmd->data_block_size = data_block_size; | 819 | pmd->data_block_size = data_block_size; |
814 | 820 | ||
@@ -851,16 +857,17 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd) | |||
851 | return -EBUSY; | 857 | return -EBUSY; |
852 | } | 858 | } |
853 | 859 | ||
854 | if (!pmd->read_only) { | 860 | if (!pmd->read_only && !pmd->fail_io) { |
855 | r = __commit_transaction(pmd); | 861 | r = __commit_transaction(pmd); |
856 | if (r < 0) | 862 | if (r < 0) |
857 | DMWARN("%s: __commit_transaction() failed, error = %d", | 863 | DMWARN("%s: __commit_transaction() failed, error = %d", |
858 | __func__, r); | 864 | __func__, r); |
859 | } | 865 | } |
860 | 866 | ||
861 | __destroy_persistent_data_objects(pmd); | 867 | if (!pmd->fail_io) |
862 | kfree(pmd); | 868 | __destroy_persistent_data_objects(pmd); |
863 | 869 | ||
870 | kfree(pmd); | ||
864 | return 0; | 871 | return 0; |
865 | } | 872 | } |
866 | 873 | ||
@@ -921,6 +928,7 @@ static int __open_device(struct dm_pool_metadata *pmd, | |||
921 | (*td)->id = dev; | 928 | (*td)->id = dev; |
922 | (*td)->open_count = 1; | 929 | (*td)->open_count = 1; |
923 | (*td)->changed = changed; | 930 | (*td)->changed = changed; |
931 | (*td)->aborted_with_changes = false; | ||
924 | (*td)->mapped_blocks = le64_to_cpu(details_le.mapped_blocks); | 932 | (*td)->mapped_blocks = le64_to_cpu(details_le.mapped_blocks); |
925 | (*td)->transaction_id = le64_to_cpu(details_le.transaction_id); | 933 | (*td)->transaction_id = le64_to_cpu(details_le.transaction_id); |
926 | (*td)->creation_time = le32_to_cpu(details_le.creation_time); | 934 | (*td)->creation_time = le32_to_cpu(details_le.creation_time); |
@@ -982,10 +990,11 @@ static int __create_thin(struct dm_pool_metadata *pmd, | |||
982 | 990 | ||
983 | int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev) | 991 | int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev) |
984 | { | 992 | { |
985 | int r; | 993 | int r = -EINVAL; |
986 | 994 | ||
987 | down_write(&pmd->root_lock); | 995 | down_write(&pmd->root_lock); |
988 | r = __create_thin(pmd, dev); | 996 | if (!pmd->fail_io) |
997 | r = __create_thin(pmd, dev); | ||
989 | up_write(&pmd->root_lock); | 998 | up_write(&pmd->root_lock); |
990 | 999 | ||
991 | return r; | 1000 | return r; |
@@ -1072,10 +1081,11 @@ int dm_pool_create_snap(struct dm_pool_metadata *pmd, | |||
1072 | dm_thin_id dev, | 1081 | dm_thin_id dev, |
1073 | dm_thin_id origin) | 1082 | dm_thin_id origin) |
1074 | { | 1083 | { |
1075 | int r; | 1084 | int r = -EINVAL; |
1076 | 1085 | ||
1077 | down_write(&pmd->root_lock); | 1086 | down_write(&pmd->root_lock); |
1078 | r = __create_snap(pmd, dev, origin); | 1087 | if (!pmd->fail_io) |
1088 | r = __create_snap(pmd, dev, origin); | ||
1079 | up_write(&pmd->root_lock); | 1089 | up_write(&pmd->root_lock); |
1080 | 1090 | ||
1081 | return r; | 1091 | return r; |
@@ -1114,10 +1124,11 @@ static int __delete_device(struct dm_pool_metadata *pmd, dm_thin_id dev) | |||
1114 | int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd, | 1124 | int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd, |
1115 | dm_thin_id dev) | 1125 | dm_thin_id dev) |
1116 | { | 1126 | { |
1117 | int r; | 1127 | int r = -EINVAL; |
1118 | 1128 | ||
1119 | down_write(&pmd->root_lock); | 1129 | down_write(&pmd->root_lock); |
1120 | r = __delete_device(pmd, dev); | 1130 | if (!pmd->fail_io) |
1131 | r = __delete_device(pmd, dev); | ||
1121 | up_write(&pmd->root_lock); | 1132 | up_write(&pmd->root_lock); |
1122 | 1133 | ||
1123 | return r; | 1134 | return r; |
@@ -1127,27 +1138,40 @@ int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd, | |||
1127 | uint64_t current_id, | 1138 | uint64_t current_id, |
1128 | uint64_t new_id) | 1139 | uint64_t new_id) |
1129 | { | 1140 | { |
1141 | int r = -EINVAL; | ||
1142 | |||
1130 | down_write(&pmd->root_lock); | 1143 | down_write(&pmd->root_lock); |
1144 | |||
1145 | if (pmd->fail_io) | ||
1146 | goto out; | ||
1147 | |||
1131 | if (pmd->trans_id != current_id) { | 1148 | if (pmd->trans_id != current_id) { |
1132 | up_write(&pmd->root_lock); | ||
1133 | DMERR("mismatched transaction id"); | 1149 | DMERR("mismatched transaction id"); |
1134 | return -EINVAL; | 1150 | goto out; |
1135 | } | 1151 | } |
1136 | 1152 | ||
1137 | pmd->trans_id = new_id; | 1153 | pmd->trans_id = new_id; |
1154 | r = 0; | ||
1155 | |||
1156 | out: | ||
1138 | up_write(&pmd->root_lock); | 1157 | up_write(&pmd->root_lock); |
1139 | 1158 | ||
1140 | return 0; | 1159 | return r; |
1141 | } | 1160 | } |
1142 | 1161 | ||
1143 | int dm_pool_get_metadata_transaction_id(struct dm_pool_metadata *pmd, | 1162 | int dm_pool_get_metadata_transaction_id(struct dm_pool_metadata *pmd, |
1144 | uint64_t *result) | 1163 | uint64_t *result) |
1145 | { | 1164 | { |
1165 | int r = -EINVAL; | ||
1166 | |||
1146 | down_read(&pmd->root_lock); | 1167 | down_read(&pmd->root_lock); |
1147 | *result = pmd->trans_id; | 1168 | if (!pmd->fail_io) { |
1169 | *result = pmd->trans_id; | ||
1170 | r = 0; | ||
1171 | } | ||
1148 | up_read(&pmd->root_lock); | 1172 | up_read(&pmd->root_lock); |
1149 | 1173 | ||
1150 | return 0; | 1174 | return r; |
1151 | } | 1175 | } |
1152 | 1176 | ||
1153 | static int __reserve_metadata_snap(struct dm_pool_metadata *pmd) | 1177 | static int __reserve_metadata_snap(struct dm_pool_metadata *pmd) |
@@ -1211,10 +1235,11 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd) | |||
1211 | 1235 | ||
1212 | int dm_pool_reserve_metadata_snap(struct dm_pool_metadata *pmd) | 1236 | int dm_pool_reserve_metadata_snap(struct dm_pool_metadata *pmd) |
1213 | { | 1237 | { |
1214 | int r; | 1238 | int r = -EINVAL; |
1215 | 1239 | ||
1216 | down_write(&pmd->root_lock); | 1240 | down_write(&pmd->root_lock); |
1217 | r = __reserve_metadata_snap(pmd); | 1241 | if (!pmd->fail_io) |
1242 | r = __reserve_metadata_snap(pmd); | ||
1218 | up_write(&pmd->root_lock); | 1243 | up_write(&pmd->root_lock); |
1219 | 1244 | ||
1220 | return r; | 1245 | return r; |
@@ -1256,10 +1281,11 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd) | |||
1256 | 1281 | ||
1257 | int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd) | 1282 | int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd) |
1258 | { | 1283 | { |
1259 | int r; | 1284 | int r = -EINVAL; |
1260 | 1285 | ||
1261 | down_write(&pmd->root_lock); | 1286 | down_write(&pmd->root_lock); |
1262 | r = __release_metadata_snap(pmd); | 1287 | if (!pmd->fail_io) |
1288 | r = __release_metadata_snap(pmd); | ||
1263 | up_write(&pmd->root_lock); | 1289 | up_write(&pmd->root_lock); |
1264 | 1290 | ||
1265 | return r; | 1291 | return r; |
@@ -1286,10 +1312,11 @@ static int __get_metadata_snap(struct dm_pool_metadata *pmd, | |||
1286 | int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd, | 1312 | int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd, |
1287 | dm_block_t *result) | 1313 | dm_block_t *result) |
1288 | { | 1314 | { |
1289 | int r; | 1315 | int r = -EINVAL; |
1290 | 1316 | ||
1291 | down_read(&pmd->root_lock); | 1317 | down_read(&pmd->root_lock); |
1292 | r = __get_metadata_snap(pmd, result); | 1318 | if (!pmd->fail_io) |
1319 | r = __get_metadata_snap(pmd, result); | ||
1293 | up_read(&pmd->root_lock); | 1320 | up_read(&pmd->root_lock); |
1294 | 1321 | ||
1295 | return r; | 1322 | return r; |
@@ -1298,10 +1325,11 @@ int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd, | |||
1298 | int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_thin_id dev, | 1325 | int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_thin_id dev, |
1299 | struct dm_thin_device **td) | 1326 | struct dm_thin_device **td) |
1300 | { | 1327 | { |
1301 | int r; | 1328 | int r = -EINVAL; |
1302 | 1329 | ||
1303 | down_write(&pmd->root_lock); | 1330 | down_write(&pmd->root_lock); |
1304 | r = __open_device(pmd, dev, 0, td); | 1331 | if (!pmd->fail_io) |
1332 | r = __open_device(pmd, dev, 0, td); | ||
1305 | up_write(&pmd->root_lock); | 1333 | up_write(&pmd->root_lock); |
1306 | 1334 | ||
1307 | return r; | 1335 | return r; |
@@ -1329,28 +1357,31 @@ static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time) | |||
1329 | int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block, | 1357 | int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block, |
1330 | int can_block, struct dm_thin_lookup_result *result) | 1358 | int can_block, struct dm_thin_lookup_result *result) |
1331 | { | 1359 | { |
1332 | int r; | 1360 | int r = -EINVAL; |
1333 | uint64_t block_time = 0; | 1361 | uint64_t block_time = 0; |
1334 | __le64 value; | 1362 | __le64 value; |
1335 | struct dm_pool_metadata *pmd = td->pmd; | 1363 | struct dm_pool_metadata *pmd = td->pmd; |
1336 | dm_block_t keys[2] = { td->id, block }; | 1364 | dm_block_t keys[2] = { td->id, block }; |
1365 | struct dm_btree_info *info; | ||
1337 | 1366 | ||
1338 | if (can_block) { | 1367 | if (can_block) { |
1339 | down_read(&pmd->root_lock); | 1368 | down_read(&pmd->root_lock); |
1340 | r = dm_btree_lookup(&pmd->info, pmd->root, keys, &value); | 1369 | info = &pmd->info; |
1341 | if (!r) | 1370 | } else if (down_read_trylock(&pmd->root_lock)) |
1342 | block_time = le64_to_cpu(value); | 1371 | info = &pmd->nb_info; |
1343 | up_read(&pmd->root_lock); | 1372 | else |
1344 | |||
1345 | } else if (down_read_trylock(&pmd->root_lock)) { | ||
1346 | r = dm_btree_lookup(&pmd->nb_info, pmd->root, keys, &value); | ||
1347 | if (!r) | ||
1348 | block_time = le64_to_cpu(value); | ||
1349 | up_read(&pmd->root_lock); | ||
1350 | |||
1351 | } else | ||
1352 | return -EWOULDBLOCK; | 1373 | return -EWOULDBLOCK; |
1353 | 1374 | ||
1375 | if (pmd->fail_io) | ||
1376 | goto out; | ||
1377 | |||
1378 | r = dm_btree_lookup(info, pmd->root, keys, &value); | ||
1379 | if (!r) | ||
1380 | block_time = le64_to_cpu(value); | ||
1381 | |||
1382 | out: | ||
1383 | up_read(&pmd->root_lock); | ||
1384 | |||
1354 | if (!r) { | 1385 | if (!r) { |
1355 | dm_block_t exception_block; | 1386 | dm_block_t exception_block; |
1356 | uint32_t exception_time; | 1387 | uint32_t exception_time; |
@@ -1389,10 +1420,11 @@ static int __insert(struct dm_thin_device *td, dm_block_t block, | |||
1389 | int dm_thin_insert_block(struct dm_thin_device *td, dm_block_t block, | 1420 | int dm_thin_insert_block(struct dm_thin_device *td, dm_block_t block, |
1390 | dm_block_t data_block) | 1421 | dm_block_t data_block) |
1391 | { | 1422 | { |
1392 | int r; | 1423 | int r = -EINVAL; |
1393 | 1424 | ||
1394 | down_write(&td->pmd->root_lock); | 1425 | down_write(&td->pmd->root_lock); |
1395 | r = __insert(td, block, data_block); | 1426 | if (!td->pmd->fail_io) |
1427 | r = __insert(td, block, data_block); | ||
1396 | up_write(&td->pmd->root_lock); | 1428 | up_write(&td->pmd->root_lock); |
1397 | 1429 | ||
1398 | return r; | 1430 | return r; |
@@ -1416,10 +1448,11 @@ static int __remove(struct dm_thin_device *td, dm_block_t block) | |||
1416 | 1448 | ||
1417 | int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block) | 1449 | int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block) |
1418 | { | 1450 | { |
1419 | int r; | 1451 | int r = -EINVAL; |
1420 | 1452 | ||
1421 | down_write(&td->pmd->root_lock); | 1453 | down_write(&td->pmd->root_lock); |
1422 | r = __remove(td, block); | 1454 | if (!td->pmd->fail_io) |
1455 | r = __remove(td, block); | ||
1423 | up_write(&td->pmd->root_lock); | 1456 | up_write(&td->pmd->root_lock); |
1424 | 1457 | ||
1425 | return r; | 1458 | return r; |
@@ -1436,12 +1469,24 @@ bool dm_thin_changed_this_transaction(struct dm_thin_device *td) | |||
1436 | return r; | 1469 | return r; |
1437 | } | 1470 | } |
1438 | 1471 | ||
1472 | bool dm_thin_aborted_changes(struct dm_thin_device *td) | ||
1473 | { | ||
1474 | bool r; | ||
1475 | |||
1476 | down_read(&td->pmd->root_lock); | ||
1477 | r = td->aborted_with_changes; | ||
1478 | up_read(&td->pmd->root_lock); | ||
1479 | |||
1480 | return r; | ||
1481 | } | ||
1482 | |||
1439 | int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result) | 1483 | int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result) |
1440 | { | 1484 | { |
1441 | int r; | 1485 | int r = -EINVAL; |
1442 | 1486 | ||
1443 | down_write(&pmd->root_lock); | 1487 | down_write(&pmd->root_lock); |
1444 | r = dm_sm_new_block(pmd->data_sm, result); | 1488 | if (!pmd->fail_io) |
1489 | r = dm_sm_new_block(pmd->data_sm, result); | ||
1445 | up_write(&pmd->root_lock); | 1490 | up_write(&pmd->root_lock); |
1446 | 1491 | ||
1447 | return r; | 1492 | return r; |
@@ -1449,9 +1494,11 @@ int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result) | |||
1449 | 1494 | ||
1450 | int dm_pool_commit_metadata(struct dm_pool_metadata *pmd) | 1495 | int dm_pool_commit_metadata(struct dm_pool_metadata *pmd) |
1451 | { | 1496 | { |
1452 | int r; | 1497 | int r = -EINVAL; |
1453 | 1498 | ||
1454 | down_write(&pmd->root_lock); | 1499 | down_write(&pmd->root_lock); |
1500 | if (pmd->fail_io) | ||
1501 | goto out; | ||
1455 | 1502 | ||
1456 | r = __commit_transaction(pmd); | 1503 | r = __commit_transaction(pmd); |
1457 | if (r <= 0) | 1504 | if (r <= 0) |
@@ -1466,12 +1513,41 @@ out: | |||
1466 | return r; | 1513 | return r; |
1467 | } | 1514 | } |
1468 | 1515 | ||
1516 | static void __set_abort_with_changes_flags(struct dm_pool_metadata *pmd) | ||
1517 | { | ||
1518 | struct dm_thin_device *td; | ||
1519 | |||
1520 | list_for_each_entry(td, &pmd->thin_devices, list) | ||
1521 | td->aborted_with_changes = td->changed; | ||
1522 | } | ||
1523 | |||
1524 | int dm_pool_abort_metadata(struct dm_pool_metadata *pmd) | ||
1525 | { | ||
1526 | int r = -EINVAL; | ||
1527 | |||
1528 | down_write(&pmd->root_lock); | ||
1529 | if (pmd->fail_io) | ||
1530 | goto out; | ||
1531 | |||
1532 | __set_abort_with_changes_flags(pmd); | ||
1533 | __destroy_persistent_data_objects(pmd); | ||
1534 | r = __create_persistent_data_objects(pmd, false); | ||
1535 | if (r) | ||
1536 | pmd->fail_io = true; | ||
1537 | |||
1538 | out: | ||
1539 | up_write(&pmd->root_lock); | ||
1540 | |||
1541 | return r; | ||
1542 | } | ||
1543 | |||
1469 | int dm_pool_get_free_block_count(struct dm_pool_metadata *pmd, dm_block_t *result) | 1544 | int dm_pool_get_free_block_count(struct dm_pool_metadata *pmd, dm_block_t *result) |
1470 | { | 1545 | { |
1471 | int r; | 1546 | int r = -EINVAL; |
1472 | 1547 | ||
1473 | down_read(&pmd->root_lock); | 1548 | down_read(&pmd->root_lock); |
1474 | r = dm_sm_get_nr_free(pmd->data_sm, result); | 1549 | if (!pmd->fail_io) |
1550 | r = dm_sm_get_nr_free(pmd->data_sm, result); | ||
1475 | up_read(&pmd->root_lock); | 1551 | up_read(&pmd->root_lock); |
1476 | 1552 | ||
1477 | return r; | 1553 | return r; |
@@ -1480,10 +1556,11 @@ int dm_pool_get_free_block_count(struct dm_pool_metadata *pmd, dm_block_t *resul | |||
1480 | int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd, | 1556 | int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd, |
1481 | dm_block_t *result) | 1557 | dm_block_t *result) |
1482 | { | 1558 | { |
1483 | int r; | 1559 | int r = -EINVAL; |
1484 | 1560 | ||
1485 | down_read(&pmd->root_lock); | 1561 | down_read(&pmd->root_lock); |
1486 | r = dm_sm_get_nr_free(pmd->metadata_sm, result); | 1562 | if (!pmd->fail_io) |
1563 | r = dm_sm_get_nr_free(pmd->metadata_sm, result); | ||
1487 | up_read(&pmd->root_lock); | 1564 | up_read(&pmd->root_lock); |
1488 | 1565 | ||
1489 | return r; | 1566 | return r; |
@@ -1492,10 +1569,11 @@ int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd, | |||
1492 | int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd, | 1569 | int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd, |
1493 | dm_block_t *result) | 1570 | dm_block_t *result) |
1494 | { | 1571 | { |
1495 | int r; | 1572 | int r = -EINVAL; |
1496 | 1573 | ||
1497 | down_read(&pmd->root_lock); | 1574 | down_read(&pmd->root_lock); |
1498 | r = dm_sm_get_nr_blocks(pmd->metadata_sm, result); | 1575 | if (!pmd->fail_io) |
1576 | r = dm_sm_get_nr_blocks(pmd->metadata_sm, result); | ||
1499 | up_read(&pmd->root_lock); | 1577 | up_read(&pmd->root_lock); |
1500 | 1578 | ||
1501 | return r; | 1579 | return r; |
@@ -1512,10 +1590,11 @@ int dm_pool_get_data_block_size(struct dm_pool_metadata *pmd, sector_t *result) | |||
1512 | 1590 | ||
1513 | int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result) | 1591 | int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result) |
1514 | { | 1592 | { |
1515 | int r; | 1593 | int r = -EINVAL; |
1516 | 1594 | ||
1517 | down_read(&pmd->root_lock); | 1595 | down_read(&pmd->root_lock); |
1518 | r = dm_sm_get_nr_blocks(pmd->data_sm, result); | 1596 | if (!pmd->fail_io) |
1597 | r = dm_sm_get_nr_blocks(pmd->data_sm, result); | ||
1519 | up_read(&pmd->root_lock); | 1598 | up_read(&pmd->root_lock); |
1520 | 1599 | ||
1521 | return r; | 1600 | return r; |
@@ -1523,13 +1602,17 @@ int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result) | |||
1523 | 1602 | ||
1524 | int dm_thin_get_mapped_count(struct dm_thin_device *td, dm_block_t *result) | 1603 | int dm_thin_get_mapped_count(struct dm_thin_device *td, dm_block_t *result) |
1525 | { | 1604 | { |
1605 | int r = -EINVAL; | ||
1526 | struct dm_pool_metadata *pmd = td->pmd; | 1606 | struct dm_pool_metadata *pmd = td->pmd; |
1527 | 1607 | ||
1528 | down_read(&pmd->root_lock); | 1608 | down_read(&pmd->root_lock); |
1529 | *result = td->mapped_blocks; | 1609 | if (!pmd->fail_io) { |
1610 | *result = td->mapped_blocks; | ||
1611 | r = 0; | ||
1612 | } | ||
1530 | up_read(&pmd->root_lock); | 1613 | up_read(&pmd->root_lock); |
1531 | 1614 | ||
1532 | return 0; | 1615 | return r; |
1533 | } | 1616 | } |
1534 | 1617 | ||
1535 | static int __highest_block(struct dm_thin_device *td, dm_block_t *result) | 1618 | static int __highest_block(struct dm_thin_device *td, dm_block_t *result) |
@@ -1551,11 +1634,12 @@ static int __highest_block(struct dm_thin_device *td, dm_block_t *result) | |||
1551 | int dm_thin_get_highest_mapped_block(struct dm_thin_device *td, | 1634 | int dm_thin_get_highest_mapped_block(struct dm_thin_device *td, |
1552 | dm_block_t *result) | 1635 | dm_block_t *result) |
1553 | { | 1636 | { |
1554 | int r; | 1637 | int r = -EINVAL; |
1555 | struct dm_pool_metadata *pmd = td->pmd; | 1638 | struct dm_pool_metadata *pmd = td->pmd; |
1556 | 1639 | ||
1557 | down_read(&pmd->root_lock); | 1640 | down_read(&pmd->root_lock); |
1558 | r = __highest_block(td, result); | 1641 | if (!pmd->fail_io) |
1642 | r = __highest_block(td, result); | ||
1559 | up_read(&pmd->root_lock); | 1643 | up_read(&pmd->root_lock); |
1560 | 1644 | ||
1561 | return r; | 1645 | return r; |
@@ -1583,10 +1667,11 @@ static int __resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count) | |||
1583 | 1667 | ||
1584 | int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count) | 1668 | int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count) |
1585 | { | 1669 | { |
1586 | int r; | 1670 | int r = -EINVAL; |
1587 | 1671 | ||
1588 | down_write(&pmd->root_lock); | 1672 | down_write(&pmd->root_lock); |
1589 | r = __resize_data_dev(pmd, new_count); | 1673 | if (!pmd->fail_io) |
1674 | r = __resize_data_dev(pmd, new_count); | ||
1590 | up_write(&pmd->root_lock); | 1675 | up_write(&pmd->root_lock); |
1591 | 1676 | ||
1592 | return r; | 1677 | return r; |
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h index 2bbe622f299d..0cecc3702885 100644 --- a/drivers/md/dm-thin-metadata.h +++ b/drivers/md/dm-thin-metadata.h | |||
@@ -80,6 +80,16 @@ int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd, | |||
80 | int dm_pool_commit_metadata(struct dm_pool_metadata *pmd); | 80 | int dm_pool_commit_metadata(struct dm_pool_metadata *pmd); |
81 | 81 | ||
82 | /* | 82 | /* |
83 | * Discards all uncommitted changes. Rereads the superblock, rolling back | ||
84 | * to the last good transaction. Thin devices remain open. | ||
85 | * dm_thin_aborted_changes() tells you if they had uncommitted changes. | ||
86 | * | ||
87 | * If this call fails it's only useful to call dm_pool_metadata_close(). | ||
88 | * All other methods will fail with -EINVAL. | ||
89 | */ | ||
90 | int dm_pool_abort_metadata(struct dm_pool_metadata *pmd); | ||
91 | |||
92 | /* | ||
83 | * Set/get userspace transaction id. | 93 | * Set/get userspace transaction id. |
84 | */ | 94 | */ |
85 | int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd, | 95 | int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd, |
@@ -150,6 +160,8 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block); | |||
150 | */ | 160 | */ |
151 | bool dm_thin_changed_this_transaction(struct dm_thin_device *td); | 161 | bool dm_thin_changed_this_transaction(struct dm_thin_device *td); |
152 | 162 | ||
163 | bool dm_thin_aborted_changes(struct dm_thin_device *td); | ||
164 | |||
153 | int dm_thin_get_highest_mapped_block(struct dm_thin_device *td, | 165 | int dm_thin_get_highest_mapped_block(struct dm_thin_device *td, |
154 | dm_block_t *highest_mapped); | 166 | dm_block_t *highest_mapped); |
155 | 167 | ||