diff options
author | Mike Snitzer <snitzer@redhat.com> | 2013-12-05 21:03:33 (GMT) |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2014-01-07 15:14:28 (GMT) |
commit | 399caddfb16f5fa30c66056a32477cf95c947e2b (patch) | |
tree | c7afb7ccdaa87205419b3715bc18b5209efde61b /drivers/md | |
parent | 6f7f51d4344d530f725e9c932fa44f00ba363fa2 (diff) | |
download | linux-399caddfb16f5fa30c66056a32477cf95c947e2b.tar.xz |
dm thin: cleanup and improve no space handling
Factor out_of_data_space() out of alloc_data_block(). Eliminate the use
of 'no_free_space' as a latch in alloc_data_block() -- this is no longer
needed now that we switch to read-only mode when we run out of data or
metadata space. In a later patch, the 'no_free_space' flag will be
eliminated entirely (in favor of checking metadata rather than relying
on a transient flag).
Move no metdata space handling into metdata_operation_failed(). Set
no_free_space when metadata space is exhausted too. This is useful,
because it offers consistency, for the following patch that will requeue
data IOs if no_free_space.
Also, rename no_space() to retry_bios_on_resume().
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Acked-by: Joe Thornber <ejt@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-thin.c | 61 |
1 files changed, 32 insertions, 29 deletions
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 2346960..96ce36a 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -198,6 +198,7 @@ struct pool { }; static enum pool_mode get_pool_mode(struct pool *pool); +static void out_of_data_space(struct pool *pool); static void metadata_operation_failed(struct pool *pool, const char *op, int r); /* @@ -922,16 +923,8 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) { int r; dm_block_t free_blocks; - unsigned long flags; struct pool *pool = tc->pool; - /* - * Once no_free_space is set we must not allow allocation to succeed. - * Otherwise it is difficult to explain, debug, test and support. - */ - if (pool->no_free_space) - return -ENOSPC; - if (get_pool_mode(pool) != PM_WRITE) return -EINVAL; @@ -958,31 +951,14 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) return r; } - /* - * If we still have no space we set a flag to avoid - * doing all this checking and return -ENOSPC. This - * flag serves as a latch that disallows allocations from - * this pool until the admin takes action (e.g. resize or - * table reload). - */ if (!free_blocks) { - DMWARN("%s: no free data space available.", - dm_device_name(pool->pool_md)); - spin_lock_irqsave(&pool->lock, flags); - pool->no_free_space = true; - spin_unlock_irqrestore(&pool->lock, flags); + out_of_data_space(pool); return -ENOSPC; } } r = dm_pool_alloc_data_block(pool->pmd, result); if (r) { - if (r == -ENOSPC && - !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) && - !free_blocks) - DMWARN("%s: no free metadata space available.", - dm_device_name(pool->pool_md)); - metadata_operation_failed(pool, "dm_pool_alloc_data_block", r); return r; } @@ -1006,7 +982,7 @@ static void retry_on_resume(struct bio *bio) spin_unlock_irqrestore(&pool->lock, flags); } -static void no_space(struct pool *pool, struct dm_bio_prison_cell *cell) +static void retry_bios_on_resume(struct pool *pool, struct dm_bio_prison_cell *cell) { struct bio *bio; struct bio_list bios; @@ -1119,7 +1095,7 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block, break; case -ENOSPC: - no_space(pool, cell); + retry_bios_on_resume(pool, cell); break; default: @@ -1197,7 +1173,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block break; case -ENOSPC: - no_space(pool, cell); + retry_bios_on_resume(pool, cell); break; default: @@ -1446,15 +1422,42 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode) } } +static void set_no_free_space(struct pool *pool) +{ + unsigned long flags; + + spin_lock_irqsave(&pool->lock, flags); + pool->no_free_space = true; + spin_unlock_irqrestore(&pool->lock, flags); +} + /* * Rather than calling set_pool_mode directly, use these which describe the * reason for mode degradation. */ +static void out_of_data_space(struct pool *pool) +{ + DMERR_LIMIT("%s: no free data space available.", + dm_device_name(pool->pool_md)); + set_no_free_space(pool); + set_pool_mode(pool, PM_READ_ONLY); +} + static void metadata_operation_failed(struct pool *pool, const char *op, int r) { + dm_block_t free_blocks; + DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d", dm_device_name(pool->pool_md), op, r); + if (r == -ENOSPC && + !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) && + !free_blocks) { + DMERR_LIMIT("%s: no free metadata space available.", + dm_device_name(pool->pool_md)); + set_no_free_space(pool); + } + set_pool_mode(pool, PM_READ_ONLY); } |