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>
This commit is contained in:
parent
6f7f51d434
commit
399caddfb1
|
@ -198,6 +198,7 @@ struct pool {
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum pool_mode get_pool_mode(struct pool *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);
|
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;
|
int r;
|
||||||
dm_block_t free_blocks;
|
dm_block_t free_blocks;
|
||||||
unsigned long flags;
|
|
||||||
struct pool *pool = tc->pool;
|
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)
|
if (get_pool_mode(pool) != PM_WRITE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -958,31 +951,14 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
|
||||||
return r;
|
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) {
|
if (!free_blocks) {
|
||||||
DMWARN("%s: no free data space available.",
|
out_of_data_space(pool);
|
||||||
dm_device_name(pool->pool_md));
|
|
||||||
spin_lock_irqsave(&pool->lock, flags);
|
|
||||||
pool->no_free_space = true;
|
|
||||||
spin_unlock_irqrestore(&pool->lock, flags);
|
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dm_pool_alloc_data_block(pool->pmd, result);
|
r = dm_pool_alloc_data_block(pool->pmd, result);
|
||||||
if (r) {
|
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);
|
metadata_operation_failed(pool, "dm_pool_alloc_data_block", r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1006,7 +982,7 @@ static void retry_on_resume(struct bio *bio)
|
||||||
spin_unlock_irqrestore(&pool->lock, flags);
|
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 *bio;
|
||||||
struct bio_list bios;
|
struct bio_list bios;
|
||||||
|
@ -1119,7 +1095,7 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -ENOSPC:
|
case -ENOSPC:
|
||||||
no_space(pool, cell);
|
retry_bios_on_resume(pool, cell);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1197,7 +1173,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case -ENOSPC:
|
case -ENOSPC:
|
||||||
no_space(pool, cell);
|
retry_bios_on_resume(pool, cell);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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
|
* Rather than calling set_pool_mode directly, use these which describe the
|
||||||
* reason for mode degradation.
|
* 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)
|
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",
|
DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d",
|
||||||
dm_device_name(pool->pool_md), op, r);
|
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);
|
set_pool_mode(pool, PM_READ_ONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue