[lvm-devel] [PATCH 07/19] lvm2app: Add function to retrieve list of PVs
Tony Asleson
tasleson at redhat.com
Wed May 8 22:45:29 UTC 2013
As locks are held, you need to call the included function
to release the memory and locks when done transversing the
list of physical volumes.
Signed-off-by: Tony Asleson <tasleson at redhat.com>
---
lib/metadata/metadata-exported.h | 12 +++-
lib/metadata/metadata.c | 81 +++++++++++++++------
liblvm/lvm2app.h | 28 ++++++++
liblvm/lvm_pv.c | 79 ++++++++++++++++++++
python/liblvm.c | 152 ++++++++++++++++++++++++++++++++++++---
5 files changed, 322 insertions(+), 30 deletions(-)
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 21ea86d..4cc42bc 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -396,6 +396,11 @@ struct lv_list {
struct logical_volume *lv;
};
+struct vg_list {
+ struct dm_list list;
+ struct volume_group *vg;
+};
+
#define PV_PE_START_CALC ((uint64_t) -1) /* Calculate pe_start value */
struct pvcreate_restorable_params {
@@ -483,7 +488,12 @@ struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vg_na
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
int warnings,
int scan_label_only);
-struct dm_list *get_pvs(struct cmd_context *cmd);
+
+#define get_pvs( cmd ) get_pvs_internal((cmd), NULL, NULL)
+#define get_pvs_perserve_vg( cmd, pv_list, vg_list ) get_pvs_internal((cmd), (pv_list), (vg_list))
+
+struct dm_list *get_pvs_internal(struct cmd_context *cmd,
+ struct dm_list *pvslist, struct dm_list *vgslist);
/*
* Add/remove LV to/from volume group
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index bde1cb0..cecf81c 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3667,7 +3667,8 @@ struct dm_list *get_vgids(struct cmd_context *cmd, int include_internal)
return lvmcache_get_vgids(cmd, include_internal);
}
-static int _get_pvs(struct cmd_context *cmd, int warnings, struct dm_list **pvslist)
+static int _get_pvs(struct cmd_context *cmd, int warnings,
+ struct dm_list *pvslist, struct dm_list *vgslist)
{
struct str_list *strl;
struct dm_list * uninitialized_var(results);
@@ -3677,18 +3678,11 @@ static int _get_pvs(struct cmd_context *cmd, int warnings, struct dm_list **pvsl
struct volume_group *vg;
int consistent = 0;
int old_pvmove;
+ struct vg_list *vgl_item = NULL;
+ int have_pv = 0;
lvmcache_label_scan(cmd, 0);
- if (pvslist) {
- if (!(results = dm_pool_alloc(cmd->mem, sizeof(*results)))) {
- log_error("PV list allocation failed");
- return 0;
- }
-
- dm_list_init(results);
- }
-
/* Get list of VGs */
if (!(vgids = get_vgids(cmd, 1))) {
log_error("get_pvs: get_vgids failed");
@@ -3724,33 +3718,78 @@ static int _get_pvs(struct cmd_context *cmd, int warnings, struct dm_list **pvsl
release_vg(vg);
return 0;
}
- dm_list_add(results, &pvl_copy->list);
+ /* If we are going to release the vg, don't store a pointer to
+ * it in the pv structure.
+ */
+ if (!vgslist) {
+ pvl_copy->pv->vg = NULL;
+ }
+ have_pv = 1;
+ dm_list_add(pvslist, &pvl_copy->list);
}
- release_vg(vg);
+
+ /* In the case of the library we want to preserve the embedded volume
+ * group as subsequent calls to retrieve data about the pv require it.
+ */
+ if (!vgslist || have_pv == 0) {
+ release_vg(vg);
+ } else {
+ /* Add vg to list of vg objects that will be returned
+ */
+ vgl_item = dm_pool_alloc(cmd->mem, sizeof(*vgl_item));
+ if (!vgl_item) {
+ log_error("VG list element allocation failed");
+ return 0;
+ }
+ vgl_item->vg = vg;
+ vg = NULL;
+ dm_list_add(vgslist, &vgl_item->list);
+ }
+ have_pv = 0;
}
init_pvmove(old_pvmove);
- if (pvslist)
- *pvslist = results;
- else
+ if (!pvslist) {
dm_pool_free(cmd->mem, vgids);
-
+ }
return 1;
}
-struct dm_list *get_pvs(struct cmd_context *cmd)
+/* Retrieve a list of all physical volumes.
+ * @param cmd Command context
+ * @param pvslist Set to NULL if you want memory for list created,
+ * else valid memory
+ * @param vgslist Set to NULL if you need the pv structures to contain
+ * valid vg pointer. This is the list of VGs
+ * @returns NULL on errors, else pvslist which will equal passes in value if
+ * supplied.
+ */
+struct dm_list *get_pvs_internal(struct cmd_context *cmd,
+ struct dm_list *pvslist, struct dm_list *vgslist)
{
- struct dm_list *results;
+ struct dm_list *results = pvslist;
- if (!_get_pvs(cmd, 1, &results))
- return NULL;
+ if (NULL == results) {
+ if (!(results = dm_pool_alloc(cmd->mem, sizeof(*results)))) {
+ log_error("PV list allocation failed");
+ return 0;
+ }
+
+ dm_list_init(results);
+ }
+ if (!_get_pvs(cmd, 1, results, vgslist)) {
+ if (NULL == pvslist) {
+ dm_pool_free(cmd->mem, results);
+ }
+ return NULL;
+ }
return results;
}
int scan_vgs_for_pvs(struct cmd_context *cmd, int warnings)
{
- return _get_pvs(cmd, warnings, NULL);
+ return _get_pvs(cmd, warnings, NULL, NULL);
}
int pv_write(struct cmd_context *cmd __attribute__((unused)),
diff --git a/liblvm/lvm2app.h b/liblvm/lvm2app.h
index 25778d1..260693c 100644
--- a/liblvm/lvm2app.h
+++ b/liblvm/lvm2app.h
@@ -543,6 +543,34 @@ vg_t lvm_vg_create(lvm_t libh, const char *vg_name);
struct dm_list *lvm_vg_list_lvs(vg_t vg);
/**
+ * Return a list of PV handles for all.
+ *
+ * \memberof lvm_t
+ *
+ * \param libh
+ * Library handle retrieved from lvm_init
+ *
+ * \return
+ * A list of lvm_pv_list structures containing pv handles for all physical
+ * volumes. If no PVs exist or a global lock was unable to be obtained a
+ * NULL is returned.
+ */
+struct dm_list *lvm_list_pvs(lvm_t libh);
+
+/**
+ * Free the resources used by acquiring the pvlist. This should be called as
+ * soon as possible after processing the needed information from the pv list as
+ * a global locks are held.
+ *
+ * \param pvlist
+ * PV list to be freed
+ *
+ * \return
+ * 0 on success, else -1 with library errno and text set.
+ */
+int lvm_list_pvs_free(struct dm_list *pvlist);
+
+/**
* Return a list of PV handles for a given VG handle.
*
* \memberof vg_t
diff --git a/liblvm/lvm_pv.c b/liblvm/lvm_pv.c
index 18b1069..9e99e7d 100644
--- a/liblvm/lvm_pv.c
+++ b/liblvm/lvm_pv.c
@@ -12,11 +12,14 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <stddef.h>
#include "lib.h"
#include "metadata.h"
#include "lvm-string.h"
#include "lvm_misc.h"
#include "lvm2app.h"
+#include "locking.h"
+#include "toolcontext.h"
const char *lvm_pv_get_uuid(const pv_t pv)
{
@@ -60,6 +63,82 @@ struct lvm_property_value lvm_pvseg_get_property(const pvseg_t pvseg,
return get_property(NULL, NULL, NULL, NULL, pvseg, NULL, name);
}
+
+#define address_of(p, t, m) ({ \
+ const typeof( ((t *)0)->m ) *__mptr = (p); \
+ (t *)( (char *)__mptr - offsetof(t,m) );})
+
+struct lvm_list_wrapper
+{
+ unsigned long magic;
+ struct dm_list pvslist;
+ struct dm_list vgslist;
+};
+
+
+struct dm_list *lvm_list_pvs(lvm_t libh)
+{
+ struct lvm_list_wrapper *rc = NULL;
+ struct cmd_context *cmd = (struct cmd_context *)libh;
+
+
+ rc = dm_pool_zalloc(cmd->mem, sizeof(*rc));
+ if (!rc) {
+ log_errno(ENOMEM, "Memory allocation fail for pv list.");
+ return NULL;
+ }
+
+ if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_WRITE)) {
+ log_errno(ENOLCK, "Unable to obtain global lock.");
+ } else {
+ dm_list_init(&rc->pvslist);
+ dm_list_init(&rc->vgslist);
+ if( !get_pvs_perserve_vg(cmd, &rc->pvslist, &rc->vgslist) ) {
+ dm_pool_free(cmd->mem, rc);
+ return NULL;
+ }
+ rc->magic = 0xF005BA11;
+ }
+
+ return &rc->pvslist;
+}
+
+int lvm_list_pvs_free(struct dm_list *pvlist)
+{
+ int rc = 0;
+ struct lvm_list_wrapper *to_delete = NULL;
+ struct vg_list *vgl = NULL;
+ struct vg_list *tmp_vgl = NULL;
+ struct pv_list *pvl = NULL;
+ struct pv_list *tmp_pvl = NULL;
+ struct cmd_context *cmd = NULL;
+
+ if (pvlist ) {
+ to_delete = address_of(pvlist, struct lvm_list_wrapper, pvslist);
+ if (to_delete->magic == 0xF005BA11) {
+
+ dm_list_iterate_items(vgl, &to_delete->vgslist) {
+ cmd = vgl->vg->cmd;
+ release_vg(vgl->vg);
+ }
+
+ dm_list_iterate_items(pvl, &to_delete->pvslist) {
+ free_pv_fid(pvl->pv);
+ }
+
+ unlock_vg(cmd, VG_GLOBAL);
+ } else {
+ log_errno(EINVAL, "Not a correct pvlist structure");
+ rc = -1;
+ }
+
+ to_delete->magic = 0xA5A5A5A5;
+ dm_pool_free(cmd->mem, to_delete);
+
+ }
+ return rc;
+}
+
struct dm_list *lvm_pv_list_pvsegs(pv_t pv)
{
struct dm_list *list;
diff --git a/python/liblvm.c b/python/liblvm.c
index 906825e..928cab0 100644
--- a/python/liblvm.c
+++ b/python/liblvm.c
@@ -34,6 +34,11 @@ typedef struct {
typedef struct {
PyObject_HEAD
+ struct dm_list *pvslist;
+} pvslistobject;
+
+typedef struct {
+ PyObject_HEAD
lv_t lv; /* lv handle */
vgobject *parent_vgobj;
} lvobject;
@@ -42,6 +47,7 @@ typedef struct {
PyObject_HEAD
pv_t pv; /* pv handle */
vgobject *parent_vgobj;
+ pvslistobject *parent_pvslistobj;
} pvobject;
typedef struct {
@@ -58,6 +64,7 @@ typedef struct {
static PyTypeObject LibLVMvgType;
static PyTypeObject LibLVMlvType;
+static PyTypeObject LibLVMpvlistType;
static PyTypeObject LibLVMpvType;
static PyTypeObject LibLVMlvsegType;
static PyTypeObject LibLVMpvsegType;
@@ -153,6 +160,90 @@ liblvm_lvm_list_vg_uuids(void)
}
static PyObject *
+liblvm_lvm_pvlist_get(pvslistobject *pvsobj)
+{
+ struct lvm_pv_list *pvl;
+ PyObject * pytuple;
+ pvobject * pvobj;
+ int i = 0;
+
+ /* unlike other LVM api calls, if there are no results, we get NULL */
+ pvsobj->pvslist = lvm_list_pvs(libh);
+
+ if (!pvsobj->pvslist)
+ return Py_BuildValue("()");
+
+ pytuple = PyTuple_New(dm_list_size(pvsobj->pvslist));
+ if (!pytuple)
+ return NULL;
+
+ dm_list_iterate_items(pvl, pvsobj->pvslist) {
+ /* Create and initialize the object */
+ pvobj = PyObject_New(pvobject, &LibLVMpvType);
+ if (!pvobj) {
+ Py_DECREF(pytuple);
+ return NULL;
+ }
+
+ /* We don't have a parent vg object to be concerned about */
+ pvobj->parent_vgobj = NULL;
+ pvobj->parent_pvslistobj = pvsobj;
+ Py_INCREF(pvobj->parent_pvslistobj);
+
+ pvobj->pv = pvl->pv;
+ PyTuple_SET_ITEM(pytuple, i, (PyObject *) pvobj);
+ i++;
+ }
+
+ return pytuple;
+}
+
+static PyObject *
+liblvm_lvm_pvlist_put(pvslistobject *self)
+{
+ int rc = 0;
+ if (self->pvslist) {
+ rc = lvm_list_pvs_free(self->pvslist);
+
+ if ( 0 != rc ) {
+ PyErr_SetObject(LibLVMError, liblvm_get_last_error());
+ return NULL;
+ }
+
+ self->pvslist = NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return NULL;
+}
+
+static PyObject *
+liblvm_pvlist_dealloc(pvslistobject *self)
+{
+ if (self->pvslist) {
+ liblvm_lvm_pvlist_put(self);
+ }
+
+ PyObject_Del(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_list_pvs(void)
+{
+ pvslistobject *pvslistobj;
+
+ LVM_VALID();
+
+ if ((pvslistobj = PyObject_New(pvslistobject, &LibLVMpvlistType)) == NULL)
+ return NULL;
+
+ pvslistobj->pvslist = NULL;
+ return (PyObject *)pvslistobj;
+}
+
+static PyObject *
liblvm_lvm_percent_to_float(PyObject *self, PyObject *arg)
{
double converted;
@@ -360,6 +451,15 @@ liblvm_vg_dealloc(vgobject *self)
} \
} while (0)
+#define PVSLIST_VALID(pvslistobject) \
+ do { \
+ LVM_VALID(); \
+ if (!pvslistobject->pvslist) { \
+ PyErr_SetString(PyExc_UnboundLocalError, "PVS object invalid"); \
+ return NULL; \
+ } \
+ } while (0)
+
static PyObject *
liblvm_lvm_vg_close(vgobject *self)
{
@@ -1030,7 +1130,16 @@ liblvm_lvm_pv_from_uuid(vgobject *self, PyObject *arg)
static void
liblvm_pv_dealloc(pvobject *self)
{
- Py_DECREF(self->parent_vgobj);
+ if (self->parent_vgobj) {
+ Py_DECREF(self->parent_vgobj);
+ }
+
+ if (self->parent_pvslistobj) {
+ Py_DECREF(self->parent_pvslistobj);
+ }
+
+ self->parent_vgobj = NULL;
+ self->parent_pvslistobj = NULL;
PyObject_Del(self);
}
@@ -1337,19 +1446,23 @@ liblvm_lvm_lv_snapshot(lvobject *self, PyObject *args)
lvobj->parent_vgobj = self->parent_vgobj;
Py_INCREF(lvobj->parent_vgobj);
-
return (PyObject *)lvobj;
}
/* PV Methods */
-#define PV_VALID(pvobject) \
- do { \
- VG_VALID(pvobject->parent_vgobj); \
- if (!pvobject->pv) { \
+#define PV_VALID(pvobject) \
+ do { \
+ if (pvobject->parent_vgobj) { \
+ VG_VALID(pvobject->parent_vgobj); \
+ } \
+ if (pvobject->parent_pvslistobj) { \
+ PVSLIST_VALID(pvobject->parent_pvslistobj); \
+ } \
+ if (!pvobject->pv) { \
PyErr_SetString(PyExc_UnboundLocalError, "PV object invalid"); \
- return NULL; \
- } \
+ return NULL; \
+ } \
} while (0)
static PyObject *
@@ -1550,6 +1663,7 @@ static PyMethodDef Liblvm_methods[] = {
{ "scan", (PyCFunction)liblvm_lvm_scan, METH_NOARGS },
{ "listVgNames", (PyCFunction)liblvm_lvm_list_vg_names, METH_NOARGS },
{ "listVgUuids", (PyCFunction)liblvm_lvm_list_vg_uuids, METH_NOARGS },
+ { "listPvs", (PyCFunction)liblvm_lvm_list_pvs, METH_NOARGS },
{ "percentToFloat", (PyCFunction)liblvm_lvm_percent_to_float, METH_VARARGS },
{ "vgNameFromPvid", (PyCFunction)liblvm_lvm_vgname_from_pvid, METH_VARARGS },
{ "vgNameFromDevice", (PyCFunction)liblvm_lvm_vgname_from_device, METH_VARARGS },
@@ -1613,6 +1727,15 @@ static PyMethodDef liblvm_lv_methods[] = {
{ NULL, NULL } /* sentinel */
};
+static PyMethodDef liblvm_pv_list_methods[] = {
+ /* pv list methods */
+ { "__enter__", (PyCFunction)liblvm_lvm_pvlist_get, METH_VARARGS },
+ { "__exit__", (PyCFunction)liblvm_lvm_pvlist_put, METH_VARARGS },
+ { "open", (PyCFunction)liblvm_lvm_pvlist_get, METH_VARARGS },
+ { "close", (PyCFunction)liblvm_lvm_pvlist_put, METH_VARARGS },
+ { NULL, NULL }
+};
+
static PyMethodDef liblvm_pv_methods[] = {
/* pv methods */
{ "getName", (PyCFunction)liblvm_lvm_pv_get_name, METH_NOARGS },
@@ -1659,6 +1782,17 @@ static PyTypeObject LibLVMlvType = {
.tp_methods = liblvm_lv_methods,
};
+static PyTypeObject LibLVMpvlistType = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ .tp_name = "liblvm.Liblvm_pvlist",
+ .tp_basicsize = sizeof(pvslistobject),
+ .tp_new = PyType_GenericNew,
+ .tp_dealloc = (destructor)liblvm_pvlist_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = "LVM Physical Volume list object",
+ .tp_methods = liblvm_pv_list_methods,
+};
+
static PyTypeObject LibLVMpvType = {
PyObject_HEAD_INIT(&PyType_Type)
.tp_name = "liblvm.Liblvm_pv",
@@ -1716,6 +1850,8 @@ initlvm(void)
return;
if (PyType_Ready(&LibLVMpvsegType) < 0)
return;
+ if (PyType_Ready(&LibLVMpvlistType) < 0)
+ return;
m = Py_InitModule3("lvm", Liblvm_methods, "Liblvm module");
if (m == NULL)
--
1.8.1.4
More information about the lvm-devel
mailing list