diff options
author | Joe Thornber <ejt@redhat.com> | 2014-12-11 11:12:19 +0000 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-01-08 10:00:49 -0800 |
commit | 1b210c873eba5ef3b84f46e1a51c360b7ffa9156 (patch) | |
tree | 9cf3395f1dd2af802bd037146824a608c67bf218 | |
parent | 3b2caa87bacb066e5c27228032c3aa9738692061 (diff) |
dm thin: fix missing out-of-data-space to write mode transition if blocks are released
commit 2c43fd26e46734430122b8d2ad3024bb532df3ef upstream.
Discard bios and thin device deletion have the potential to release data
blocks. If the thin-pool is in out-of-data-space mode, and blocks were
released, transition the thin-pool back to full write mode.
The correct time to do this is just after the thin-pool metadata commit.
It cannot be done before the commit because the space maps will not
allow immediate reuse of the data blocks in case there's a rollback
following power failure.
Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/md/dm-thin.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index eb6aac8e3061..f7e052c7ab5f 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -916,6 +916,24 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block, } } +static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); + +static void check_for_space(struct pool *pool) +{ + int r; + dm_block_t nr_free; + + if (get_pool_mode(pool) != PM_OUT_OF_DATA_SPACE) + return; + + r = dm_pool_get_free_block_count(pool->pmd, &nr_free); + if (r) + return; + + if (nr_free) + set_pool_mode(pool, PM_WRITE); +} + /* * A non-zero return indicates read_only or fail_io mode. * Many callers don't care about the return value. @@ -930,6 +948,8 @@ static int commit(struct pool *pool) r = dm_pool_commit_metadata(pool->pmd); if (r) metadata_operation_failed(pool, "dm_pool_commit_metadata", r); + else + check_for_space(pool); return r; } @@ -948,8 +968,6 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks) } } -static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); - static int alloc_data_block(struct thin_c *tc, dm_block_t *result) { int r; |