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 1abb4a24c338..357eb272dbd9 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c | |||
@@ -645,7 +645,9 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m) | |||
645 | */ | 645 | */ |
646 | r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block); | 646 | r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block); |
647 | if (r) { | 647 | if (r) { |
648 | DMERR_LIMIT("dm_thin_insert_block() failed"); | 648 | DMERR_LIMIT("%s: dm_thin_insert_block() failed: error = %d", |
649 | dm_device_name(pool->pool_md), r); | ||
650 | set_pool_mode(pool, PM_READ_ONLY); | ||
649 | cell_error(pool, m->cell); | 651 | cell_error(pool, m->cell); |
650 | goto out; | 652 | goto out; |
651 | } | 653 | } |
@@ -887,32 +889,23 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block, | |||
887 | } | 889 | } |
888 | } | 890 | } |
889 | 891 | ||
890 | static int commit(struct pool *pool) | ||
891 | { | ||
892 | int r; | ||
893 | |||
894 | r = dm_pool_commit_metadata(pool->pmd); | ||
895 | if (r) | ||
896 | DMERR_LIMIT("%s: commit failed: error = %d", | ||
897 | dm_device_name(pool->pool_md), r); | ||
898 | |||
899 | return r; | ||
900 | } | ||
901 | |||
902 | /* | 892 | /* |
903 | * A non-zero return indicates read_only or fail_io mode. | 893 | * A non-zero return indicates read_only or fail_io mode. |
904 | * Many callers don't care about the return value. | 894 | * Many callers don't care about the return value. |
905 | */ | 895 | */ |
906 | static int commit_or_fallback(struct pool *pool) | 896 | static int commit(struct pool *pool) |
907 | { | 897 | { |
908 | int r; | 898 | int r; |
909 | 899 | ||
910 | if (get_pool_mode(pool) != PM_WRITE) | 900 | if (get_pool_mode(pool) != PM_WRITE) |
911 | return -EINVAL; | 901 | return -EINVAL; |
912 | 902 | ||
913 | r = commit(pool); | 903 | r = dm_pool_commit_metadata(pool->pmd); |
914 | if (r) | 904 | if (r) { |
905 | DMERR_LIMIT("%s: dm_pool_commit_metadata failed: error = %d", | ||
906 | dm_device_name(pool->pool_md), r); | ||
915 | set_pool_mode(pool, PM_READ_ONLY); | 907 | set_pool_mode(pool, PM_READ_ONLY); |
908 | } | ||
916 | 909 | ||
917 | return r; | 910 | return r; |
918 | } | 911 | } |
@@ -949,7 +942,9 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) | |||
949 | * Try to commit to see if that will free up some | 942 | * Try to commit to see if that will free up some |
950 | * more space. | 943 | * more space. |
951 | */ | 944 | */ |
952 | (void) commit_or_fallback(pool); | 945 | r = commit(pool); |
946 | if (r) | ||
947 | return r; | ||
953 | 948 | ||
954 | r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); | 949 | r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); |
955 | if (r) | 950 | if (r) |
@@ -963,7 +958,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) | |||
963 | * table reload). | 958 | * table reload). |
964 | */ | 959 | */ |
965 | if (!free_blocks) { | 960 | if (!free_blocks) { |
966 | DMWARN("%s: no free space available.", | 961 | DMWARN("%s: no free data space available.", |
967 | dm_device_name(pool->pool_md)); | 962 | dm_device_name(pool->pool_md)); |
968 | spin_lock_irqsave(&pool->lock, flags); | 963 | spin_lock_irqsave(&pool->lock, flags); |
969 | pool->no_free_space = 1; | 964 | pool->no_free_space = 1; |
@@ -973,8 +968,16 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) | |||
973 | } | 968 | } |
974 | 969 | ||
975 | r = dm_pool_alloc_data_block(pool->pmd, result); | 970 | r = dm_pool_alloc_data_block(pool->pmd, result); |
976 | if (r) | 971 | if (r) { |
972 | if (r == -ENOSPC && | ||
973 | !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) && | ||
974 | !free_blocks) { | ||
975 | DMWARN("%s: no free metadata space available.", | ||
976 | dm_device_name(pool->pool_md)); | ||
977 | set_pool_mode(pool, PM_READ_ONLY); | ||
978 | } | ||
977 | return r; | 979 | return r; |
980 | } | ||
978 | 981 | ||
979 | return 0; | 982 | return 0; |
980 | } | 983 | } |
@@ -1355,7 +1358,7 @@ static void process_deferred_bios(struct pool *pool) | |||
1355 | if (bio_list_empty(&bios) && !need_commit_due_to_time(pool)) | 1358 | if (bio_list_empty(&bios) && !need_commit_due_to_time(pool)) |
1356 | return; | 1359 | return; |
1357 | 1360 | ||
1358 | if (commit_or_fallback(pool)) { | 1361 | if (commit(pool)) { |
1359 | while ((bio = bio_list_pop(&bios))) | 1362 | while ((bio = bio_list_pop(&bios))) |
1360 | bio_io_error(bio); | 1363 | bio_io_error(bio); |
1361 | return; | 1364 | return; |
@@ -1403,6 +1406,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode) | |||
1403 | case PM_FAIL: | 1406 | case PM_FAIL: |
1404 | DMERR("%s: switching pool to failure mode", | 1407 | DMERR("%s: switching pool to failure mode", |
1405 | dm_device_name(pool->pool_md)); | 1408 | dm_device_name(pool->pool_md)); |
1409 | dm_pool_metadata_read_only(pool->pmd); | ||
1406 | pool->process_bio = process_bio_fail; | 1410 | pool->process_bio = process_bio_fail; |
1407 | pool->process_discard = process_bio_fail; | 1411 | pool->process_discard = process_bio_fail; |
1408 | pool->process_prepared_mapping = process_prepared_mapping_fail; | 1412 | pool->process_prepared_mapping = process_prepared_mapping_fail; |
@@ -1427,6 +1431,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode) | |||
1427 | break; | 1431 | break; |
1428 | 1432 | ||
1429 | case PM_WRITE: | 1433 | case PM_WRITE: |
1434 | dm_pool_metadata_read_write(pool->pmd); | ||
1430 | pool->process_bio = process_bio; | 1435 | pool->process_bio = process_bio; |
1431 | pool->process_discard = process_discard; | 1436 | pool->process_discard = process_discard; |
1432 | pool->process_prepared_mapping = process_prepared_mapping; | 1437 | pool->process_prepared_mapping = process_prepared_mapping; |
@@ -1643,12 +1648,19 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti) | |||
1643 | struct pool_c *pt = ti->private; | 1648 | struct pool_c *pt = ti->private; |
1644 | 1649 | ||
1645 | /* | 1650 | /* |
1646 | * We want to make sure that degraded pools are never upgraded. | 1651 | * We want to make sure that a pool in PM_FAIL mode is never upgraded. |
1647 | */ | 1652 | */ |
1648 | enum pool_mode old_mode = pool->pf.mode; | 1653 | enum pool_mode old_mode = pool->pf.mode; |
1649 | enum pool_mode new_mode = pt->adjusted_pf.mode; | 1654 | enum pool_mode new_mode = pt->adjusted_pf.mode; |
1650 | 1655 | ||
1651 | if (old_mode > new_mode) | 1656 | /* |
1657 | * If we were in PM_FAIL mode, rollback of metadata failed. We're | ||
1658 | * not going to recover without a thin_repair. So we never let the | ||
1659 | * pool move out of the old mode. On the other hand a PM_READ_ONLY | ||
1660 | * may have been due to a lack of metadata or data space, and may | ||
1661 | * now work (ie. if the underlying devices have been resized). | ||
1662 | */ | ||
1663 | if (old_mode == PM_FAIL) | ||
1652 | new_mode = old_mode; | 1664 | new_mode = old_mode; |
1653 | 1665 | ||
1654 | pool->ti = ti; | 1666 | pool->ti = ti; |
@@ -2272,7 +2284,7 @@ static int pool_preresume(struct dm_target *ti) | |||
2272 | return r; | 2284 | return r; |
2273 | 2285 | ||
2274 | if (need_commit1 || need_commit2) | 2286 | if (need_commit1 || need_commit2) |
2275 | (void) commit_or_fallback(pool); | 2287 | (void) commit(pool); |
2276 | 2288 | ||
2277 | return 0; | 2289 | return 0; |
2278 | } | 2290 | } |
@@ -2299,7 +2311,7 @@ static void pool_postsuspend(struct dm_target *ti) | |||
2299 | 2311 | ||
2300 | cancel_delayed_work(&pool->waker); | 2312 | cancel_delayed_work(&pool->waker); |
2301 | flush_workqueue(pool->wq); | 2313 | flush_workqueue(pool->wq); |
2302 | (void) commit_or_fallback(pool); | 2314 | (void) commit(pool); |
2303 | } | 2315 | } |
2304 | 2316 | ||
2305 | static int check_arg_count(unsigned argc, unsigned args_required) | 2317 | static int check_arg_count(unsigned argc, unsigned args_required) |
@@ -2433,7 +2445,7 @@ static int process_reserve_metadata_snap_mesg(unsigned argc, char **argv, struct | |||
2433 | if (r) | 2445 | if (r) |
2434 | return r; | 2446 | return r; |
2435 | 2447 | ||
2436 | (void) commit_or_fallback(pool); | 2448 | (void) commit(pool); |
2437 | 2449 | ||
2438 | r = dm_pool_reserve_metadata_snap(pool->pmd); | 2450 | r = dm_pool_reserve_metadata_snap(pool->pmd); |
2439 | if (r) | 2451 | if (r) |
@@ -2495,7 +2507,7 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv) | |||
2495 | DMWARN("Unrecognised thin pool target message received: %s", argv[0]); | 2507 | DMWARN("Unrecognised thin pool target message received: %s", argv[0]); |
2496 | 2508 | ||
2497 | if (!r) | 2509 | if (!r) |
2498 | (void) commit_or_fallback(pool); | 2510 | (void) commit(pool); |
2499 | 2511 | ||
2500 | return r; | 2512 | return r; |
2501 | } | 2513 | } |
@@ -2550,7 +2562,7 @@ static void pool_status(struct dm_target *ti, status_type_t type, | |||
2550 | 2562 | ||
2551 | /* Commit to ensure statistics aren't out-of-date */ | 2563 | /* Commit to ensure statistics aren't out-of-date */ |
2552 | if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti)) | 2564 | if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti)) |
2553 | (void) commit_or_fallback(pool); | 2565 | (void) commit(pool); |
2554 | 2566 | ||
2555 | r = dm_pool_get_metadata_transaction_id(pool->pmd, &transaction_id); | 2567 | r = dm_pool_get_metadata_transaction_id(pool->pmd, &transaction_id); |
2556 | if (r) { | 2568 | if (r) { |