dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort
commit 352b837a5541690d4f843819028cf2b8be83d424 upstream.
Same ABBA deadlock pattern fixed in commit 4b60f452ec51 ("dm thin: Fix
ABBA deadlock between shrink_slab and dm_pool_abort_metadata") to
DM-cache's metadata.
Reported-by: Zhihao Cheng <chengzhihao1@huawei.com>
Cc: stable@vger.kernel.org
Fixes: 028ae9f76f
("dm cache: add fail io mode and needs_check flag")
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
52ba5b87a3
commit
f472bfc95d
@ -551,10 +551,12 @@ static int __create_persistent_data_objects(struct dm_cache_metadata *cmd,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd)
|
static void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd,
|
||||||
|
bool destroy_bm)
|
||||||
{
|
{
|
||||||
dm_sm_destroy(cmd->metadata_sm);
|
dm_sm_destroy(cmd->metadata_sm);
|
||||||
dm_tm_destroy(cmd->tm);
|
dm_tm_destroy(cmd->tm);
|
||||||
|
if (destroy_bm)
|
||||||
dm_block_manager_destroy(cmd->bm);
|
dm_block_manager_destroy(cmd->bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -826,7 +828,7 @@ static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev,
|
|||||||
cmd2 = lookup(bdev);
|
cmd2 = lookup(bdev);
|
||||||
if (cmd2) {
|
if (cmd2) {
|
||||||
mutex_unlock(&table_lock);
|
mutex_unlock(&table_lock);
|
||||||
__destroy_persistent_data_objects(cmd);
|
__destroy_persistent_data_objects(cmd, true);
|
||||||
kfree(cmd);
|
kfree(cmd);
|
||||||
return cmd2;
|
return cmd2;
|
||||||
}
|
}
|
||||||
@ -874,7 +876,7 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd)
|
|||||||
mutex_unlock(&table_lock);
|
mutex_unlock(&table_lock);
|
||||||
|
|
||||||
if (!cmd->fail_io)
|
if (!cmd->fail_io)
|
||||||
__destroy_persistent_data_objects(cmd);
|
__destroy_persistent_data_objects(cmd, true);
|
||||||
kfree(cmd);
|
kfree(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1808,14 +1810,52 @@ int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result)
|
|||||||
|
|
||||||
int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
|
int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
|
||||||
{
|
{
|
||||||
int r;
|
int r = -EINVAL;
|
||||||
|
struct dm_block_manager *old_bm = NULL, *new_bm = NULL;
|
||||||
|
|
||||||
|
/* fail_io is double-checked with cmd->root_lock held below */
|
||||||
|
if (unlikely(cmd->fail_io))
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Replacement block manager (new_bm) is created and old_bm destroyed outside of
|
||||||
|
* cmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
|
||||||
|
* shrinker associated with the block manager's bufio client vs cmd root_lock).
|
||||||
|
* - must take shrinker_rwsem without holding cmd->root_lock
|
||||||
|
*/
|
||||||
|
new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
|
||||||
|
CACHE_MAX_CONCURRENT_LOCKS);
|
||||||
|
|
||||||
WRITE_LOCK(cmd);
|
WRITE_LOCK(cmd);
|
||||||
__destroy_persistent_data_objects(cmd);
|
if (cmd->fail_io) {
|
||||||
r = __create_persistent_data_objects(cmd, false);
|
WRITE_UNLOCK(cmd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
__destroy_persistent_data_objects(cmd, false);
|
||||||
|
old_bm = cmd->bm;
|
||||||
|
if (IS_ERR(new_bm)) {
|
||||||
|
DMERR("could not create block manager during abort");
|
||||||
|
cmd->bm = NULL;
|
||||||
|
r = PTR_ERR(new_bm);
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->bm = new_bm;
|
||||||
|
r = __open_or_format_metadata(cmd, false);
|
||||||
|
if (r) {
|
||||||
|
cmd->bm = NULL;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
new_bm = NULL;
|
||||||
|
out_unlock:
|
||||||
if (r)
|
if (r)
|
||||||
cmd->fail_io = true;
|
cmd->fail_io = true;
|
||||||
WRITE_UNLOCK(cmd);
|
WRITE_UNLOCK(cmd);
|
||||||
|
dm_block_manager_destroy(old_bm);
|
||||||
|
out:
|
||||||
|
if (new_bm && !IS_ERR(new_bm))
|
||||||
|
dm_block_manager_destroy(new_bm);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user