summaryrefslogtreecommitdiff
path: root/drivers/md
diff options
context:
space:
mode:
authorliyouhong <liyouhong@kylinos.cn>2026-07-31 10:08:49 +0800
committerMikulas Patocka <mpatocka@redhat.com>2026-08-06 13:55:01 +0200
commit39c5aa3bd8ec3912d2cd0b3fe092642b0d2b0713 (patch)
tree2a062f984a77dbb7af0fd32bdb99b0ce524ae7cd /drivers/md
parent066976b7dbc7e2022efa0244457d804163bc1ee8 (diff)
downloadlinux-next-39c5aa3bd8ec3912d2cd0b3fe092642b0d2b0713.tar.gz
linux-next-39c5aa3bd8ec3912d2cd0b3fe092642b0d2b0713.zip
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: eec40579d848 ("dm: add era target") Cc: stable@vger.kernel.org Signed-off-by: liyouhong <liyouhong@kylinos.cn> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-era-target.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c
index 7fe4d19ade4f..ea499adca4ce 100644
--- a/drivers/md/dm-era-target.c
+++ b/drivers/md/dm-era-target.c
@@ -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;
}