Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 399caddf authored by Mike Snitzer's avatar Mike Snitzer
Browse files

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: default avatarMike Snitzer <snitzer@redhat.com>
Acked-by: default avatarJoe Thornber <ejt@redhat.com>
parent 6f7f51d4
Loading
Loading
Loading
Loading
+32 −29
Original line number Diff line number Diff line
@@ -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);
}