diff options
Diffstat (limited to 'drivers/md/dm-thin.c')
-rw-r--r-- | drivers/md/dm-thin.c | 66 |
1 files changed, 39 insertions, 27 deletions
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 2c0cf511ec23..ee29037ffc2e 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c | |||
@@ -640,7 +640,9 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m) | |||
640 | */ | 640 | */ |
641 | r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block); | 641 | r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block); |
642 | if (r) { | 642 | if (r) { |
643 | DMERR_LIMIT("dm_thin_insert_block() failed"); | 643 | DMERR_LIMIT("%s: dm_thin_insert_block() failed: error = %d", |
644 | dm_device_name(pool->pool_md), r); | ||
645 | set_pool_mode(pool, PM_READ_ONLY); | ||
644 | cell_error(pool, m->cell); | 646 | cell_error(pool, m->cell); |
645 | goto out; | 647 | goto out; |
646 | } | 648 | } |
@@ -881,32 +883,23 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block, | |||
881 | } | 883 | } |
882 | } | 884 | } |
883 | 885 | ||
884 | static int commit(struct pool *pool) | ||
885 | { | ||
886 | int r; | ||
887 | |||
888 | r = dm_pool_commit_metadata(pool->pmd); | ||
889 | if (r) | ||
890 | DMERR_LIMIT("%s: commit failed: error = %d", | ||
891 | dm_device_name(pool->pool_md), r); | ||
892 | |||
893 | return r; | ||
894 | } | ||
895 | |||
896 | /* | 886 | /* |
897 | * A non-zero return indicates read_only or fail_io mode. | 887 | * A non-zero return indicates read_only or fail_io mode. |
898 | * Many callers don't care about the return value. | 888 | * Many callers don't care about the return value. |
899 | */ | 889 | */ |
900 | static int commit_or_fallback(struct pool *pool) | 890 | static int commit(struct pool *pool) |
901 | { | 891 | { |
902 | int r; | 892 | int r; |
903 | 893 | ||
904 | if (get_pool_mode(pool) != PM_WRITE) | 894 | if (get_pool_mode(pool) != PM_WRITE) |
905 | return -EINVAL; | 895 | return -EINVAL; |
906 | 896 | ||
907 | r = commit(pool); | 897 | r = dm_pool_commit_metadata(pool->pmd); |
908 | if (r) | 898 | if (r) { |
899 | DMERR_LIMIT("%s: dm_pool_commit_metadata failed: error = %d", | ||
900 | dm_device_name(pool->pool_md), r); | ||
909 | set_pool_mode(pool, PM_READ_ONLY); | 901 | set_pool_mode(pool, PM_READ_ONLY); |
902 | } | ||
910 | 903 | ||
911 | return r; | 904 | return r; |
912 | } | 905 | } |
@@ -943,7 +936,9 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) | |||
943 | * Try to commit to see if that will free up some | 936 | * Try to commit to see if that will free up some |
944 | * more space. | 937 | * more space. |
945 | */ | 938 | */ |
946 | (void) commit_or_fallback(pool); | 939 | r = commit(pool); |
940 | if (r) | ||
941 | return r; | ||
947 | 942 | ||
948 | r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); | 943 | r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); |
949 | if (r) | 944 | if (r) |
@@ -957,7 +952,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) | |||
957 | * table reload). | 952 | * table reload). |
958 | */ | 953 | */ |
959 | if (!free_blocks) { | 954 | if (!free_blocks) { |
960 | DMWARN("%s: no free space available.", | 955 | DMWARN("%s: no free data space available.", |
961 | dm_device_name(pool->pool_md)); | 956 | dm_device_name(pool->pool_md)); |
962 | spin_lock_irqsave(&pool->lock, flags); | 957 | spin_lock_irqsave(&pool->lock, flags); |
963 | pool->no_free_space = 1; | 958 | pool->no_free_space = 1; |
@@ -967,8 +962,16 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) | |||
967 | } | 962 | } |
968 | 963 | ||
969 | r = dm_pool_alloc_data_block(pool->pmd, result); | 964 | r = dm_pool_alloc_data_block(pool->pmd, result); |
970 | if (r) | 965 | if (r) { |
966 | if (r == -ENOSPC && | ||
967 | !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) && | ||
968 | !free_blocks) { | ||
969 | DMWARN("%s: no free metadata space available.", | ||
970 | dm_device_name(pool->pool_md)); | ||
971 | set_pool_mode(pool, PM_READ_ONLY); | ||
972 | } | ||
971 | return r; | 973 | return r; |
974 | } | ||
972 | 975 | ||
973 | return 0; | 976 | return 0; |
974 | } | 977 | } |
@@ -1349,7 +1352,7 @@ static void process_deferred_bios(struct pool *pool) | |||
1349 | if (bio_list_empty(&bios) && !need_commit_due_to_time(pool)) | 1352 | if (bio_list_empty(&bios) && !need_commit_due_to_time(pool)) |
1350 | return; | 1353 | return; |
1351 | 1354 | ||
1352 | if (commit_or_fallback(pool)) { | 1355 | if (commit(pool)) { |
1353 | while ((bio = bio_list_pop(&bios))) | 1356 | while ((bio = bio_list_pop(&bios))) |
1354 | bio_io_error(bio); | 1357 | bio_io_error(bio); |
1355 | return; | 1358 | return; |
@@ -1397,6 +1400,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode) | |||
1397 | case PM_FAIL: | 1400 | case PM_FAIL: |
1398 | DMERR("%s: switching pool to failure mode", | 1401 | DMERR("%s: switching pool to failure mode", |
1399 | dm_device_name(pool->pool_md)); | 1402 | dm_device_name(pool->pool_md)); |
1403 | dm_pool_metadata_read_only(pool->pmd); | ||
1400 | pool->process_bio = process_bio_fail; | 1404 | pool->process_bio = process_bio_fail; |
1401 | pool->process_discard = process_bio_fail; | 1405 | pool->process_discard = process_bio_fail; |
1402 | pool->process_prepared_mapping = process_prepared_mapping_fail; | 1406 | pool->process_prepared_mapping = process_prepared_mapping_fail; |
@@ -1421,6 +1425,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode) | |||
1421 | break; | 1425 | break; |
1422 | 1426 | ||
1423 | case PM_WRITE: | 1427 | case PM_WRITE: |
1428 | dm_pool_metadata_read_write(pool->pmd); | ||
1424 | pool->process_bio = process_bio; | 1429 | pool->process_bio = process_bio; |
1425 | pool->process_discard = process_discard; | 1430 | pool->process_discard = process_discard; |
1426 | pool->process_prepared_mapping = process_prepared_mapping; | 1431 | pool->process_prepared_mapping = process_prepared_mapping; |
@@ -1637,12 +1642,19 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti) | |||
1637 | struct pool_c *pt = ti->private; | 1642 | struct pool_c *pt = ti->private; |
1638 | 1643 | ||
1639 | /* | 1644 | /* |
1640 | * We want to make sure that degraded pools are never upgraded. | 1645 | * We want to make sure that a pool in PM_FAIL mode is never upgraded. |
1641 | */ | 1646 | */ |
1642 | enum pool_mode old_mode = pool->pf.mode; | 1647 | enum pool_mode old_mode = pool->pf.mode; |
1643 | enum pool_mode new_mode = pt->adjusted_pf.mode; | 1648 | enum pool_mode new_mode = pt->adjusted_pf.mode; |
1644 | 1649 | ||
1645 | if (old_mode > new_mode) | 1650 | /* |
1651 | * If we were in PM_FAIL mode, rollback of metadata failed. We're | ||
1652 | * not going to recover without a thin_repair. So we never let the | ||
1653 | * pool move out of the old mode. On the other hand a PM_READ_ONLY | ||
1654 | * may have been due to a lack of metadata or data space, and may | ||
1655 | * now work (ie. if the underlying devices have been resized). | ||
1656 | */ | ||
1657 | if (old_mode == PM_FAIL) | ||
1646 | new_mode = old_mode; | 1658 | new_mode = old_mode; |
1647 | 1659 | ||
1648 | pool->ti = ti; | 1660 | pool->ti = ti; |
@@ -2266,7 +2278,7 @@ static int pool_preresume(struct dm_target *ti) | |||
2266 | return r; | 2278 | return r; |
2267 | 2279 | ||
2268 | if (need_commit1 || need_commit2) | 2280 | if (need_commit1 || need_commit2) |
2269 | (void) commit_or_fallback(pool); | 2281 | (void) commit(pool); |
2270 | 2282 | ||
2271 | return 0; | 2283 | return 0; |
2272 | } | 2284 | } |
@@ -2293,7 +2305,7 @@ static void pool_postsuspend(struct dm_target *ti) | |||
2293 | 2305 | ||
2294 | cancel_delayed_work(&pool->waker); | 2306 | cancel_delayed_work(&pool->waker); |
2295 | flush_workqueue(pool->wq); | 2307 | flush_workqueue(pool->wq); |
2296 | (void) commit_or_fallback(pool); | 2308 | (void) commit(pool); |
2297 | } | 2309 | } |
2298 | 2310 | ||
2299 | static int check_arg_count(unsigned argc, unsigned args_required) | 2311 | static int check_arg_count(unsigned argc, unsigned args_required) |
@@ -2427,7 +2439,7 @@ static int process_reserve_metadata_snap_mesg(unsigned argc, char **argv, struct | |||
2427 | if (r) | 2439 | if (r) |
2428 | return r; | 2440 | return r; |
2429 | 2441 | ||
2430 | (void) commit_or_fallback(pool); | 2442 | (void) commit(pool); |
2431 | 2443 | ||
2432 | r = dm_pool_reserve_metadata_snap(pool->pmd); | 2444 | r = dm_pool_reserve_metadata_snap(pool->pmd); |
2433 | if (r) | 2445 | if (r) |
@@ -2489,7 +2501,7 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv) | |||
2489 | DMWARN("Unrecognised thin pool target message received: %s", argv[0]); | 2501 | DMWARN("Unrecognised thin pool target message received: %s", argv[0]); |
2490 | 2502 | ||
2491 | if (!r) | 2503 | if (!r) |
2492 | (void) commit_or_fallback(pool); | 2504 | (void) commit(pool); |
2493 | 2505 | ||
2494 | return r; | 2506 | return r; |
2495 | } | 2507 | } |
@@ -2544,7 +2556,7 @@ static void pool_status(struct dm_target *ti, status_type_t type, | |||
2544 | 2556 | ||
2545 | /* Commit to ensure statistics aren't out-of-date */ | 2557 | /* Commit to ensure statistics aren't out-of-date */ |
2546 | if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti)) | 2558 | if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti)) |
2547 | (void) commit_or_fallback(pool); | 2559 | (void) commit(pool); |
2548 | 2560 | ||
2549 | r = dm_pool_get_metadata_transaction_id(pool->pmd, &transaction_id); | 2561 | r = dm_pool_get_metadata_transaction_id(pool->pmd, &transaction_id); |
2550 | if (r) { | 2562 | if (r) { |