[lvm-devel] [PATCH 3/6] Share VG multiple times

Zdenek Kabelac zkabelac at redhat.com
Tue Mar 22 21:21:57 UTC 2011


Saves time of the creation of the same volume_group structure.

Structure vginfo is extended with linked list of vg_pool_list elements.

It tracks the number of reuses of every cached VG.  As especially clvmd
and few other situation requires more then 1 parsed VG - so using
this vg_pool implementation.

Sharing is not used when VG is opened RW recover mode.
As there is far more case when sharing is possible - use rather specific
lvmcache_drop_vg() call to drop parsed VG from cache - such VG is then
unlocked moved away from the vg pool and it is fully modifiable.

Signed-off-by: Zdenek Kabelac <zkabelac at redhat.com>
---
 lib/cache/lvmcache.c    |  104 +++++++++++++++++++++++++++++++++++++++++++++-
 lib/cache/lvmcache.h    |    3 +
 lib/metadata/metadata.c |   20 ++++++++-
 lib/metadata/vg.h       |    2 +
 4 files changed, 124 insertions(+), 5 deletions(-)

diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index d0de34f..9ee009d 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -38,6 +38,13 @@ static int _has_scanned = 0;
 static int _vgs_locked = 0;
 static int _vg_global_lock_held = 0;	/* Global lock held when cache wiped? */
 
+struct vg_pool_list {
+	struct dm_list list;    /* vg_pool list */
+	struct volume_group *vg;
+	int in_use;
+	unsigned use_count;	/* Reuse counter for statistics */
+};
+
 int lvmcache_init(void)
 {
 	/*
@@ -76,6 +83,10 @@ int lvmcache_init(void)
 /* Volume Group metadata cache functions */
 static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo)
 {
+	struct vg_pool_list *vgpl, *tvgpl;
+	struct volume_group *vg;
+	int in_use;
+
 	if (!vginfo || !vginfo->vgmetadata)
 		return;
 
@@ -89,6 +100,17 @@ static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo)
 		vginfo->cft = NULL;
 	}
 
+	dm_list_iterate_items_safe(vgpl, tvgpl, &vginfo->vg_pool) {
+		vg = vgpl->vg;
+		in_use = vgpl->in_use;
+		if (!lvmcache_drop_vg(vg))
+			stack;
+		if (in_use)
+			log_debug("Unpooling referenced VG:%p %s", vg, vg->name);
+		else
+			free_vg(vg);
+	}
+
 	log_debug("Metadata cache: VG %s wiped.", vginfo->vgname);
 }
 
@@ -637,6 +659,7 @@ struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted)
 {
 	struct lvmcache_vginfo *vginfo;
 	struct volume_group *vg = NULL;
+	struct vg_pool_list *vgpl = NULL;
 	struct format_instance *fid;
 	struct format_instance_ctx fic;
 	int vg_missing;
@@ -663,12 +686,32 @@ struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted)
 	    (!precommitted && vginfo->precommitted && !critical_section()))
 		return NULL;
 
+	/* Try to find some usable VG in pool - short list is expected */
+	dm_list_iterate_items(vgpl, &vginfo->vg_pool)  {
+		if (!vgpl->in_use) {
+			if (!dm_pool_restore(vgpl->vg->vgmem, 0))
+				/* Should not happen, but ignore such VG */
+				stack;
+			else {
+				vg = vgpl->vg;
+				vgpl->in_use = 1;
+				vgpl->use_count++;
+				goto out;
+			}
+		}
+	}
+
 	fic.type = FMT_INSTANCE_VG | FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
 	fic.context.vg_ref.vg_name = vginfo->vgname;
 	fic.context.vg_ref.vg_id = vgid;
 	if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt, &fic)))
 		return_NULL;
 
+	if (!(vgpl = dm_zalloc(sizeof(*vgpl)))) {
+		log_error("Failed to allocate memory for pool list.");
+		goto bad;
+	}
+
 	/* Build config tree from vgmetadata, if not yet cached */
 	if (!vginfo->cft &&
 	    !(vginfo->cft =
@@ -685,17 +728,71 @@ struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted)
 		vg_mark_partial_lvs(vg);
 	}
 
-	log_debug("Using cached %smetadata for VG %s.",
-		  vginfo->precommitted ? "pre-committed" : "", vginfo->vgname);
+	/* Add to VGs pool */
+	vg->vg_pool = vgpl;
+	vgpl->vg = vg;
+	vgpl->in_use = 1; /* Also for goto_bad fail path */
+	dm_list_add(&vginfo->vg_pool, &vgpl->list);
+	log_debug("Add VG:%p %s to the vginfo %p vg_pool (%d).",
+		  vg, vg->name, vginfo, dm_list_size(&vginfo->vg_pool));
+	if (!dm_pool_lock(vg->vgmem, 8 + dm_list_size(&vg->lvs)))
+		goto_bad;
+out:
+	log_debug("Using cached (%u) %smetadata for VG %s.", vgpl->use_count,
+		  vginfo->precommitted ? "pre-committed " : "", vginfo->vgname);
 
 	return vg;
 
 bad:
 	free_vg(vg);
 	_free_cached_vgmetadata(vginfo);
+	dm_free(vgpl);
 	return NULL;
 }
 
+/**
+ * Put back VG as reusable in vg_pool list
+ */
+int lvmcache_put_vg(struct volume_group *vg)
+{
+	if (!vg->vg_pool || !vg->vg_pool->in_use)
+		return 0;
+
+	log_debug("Putting back to cache list VG:%p %s (reused:%d).",
+		  vg, vg->name, vg->vg_pool->use_count);
+	vg->vg_pool->in_use = 0;
+	return 1;
+}
+
+/**
+ * Drop VG from the vginfo vg_pool list so it can be used
+ * for modification.
+ */
+int lvmcache_drop_vg(struct volume_group *vg)
+{
+	if (!vg->vg_pool)
+		return 0;
+
+	log_debug("Dropping VG:%p %s from cache (reused:%d).",
+		  vg, vg->name, vg->vg_pool->use_count);
+
+	/* Debug perform crc check */
+	if (!vg->vg_pool->in_use &&
+	    vg->vg_pool->use_count &&
+	    !dm_pool_restore(vg->vgmem, 1))
+		/* Should not happen, but ignore such VG */
+		stack;
+
+	if (!dm_pool_unlock(vg->vgmem))
+		stack;
+
+	dm_list_del(&vg->vg_pool->list);
+	dm_free(vg->vg_pool);
+	vg->vg_pool = NULL;
+
+	return 1;
+}
+
 struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
 				   int include_internal)
 {
@@ -1117,6 +1214,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
 			return 0;
 		}
 		dm_list_init(&vginfo->infos);
+		dm_list_init(&vginfo->vg_pool);
 
 		/*
 		 * If we're scanning and there's an invalidated entry, remove it.
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index f13cad2..6360f30 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -50,6 +50,7 @@ struct lvmcache_vginfo {
 	char *vgmetadata;	/* Copy of VG metadata as format_text string */
 	struct config_tree *cft; /* Config tree created from vgmetadata */
 				/* Lifetime is directly tied to vgmetadata */
+	struct dm_list vg_pool; /* List of cached parsed struct volume_group */
 	unsigned precommitted;	/* Is vgmetadata live or precommitted? */
 };
 
@@ -122,6 +123,8 @@ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
 
 /* Returns cached volume group metadata. */
 struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted);
+int lvmcache_put_vg(struct volume_group *vg);
+int lvmcache_drop_vg(struct volume_group *vg);
 void lvmcache_drop_metadata(const char *vgname, int drop_precommitted);
 void lvmcache_commit_metadata(const char *vgname);
 
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index b6312a0..e466821 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -855,6 +855,12 @@ static struct volume_group *_vg_make_handle(struct cmd_context *cmd,
 					    struct volume_group *vg,
 					    uint32_t failure)
 {
+	if (vg && vg->vg_pool && (failure != SUCCESS)) {
+		/* Avoid overwrite of shared VG structure */
+		free_vg(vg);
+		vg = NULL;
+	}
+
 	if (!vg && !(vg = alloc_vg("vg_make_handle", cmd, NULL)))
 		return_NULL;
 
@@ -2816,8 +2822,11 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
 	    (use_precommitted || !*consistent || !(correct_vg->status & INCONSISTENT_VG))) {
 		if (!(correct_vg->status & INCONSISTENT_VG))
 			*consistent = 1;
-		else	/* Inconsistent but we can't repair it */
+		else { 
+			lvmcache_drop_vg(correct_vg);
+			/* Inconsistent but we can't repair it */
 			correct_vg->status &= ~INCONSISTENT_VG;
+		}
 
 		return correct_vg;
 	} else {
@@ -3243,6 +3252,11 @@ void free_vg(struct volume_group *vg)
 	if (!vg)
 		return;
 
+	log_debug("Releasing VG:%p %s.", vg, vg->name);
+
+	if (lvmcache_put_vg(vg))
+		return;
+
 	dm_list_iterate_items(pvl, &vg->pvs)
 		pvl->pv->fid->fmt->ops->destroy_instance(pvl->pv->fid);
 
@@ -3789,7 +3803,9 @@ static struct volume_group *_recover_vg(struct cmd_context *cmd,
 		return_NULL;
 	}
 
-	return (struct volume_group *)vg;
+	lvmcache_drop_vg(vg);
+
+	return vg;
 }
 
 /*
diff --git a/lib/metadata/vg.h b/lib/metadata/vg.h
index 2cc6047..e153c76 100644
--- a/lib/metadata/vg.h
+++ b/lib/metadata/vg.h
@@ -20,6 +20,7 @@ struct dm_pool;
 struct format_instance;
 struct dm_list;
 struct id;
+struct vg_pool_list;
 
 typedef enum {
 	ALLOC_INVALID,
@@ -35,6 +36,7 @@ struct volume_group {
 	struct cmd_context *cmd;
 	struct dm_pool *vgmem;
 	struct format_instance *fid;
+	struct vg_pool_list *vg_pool; /* Backward reference to lvmcache */
 	struct dm_list *cmd_vgs;/* List of wanted/locked and opened VGs */
 	uint32_t cmd_missing_vgs;/* Flag marks missing VG */
 	uint32_t seqno;		/* Metadata sequence number */
-- 
1.7.4.1




More information about the lvm-devel mailing list