| From 50dd842ad83b43bed71790efb31cfb2f6c05c9c1 Mon Sep 17 00:00:00 2001 |
| From: Joe Thornber <ejt@redhat.com> |
| Date: Wed, 9 Dec 2015 16:38:12 +0000 |
| Subject: dm space map metadata: fix ref counting bug when bootstrapping a new space map |
| |
| From: Joe Thornber <ejt@redhat.com> |
| |
| commit 50dd842ad83b43bed71790efb31cfb2f6c05c9c1 upstream. |
| |
| When applying block operations (BOPs) do not remove them from the |
| uncommitted BOP ring-buffer until after they've been applied -- in case |
| we recurse. |
| |
| Also, perform BOP_INC operation, in dm_sm_metadata_create() and |
| sm_metadata_extend(), in terms of the uncommitted BOP ring-buffer rather |
| than using direct calls to sm_ll_inc(). |
| |
| Signed-off-by: Joe Thornber <ejt@redhat.com> |
| Signed-off-by: Mike Snitzer <snitzer@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/md/persistent-data/dm-space-map-metadata.c | 32 ++++++++++++++------- |
| 1 file changed, 22 insertions(+), 10 deletions(-) |
| |
| --- a/drivers/md/persistent-data/dm-space-map-metadata.c |
| +++ b/drivers/md/persistent-data/dm-space-map-metadata.c |
| @@ -136,7 +136,7 @@ static int brb_push(struct bop_ring_buff |
| return 0; |
| } |
| |
| -static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result) |
| +static int brb_peek(struct bop_ring_buffer *brb, struct block_op *result) |
| { |
| struct block_op *bop; |
| |
| @@ -147,6 +147,17 @@ static int brb_pop(struct bop_ring_buffe |
| result->type = bop->type; |
| result->block = bop->block; |
| |
| + return 0; |
| +} |
| + |
| +static int brb_pop(struct bop_ring_buffer *brb) |
| +{ |
| + struct block_op *bop; |
| + |
| + if (brb_empty(brb)) |
| + return -ENODATA; |
| + |
| + bop = brb->bops + brb->begin; |
| brb->begin = brb_next(brb, brb->begin); |
| |
| return 0; |
| @@ -211,7 +222,7 @@ static int apply_bops(struct sm_metadata |
| while (!brb_empty(&smm->uncommitted)) { |
| struct block_op bop; |
| |
| - r = brb_pop(&smm->uncommitted, &bop); |
| + r = brb_peek(&smm->uncommitted, &bop); |
| if (r) { |
| DMERR("bug in bop ring buffer"); |
| break; |
| @@ -220,6 +231,8 @@ static int apply_bops(struct sm_metadata |
| r = commit_bop(smm, &bop); |
| if (r) |
| break; |
| + |
| + brb_pop(&smm->uncommitted); |
| } |
| |
| return r; |
| @@ -681,7 +694,6 @@ static struct dm_space_map bootstrap_ops |
| static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks) |
| { |
| int r, i; |
| - enum allocation_event ev; |
| struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); |
| dm_block_t old_len = smm->ll.nr_blocks; |
| |
| @@ -703,11 +715,12 @@ static int sm_metadata_extend(struct dm_ |
| * allocate any new blocks. |
| */ |
| do { |
| - for (i = old_len; !r && i < smm->begin; i++) { |
| - r = sm_ll_inc(&smm->ll, i, &ev); |
| - if (r) |
| - goto out; |
| - } |
| + for (i = old_len; !r && i < smm->begin; i++) |
| + r = add_bop(smm, BOP_INC, i); |
| + |
| + if (r) |
| + goto out; |
| + |
| old_len = smm->begin; |
| |
| r = apply_bops(smm); |
| @@ -752,7 +765,6 @@ int dm_sm_metadata_create(struct dm_spac |
| { |
| int r; |
| dm_block_t i; |
| - enum allocation_event ev; |
| struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); |
| |
| smm->begin = superblock + 1; |
| @@ -780,7 +792,7 @@ int dm_sm_metadata_create(struct dm_spac |
| * allocated blocks that they were built from. |
| */ |
| for (i = superblock; !r && i < smm->begin; i++) |
| - r = sm_ll_inc(&smm->ll, i, &ev); |
| + r = add_bop(smm, BOP_INC, i); |
| |
| if (r) |
| return r; |