diff options
author | Mike Snitzer <snitzer@redhat.com> | 2015-07-15 16:52:04 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2015-07-16 10:23:49 -0400 |
commit | bcc696fac11fe13e59dda5aaec6322a25b7c9a3a (patch) | |
tree | 956a9236835e48e108c0547eca1da8b0e8a1e2e9 /drivers/md/dm-thin.c | |
parent | b06075a98d595b761881fb2d7b8a557ea2f8b7ac (diff) |
dm thin: stay in out-of-data-space mode once no_space_timeout expires
This fixes an issue where running out of data space would cause the
thin-pool's metadata to become read-only. There was no reason to make
metadata read-only -- calling set_pool_mode() with PM_READ_ONLY was a
misguided way to error all queued and future write IOs. We can
accomplish the same by degrading from PM_OUT_OF_DATA_SPACE to
PM_OUT_OF_DATA_SPACE with error_if_no_space enabled.
Otherwise, the use of PM_READ_ONLY could cause a race where commit() was
started before the PM_READ_ONLY transition but dm_pool_commit_metadata()
would go on to fail because the block manager had transitioned to
read-only. The return of -EPERM from dm_pool_commit_metadata(), due to
attempting to commit while in read-only mode, caused the thin-pool to
set 'needs_check' because a metadata_operation_failed(). This needless
cascade of failures makes life for users more difficult than needed.
Reported-by: Vivek Goyal <vgoyal@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 | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 8f015d924a24..34e79531ea3f 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c | |||
@@ -2282,18 +2282,23 @@ static void do_waker(struct work_struct *ws) | |||
2282 | queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD); | 2282 | queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD); |
2283 | } | 2283 | } |
2284 | 2284 | ||
2285 | static void notify_of_pool_mode_change_to_oods(struct pool *pool); | ||
2286 | |||
2285 | /* | 2287 | /* |
2286 | * We're holding onto IO to allow userland time to react. After the | 2288 | * We're holding onto IO to allow userland time to react. After the |
2287 | * timeout either the pool will have been resized (and thus back in | 2289 | * timeout either the pool will have been resized (and thus back in |
2288 | * PM_WRITE mode), or we degrade to PM_READ_ONLY and start erroring IO. | 2290 | * PM_WRITE mode), or we degrade to PM_OUT_OF_DATA_SPACE w/ error_if_no_space. |
2289 | */ | 2291 | */ |
2290 | static void do_no_space_timeout(struct work_struct *ws) | 2292 | static void do_no_space_timeout(struct work_struct *ws) |
2291 | { | 2293 | { |
2292 | struct pool *pool = container_of(to_delayed_work(ws), struct pool, | 2294 | struct pool *pool = container_of(to_delayed_work(ws), struct pool, |
2293 | no_space_timeout); | 2295 | no_space_timeout); |
2294 | 2296 | ||
2295 | if (get_pool_mode(pool) == PM_OUT_OF_DATA_SPACE && !pool->pf.error_if_no_space) | 2297 | if (get_pool_mode(pool) == PM_OUT_OF_DATA_SPACE && !pool->pf.error_if_no_space) { |
2296 | set_pool_mode(pool, PM_READ_ONLY); | 2298 | pool->pf.error_if_no_space = true; |
2299 | notify_of_pool_mode_change_to_oods(pool); | ||
2300 | error_retry_list(pool); | ||
2301 | } | ||
2297 | } | 2302 | } |
2298 | 2303 | ||
2299 | /*----------------------------------------------------------------*/ | 2304 | /*----------------------------------------------------------------*/ |
@@ -2371,6 +2376,14 @@ static void notify_of_pool_mode_change(struct pool *pool, const char *new_mode) | |||
2371 | dm_device_name(pool->pool_md), new_mode); | 2376 | dm_device_name(pool->pool_md), new_mode); |
2372 | } | 2377 | } |
2373 | 2378 | ||
2379 | static void notify_of_pool_mode_change_to_oods(struct pool *pool) | ||
2380 | { | ||
2381 | if (!pool->pf.error_if_no_space) | ||
2382 | notify_of_pool_mode_change(pool, "out-of-data-space (queue IO)"); | ||
2383 | else | ||
2384 | notify_of_pool_mode_change(pool, "out-of-data-space (error IO)"); | ||
2385 | } | ||
2386 | |||
2374 | static bool passdown_enabled(struct pool_c *pt) | 2387 | static bool passdown_enabled(struct pool_c *pt) |
2375 | { | 2388 | { |
2376 | return pt->adjusted_pf.discard_passdown; | 2389 | return pt->adjusted_pf.discard_passdown; |
@@ -2455,7 +2468,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) | |||
2455 | * frequently seeing this mode. | 2468 | * frequently seeing this mode. |
2456 | */ | 2469 | */ |
2457 | if (old_mode != new_mode) | 2470 | if (old_mode != new_mode) |
2458 | notify_of_pool_mode_change(pool, "out-of-data-space"); | 2471 | notify_of_pool_mode_change_to_oods(pool); |
2459 | pool->process_bio = process_bio_read_only; | 2472 | pool->process_bio = process_bio_read_only; |
2460 | pool->process_discard = process_discard_bio; | 2473 | pool->process_discard = process_discard_bio; |
2461 | pool->process_cell = process_cell_read_only; | 2474 | pool->process_cell = process_cell_read_only; |