Add memory pool for format instance and fix memory leaks
cover Add memory pool for format instance and fix memory leaks
This patchset fixes memory leaks introduced with changes in format instance handling.
Now, the format instances have their own memory pool with reference counting (since the instances could be shared). This makes the memory handling much controllable and it uses memory in a more optimal way (long living cmd context mempool was used before and we couldn't free the memory from unused format instances).
Peter Rajnoha (7):
Add memory pool and reference counting for format instances. Move text_context allocation inside create_instance fn. Use vg_set_fid and new pv_set_fid throughout.
Add new free_pv_fid fn and use it throughout.
Call destroy_instance for all PVs in a VG while calling free_vg. Various cleanups for fid mem and ref_count changes. Switch over to format instance mempool use where possible.
lib/cache/lvmcache.c | 19 ++-- lib/format1/format1.c | 17 +++- lib/format_pool/format_pool.c | 15 ++- lib/format_text/archive.c | 8 +- lib/format_text/archiver.c | 19 +++- lib/format_text/format-text.c | 143 +++++++++++++-------------- lib/format_text/format-text.h | 7 +- lib/format_text/import_vsn1.c | 8 +- lib/metadata/metadata-exported.h | 11 ++ lib/metadata/metadata.c | 204 +++++++++++++++++++++++++++++--------- lib/metadata/metadata.h | 1 + lib/metadata/mirror.c | 6 +- tools/lvconvert.c | 1 + tools/pvcreate.c | 4 +- tools/pvmove.c | 9 ++- tools/pvremove.c | 18 +++- tools/pvresize.c | 2 + tools/pvscan.c | 4 +- tools/toollib.c | 13 +++ tools/vgconvert.c | 3 + tools/vgreduce.c | 3 + 21 files changed, 352 insertions(+), 163 deletions(-)
Signature · 1 line
1.7.4
PATCH 1/7 Add memory pool and reference counting for format instances.
Format instances can be created anytime on demand and it contains metadata area information mostly (at least for now, but in the future, we may store more things here to update/edit in a PV/VG). In case we have lots of metadata areas, memory consumption will rise. Using cmd context mempool is not quite optimal here because it is destroyed too late.
So let's use a separate mempool for format instances.
Also, we need to destroy the hash which does not use a mempool in destroy_instance fn. This call was not used explicitly before, but now it has to be (and I can't free any cmd mempool allocations for format instance since there could be other non-format-instance allocations throughout the code and I'm not able to track those at all, so I can't simply call dm_pool_free for the various fid allocations).
This change will definitely make it much easier to maintain the memory allocations within the fid....
Reference counting is used because fids could be shared, e.g. each PV has either a PV-based fid or VG-based fid. If it's VG-based, each PV has a shared fid with the VG - a reference to VG's fid.
--- lib/format1/format1.c | 12 ++++++++++-- lib/format_pool/format_pool.c | 10 ++++++++-- lib/format_text/format-text.c | 24 +++++++++++------------- lib/metadata/metadata-exported.h | 3 +++ lib/metadata/metadata.c | 14 ++++++++++++-- 5 files changed, 44 insertions(+), 19 deletions(-)
lib/format1/format1.c +10 -2
@@ -535,8 +535,10 @@ static struct format_instance *_format1_create_instance(const struct format_type/* Define a NULL metadata area */ if (!(mda =dm_pool_zalloc (fmt->cmd->mem,sizeof (*mda)))) { +log_error ("Unable to allocate metadata area structure " +"for lvm1 format" );dm_pool_free (fmt->cmd->mem, fid); - return_NULL; + goto bad; } mda->ops = &_metadata_format1_ops;
@@ -545,10 +547,16 @@ static struct format_instance *_format1_create_instance(const struct format_typedm_list_add (&fid->metadata_areas_in_use, &mda->list);return fid; + +bad: +dm_pool_destroy (fid->mem); +return NULL ; } -static void _format1_destroy_instance (struct format_instance *fid __attribute__((unused))) +static void _format1_destroy_instance (struct format_instance *fid) { +if (--fid->ref_count <=1 ) +dm_pool_destroy (fid->mem); }static void _format1_destroy (struct format_type *fmt)
lib/format_pool/format_pool.c +8 -2
@@ -264,7 +264,7 @@ static struct format_instance *_pool_create_instance(const struct format_type *flog_error ("Unable to allocate metadata area structure " "for pool format" );dm_pool_free (fmt->cmd->mem, fid); -return NULL ; + goto bad; } mda->ops = &_metadata_format_pool_ops;
@@ -273,10 +273,16 @@ static struct format_instance *_pool_create_instance(const struct format_type *fdm_list_add (&fid->metadata_areas_in_use, &mda->list);return fid; + +bad: +dm_pool_destroy (fid->mem); +return NULL ; } -static void _pool_destroy_instance (struct format_instance *fid __attribute__((unused))) +static void _pool_destroy_instance (struct format_instance *fid) { +if (--fid->ref_count <=1 ) +dm_pool_destroy (fid->mem); }static void _pool_destroy (struct format_type *fmt)
lib/format_text/format-text.c +11 -13
@@ -1571,8 +1571,13 @@ static int _text_pv_initialise(const struct format_type *fmt,return 1 ; } -static void _text_destroy_instance (struct format_instance *fid __attribute__((unused))) +static void _text_destroy_instance (struct format_instance *fid) { +if (--fid->ref_count <=1 ) { +if (fid->type &FMT_INSTANCE_VG && fid->metadata_areas_index.hash) +dm_hash_destroy (fid->metadata_areas_index.hash); +dm_pool_destroy (fid->mem); + } }static void _free_dirs (struct dm_list *dir_list)
@@ -2188,28 +2193,21 @@ static int _text_pv_resize(const struct format_type *fmt,return 1 ; } -/* NULL vgname means use only the supplied context e.g. an archive file */ static struct format_instance *_text_create_text_instance (const struct format_type *fmt,const struct format_instance_ctx *fic) {struct format_instance *fid; -int r;if (!(fid =alloc_fid (fmt, fic))) return_NULL; -if (fid->type &FMT_INSTANCE_VG ) - r =_create_vg_text_instance (fid, fic); -else - r =_create_pv_text_instance (fid, fic); - -if (r) +if (fid->type &FMT_INSTANCE_VG ?_create_vg_text_instance (fid, fic) : +_create_pv_text_instance (fid, fic))return fid; -else { -dm_pool_free (fmt->cmd->mem, fid); -return NULL ; - } +dm_pool_free (fmt->cmd->mem, fid); +dm_pool_destroy (fid->mem); +return NULL ; } void *create_text_context(struct cmd_context *cmd, const char *path,
lib/metadata/metadata-exported.h +3 -0
@@ -196,6 +196,9 @@ struct pv_segment {#define FMT_INSTANCE_PRIVATE_MDAS 0x00000008Ustruct format_instance { +unsigned ref_count; +struct dm_pool *mem; +uint32_t type;const struct format_type *fmt;
lib/metadata/metadata.c +12 -2
@@ -3954,20 +3954,30 @@ uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname)struct format_instance *alloc_fid (const struct format_type *fmt,const struct format_instance_ctx *fic) { +struct dm_pool *mem;struct format_instance *fid; +if (!(mem =dm_pool_create ("format_instance" ,1024 ))) + return_NULL; +if (!(fid =dm_pool_zalloc (fmt->cmd->mem,sizeof (*fid)))) {log_error ("Couldn't allocate format_instance object." ); -return NULL ; + goto bad; } - fid->fmt = fmt; + fid->ref_count =1 ; + fid->mem = mem; fid->type = fic->type; + fid->fmt = fmt;dm_list_init (&fid->metadata_areas_in_use);dm_list_init (&fid->metadata_areas_ignored);return fid; + +bad: +dm_pool_destroy (mem); +return NULL ; } void vg_set_fid(struct volume_group *vg,
Signature · 1 line
1.7.4
PATCH 2/7 Move text_context allocation inside create_instance fn.
In reply to Peter RajnohaJust another cleanup - moving the text_context part allocation inside the create_instance fn. There are two simple reasons for this:
- we'd like to use the fid mempool for text_context that is stored in the instance (we used cmd mempool before, so the order of initialisation was not a matter, but now it is since we need to create the fid mempool first which happens in create_instance fn)
- there's really no other need to have the allocation code outside (the "create_text_context" call)
--- lib/format_text/archive.c | 7 ++- lib/format_text/archiver.c | 14 ++++-- lib/format_text/format-text.c | 96 +++++++++++++++++++++------------------- lib/format_text/format-text.h | 7 ++- 4 files changed, 70 insertions(+), 54 deletions(-)
lib/format_text/archive.c +5 -2
@@ -301,6 +301,9 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)struct volume_group *vg =NULL ;struct format_instance *tf;struct format_instance_ctx fic; +struct text_context tc = {.path_live = af->path, + .path_edit =NULL , + .desc =NULL };time_t when;char *desc;
@@ -308,8 +311,8 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)log_print ("File:\t\t%s" , af->path); fic.type =FMT_INSTANCE_VG |FMT_INSTANCE_PRIVATE_MDAS ; -if (!(fic.context.private =create_text_context (cmd, af->path,NULL )) || - !(tf = cmd->fmt_backup->ops->create_instance (cmd->fmt_backup, &fic))) { + fic.context.private = &tc; +if (!(tf = cmd->fmt_backup->ops->create_instance (cmd->fmt_backup, &fic))) {log_error ("Couldn't create text instance object." );return ; }
lib/format_text/archiver.c +10 -4
@@ -271,11 +271,14 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,struct volume_group *vg =NULL ;struct format_instance *tf;struct format_instance_ctx fic; +struct text_context tc = {.path_live = file, + .path_edit =NULL , + .desc = cmd->cmd_line};struct metadata_area *mda; fic.type =FMT_INSTANCE_VG |FMT_INSTANCE_PRIVATE_MDAS ; -if (!(fic.context.private =create_text_context (cmd, file, cmd->cmd_line)) || - !(tf = cmd->fmt_backup->ops->create_instance (cmd->fmt_backup, &fic))) { + fic.context.private = &tc; +if (!(tf = cmd->fmt_backup->ops->create_instance (cmd->fmt_backup, &fic))) {log_error ("Couldn't create text format object." );return NULL ; }
@@ -379,6 +382,9 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)int r =0 ;struct format_instance *tf;struct format_instance_ctx fic; +struct text_context tc = {.path_live = file, + .path_edit =NULL , + .desc = desc};struct metadata_area *mda;struct cmd_context *cmd;
@@ -387,8 +393,8 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)log_verbose ("Creating volume group backup \"%s\" (seqno %u)." , file, vg->seqno); fic.type =FMT_INSTANCE_VG |FMT_INSTANCE_PRIVATE_MDAS ; -if (!(fic.context.private =create_text_context (cmd, file, desc)) || - !(tf = cmd->fmt_backup->ops->create_instance (cmd->fmt_backup, &fic))) { + fic.context.private = &tc; +if (!(tf = cmd->fmt_backup->ops->create_instance (cmd->fmt_backup, &fic))) {log_error ("Couldn't create backup object." );return 0 ; }
lib/format_text/format-text.c +50 -46
132 lines not on this page · raw message
lib/format_text/format-text.h +5 -2
@@ -44,9 +44,12 @@ int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname);/* * The text format can read and write a volume_group to a file. */ +struct text_context { +const char *path_live;/* Path to file holding live metadata */ +const char *path_edit;/* Path to file holding edited metadata */ +const char *desc;/* Description placed inside file */ +};struct format_type *create_text_format (struct cmd_context *cmd); -void *create_text_context (struct cmd_context *cmd,const char *path, -const char *desc);struct labeller *text_labeller_create (const struct format_type *fmt);
Signature · 1 line
1.7.4
PATCH 3/7 Use vg_set_fid and new pv_set_fid throughout.
In reply to Peter RajnohaLet's define a strict rule that each fid assignment to a PV/VG will be done via pv_set_fid/vg_set_fid fn. This is needed for proper reference counting.
(Even a NULL fid should be assigned using these fns to decrement ref_count for any currently assigned fid)
--- lib/format1/format1.c | 2 +- lib/format_pool/format_pool.c | 2 +- lib/format_text/format-text.c | 6 +---- lib/format_text/import_vsn1.c | 8 +++--- lib/metadata/metadata.c | 52 +++++++++++++++++++++++++++++++++++----- lib/metadata/metadata.h | 1 + 6 files changed, 53 insertions(+), 18 deletions(-)
lib/format1/format1.c +1 -1
@@ -192,12 +192,12 @@ static struct volume_group *_build_vg(struct format_instance *fid, vg->cmd = fid->fmt->cmd; vg->vgmem = mem; - vg->fid = fid; vg->seqno =0 ;dm_list_init (&vg->pvs);dm_list_init (&vg->lvs);dm_list_init (&vg->tags);dm_list_init (&vg->removed_pvs); +vg_set_fid (vg, fid);if (!_check_vgs (pvs, vg)) goto_bad;
lib/format_pool/format_pool.c +1 -1
@@ -114,7 +114,6 @@ static struct volume_group *_build_vg_from_pds(struct format_instance vg->cmd = fid->fmt->cmd; vg->vgmem = mem; - vg->fid = fid; vg->name =NULL ; vg->status =0 ; vg->extent_count =0 ;
@@ -125,6 +124,7 @@ static struct volume_group *_build_vg_from_pds(struct format_instancedm_list_init (&vg->lvs);dm_list_init (&vg->tags);dm_list_init (&vg->removed_pvs); +vg_set_fid (vg, fid);if (!import_pool_vg (vg, smem, pds)) return_NULL;
lib/format_text/format-text.c +1 -5
@@ -1690,12 +1690,8 @@ static int _text_pv_setup(const struct format_type *fmt, (pv_mdac = pv_mda->metadata_locn)) size_reduction = pv_mdac->area.size >>SECTOR_SHIFT ; -/* Destroy old PV-based format instance if it exists. */ -if (!(pv->fid->type &FMT_INSTANCE_VG )) - pv->fmt->ops->destroy_instance (pv->fid); -/* From now on, VG format instance will be used. */ - pv->fid = vg->fid; +pv_set_fid (pv, vg->fid);/* FIXME Cope with genuine pe_count 0 */
lib/format_text/import_vsn1.c +4 -4
@@ -673,10 +673,6 @@ static struct volume_group *_read_vg(struct format_instance *fid, vg->vgmem = mem; vg->cmd = fid->fmt->cmd; -/* FIXME Determine format type from file contents */ -/* eg Set to instance of fmt1 here if reading a format1 backup? */ - vg->fid = fid; -if (!(vg->name =dm_pool_strdup (mem, vgn->key))) goto_bad;
@@ -812,6 +808,10 @@ static struct volume_group *_read_vg(struct format_instance *fid,dm_hash_destroy (pv_hash);dm_hash_destroy (lv_hash); +/* FIXME Determine format type from file contents */ +/* eg Set to instance of fmt1 here if reading a format1 backup? */ +vg_set_fid (vg, fid); +/* * Finished. */
lib/metadata/metadata.c +45 -7
145 lines not on this page · raw message
lib/metadata/metadata.h +1 -0
@@ -206,6 +206,7 @@ struct format_instance_ctx {struct format_instance *alloc_fid (const struct format_type *fmt,const struct format_instance_ctx *fic); +void pv_set_fid (struct physical_volume *pv,struct format_instance *fid);void vg_set_fid (struct volume_group *vg,struct format_instance *fid);/* FIXME: Add generic interface for mda counts based on given key. */ int fid_add_mda(struct format_instance *fid, struct metadata_area *mda,
Signature · 1 line
1.7.4
PATCH 4/7 Add new free_pv_fid fn and use it throughout.
In reply to Peter RajnohaNormally, when the PV structure is part of the VG (vg->pvs/vg->removed->pvs list), a call to free_vg fn will also free the PV fid part automatically (that will be in following patch). But for any standalone PV structures, we have to call free_pv_fid directly now.
I meant this to be "free_pv" at first, but since PV does not have its own "mem" yet, we have only the format instance part to deallocate (therefore "free_pv_fid"). Whenever we have a mempool or anything else to destroy/deallocate for the PV, we can just rename the free_pv_fid to free_pv and add the code there. Just like we have the "free_vg".
--- lib/metadata/metadata-exported.h | 8 +++ lib/metadata/metadata.c | 116 ++++++++++++++++++++++++++------------ lib/metadata/mirror.c | 6 ++- tools/lvconvert.c | 1 + tools/pvcreate.c | 4 +- tools/pvmove.c | 9 +++- tools/pvremove.c | 18 ++++-- tools/pvresize.c | 2 + tools/pvscan.c | 4 +- tools/toollib.c | 13 ++++ tools/vgconvert.c | 3 + tools/vgreduce.c | 3 + 12 files changed, 142 insertions(+), 45 deletions(-)
lib/metadata/metadata-exported.h +8 -0
@@ -460,6 +460,14 @@ void del_pvl_from_vgs(struct volume_group *vg, struct pv_list *pvl);int remove_lvs_in_vg (struct cmd_context *cmd,struct volume_group *vg,force_t force); + +/* +* free_pv_fid() must be called on every struct physical_volume allocated +* by pv_create, pv_read, find_pv_by_name or pv_by_path to free it when +* no longer required. +*/ +void free_pv_fid (struct physical_volume *pv); +/* * free_vg() must be called on every struct volume_group allocated * by vg_create() or vg_read_internal() to free it when no longer required.
lib/metadata/metadata.c +80 -36
359 lines not on this page · raw message
lib/metadata/mirror.c +5 -1
@@ -1463,11 +1463,15 @@ struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd, uint32_t lv_type) {struct physical_volume *pv; +struct logical_volume *lv;if (!(pv =find_pv_by_name (cmd, name))) return_NULL; -return find_pvmove_lv (vg, pv->dev, lv_type); + lv =find_pvmove_lv (vg, pv->dev, lv_type); +free_pv_fid (pv); + +return lv; } struct dm_list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
tools/lvconvert.c +1 -0
@@ -791,6 +791,7 @@ static void _remove_missing_empty_pv(struct volume_group *vg, struct dm_list *re vg->free_count -= pvl_vg->pv->pe_count; vg->extent_count -= pvl_vg->pv->pe_count;del_pvl_from_vgs (vg, pvl_vg); +free_pv_fid (pvl_vg->pv); removed++; }
tools/pvcreate.c +3 -1
@@ -93,6 +93,7 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)int i;int ret =ECMD_PROCESSED ;struct pvcreate_params pp; +struct physical_volume *pv;pvcreate_params_set_defaults (&pp);
@@ -111,11 +112,12 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)unescape_colons_and_at_signs (argv[i],NULL ,NULL ); -if (!pvcreate_single (cmd, argv[i], &pp)) { +if (!(pv =pvcreate_single (cmd, argv[i], &pp))) { stack; ret =ECMD_FAILED ; } +free_pv_fid (pv);unlock_vg (cmd,VG_ORPHANS );if (sigint_caught ())return ret;
tools/pvmove.c +8 -1
@@ -431,11 +431,13 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,if (!(lv_name =_extract_lvname (cmd,pv_vg_name (pv),arg_value (cmd, name_ARG)))) { stack; +free_pv_fid (pv);return EINVALID_CMD_LINE ; }if (!validate_name (lv_name)) {log_error ("Logical volume name %s is invalid" , lv_name); +free_pv_fid (pv);return EINVALID_CMD_LINE ; } }
@@ -510,6 +512,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,/* LVs are all in status LOCKED */ r =ECMD_PROCESSED ; out: +free_pv_fid (pv);unlock_and_free_vg (cmd, vg,pv_vg_name (pv));return r; }
@@ -600,6 +603,7 @@ static struct volume_group *_get_move_vg(struct cmd_context *cmd, const char *uuid __attribute__((unused))) {struct physical_volume *pv; +struct volume_group *vg;/* Reread all metadata in case it got changed */ if (!(pv =find_pv_by_name (cmd, name))) {
@@ -608,7 +612,10 @@ static struct volume_group *_get_move_vg(struct cmd_context *cmd,return NULL ; } -return _get_vg (cmd,pv_vg_name (pv)); + vg =_get_vg (cmd,pv_vg_name (pv)); +free_pv_fid (pv); + +return vg; }static struct poll_functions _pvmove_fns = {
tools/pvremove.c +13 -5
@@ -49,31 +49,34 @@ static int pvremove_check(struct cmd_context *cmd, const char *name)if (!scan_vgs_for_pvs (cmd,0 )) {log_error ("Rescan for PVs without metadata areas " "failed." ); -return 0 ; + goto bad; } +free_pv_fid (pv);if (!(pv =pv_read (cmd, name,NULL ,1 ,0 ))) {log_error ("Failed to read physical volume %s" , name); -return 0 ; + goto bad; } }/* orphan ? */ -if (is_orphan (pv)) +if (is_orphan (pv)) { +free_pv_fid (pv);return 1 ; + }/* Allow partial & exported VGs to be destroyed. */ /* we must have -ff to overwrite a non orphan */ if (arg_count (cmd, force_ARG) <2 ) {log_error ("PV %s belongs to Volume Group %s so please use vgreduce first." , name,pv_vg_name (pv));log_error ("(If you are certain you need pvremove, then confirm by using --force twice.)" ); -return 0 ; + goto bad; }/* prompt */ if (!arg_count (cmd, yes_ARG) &&yes_no_prompt (_really_wipe, name,pv_vg_name (pv)) =='n' ) {log_error ("%s: physical volume label not removed" , name); -return 0 ; + goto bad; }if (arg_count (cmd, force_ARG)) {
@@ -84,7 +87,12 @@ static int pvremove_check(struct cmd_context *cmd, const char *name) !is_orphan(pv) ? "\"" : ""); } +free_pv_fid (pv);return 1 ; + +bad: +free_pv_fid (pv); +return 0 ; } static int pvremove_single(struct cmd_context *cmd, const char *pv_name,
tools/pvresize.c +2 -0
@@ -126,6 +126,8 @@ out:log_error ("Use pvcreate and vgcfgrestore " "to repair from archived metadata." );unlock_vg (cmd, vg_name); +if (is_orphan_vg (vg_name)) +free_pv_fid (pv);if (!old_vg)free_vg (vg);return r;
tools/pvscan.c +3 -1
@@ -183,8 +183,10 @@ int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)), pv_max_name_len +=2 ; vg_max_name_len +=2 ; - dm_list_iterate_items(pvl, pvslist) + dm_list_iterate_items(pvl, pvslist) {_pvscan_display_single (cmd, pvl->pv,NULL ); +free_pv_fid (pvl->pv); + }if (!pvs_found) {log_print ("No matching physical volumes found" );
tools/toollib.c +13 -0
@@ -658,6 +658,9 @@ static int _process_all_devs(struct cmd_context *cmd, void *handle, pv = &pv_dummy; } ret =process_single_pv (cmd,NULL , pv, handle); + +free_pv_fid (pv); +if (ret > ret_max) ret_max = ret;if (sigint_caught ())
@@ -757,6 +760,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,continue ; } scanned =1 ; +free_pv_fid (pv);if (!(pv =pv_read (cmd, argv[opt],NULL ,1 , scan_label_only))) {
@@ -770,6 +774,14 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv, } ret =process_single_pv (cmd, vg, pv, handle); + +/* +* Free PV only if we called pv_read before, +* otherwise the PV structure is part of the VG. +*/ +if (!vg) +free_pv_fid (pv); +if (ret > ret_max) ret_max = ret;if (sigint_caught ())
@@ -823,6 +835,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv, dm_list_iterate_items(pvl, pvslist) { ret =process_single_pv (cmd,NULL , pvl->pv, handle); +free_pv_fid (pvl->pv);if (ret > ret_max) ret_max = ret;if (sigint_caught ())
tools/vgconvert.c +3 -0
@@ -146,6 +146,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, pv_dev_name(pv));log_error ("Use pvcreate and vgcfgrestore to repair " "from archived metadata." ); +free_pv_fid (pv);return ECMD_FAILED ; }
@@ -156,11 +157,13 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, pv_dev_name(pv));log_error ("Use pvcreate and vgcfgrestore to repair " "from archived metadata." ); +free_pv_fid (pv);return ECMD_FAILED ; }log_verbose ("Physical volume \"%s\" successfully created" ,pv_dev_name (pv)); +free_pv_fid (pv); }log_verbose ("Deleting existing metadata for VG %s" , vg_name);
tools/vgreduce.c +3 -0
@@ -40,6 +40,7 @@ static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent) vg->free_count -= pvl->pv->pe_count; vg->extent_count -= pvl->pv->pe_count;del_pvl_from_vgs (vg, pvl); +free_pv_fid (pvl->pv);return 1 ; }
@@ -450,6 +451,8 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,log_print ("Removed \"%s\" from volume group \"%s\"" , name, vg->name); r =ECMD_PROCESSED ; bad: +if (pvl) +free_pv_fid (pvl->pv);unlock_and_free_vg (cmd, orphan_vg,VG_ORPHANS );return r; }
Signature · 1 line
1.7.4
PATCH 5/7 Call destroy_instance for all PVs in a VG while calling free_vg.
In reply to Peter RajnohaThis destroys/decrements ref_count for all PVs found in the vg->pvs or vg->removed_pvs list.
--- lib/metadata/metadata.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-)
lib/metadata/metadata.c +15 -0
@@ -3254,9 +3254,24 @@ void free_pv_fid(struct physical_volume *pv)void free_vg (struct volume_group *vg) { +struct pv_list *pvl; +if (!vg)return ; +if (vg->pvs.n) + dm_list_iterate_items(pvl, &vg->pvs) +if (pvl) + pvl->pv->fid->fmt->ops->destroy_instance (pvl->pv->fid); + +if (vg->removed_pvs.n) + dm_list_iterate_items(pvl, &vg->removed_pvs) +if (pvl) + pvl->pv->fid->fmt->ops->destroy_instance (pvl->pv->fid); + +if (vg->fid) + vg->fid->fmt->ops->destroy_instance (vg->fid); +if (vg->cmd && vg->vgmem == vg->cmd->mem) {log_error (INTERNAL_ERROR "global memory pool used for VG %s" , vg->name);
Signature · 1 line
1.7.4
PATCH 6/7 Various cleanups for fid mem and ref_count changes.
In reply to Peter RajnohaWell, I've encountered these by chance:
Missing free_vg on error_paths in lvmcache_get_vg and _vg_read_orphans fn. Call destroy_instance only if the fid is not part of the vg in backup_read_vg fn (otherwise it's part of the VG we're returning and we definitely don't want to destroy it!).
--- lib/cache/lvmcache.c | 19 ++++++++++--------- lib/format_text/archive.c | 1 - lib/format_text/archiver.c | 5 ++++- lib/metadata/metadata.c | 3 ++- 4 files changed, 16 insertions(+), 12 deletions(-)
lib/cache/lvmcache.c +10 -9
@@ -627,7 +627,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)struct volume_group *lvmcache_get_vg (const char *vgid,unsigned precommitted) {struct lvmcache_vginfo *vginfo; -struct volume_group *vg; +struct volume_group *vg =NULL ;struct format_instance *fid;struct format_instance_ctx fic;
@@ -663,20 +663,21 @@ struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted)if (!vginfo->cft && !(vginfo->cft =create_config_tree_from_string (fid->fmt->cmd, - vginfo->vgmetadata))) { -_free_cached_vgmetadata (vginfo); - return_NULL; - } + vginfo->vgmetadata))) + goto_bad; -if (!(vg =import_vg_from_config_tree (vginfo->cft, fid))) { -_free_cached_vgmetadata (vginfo); - return_NULL; - } +if (!(vg =import_vg_from_config_tree (vginfo->cft, fid))) + goto_bad;log_debug ("Using cached %smetadata for VG %s." , vginfo->precommitted ?"pre-committed" :"" , vginfo->vgname);return vg; + +bad: +free_vg (vg); +_free_cached_vgmetadata (vginfo); +return NULL ; } struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
lib/format_text/archive.c +0 -1
@@ -333,7 +333,6 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)log_print ("Backup Time:\t%s" ,ctime (&when));free_vg (vg); - tf->fmt->ops->destroy_instance (tf); }int archive_list (struct cmd_context *cmd,const char *dir,const char *vgname)
lib/format_text/archiver.c +4 -1
@@ -289,7 +289,9 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,break ; } - tf->fmt->ops->destroy_instance (tf); +if (!vg) + tf->fmt->ops->destroy_instance (tf); +return vg; }
@@ -401,6 +403,7 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)if (!dm_list_size (&tf->metadata_areas_in_use)) {log_error (INTERNAL_ERROR "No in use metadata areas to write." ); + tf->fmt->ops->destroy_instance (tf);return 0 ; }
lib/metadata/metadata.c +2 -1
@@ -2641,7 +2641,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,struct lvmcache_vginfo *vginfo;struct lvmcache_info *info;struct pv_list *pvl; -struct volume_group *vg; +struct volume_group *vg =NULL ;struct physical_volume *pv =NULL ;struct dm_pool *mem;
@@ -2694,6 +2694,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,return vg; bad:free_pv_fid (pv); +free_vg (vg);dm_pool_destroy (mem);return NULL ; }
Signature · 1 line
1.7.4
PATCH 7/7 Switch over to format instance mempool use where possible.
In reply to Peter RajnohaWe used cmd mempool before in format instances, now we have our own mempool...
--- lib/format1/format1.c | 3 +-- lib/format_pool/format_pool.c | 3 +-- lib/format_text/format-text.c | 25 ++++++++++++------------- lib/metadata/metadata.c | 4 ++-- 4 files changed, 16 insertions(+), 19 deletions(-)
lib/format1/format1.c +1 -2
@@ -534,10 +534,9 @@ static struct format_instance *_format1_create_instance(const struct format_type return_NULL;/* Define a NULL metadata area */ -if (!(mda =dm_pool_zalloc (fmt->cmd->mem,sizeof (*mda)))) { +if (!(mda =dm_pool_zalloc (fid->mem,sizeof (*mda)))) {log_error ("Unable to allocate metadata area structure " "for lvm1 format" ); -dm_pool_free (fmt->cmd->mem, fid); goto bad; }
lib/format_pool/format_pool.c +1 -2
@@ -260,10 +260,9 @@ static struct format_instance *_pool_create_instance(const struct format_type *f return_NULL;/* Define a NULL metadata area */ -if (!(mda =dm_pool_zalloc (fmt->cmd->mem,sizeof (*mda)))) { +if (!(mda =dm_pool_zalloc (fid->mem,sizeof (*mda)))) {log_error ("Unable to allocate metadata area structure " "for pool format" ); -dm_pool_free (fmt->cmd->mem, fid); goto bad; }
lib/format_text/format-text.c +12 -13
@@ -1659,7 +1659,7 @@ static int _text_pv_setup(const struct format_type *fmt,/* Be sure it's not already in VG's format instance! */ if (!fid_get_mda_indexed (vg->fid, pvid,ID_LEN , mda_index)) { - pv_mda_copy =mda_copy (vg->fid->fmt->cmd->mem, pv_mda); + pv_mda_copy =mda_copy (vg->fid->mem, pv_mda);fid_add_mda (vg->fid, pv_mda_copy, pvid,ID_LEN , mda_index); } }
@@ -1727,14 +1727,14 @@ static int _create_pv_text_instance(struct format_instance *fid,struct lvmcache_info *info;if (!(fid_pv_tc = (struct text_fid_pv_context *) -dm_pool_zalloc (fid->fmt->cmd->mem,sizeof (*fid_pv_tc)))) { +dm_pool_zalloc (fid->mem,sizeof (*fid_pv_tc)))) {log_error ("Couldn't allocate text_fid_pv_context." );return 0 ; } fid_pv_tc->label_sector =-1 ; fid->private = (void *) fid_pv_tc; -if (!(fid->metadata_areas_index.array =dm_pool_zalloc (fid->fmt->cmd->mem, +if (!(fid->metadata_areas_index.array =dm_pool_zalloc (fid->mem,FMT_TEXT_MAX_MDAS_PER_PV *sizeof (struct metadata_area *)))) {log_error ("Couldn't allocate format instance metadata index." );
@@ -1810,7 +1810,7 @@ static int _create_vg_text_instance(struct format_instance *fid,const char *vg_name, *vg_id;if (!(fidtc = (struct text_fid_context *) -dm_pool_zalloc (fid->fmt->cmd->mem,sizeof (*fidtc)))) { +dm_pool_zalloc (fid->mem,sizeof (*fidtc)))) {log_error ("Couldn't allocate text_fid_context." );return 0 ; }
@@ -1819,10 +1819,10 @@ static int _create_vg_text_instance(struct format_instance *fid, fid->private = (void *) fidtc;if (type &FMT_INSTANCE_PRIVATE_MDAS ) { -if (!(mda =dm_pool_zalloc (fid->fmt->cmd->mem,sizeof (*mda)))) +if (!(mda =dm_pool_zalloc (fid->mem,sizeof (*mda)))) return_0; mda->ops = &_metadata_text_file_backup_ops; - mda->metadata_locn =_create_text_context (fid->fmt->cmd->mem, fic->context.private); + mda->metadata_locn =_create_text_context (fid->mem, fic->context.private); mda->status =0 ; fid->metadata_areas_index.hash =NULL ;fid_add_mda (fid, mda,NULL ,0 ,0 );
@@ -1844,12 +1844,12 @@ static int _create_vg_text_instance(struct format_instance *fid,return 0 ; } -if (!(mda =dm_pool_zalloc (fid->fmt->cmd->mem,sizeof (*mda)))) +if (!(mda =dm_pool_zalloc (fid->mem,sizeof (*mda)))) return_0; mda->ops = &_metadata_text_file_ops; tc.path_live = path; tc.path_edit = tc.desc =NULL ; - mda->metadata_locn =_create_text_context (fid->fmt->cmd->mem, &tc); + mda->metadata_locn =_create_text_context (fid->mem, &tc); mda->status =0 ;fid_add_mda (fid, mda,NULL ,0 ,0 ); }
@@ -1860,10 +1860,10 @@ static int _create_vg_text_instance(struct format_instance *fid,if (!_raw_holds_vgname (fid, &rl->dev_area, vg_name))continue ; -if (!(mda =dm_pool_zalloc (fid->fmt->cmd->mem,sizeof (*mda)))) +if (!(mda =dm_pool_zalloc (fid->mem,sizeof (*mda)))) return_0; -if (!(mdac =dm_pool_zalloc (fid->fmt->cmd->mem,sizeof (*mdac)))) +if (!(mdac =dm_pool_zalloc (fid->mem,sizeof (*mdac)))) return_0; mda->metadata_locn = mdac;/* FIXME Allow multiple dev_areas inside area */
@@ -1911,12 +1911,12 @@ static int _add_metadata_area_to_pv(struct physical_volume *pv, pv->fmt->name); } -if (!(mda =dm_malloc (sizeof (struct metadata_area )))) { +if (!(mda =dm_pool_zalloc (pv->fid->mem,sizeof (struct metadata_area )))) {log_error ("struct metadata_area allocation failed" );return 0 ; } -if (!(mdac =dm_malloc (sizeof (struct mda_context )))) { +if (!(mdac =dm_pool_zalloc (pv->fid->mem,sizeof (struct mda_context )))) {log_error ("struct mda_context allocation failed" );dm_free (mda);return 0 ;
@@ -2243,7 +2243,6 @@ static struct format_instance *_text_create_text_instance(const struct format_ty _create_pv_text_instance(fid, fic))return fid; -dm_pool_free (fmt->cmd->mem, fid);dm_pool_destroy (fid->mem);return NULL ; }
lib/metadata/metadata.c +2 -2
@@ -4041,7 +4041,7 @@ struct format_instance *alloc_fid(const struct format_type *fmt,if (!(mem =dm_pool_create ("format_instance" ,1024 ))) return_NULL; -if (!(fid =dm_pool_zalloc (fmt->cmd->mem,sizeof (*fid)))) { +if (!(fid =dm_pool_zalloc (mem,sizeof (*fid)))) {log_error ("Couldn't allocate format_instance object." ); goto bad; }
@@ -4133,7 +4133,7 @@ int fid_add_mdas(struct format_instance *fid, struct dm_list *mdas,unsigned mda_index =0 ; dm_list_iterate_items(mda, mdas) { - mda_new =mda_copy (fid->fmt->cmd->mem, mda); + mda_new =mda_copy (fid->mem, mda);if (!mda_new) return_0;fid_remove_mda (fid,NULL , key, key_len, mda_index);
Signature · 1 line
1.7.4
cover Add memory pool for format instance and fix memory leaks
In reply to Peter RajnohaQuoted 7 lines · Peter Rajnoha
Add memory pool and reference counting for format instances. Move
text_contextallocation insidecreate_instancefn. Usevg_set_fidand newpv_set_fidthroughout.
Add newfree_pv_fidfn and use it throughout.
Calldestroy_instancefor all PVs in a VG while callingfree_vg. Various cleanups for fid mem andref_countchanges. Switch over to format instance mempool use where possible.
+ one more that has to come as the very first one!
Use new alloc_fid fn for common format instance initialisation.
Just a little cleanup for each format's create_instance fn. There's common code that doesn't need to be repeated. Factor it out into a separate "alloc_fid" fn. This makes the code easier to maintain.
--- lib/format1/format1.c | 8 +------- lib/format_pool/format_pool.c | 13 ++----------- lib/format_text/format-text.c | 14 +++----------- lib/metadata/metadata.c | 19 +++++++++++++++++++ lib/metadata/metadata.h | 27 +++++++++++++++------------ 5 files changed, 40 insertions(+), 41 deletions(-)
lib/format1/format1.c +1 -7
@@ -530,15 +530,9 @@ static struct format_instance *_format1_create_instance(const struct format_typestruct format_instance *fid;struct metadata_area *mda; -if (!(fid =dm_pool_alloc (fmt->cmd->mem,sizeof (*fid)))) +if (!(fid =alloc_fid (fmt, fic))) return_NULL; - fid->fmt = fmt; - fid->type = fic->type; - -dm_list_init (&fid->metadata_areas_in_use); -dm_list_init (&fid->metadata_areas_ignored); -/* Define a NULL metadata area */ if (!(mda =dm_pool_zalloc (fmt->cmd->mem,sizeof (*mda)))) {dm_pool_free (fmt->cmd->mem, fid);
lib/format_pool/format_pool.c +2 -11
@@ -256,17 +256,8 @@ static struct format_instance *_pool_create_instance(const struct format_type *fstruct format_instance *fid;struct metadata_area *mda; -if (!(fid =dm_pool_zalloc (fmt->cmd->mem,sizeof (*fid)))) { -log_error ("Unable to allocate format instance structure for " -"pool format" ); -return NULL ; - } - - fid->fmt = fmt; - fid->type = fic->type; - -dm_list_init (&fid->metadata_areas_in_use); -dm_list_init (&fid->metadata_areas_ignored); +if (!(fid =alloc_fid (fmt, fic))) + return_NULL;/* Define a NULL metadata area */ if (!(mda =dm_pool_zalloc (fmt->cmd->mem,sizeof (*mda)))) {
lib/format_text/format-text.c +3 -11
@@ -2190,21 +2190,13 @@ static int _text_pv_resize(const struct format_type *fmt,/* NULL vgname means use only the supplied context e.g. an archive file */ static struct format_instance *_text_create_text_instance (const struct format_type *fmt, -const struct format_instance_ctx *fic) +const struct format_instance_ctx *fic) {struct format_instance *fid;int r; -if (!(fid =dm_pool_alloc (fmt->cmd->mem,sizeof (*fid)))) { -log_error ("Couldn't allocate format instance object." ); -return NULL ; - } - - fid->fmt = fmt; - fid->type = fic->type; - -dm_list_init (&fid->metadata_areas_in_use); -dm_list_init (&fid->metadata_areas_ignored); +if (!(fid =alloc_fid (fmt, fic))) + return_NULL;if (fid->type &FMT_INSTANCE_VG ) r =_create_vg_text_instance (fid, fic);
lib/metadata/metadata.c +19 -0
@@ -3951,6 +3951,25 @@ uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname)return FAILED_EXIST ; } +struct format_instance *alloc_fid (const struct format_type *fmt, +const struct format_instance_ctx *fic) +{ +struct format_instance *fid; + +if (!(fid =dm_pool_zalloc (fmt->cmd->mem,sizeof (*fid)))) { +log_error ("Couldn't allocate format_instance object." ); +return NULL ; + } + + fid->fmt = fmt; + fid->type = fic->type; + +dm_list_init (&fid->metadata_areas_in_use); +dm_list_init (&fid->metadata_areas_ignored); + +return fid; +} +void vg_set_fid (struct volume_group *vg,struct format_instance *fid) {
lib/metadata/metadata.h +15 -12
@@ -191,6 +191,21 @@ struct metadata_area *mda_copy(struct dm_pool *mem,unsigned mda_is_ignored (struct metadata_area *mda);void mda_set_ignored (struct metadata_area *mda,unsigned ignored);unsigned mda_locns_match (struct metadata_area *mda1,struct metadata_area *mda2); + +struct format_instance_ctx { +uint32_t type; +union { +const char *pv_id; +struct { +const char *vg_name; +const char *vg_id; + } vg_ref; +void *private; + } context; +}; + +struct format_instance *alloc_fid (const struct format_type *fmt, +const struct format_instance_ctx *fic);void vg_set_fid (struct volume_group *vg,struct format_instance *fid);/* FIXME: Add generic interface for mda counts based on given key. */ int fid_add_mda(struct format_instance *fid, struct metadata_area *mda,
@@ -229,18 +244,6 @@ struct seg_list {struct lv_segment *seg; }; -struct format_instance_ctx { -uint32_t type; -union { -const char *pv_id; -struct { -const char *vg_name; -const char *vg_id; - } vg_ref; -void *private; - } context; -}; -/* * Ownership of objects passes to caller. */
Signature · 1 line
1.7.4