aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Thornber <ejt@redhat.com>2015-06-17 08:35:19 -0400
committerMike Snitzer <snitzer@redhat.com>2015-06-17 10:09:23 -0400
commit6096d91af0b65a3967139b32d5adbb3647858a26 (patch)
tree1c78bce04092967acee14e57887ab64c48d865a7
parentb1f11aff04cc86daa0757ada5deb669a92a8f0fb (diff)
dm space map metadata: fix occasional leak of a metadata block on resize
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
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.c50
1 files changed, 35 insertions, 15 deletions
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c
index e8a904298887..53091295fce9 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.c
+++ b/drivers/md/persistent-data/dm-space-map-metadata.c
@@ -204,6 +204,27 @@ static void in(struct sm_metadata *smm)
204 smm->recursion_count++; 204 smm->recursion_count++;
205} 205}
206 206
207static int apply_bops(struct sm_metadata *smm)
208{
209 int r = 0;
210
211 while (!brb_empty(&smm->uncommitted)) {
212 struct block_op bop;
213
214 r = brb_pop(&smm->uncommitted, &bop);
215 if (r) {
216 DMERR("bug in bop ring buffer");
217 break;
218 }
219
220 r = commit_bop(smm, &bop);
221 if (r)
222 break;
223 }
224
225 return r;
226}
227
207static int out(struct sm_metadata *smm) 228static int out(struct sm_metadata *smm)
208{ 229{
209 int r = 0; 230 int r = 0;
@@ -216,21 +237,8 @@ static int out(struct sm_metadata *smm)
216 return -ENOMEM; 237 return -ENOMEM;
217 } 238 }
218 239
219 if (smm->recursion_count == 1) { 240 if (smm->recursion_count == 1)
220 while (!brb_empty(&smm->uncommitted)) { 241 apply_bops(smm);
221 struct block_op bop;
222
223 r = brb_pop(&smm->uncommitted, &bop);
224 if (r) {
225 DMERR("bug in bop ring buffer");
226 break;
227 }
228
229 r = commit_bop(smm, &bop);
230 if (r)
231 break;
232 }
233 }
234 242
235 smm->recursion_count--; 243 smm->recursion_count--;
236 244
@@ -704,6 +712,12 @@ static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
704 } 712 }
705 old_len = smm->begin; 713 old_len = smm->begin;
706 714
715 r = apply_bops(smm);
716 if (r) {
717 DMERR("%s: apply_bops failed", __func__);
718 goto out;
719 }
720
707 r = sm_ll_commit(&smm->ll); 721 r = sm_ll_commit(&smm->ll);
708 if (r) 722 if (r)
709 goto out; 723 goto out;
@@ -773,6 +787,12 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
773 if (r) 787 if (r)
774 return r; 788 return r;
775 789
790 r = apply_bops(smm);
791 if (r) {
792 DMERR("%s: apply_bops failed", __func__);
793 return r;
794 }
795
776 return sm_metadata_commit(sm); 796 return sm_metadata_commit(sm);
777} 797}
778 798