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:
Mike Snitzer 2013-12-05 16:03:33 -05:00
Родитель 6f7f51d434
Коммит 399caddfb1
1 изменённых файлов: 32 добавлений и 29 удалений

Просмотреть файл

@ -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);
}