Skip to content

Commit

Permalink
dm thin: cleanup and improve no space handling
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mike Snitzer committed Jan 7, 2014
1 parent 6f7f51d commit 399cadd
Showing 1 changed file with 32 additions and 29 deletions.
61 changes: 32 additions & 29 deletions drivers/md/dm-thin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/*
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 399cadd

Please sign in to comment.