Commit 294710dd authored by Joe Thornber's avatar Joe Thornber Committed by Greg Kroah-Hartman

dm thin: fix passdown_double_checking_shared_status()

commit d445bd9c upstream.

Commit 00a0ea33 ("dm thin: do not queue freed thin mapping for next
stage processing") changed process_prepared_discard_passdown_pt1() to
increment all the blocks being discarded until after the passdown had
completed to avoid them being prematurely reused.

IO issued to a thin device that breaks sharing with a snapshot, followed
by a discard issued to snapshot(s) that previously shared the block(s),
results in passdown_double_checking_shared_status() being called to
iterate through the blocks double checking their reference count is zero
and issuing the passdown if so.  So a side effect of commit 00a0ea33
is passdown_double_checking_shared_status() was broken.

Fix this by checking if the block reference count is greater than 1.
Also, rename dm_pool_block_is_used() to dm_pool_block_is_shared().

Fixes: 00a0ea33 ("dm thin: do not queue freed thin mapping for next stage processing")
Cc: stable@vger.kernel.org # 4.9+
Reported-by: ryan.p.norwood@gmail.com
Signed-off-by: default avatarJoe Thornber <ejt@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1c285c34
...@@ -1687,7 +1687,7 @@ int dm_thin_remove_range(struct dm_thin_device *td, ...@@ -1687,7 +1687,7 @@ int dm_thin_remove_range(struct dm_thin_device *td,
return r; return r;
} }
int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result) int dm_pool_block_is_shared(struct dm_pool_metadata *pmd, dm_block_t b, bool *result)
{ {
int r; int r;
uint32_t ref_count; uint32_t ref_count;
...@@ -1695,7 +1695,7 @@ int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *resu ...@@ -1695,7 +1695,7 @@ int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *resu
down_read(&pmd->root_lock); down_read(&pmd->root_lock);
r = dm_sm_get_count(pmd->data_sm, b, &ref_count); r = dm_sm_get_count(pmd->data_sm, b, &ref_count);
if (!r) if (!r)
*result = (ref_count != 0); *result = (ref_count > 1);
up_read(&pmd->root_lock); up_read(&pmd->root_lock);
return r; return r;
......
...@@ -195,7 +195,7 @@ int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd, ...@@ -195,7 +195,7 @@ int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd,
int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result); int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result);
int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result); int dm_pool_block_is_shared(struct dm_pool_metadata *pmd, dm_block_t b, bool *result);
int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e); int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e);
int dm_pool_dec_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e); int dm_pool_dec_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e);
......
...@@ -1042,7 +1042,7 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m ...@@ -1042,7 +1042,7 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m
* passdown we have to check that these blocks are now unused. * passdown we have to check that these blocks are now unused.
*/ */
int r = 0; int r = 0;
bool used = true; bool shared = true;
struct thin_c *tc = m->tc; struct thin_c *tc = m->tc;
struct pool *pool = tc->pool; struct pool *pool = tc->pool;
dm_block_t b = m->data_block, e, end = m->data_block + m->virt_end - m->virt_begin; dm_block_t b = m->data_block, e, end = m->data_block + m->virt_end - m->virt_begin;
...@@ -1052,11 +1052,11 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m ...@@ -1052,11 +1052,11 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m
while (b != end) { while (b != end) {
/* find start of unmapped run */ /* find start of unmapped run */
for (; b < end; b++) { for (; b < end; b++) {
r = dm_pool_block_is_used(pool->pmd, b, &used); r = dm_pool_block_is_shared(pool->pmd, b, &shared);
if (r) if (r)
goto out; goto out;
if (!used) if (!shared)
break; break;
} }
...@@ -1065,11 +1065,11 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m ...@@ -1065,11 +1065,11 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m
/* find end of run */ /* find end of run */
for (e = b + 1; e != end; e++) { for (e = b + 1; e != end; e++) {
r = dm_pool_block_is_used(pool->pmd, e, &used); r = dm_pool_block_is_shared(pool->pmd, e, &shared);
if (r) if (r)
goto out; goto out;
if (used) if (shared)
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment