]> git.hungrycats.org Git - linux/commitdiff
dm space map metadata: fix occasional leak of a metadata block on resize
authorJoe Thornber <ejt@redhat.com>
Wed, 17 Jun 2015 12:35:19 +0000 (13:35 +0100)
committerSasha Levin <sasha.levin@oracle.com>
Sat, 4 Jul 2015 03:02:32 +0000 (23:02 -0400)
[ Upstream commit 6096d91af0b65a3967139b32d5adbb3647858a26 ]

The metadata space map has a simplified 'bootstrap' mode that is
operational when extending the space maps.  Whilst in this mode it's
possible for some refcount decrement operations to become queued (eg, as
a result of shadowing one of the bitmap indexes).  These decrements were
not being applied when switching out of bootstrap mode.

The effect of this bug was the leaking of a 4k metadata block.  This is
detected by the latest version of thin_check as a non fatal error.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
drivers/md/persistent-data/dm-space-map-metadata.c

index f4e22bcc7fb8c6ad79d20cbb03e82093ed5a7d13..199c9ccd1f5d3364eeff90082e71f8aeb3b155ff 100644 (file)
@@ -204,6 +204,27 @@ static void in(struct sm_metadata *smm)
        smm->recursion_count++;
 }
 
+static int apply_bops(struct sm_metadata *smm)
+{
+       int r = 0;
+
+       while (!brb_empty(&smm->uncommitted)) {
+               struct block_op bop;
+
+               r = brb_pop(&smm->uncommitted, &bop);
+               if (r) {
+                       DMERR("bug in bop ring buffer");
+                       break;
+               }
+
+               r = commit_bop(smm, &bop);
+               if (r)
+                       break;
+       }
+
+       return r;
+}
+
 static int out(struct sm_metadata *smm)
 {
        int r = 0;
@@ -216,21 +237,8 @@ static int out(struct sm_metadata *smm)
                return -ENOMEM;
        }
 
-       if (smm->recursion_count == 1) {
-               while (!brb_empty(&smm->uncommitted)) {
-                       struct block_op bop;
-
-                       r = brb_pop(&smm->uncommitted, &bop);
-                       if (r) {
-                               DMERR("bug in bop ring buffer");
-                               break;
-                       }
-
-                       r = commit_bop(smm, &bop);
-                       if (r)
-                               break;
-               }
-       }
+       if (smm->recursion_count == 1)
+               apply_bops(smm);
 
        smm->recursion_count--;
 
@@ -702,6 +710,12 @@ static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
                }
                old_len = smm->begin;
 
+               r = apply_bops(smm);
+               if (r) {
+                       DMERR("%s: apply_bops failed", __func__);
+                       goto out;
+               }
+
                r = sm_ll_commit(&smm->ll);
                if (r)
                        goto out;
@@ -771,6 +785,12 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
        if (r)
                return r;
 
+       r = apply_bops(smm);
+       if (r) {
+               DMERR("%s: apply_bops failed", __func__);
+               return r;
+       }
+
        return sm_metadata_commit(sm);
 }