diff options
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 234696009d7..96ce36a1a76 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); } |