mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Introduce memory pool per volume group.
Since now, all code reading volume group is responsible for releasing the memory allocated by calling vg_release(vg). (For simplicity of use, vg_releae can be called for vg == NULL, the same logic like free(NULL)). Also providing simple macro for unlocking & releasing in one step, tools usualy uses this approach. The global memory pool (cmd->mem) should be used only for global physical volume operations. This patch have to be applied with all subsequent patches to complete memory pool per vg logic. Using separate memory pool has quite bit memory saving impact when using large VGs, this is mainly needed when we have to use preallocated and locked memory (and should not overflow from that memory space).
This commit is contained in:
parent
d828b9a4d7
commit
8e1d5615b4
@ -1,5 +1,6 @@
|
|||||||
Version 2.02.46 -
|
Version 2.02.46 -
|
||||||
================================
|
================================
|
||||||
|
Introduce memory pools per volume group (to reduce memory for large VGs).
|
||||||
Add memory pool leaks detection.
|
Add memory pool leaks detection.
|
||||||
Use copy of PV structure when manipulating with global PV lists.
|
Use copy of PV structure when manipulating with global PV lists.
|
||||||
Always return exit error status when locking of volume group fails.
|
Always return exit error status when locking of volume group fails.
|
||||||
|
@ -111,9 +111,9 @@ static int _check_vgs(struct dm_list *pvs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct volume_group *_build_vg(struct format_instance *fid,
|
static struct volume_group *_build_vg(struct format_instance *fid,
|
||||||
struct dm_list *pvs)
|
struct dm_list *pvs,
|
||||||
|
struct dm_pool *mem)
|
||||||
{
|
{
|
||||||
struct dm_pool *mem = fid->fmt->cmd->mem;
|
|
||||||
struct volume_group *vg = dm_pool_alloc(mem, sizeof(*vg));
|
struct volume_group *vg = dm_pool_alloc(mem, sizeof(*vg));
|
||||||
struct disk_list *dl;
|
struct disk_list *dl;
|
||||||
|
|
||||||
@ -126,6 +126,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
|||||||
memset(vg, 0, sizeof(*vg));
|
memset(vg, 0, sizeof(*vg));
|
||||||
|
|
||||||
vg->cmd = fid->fmt->cmd;
|
vg->cmd = fid->fmt->cmd;
|
||||||
|
vg->vgmem = mem;
|
||||||
vg->fid = fid;
|
vg->fid = fid;
|
||||||
vg->seqno = 0;
|
vg->seqno = 0;
|
||||||
dm_list_init(&vg->pvs);
|
dm_list_init(&vg->pvs);
|
||||||
@ -163,7 +164,7 @@ static struct volume_group *_format1_vg_read(struct format_instance *fid,
|
|||||||
const char *vg_name,
|
const char *vg_name,
|
||||||
struct metadata_area *mda __attribute((unused)))
|
struct metadata_area *mda __attribute((unused)))
|
||||||
{
|
{
|
||||||
struct dm_pool *mem = dm_pool_create("lvm1 vg_read", 1024 * 10);
|
struct dm_pool *mem = dm_pool_create("lvm1 vg_read", VG_MEMPOOL_CHUNK);
|
||||||
struct dm_list pvs;
|
struct dm_list pvs;
|
||||||
struct volume_group *vg = NULL;
|
struct volume_group *vg = NULL;
|
||||||
dm_list_init(&pvs);
|
dm_list_init(&pvs);
|
||||||
@ -178,12 +179,13 @@ static struct volume_group *_format1_vg_read(struct format_instance *fid,
|
|||||||
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs))
|
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
if (!(vg = _build_vg(fid, &pvs)))
|
if (!(vg = _build_vg(fid, &pvs, mem)))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
|
return vg;
|
||||||
bad:
|
bad:
|
||||||
dm_pool_destroy(mem);
|
dm_pool_destroy(mem);
|
||||||
return vg;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct disk_list *_flatten_pv(struct format_instance *fid,
|
static struct disk_list *_flatten_pv(struct format_instance *fid,
|
||||||
@ -240,7 +242,7 @@ static int _flatten_vg(struct format_instance *fid, struct dm_pool *mem,
|
|||||||
static int _format1_vg_write(struct format_instance *fid, struct volume_group *vg,
|
static int _format1_vg_write(struct format_instance *fid, struct volume_group *vg,
|
||||||
struct metadata_area *mda __attribute((unused)))
|
struct metadata_area *mda __attribute((unused)))
|
||||||
{
|
{
|
||||||
struct dm_pool *mem = dm_pool_create("lvm1 vg_write", 1024 * 10);
|
struct dm_pool *mem = dm_pool_create("lvm1 vg_write", VG_MEMPOOL_CHUNK);
|
||||||
struct dm_list pvds;
|
struct dm_list pvds;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
|
@ -113,6 +113,7 @@ static struct volume_group *_build_vg_from_pds(struct format_instance
|
|||||||
}
|
}
|
||||||
|
|
||||||
vg->cmd = fid->fmt->cmd;
|
vg->cmd = fid->fmt->cmd;
|
||||||
|
vg->vgmem = mem;
|
||||||
vg->fid = fid;
|
vg->fid = fid;
|
||||||
vg->name = NULL;
|
vg->name = NULL;
|
||||||
vg->status = 0;
|
vg->status = 0;
|
||||||
@ -160,7 +161,7 @@ static struct volume_group *_pool_vg_read(struct format_instance *fid,
|
|||||||
const char *vg_name,
|
const char *vg_name,
|
||||||
struct metadata_area *mda __attribute((unused)))
|
struct metadata_area *mda __attribute((unused)))
|
||||||
{
|
{
|
||||||
struct dm_pool *mem = dm_pool_create("pool vg_read", 1024);
|
struct dm_pool *mem = dm_pool_create("pool vg_read", VG_MEMPOOL_CHUNK);
|
||||||
struct dm_list pds;
|
struct dm_list pds;
|
||||||
struct volume_group *vg = NULL;
|
struct volume_group *vg = NULL;
|
||||||
|
|
||||||
@ -182,9 +183,10 @@ static struct volume_group *_pool_vg_read(struct format_instance *fid,
|
|||||||
if (!(vg = _build_vg_from_pds(fid, mem, &pds)))
|
if (!(vg = _build_vg_from_pds(fid, mem, &pds)))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
|
return vg;
|
||||||
out:
|
out:
|
||||||
dm_pool_destroy(mem);
|
dm_pool_destroy(mem);
|
||||||
return vg;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _pool_pv_setup(const struct format_type *fmt __attribute((unused)),
|
static int _pool_pv_setup(const struct format_type *fmt __attribute((unused)),
|
||||||
|
@ -662,18 +662,23 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
|||||||
struct config_node *vgn, *cn;
|
struct config_node *vgn, *cn;
|
||||||
struct volume_group *vg;
|
struct volume_group *vg;
|
||||||
struct dm_hash_table *pv_hash = NULL;
|
struct dm_hash_table *pv_hash = NULL;
|
||||||
struct dm_pool *mem = fid->fmt->cmd->mem;
|
struct dm_pool *mem = dm_pool_create("lvm2 vg_read", VG_MEMPOOL_CHUNK);
|
||||||
|
|
||||||
|
if (!mem)
|
||||||
|
return_NULL;
|
||||||
|
|
||||||
/* skip any top-level values */
|
/* skip any top-level values */
|
||||||
for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ;
|
for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ;
|
||||||
|
|
||||||
if (!vgn) {
|
if (!vgn) {
|
||||||
log_error("Couldn't find volume group in file.");
|
log_error("Couldn't find volume group in file.");
|
||||||
return NULL;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
|
if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
|
||||||
return_NULL;
|
goto_bad;
|
||||||
|
|
||||||
|
vg->vgmem = mem;
|
||||||
vg->cmd = fid->fmt->cmd;
|
vg->cmd = fid->fmt->cmd;
|
||||||
|
|
||||||
/* FIXME Determine format type from file contents */
|
/* FIXME Determine format type from file contents */
|
||||||
@ -807,7 +812,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
|||||||
if (pv_hash)
|
if (pv_hash)
|
||||||
dm_hash_destroy(pv_hash);
|
dm_hash_destroy(pv_hash);
|
||||||
|
|
||||||
dm_pool_free(mem, vg);
|
dm_pool_destroy(mem);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +115,9 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
|||||||
lock_vol(cmd, (lv)->lvid.s, flags | LCK_LV_CLUSTERED(lv))
|
lock_vol(cmd, (lv)->lvid.s, flags | LCK_LV_CLUSTERED(lv))
|
||||||
|
|
||||||
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)
|
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)
|
||||||
|
#define unlock_release_vg(cmd, vg, vol) do { unlock_vg(cmd, vol); \
|
||||||
|
vg_release(vg); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define resume_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_RESUME)
|
#define resume_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_RESUME)
|
||||||
#define suspend_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_SUSPEND | LCK_HOLD)
|
#define suspend_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_SUSPEND | LCK_HOLD)
|
||||||
|
@ -212,6 +212,7 @@ struct format_instance {
|
|||||||
|
|
||||||
struct volume_group {
|
struct volume_group {
|
||||||
struct cmd_context *cmd;
|
struct cmd_context *cmd;
|
||||||
|
struct dm_pool *vgmem;
|
||||||
struct format_instance *fid;
|
struct format_instance *fid;
|
||||||
uint32_t seqno; /* Metadata sequence number */
|
uint32_t seqno; /* Metadata sequence number */
|
||||||
|
|
||||||
@ -437,6 +438,7 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
|
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
|
||||||
struct volume_group *vg_to);
|
struct volume_group *vg_to);
|
||||||
|
|
||||||
|
void vg_release(struct volume_group *vg);
|
||||||
/* Manipulate LVs */
|
/* Manipulate LVs */
|
||||||
struct logical_volume *lv_create_empty(const char *name,
|
struct logical_volume *lv_create_empty(const char *name,
|
||||||
union lvid *lvid,
|
union lvid *lvid,
|
||||||
|
@ -517,18 +517,22 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
|||||||
int pv_count, char **pv_names)
|
int pv_count, char **pv_names)
|
||||||
{
|
{
|
||||||
struct volume_group *vg;
|
struct volume_group *vg;
|
||||||
struct dm_pool *mem = cmd->mem;
|
|
||||||
int consistent = 0;
|
int consistent = 0;
|
||||||
|
struct dm_pool *mem;
|
||||||
if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
|
|
||||||
return_NULL;
|
|
||||||
|
|
||||||
/* is this vg name already in use ? */
|
/* is this vg name already in use ? */
|
||||||
if (vg_read_internal(cmd, vg_name, NULL, &consistent)) {
|
if ((vg = vg_read_internal(cmd, vg_name, NULL, &consistent))) {
|
||||||
log_err("A volume group called '%s' already exists.", vg_name);
|
log_err("A volume group called '%s' already exists.", vg_name);
|
||||||
goto bad;
|
vg_release(vg);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(mem = dm_pool_create("lvm2 vg_create", VG_MEMPOOL_CHUNK)))
|
||||||
|
return_NULL;
|
||||||
|
|
||||||
|
if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
|
||||||
|
goto_bad;
|
||||||
|
|
||||||
if (!id_create(&vg->id)) {
|
if (!id_create(&vg->id)) {
|
||||||
log_err("Couldn't create uuid for volume group '%s'.", vg_name);
|
log_err("Couldn't create uuid for volume group '%s'.", vg_name);
|
||||||
goto bad;
|
goto bad;
|
||||||
@ -537,6 +541,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
|||||||
/* Strip dev_dir if present */
|
/* Strip dev_dir if present */
|
||||||
vg_name = strip_dir(vg_name, cmd->dev_dir);
|
vg_name = strip_dir(vg_name, cmd->dev_dir);
|
||||||
|
|
||||||
|
vg->vgmem = mem;
|
||||||
vg->cmd = cmd;
|
vg->cmd = cmd;
|
||||||
|
|
||||||
if (!(vg->name = dm_pool_strdup(mem, vg_name)))
|
if (!(vg->name = dm_pool_strdup(mem, vg_name)))
|
||||||
@ -589,7 +594,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
|||||||
return vg;
|
return vg;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
dm_pool_free(mem, vg);
|
dm_pool_destroy(mem);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1643,23 +1648,28 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
|
|||||||
struct pv_list *pvl;
|
struct pv_list *pvl;
|
||||||
struct volume_group *vg;
|
struct volume_group *vg;
|
||||||
struct physical_volume *pv;
|
struct physical_volume *pv;
|
||||||
|
struct dm_pool *mem;
|
||||||
|
|
||||||
lvmcache_label_scan(cmd, 0);
|
lvmcache_label_scan(cmd, 0);
|
||||||
|
|
||||||
if (!(vginfo = vginfo_from_vgname(orphan_vgname, NULL)))
|
if (!(vginfo = vginfo_from_vgname(orphan_vgname, NULL)))
|
||||||
return_NULL;
|
return_NULL;
|
||||||
|
|
||||||
if (!(vg = dm_pool_zalloc(cmd->mem, sizeof(*vg)))) {
|
if (!(mem = dm_pool_create("vg_read orphan", VG_MEMPOOL_CHUNK)))
|
||||||
|
return_NULL;
|
||||||
|
|
||||||
|
if (!(vg = dm_pool_zalloc(mem, sizeof(*vg)))) {
|
||||||
log_error("vg allocation failed");
|
log_error("vg allocation failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
dm_list_init(&vg->pvs);
|
dm_list_init(&vg->pvs);
|
||||||
dm_list_init(&vg->lvs);
|
dm_list_init(&vg->lvs);
|
||||||
dm_list_init(&vg->tags);
|
dm_list_init(&vg->tags);
|
||||||
|
vg->vgmem = mem;
|
||||||
vg->cmd = cmd;
|
vg->cmd = cmd;
|
||||||
if (!(vg->name = dm_pool_strdup(cmd->mem, orphan_vgname))) {
|
if (!(vg->name = dm_pool_strdup(mem, orphan_vgname))) {
|
||||||
log_error("vg name allocation failed");
|
log_error("vg name allocation failed");
|
||||||
return NULL;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create format instance with appropriate metadata area */
|
/* create format instance with appropriate metadata area */
|
||||||
@ -1667,17 +1677,16 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
|
|||||||
orphan_vgname, NULL,
|
orphan_vgname, NULL,
|
||||||
NULL))) {
|
NULL))) {
|
||||||
log_error("Failed to create format instance");
|
log_error("Failed to create format instance");
|
||||||
dm_pool_free(cmd->mem, vg);
|
goto bad;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dm_list_iterate_items(info, &vginfo->infos) {
|
dm_list_iterate_items(info, &vginfo->infos) {
|
||||||
if (!(pv = _pv_read(cmd, dev_name(info->dev), NULL, NULL, 1, 0))) {
|
if (!(pv = _pv_read(cmd, dev_name(info->dev), NULL, NULL, 1, 0))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!(pvl = dm_pool_zalloc(cmd->mem, sizeof(*pvl)))) {
|
if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) {
|
||||||
log_error("pv_list allocation failed");
|
log_error("pv_list allocation failed");
|
||||||
return NULL;
|
goto bad;
|
||||||
}
|
}
|
||||||
pvl->pv = pv;
|
pvl->pv = pv;
|
||||||
dm_list_add(&vg->pvs, &pvl->list);
|
dm_list_add(&vg->pvs, &pvl->list);
|
||||||
@ -1685,6 +1694,9 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return vg;
|
return vg;
|
||||||
|
bad:
|
||||||
|
dm_pool_destroy(mem);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _update_pv_list(struct dm_pool *pvmem, struct dm_list *all_pvs, struct volume_group *vg)
|
static int _update_pv_list(struct dm_pool *pvmem, struct dm_list *all_pvs, struct volume_group *vg)
|
||||||
@ -2040,6 +2052,18 @@ struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgnam
|
|||||||
return vg;
|
return vg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vg_release(struct volume_group *vg)
|
||||||
|
{
|
||||||
|
if (!vg || !vg->vgmem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (vg->vgmem == vg->cmd->mem)
|
||||||
|
log_error("Internal error: global memory pool used for VG %s",
|
||||||
|
vg->name);
|
||||||
|
|
||||||
|
dm_pool_destroy(vg->vgmem);
|
||||||
|
}
|
||||||
|
|
||||||
/* This is only called by lv_from_lvid, which is only called from
|
/* This is only called by lv_from_lvid, which is only called from
|
||||||
* activate.c so we know the appropriate VG lock is already held and
|
* activate.c so we know the appropriate VG lock is already held and
|
||||||
* the vg_read_internal is therefore safe.
|
* the vg_read_internal is therefore safe.
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
//#define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
|
//#define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
|
||||||
//#define MAX_RESTRICTED_LVS 255 /* Used by FMT_RESTRICTED_LVIDS */
|
//#define MAX_RESTRICTED_LVS 255 /* Used by FMT_RESTRICTED_LVIDS */
|
||||||
#define MIRROR_LOG_OFFSET 2 /* sectors */
|
#define MIRROR_LOG_OFFSET 2 /* sectors */
|
||||||
|
#define VG_MEMPOOL_CHUNK 10240 /* in bytes, hint only */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ceiling(n / sz)
|
* Ceiling(n / sz)
|
||||||
|
Loading…
Reference in New Issue
Block a user