diff options
author | Joe Thornber <ejt@redhat.com> | 2013-12-04 19:51:33 -0500 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2014-01-07 10:14:27 -0500 |
commit | b53306558526a097a587774573b76d0d9903c5bf (patch) | |
tree | a9a22bb9eb5f272ac6f59b52fc3627a314e64dfd /drivers/md/dm-thin.c | |
parent | 88a6621bed65ce2d421a808a2f60e1b64914d777 (diff) |
dm thin: handle metadata failures more consistently
Introduce metadata_operation_failed() wrappers, around set_pool_mode(),
to assist with improving the consistency of how metadata failures are
handled. Logging is improved and metadata operation failures trigger
read-only mode immediately.
Also, eliminate redundant set_pool_mode() calls in the two
alloc_data_block() caller's error paths.
Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md/dm-thin.c')
-rw-r--r-- | drivers/md/dm-thin.c | 48 |
1 files changed, 27 insertions, 21 deletions
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index e49c27c91a1f..35d2e41ef82f 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c | |||
@@ -198,7 +198,7 @@ struct pool { | |||
198 | }; | 198 | }; |
199 | 199 | ||
200 | static enum pool_mode get_pool_mode(struct pool *pool); | 200 | static enum pool_mode get_pool_mode(struct pool *pool); |
201 | static void set_pool_mode(struct pool *pool, enum pool_mode mode); | 201 | static void metadata_operation_failed(struct pool *pool, const char *op, int r); |
202 | 202 | ||
203 | /* | 203 | /* |
204 | * Target context for a pool. | 204 | * Target context for a pool. |
@@ -641,9 +641,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m) | |||
641 | */ | 641 | */ |
642 | r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block); | 642 | r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block); |
643 | if (r) { | 643 | if (r) { |
644 | DMERR_LIMIT("%s: dm_thin_insert_block() failed: error = %d", | 644 | metadata_operation_failed(pool, "dm_thin_insert_block", r); |
645 | dm_device_name(pool->pool_md), r); | ||
646 | set_pool_mode(pool, PM_READ_ONLY); | ||
647 | cell_error(pool, m->cell); | 645 | cell_error(pool, m->cell); |
648 | goto out; | 646 | goto out; |
649 | } | 647 | } |
@@ -900,11 +898,8 @@ static int commit(struct pool *pool) | |||
900 | return -EINVAL; | 898 | return -EINVAL; |
901 | 899 | ||
902 | r = dm_pool_commit_metadata(pool->pmd); | 900 | r = dm_pool_commit_metadata(pool->pmd); |
903 | if (r) { | 901 | if (r) |
904 | DMERR_LIMIT("%s: dm_pool_commit_metadata failed: error = %d", | 902 | metadata_operation_failed(pool, "dm_pool_commit_metadata", r); |
905 | dm_device_name(pool->pool_md), r); | ||
906 | set_pool_mode(pool, PM_READ_ONLY); | ||
907 | } | ||
908 | 903 | ||
909 | return r; | 904 | return r; |
910 | } | 905 | } |
@@ -941,8 +936,10 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) | |||
941 | return -EINVAL; | 936 | return -EINVAL; |
942 | 937 | ||
943 | r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); | 938 | r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); |
944 | if (r) | 939 | if (r) { |
940 | metadata_operation_failed(pool, "dm_pool_get_free_block_count", r); | ||
945 | return r; | 941 | return r; |
942 | } | ||
946 | 943 | ||
947 | check_low_water_mark(pool, free_blocks); | 944 | check_low_water_mark(pool, free_blocks); |
948 | 945 | ||
@@ -956,8 +953,10 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) | |||
956 | return r; | 953 | return r; |
957 | 954 | ||
958 | r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); | 955 | r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); |
959 | if (r) | 956 | if (r) { |
957 | metadata_operation_failed(pool, "dm_pool_get_free_block_count", r); | ||
960 | return r; | 958 | return r; |
959 | } | ||
961 | 960 | ||
962 | /* | 961 | /* |
963 | * If we still have no space we set a flag to avoid | 962 | * If we still have no space we set a flag to avoid |
@@ -980,11 +979,11 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) | |||
980 | if (r) { | 979 | if (r) { |
981 | if (r == -ENOSPC && | 980 | if (r == -ENOSPC && |
982 | !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) && | 981 | !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) && |
983 | !free_blocks) { | 982 | !free_blocks) |
984 | DMWARN("%s: no free metadata space available.", | 983 | DMWARN("%s: no free metadata space available.", |
985 | dm_device_name(pool->pool_md)); | 984 | dm_device_name(pool->pool_md)); |
986 | set_pool_mode(pool, PM_READ_ONLY); | 985 | |
987 | } | 986 | metadata_operation_failed(pool, "dm_pool_alloc_data_block", r); |
988 | return r; | 987 | return r; |
989 | } | 988 | } |
990 | 989 | ||
@@ -1126,7 +1125,6 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block, | |||
1126 | default: | 1125 | default: |
1127 | DMERR_LIMIT("%s: alloc_data_block() failed: error = %d", | 1126 | DMERR_LIMIT("%s: alloc_data_block() failed: error = %d", |
1128 | __func__, r); | 1127 | __func__, r); |
1129 | set_pool_mode(pool, PM_READ_ONLY); | ||
1130 | cell_error(pool, cell); | 1128 | cell_error(pool, cell); |
1131 | break; | 1129 | break; |
1132 | } | 1130 | } |
@@ -1205,7 +1203,6 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block | |||
1205 | default: | 1203 | default: |
1206 | DMERR_LIMIT("%s: alloc_data_block() failed: error = %d", | 1204 | DMERR_LIMIT("%s: alloc_data_block() failed: error = %d", |
1207 | __func__, r); | 1205 | __func__, r); |
1208 | set_pool_mode(pool, PM_READ_ONLY); | ||
1209 | cell_error(pool, cell); | 1206 | cell_error(pool, cell); |
1210 | break; | 1207 | break; |
1211 | } | 1208 | } |
@@ -1449,6 +1446,18 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode) | |||
1449 | } | 1446 | } |
1450 | } | 1447 | } |
1451 | 1448 | ||
1449 | /* | ||
1450 | * Rather than calling set_pool_mode directly, use these which describe the | ||
1451 | * reason for mode degradation. | ||
1452 | */ | ||
1453 | static void metadata_operation_failed(struct pool *pool, const char *op, int r) | ||
1454 | { | ||
1455 | DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d", | ||
1456 | dm_device_name(pool->pool_md), op, r); | ||
1457 | |||
1458 | set_pool_mode(pool, PM_READ_ONLY); | ||
1459 | } | ||
1460 | |||
1452 | /*----------------------------------------------------------------*/ | 1461 | /*----------------------------------------------------------------*/ |
1453 | 1462 | ||
1454 | /* | 1463 | /* |
@@ -2209,9 +2218,7 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit) | |||
2209 | } else if (data_size > sb_data_size) { | 2218 | } else if (data_size > sb_data_size) { |
2210 | r = dm_pool_resize_data_dev(pool->pmd, data_size); | 2219 | r = dm_pool_resize_data_dev(pool->pmd, data_size); |
2211 | if (r) { | 2220 | if (r) { |
2212 | DMERR("%s: failed to resize data device", | 2221 | metadata_operation_failed(pool, "dm_pool_resize_data_dev", r); |
2213 | dm_device_name(pool->pool_md)); | ||
2214 | set_pool_mode(pool, PM_READ_ONLY); | ||
2215 | return r; | 2222 | return r; |
2216 | } | 2223 | } |
2217 | 2224 | ||
@@ -2248,8 +2255,7 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit) | |||
2248 | } else if (metadata_dev_size > sb_metadata_dev_size) { | 2255 | } else if (metadata_dev_size > sb_metadata_dev_size) { |
2249 | r = dm_pool_resize_metadata_dev(pool->pmd, metadata_dev_size); | 2256 | r = dm_pool_resize_metadata_dev(pool->pmd, metadata_dev_size); |
2250 | if (r) { | 2257 | if (r) { |
2251 | DMERR("%s: failed to resize metadata device", | 2258 | metadata_operation_failed(pool, "dm_pool_resize_metadata_dev", r); |
2252 | dm_device_name(pool->pool_md)); | ||
2253 | return r; | 2259 | return r; |
2254 | } | 2260 | } |
2255 | 2261 | ||