mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 03:35:32 -04:00
dm-era: fix shadowed superblock leak on take-snap failure
metadata_take_snap() bumps the live superblock refcount and then
dm_tm_shadow_block() allocates a new block for the metadata snapshot.
If the subsequent dm_sm_inc_block() of writeset_tree_root or
era_array_root fails, the function only unlocks the clone and
returns. The newly allocated shadow block is never returned to the
metadata space map, so each failed take-snap permanently leaks one
metadata block.
Free the clone with dm_sm_dec_block() on those error paths, matching
the final step of metadata_drop_snap().
Fixes: eec40579d8 ("dm: add era target")
Cc: stable@vger.kernel.org
Signed-off-by: liyouhong <liyouhong@kylinos.cn>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
This commit is contained in:
committed by
Mikulas Patocka
parent
066976b7db
commit
39c5aa3bd8
@@ -1034,6 +1034,7 @@ static int metadata_checkpoint(struct era_metadata *md)
|
||||
static int metadata_take_snap(struct era_metadata *md)
|
||||
{
|
||||
int r, inc;
|
||||
dm_block_t location;
|
||||
struct dm_block *clone;
|
||||
|
||||
if (md->metadata_snap != SUPERBLOCK_LOCATION) {
|
||||
@@ -1071,7 +1072,9 @@ static int metadata_take_snap(struct era_metadata *md)
|
||||
r = dm_sm_inc_block(md->sm, md->writeset_tree_root);
|
||||
if (r) {
|
||||
DMERR("%s: couldn't inc writeset tree root", __func__);
|
||||
location = dm_block_location(clone);
|
||||
dm_tm_unlock(md->tm, clone);
|
||||
dm_sm_dec_block(md->sm, location);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1079,7 +1082,9 @@ static int metadata_take_snap(struct era_metadata *md)
|
||||
if (r) {
|
||||
DMERR("%s: couldn't inc era tree root", __func__);
|
||||
dm_sm_dec_block(md->sm, md->writeset_tree_root);
|
||||
location = dm_block_location(clone);
|
||||
dm_tm_unlock(md->tm, clone);
|
||||
dm_sm_dec_block(md->sm, location);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user