| From 314c25c56c1ee5026cf99c570bdfe01847927acb Mon Sep 17 00:00:00 2001 |
| From: Benjamin Marzinski <bmarzins@redhat.com> |
| Date: Wed, 30 Nov 2016 17:56:14 -0600 |
| Subject: dm space map metadata: fix 'struct sm_metadata' leak on failed create |
| |
| From: Benjamin Marzinski <bmarzins@redhat.com> |
| |
| commit 314c25c56c1ee5026cf99c570bdfe01847927acb upstream. |
| |
| In dm_sm_metadata_create() we temporarily change the dm_space_map |
| operations from 'ops' (whose .destroy function deallocates the |
| sm_metadata) to 'bootstrap_ops' (whose .destroy function doesn't). |
| |
| If dm_sm_metadata_create() fails in sm_ll_new_metadata() or |
| sm_ll_extend(), it exits back to dm_tm_create_internal(), which calls |
| dm_sm_destroy() with the intention of freeing the sm_metadata, but it |
| doesn't (because the dm_space_map operations is still set to |
| 'bootstrap_ops'). |
| |
| Fix this by setting the dm_space_map operations back to 'ops' if |
| dm_sm_metadata_create() fails when it is set to 'bootstrap_ops'. |
| |
| Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> |
| Acked-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 | 14 ++++++-------- |
| 1 file changed, 6 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/md/persistent-data/dm-space-map-metadata.c |
| +++ b/drivers/md/persistent-data/dm-space-map-metadata.c |
| @@ -775,17 +775,15 @@ int dm_sm_metadata_create(struct dm_spac |
| memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm)); |
| |
| r = sm_ll_new_metadata(&smm->ll, tm); |
| + if (!r) { |
| + if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS) |
| + nr_blocks = DM_SM_METADATA_MAX_BLOCKS; |
| + r = sm_ll_extend(&smm->ll, nr_blocks); |
| + } |
| + memcpy(&smm->sm, &ops, sizeof(smm->sm)); |
| if (r) |
| return r; |
| |
| - if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS) |
| - nr_blocks = DM_SM_METADATA_MAX_BLOCKS; |
| - r = sm_ll_extend(&smm->ll, nr_blocks); |
| - if (r) |
| - return r; |
| - |
| - memcpy(&smm->sm, &ops, sizeof(smm->sm)); |
| - |
| /* |
| * Now we need to update the newly created data structures with the |
| * allocated blocks that they were built from. |