On Tue, Feb 12, 2008 at 04:38:39AM +0000, Daniel P. Berrange wrote:
This patch implements a storage pool based on logical volume
management. The underlying implementation calls out to LVM
on Linux. A future implementation for Solaris would use the
ZFS pool support to achieve the same functionality. The LVM
impl uses the LVM command line tools, in particular lvs, and
vgs for listing, and the *create, *remove tools for modifications.
The 'build' operation will construct a new volume group, and
initialize any physical volume members. The 'delete' operation
will permanently remove the group. Volumes are allocated by
carving out logical volumes. There are no placement constraints
how the volume XML will show the actual storage per-volume on
the underlying physical volumes. The LVM UUID is used for the
unique volume keys.
b/docs/storage/pool-logical.xml | 9
b/src/storage_backend_logical.c | 531 ++++++++++++++++++++++++++++++++++++++++
b/src/storage_backend_logical.h | 45 +++
configure.in | 58 ++++
libvirt.spec.in | 4
po/POTFILES.in | 1
qemud/qemud.c | 4
src/Makefile.am | 8
src/storage_backend.c | 14 +
9 files changed, 673 insertions(+), 1 deletion(-)
diff -r 555d6e919c35 configure.in
--- a/configure.in Tue Feb 19 17:22:05 2008 -0500
+++ b/configure.in Tue Feb 19 17:31:03 2008 -0500
@@ -559,6 +559,8 @@ dnl
AC_ARG_WITH(storage-fs,
[ --with-storage-fs with FileSystem backend for the storage driver
(on)],[],[with_storage_fs=check])
+AC_ARG_WITH(storage-lvm,
+[ --with-storage-lvm with LVM backend for the storage driver
(on)],[],[with_storage_lvm=check])
if test "$with_storage_fs" = "yes" -o "$with_storage_fs" =
"check"; then
AC_PATH_PROG(MOUNT, [mount], [], [$PATH:/sbin:/usr/sbin])
@@ -596,6 +598,61 @@ if test -n "$QCOW_CREATE" ; then
AC_DEFINE_UNQUOTED([QCOW_CREATE],["$QCOW_CREATE"],
[Location or name of the qcow-create program])
fi
+
+
+if test "$with_storage_lvm" = "yes" -o "$with_storage_lvm"
= "check"; then
+ AC_PATH_PROG(PVCREATE, [pvcreate], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(VGCREATE, [vgcreate], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(LVCREATE, [lvcreate], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(PVREMOVE, [pvremove], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(VGREMOVE, [vgremove], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(LVREMOVE, [lvremove], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(VGCHANGE, [vgchange], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(PVS, [pvs], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(VGS, [vgs], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(LVS, [lvs], [], [$PATH:/sbin:/usr/sbin])
+
+ if test "$with_storage_lvm" = "yes" ; then
+ if test -z "$PVCREATE" ; then AC_MSG_ERROR(We need pvcreate for LVM storage
driver) ; fi
+ if test -z "$VGCREATE" ; then AC_MSG_ERROR(We need vgcreate for LVM storage
driver) ; fi
+ if test -z "$LVCREATE" ; then AC_MSG_ERROR(We need lvcreate for LVM storage
driver) ; fi
+ if test -z "$PVREMOVE" ; then AC_MSG_ERROR(We need pvremove for LVM storage
driver) ; fi
+ if test -z "$VGREMOVE" ; then AC_MSG_ERROR(We need vgremove for LVM storage
driver) ; fi
+ if test -z "$LVREMOVE" ; then AC_MSG_ERROR(We need lvremove for LVM storage
driver) ; fi
+ if test -z "$VGCHANGE" ; then AC_MSG_ERROR(We need vgchange for LVM storage
driver) ; fi
+ if test -z "$PVS" ; then AC_MSG_ERROR(We need pvs for LVM storage driver) ;
fi
+ if test -z "$VGS" ; then AC_MSG_ERROR(We need vgs for LVM storage driver) ;
fi
+ if test -z "$LVS" ; then AC_MSG_ERROR(We need lvs for LVM storage driver) ;
fi
+ else
+ if test -z "$PVCREATE" ; then with_storage_lvm=no ; fi
+ if test -z "$VGCREATE" ; then with_storage_lvm=no ; fi
+ if test -z "$LVCREATE" ; then with_storage_lvm=no ; fi
+ if test -z "$PVREMOVE" ; then with_storage_lvm=no ; fi
+ if test -z "$VGREMOVE" ; then with_storage_lvm=no ; fi
+ if test -z "$LVREMOVE" ; then with_storage_lvm=no ; fi
+ if test -z "VGCHANGE" ; then with_storage_lvm=no ; fi
+ if test -z "$PVS" ; then with_storage_lvm=no ; fi
+ if test -z "$VGS" ; then with_storage_lvm=no ; fi
+ if test -z "$LVS" ; then with_storage_lvm=no ; fi
+
+ if test "$with_storage_lvm" = "check" ; then with_storage_lvm=yes
; fi
+ fi
+
+ if test "$with_storage_lvm" = "yes" ; then
+ AC_DEFINE_UNQUOTED(WITH_STORAGE_LVM, 1, [whether LVM backend for storage driver is
enabled])
+ AC_DEFINE_UNQUOTED([PVCREATE],["$PVCREATE"],[Location of pvcreate
program])
+ AC_DEFINE_UNQUOTED([VGCREATE],["$VGCREATE"],[Location of vgcreate
program])
+ AC_DEFINE_UNQUOTED([LVCREATE],["$LVCREATE"],[Location of lvcreate
program])
+ AC_DEFINE_UNQUOTED([PVREMOVE],["$PVREMOVE"],[Location of pvcreate
program])
+ AC_DEFINE_UNQUOTED([VGREMOVE],["$VGREMOVE"],[Location of vgcreate
program])
+ AC_DEFINE_UNQUOTED([LVREMOVE],["$LVREMOVE"],[Location of lvcreate
program])
+ AC_DEFINE_UNQUOTED([VGCHANGE],["$VGCHANGE"],[Location of vgchange
program])
+ AC_DEFINE_UNQUOTED([PVS],["$PVS"],[Location of pvs program])
+ AC_DEFINE_UNQUOTED([VGS],["$VGS"],[Location of vgs program])
+ AC_DEFINE_UNQUOTED([LVS],["$LVS"],[Location of lvs program])
+ fi
+fi
+AM_CONDITIONAL(WITH_STORAGE_LVM, [test "$with_storage_lvm" = "yes"])
dnl
@@ -811,6 +868,7 @@ AC_MSG_NOTICE([ Dir: yes])
AC_MSG_NOTICE([ Dir: yes])
AC_MSG_NOTICE([ FS: $with_storage_fs])
AC_MSG_NOTICE([ NetFS: $with_storage_fs])
+AC_MSG_NOTICE([ LVM: $with_storage_lvm])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Libraries])
AC_MSG_NOTICE([])
diff -r 555d6e919c35 docs/storage/pool-logical.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/pool-logical.xml Tue Feb 19 17:31:03 2008 -0500
@@ -0,0 +1,9 @@
+<pool type="logical">
+ <name>HostVG</name>
+ <source>
+ <device path="/dev/sda1"/>
+ </source>
+ <target>
+ <path>/dev/HostVG</path>
+ </target>
+</pool>
diff -r 555d6e919c35 libvirt.spec.in
--- a/libvirt.spec.in Tue Feb 19 17:22:05 2008 -0500
+++ b/libvirt.spec.in Tue Feb 19 17:31:03 2008 -0500
@@ -49,6 +49,8 @@ Requires: /usr/bin/qemu-img
# From Xen RPMs
Requires: /usr/sbin/qcow-create
%endif
+# For LVM drivers
+Requires: lvm2
BuildRequires: xen-devel
BuildRequires: libxml2-devel
BuildRequires: readline-devel
@@ -73,6 +75,8 @@ BuildRequires: /usr/bin/qemu-img
# From Xen RPMs
BuildRequires: /usr/sbin/qcow-create
%endif
+# For LVM drivers
+BuildRequires: lvm2
Obsoletes: libvir
ExclusiveArch: i386 x86_64 ia64
diff -r 555d6e919c35 po/POTFILES.in
--- a/po/POTFILES.in Tue Feb 19 17:22:05 2008 -0500
+++ b/po/POTFILES.in Tue Feb 19 17:31:03 2008 -0500
@@ -12,6 +12,7 @@ src/remote_internal.c
src/remote_internal.c
src/storage_backend.c
src/storage_backend_fs.c
+src/storage_backend_logical.c
src/storage_conf.c
src/storage_driver.c
src/sexpr.c
diff -r 555d6e919c35 qemud/qemud.c
--- a/qemud/qemud.c Tue Feb 19 17:22:05 2008 -0500
+++ b/qemud/qemud.c Tue Feb 19 17:31:03 2008 -0500
@@ -2089,7 +2089,9 @@ int main(int argc, char **argv) {
if (pipe(sigpipe) < 0 ||
qemudSetNonBlock(sigpipe[0]) < 0 ||
- qemudSetNonBlock(sigpipe[1]) < 0) {
+ qemudSetNonBlock(sigpipe[1]) < 0 ||
+ qemudSetCloseExec(sigpipe[0]) < 0 ||
+ qemudSetCloseExec(sigpipe[1]) < 0) {
qemudLog(QEMUD_ERR, _("Failed to create pipe: %s"),
strerror(errno));
goto error1;
diff -r 555d6e919c35 src/Makefile.am
--- a/src/Makefile.am Tue Feb 19 17:22:05 2008 -0500
+++ b/src/Makefile.am Tue Feb 19 17:31:03 2008 -0500
@@ -68,6 +68,14 @@ SERVER_SOURCES = \
SERVER_SOURCES = \
../qemud/remote_protocol.c ../qemud/remote_protocol.h
+if WITH_STORAGE_LVM
+CLIENT_SOURCES += storage_backend_logical.h storage_backend_logical.c
+else
+EXTRA_DIST += storage_backend_logical.h storage_backend_logical.c
+endif
+
+
+
libvirt_la_SOURCES = $(CLIENT_SOURCES) $(SERVER_SOURCES)
libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS) $(SELINUX_LIBS) \
@CYGWIN_EXTRA_LIBADD@ ../gnulib/lib/libgnu.la
diff -r 555d6e919c35 src/storage_backend.c
--- a/src/storage_backend.c Tue Feb 19 17:22:05 2008 -0500
+++ b/src/storage_backend.c Tue Feb 19 17:31:03 2008 -0500
@@ -36,6 +36,9 @@
#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
+#if WITH_STORAGE_LVM
+#include "storage_backend_logical.h"
+#endif
#include "util.h"
@@ -47,6 +50,9 @@ static virStorageBackendPtr backends[] =
#if WITH_STORAGE_FS
&virStorageBackendFileSystem,
&virStorageBackendNetFileSystem,
+#endif
+#if WITH_STORAGE_LVM
+ &virStorageBackendLogical,
#endif
};
@@ -89,6 +95,10 @@ virStorageBackendFromString(const char *
return VIR_STORAGE_POOL_FS;
if (STREQ(type, "netfs"))
return VIR_STORAGE_POOL_NETFS;
+#endif
+#if WITH_STORAGE_LVM
+ if (STREQ(type, "logical"))
+ return VIR_STORAGE_POOL_LOGICAL;
#endif
virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
@@ -106,6 +116,10 @@ virStorageBackendToString(int type) {
return "fs";
case VIR_STORAGE_POOL_NETFS:
return "netfs";
+#endif
+#if WITH_STORAGE_LVM
+ case VIR_STORAGE_POOL_LOGICAL:
+ return "logical";
#endif
}
diff -r 555d6e919c35 src/storage_backend_logical.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_logical.c Tue Feb 19 17:31:03 2008 -0500
@@ -0,0 +1,531 @@
+/*
+ * storage_backend_logvol.c: storage backend for logical volume handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <regex.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "storage_backend_logical.h"
+#include "storage_conf.h"
+#include "util.h"
+
+
+#define PV_BLANK_SECTOR_SIZE 512
+
+enum {
+ VIR_STORAGE_POOL_LOGICAL_LVM2 = 0,
+};
+
+
+static int
+virStorageBackendLogicalPoolFormatFromString(virConnectPtr conn,
+ const char *format) {
+ if (format == NULL)
+ return VIR_STORAGE_POOL_LOGICAL_LVM2;
+
+ if (STREQ(format, "lvm2"))
+ return VIR_STORAGE_POOL_LOGICAL_LVM2;
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported pool format %s"), format);
+ return -1;
+}
+
+static const char *
+virStorageBackendLogicalPoolFormatToString(virConnectPtr conn,
+ int format) {
+ switch (format) {
+ case VIR_STORAGE_POOL_LOGICAL_LVM2:
+ return "lvm2";
+ }
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported pool format %d"), format);
+ return NULL;
+}
+
+static int
+virStorageBackendLogicalSetActive(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ int on)
+{
+ const char *cmdargv[4];
+
+ cmdargv[0] = VGCHANGE;
+ cmdargv[1] = on ? "-ay" : "-an";
+ cmdargv[2] = pool->def->name;
+ cmdargv[3] = NULL;
+
+ if (virRun(conn, (char**)cmdargv, NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+virStorageBackendLogicalMakeVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ char **const groups,
+ void *data)
+{
+ virStorageVolDefPtr vol = NULL;
+ virStorageVolSourceExtentPtr tmp;
+ unsigned long long offset, size, length;
+
+ /* See if we're only looking for a specific volume */
+ if (data != NULL) {
+ vol = data;
+ if (STRNEQ(vol->name, groups[0]))
+ return 0;
+ }
+
+ /* Or filling in more data on an existing volume */
+ if (vol == NULL)
+ vol = virStorageVolDefFindByName(pool, groups[0]);
+
+ /* Or a completely new volume */
+ if (vol == NULL) {
+ if ((vol = calloc(1, sizeof(*vol))) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("volume"));
+ return -1;
+ }
+
+ if ((vol->name = strdup(groups[0])) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("volume"));
+ return -1;
+ }
+
+ vol->next = pool->volumes;
+ pool->volumes = vol;
+ pool->nvolumes++;
+ }
+
+ if (vol->target.path == NULL) {
+ if ((vol->target.path = malloc(strlen(pool->def->target.path) +
+ 1 + strlen(vol->name) + 1)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("volume"));
+ return -1;
+ }
+ strcpy(vol->target.path, pool->def->target.path);
+ strcat(vol->target.path, "/");
+ strcat(vol->target.path, vol->name);
+ }
+
+ if (vol->key == NULL &&
+ (vol->key = strdup(groups[1])) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("volume"));
+ return -1;
+ }
+
+ if (virStorageBackendUpdateVolInfo(conn, vol, 1) < 0)
+ return -1;
+
+
+ /* Finally fill in extents information */
+ if ((tmp = realloc(vol->source.extents, sizeof(*tmp)
+ * (vol->source.nextent + 1))) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("extents"));
+ return -1;
+ }
+ vol->source.extents = tmp;
+
+ if ((vol->source.extents[vol->source.nextent].path =
+ strdup(groups[2])) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("extents"));
+ return -1;
+ }
+
+ if (virStrToLong_ull(groups[3], NULL, 10, &offset) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("malformed volume extent offset value"));
+ return -1;
+ }
+ if (virStrToLong_ull(groups[4], NULL, 10, &length) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("malformed volume extent length value"));
+ return -1;
+ }
+ if (virStrToLong_ull(groups[5], NULL, 10, &size) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("malformed volume extent size value"));
+ return -1;
+ }
+
+ vol->source.extents[vol->source.nextent].start = offset * size;
+ vol->source.extents[vol->source.nextent].end = (offset * size) + length;
+ vol->source.nextent++;
+
+ return 0;
+}
+
+static int
+virStorageBackendLogicalFindLVs(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol)
+{
+ /*
+ * # lvs --separator : --noheadings --units b --unbuffered --nosuffix --options
"lv_name,uuid,devices,seg_size,vg_extent_size" VGNAME
+ * RootLV:06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky:/dev/hda2(0):5234491392:33554432
+ * SwapLV:oHviCK-8Ik0-paqS-V20c-nkhY-Bm1e-zgzU0M:/dev/hda2(156):1040187392:33554432
+ * Test2:3pg3he-mQsA-5Sui-h0i6-HNmc-Cz7W-QSndcR:/dev/hda2(219):1073741824:33554432
+ * Test3:UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht:/dev/hda2(251):2181038080:33554432
+ * Test3:UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht:/dev/hda2(187):1040187392:33554432
+ *
+ * Pull out name & uuid, device, device extent start #, segment size, extent
size.
+ *
+ * NB can be multiple rows per volume if they have many extents
+ */
+ const char *regexes[] = {
+ "^\\s*(\\S+):(\\S+):(\\S+)\\((\\S+)\\):(\\S+):(\\S+)\\s*$"
+ };
+ int vars[] = {
+ 6
+ };
+ const char *prog[] = {
+ LVS, "--separator", ":", "--noheadings",
"--units", "b",
+ "--unbuffered", "--nosuffix", "--options",
+ "lv_name,uuid,devices,seg_size,vg_extent_size",
+ pool->def->name, NULL
+ };
+
+ return virStorageBackendRunProgRegex(conn,
+ pool,
+ prog,
+ 1,
+ regexes,
+ vars,
+ virStorageBackendLogicalMakeVol,
+ vol);
+}
+
+static int
+virStorageBackendLogicalRefreshPoolFunc(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ char **const groups,
+ void *data ATTRIBUTE_UNUSED)
+{
+ if (virStrToLong_ull(groups[0], NULL, 10, &pool->def->capacity) < 0)
+ return -1;
+ if (virStrToLong_ull(groups[1], NULL, 10, &pool->def->available) < 0)
+ return -1;
+ pool->def->allocation = pool->def->capacity -
pool->def->available;
+
+ return 0;
+}
+
+
+static int
+virStorageBackendLogicalStartPool(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ if (virStorageBackendLogicalSetActive(conn, pool, 1) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+virStorageBackendLogicalBuildPool(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ const char **vgargv;
+ const char *pvargv[3];
+ int n = 0, i, fd;
+ char zeros[PV_BLANK_SECTOR_SIZE];
+
+ memset(zeros, 0, sizeof(zeros));
+
+ /* XXX multiple pvs */
+ if ((vgargv = malloc(sizeof(char*) * (1))) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("command line"));
+ return -1;
+ }
+
+ vgargv[n++] = VGCREATE;
+ vgargv[n++] = pool->def->name;
+
+ pvargv[0] = PVCREATE;
+ pvargv[2] = NULL;
+ for (i = 0 ; i < pool->def->source.ndevice ; i++) {
+ /*
+ * LVM requires that the first sector is blanked if using
+ * a whole disk as a PV. So we just blank them out regardless
+ * rather than trying to figure out if we're a disk or partition
+ */
+ if ((fd = open(pool->def->source.devices[i].path, O_WRONLY)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot open device %s"),
+ strerror(errno));
+ goto cleanup;
+ }
+ if (write(fd, zeros, sizeof(zeros)) != sizeof(zeros)) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot clear device header %s"),
+ strerror(errno));
+ close(fd);
+ goto cleanup;
+ }
+ if (close(fd) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot close device %s"),
+ strerror(errno));
+ goto cleanup;
+ }
+
+ /*
+ * Initialize the physical volume because vgcreate is not
+ * clever enough todo this for us :-(
+ */
+ vgargv[n++] = pool->def->source.devices[i].path;
+ pvargv[1] = pool->def->source.devices[i].path;
+ if (virRun(conn, (char**)pvargv, NULL) < 0)
+ goto cleanup;
+ }
+
+ vgargv[n++] = NULL;
+
+ /* Now create the volume group itself */
+ if (virRun(conn, (char**)vgargv, NULL) < 0)
+ goto cleanup;
+
+ free(vgargv);
+
+ return 0;
+
+ cleanup:
+ free(vgargv);
+ return -1;
+}
+
+
+static int
+virStorageBackendLogicalRefreshPool(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ /*
+ * # vgs --separator : --noheadings --units b --unbuffered --nosuffix --options
"vg_size,vg_free" VGNAME
+ * 10603200512:4328521728
+ *
+ * Pull out size & free
+ */
+ const char *regexes[] = {
+ "^\\s*(\\S+):(\\S+)\\s*$"
+ };
+ int vars[] = {
+ 2
+ };
+ const char *prog[] = {
+ VGS, "--separator", ":", "--noheadings",
"--units", "b", "--unbuffered",
+ "--nosuffix", "--options", "vg_size,vg_free",
+ pool->def->name, NULL
+ };
+
+ /* Get list of all logical volumes */
+ if (virStorageBackendLogicalFindLVs(conn, pool, NULL) < 0) {
+ virStoragePoolObjClearVols(pool);
+ return -1;
+ }
+
+ /* Now get basic volgrp metadata */
+ if (virStorageBackendRunProgRegex(conn,
+ pool,
+ prog,
+ 1,
+ regexes,
+ vars,
+ virStorageBackendLogicalRefreshPoolFunc,
+ NULL) < 0) {
+ virStoragePoolObjClearVols(pool);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* XXX should we set LVM to inactive ? Probably not - it would
+ * suck if this were your LVM root fs :-)
+ */
+#if 0
+static int
+virStorageBackendLogicalStopPool(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ if (virStorageBackendLogicalSetActive(conn, pool, 0) < 0)
+ return -1;
+
+ return 0;
+}
+#endif
+
+static int
+virStorageBackendLogicalDeletePool(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ const char *cmdargv[] = {
+ VGREMOVE, "-f", pool->def->name, NULL
+ };
+
+ if (virRun(conn, (char**)cmdargv, NULL) < 0)
+ return -1;
+
+ /* XXX clear the PVs too ? ie pvremove ? probably ought to */
+
+ return 0;
+}
+
+
+static int
+virStorageBackendLogicalDeleteVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ unsigned int flags);
+
+
+static int
+virStorageBackendLogicalCreateVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol)
+{
+ int fd = -1;
+ char size[100];
+ const char *cmdargv[] = {
+ LVCREATE, "--name", vol->name, "-L", size,
+ pool->def->target.path, NULL
+ };
+
+ snprintf(size, sizeof(size)-1, "%lluK", vol->capacity/1024);
+ size[sizeof(size)-1] = '\0';
+
+ if (virRun(conn, (char**)cmdargv, NULL) < 0)
+ return -1;
+
+ if ((fd = open(vol->target.path, O_RDONLY)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read path '%s': %s"),
+ vol->target.path, strerror(errno));
+ goto cleanup;
+ }
+
+ /* We can only chown/grp if root */
+ if (getuid() == 0) {
+ if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot set file owner '%s': %s"),
+ vol->target.path, strerror(errno));
+ goto cleanup;
+ }
+ }
+ if (fchmod(fd, vol->target.perms.mode) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot set file mode '%s': %s"),
+ vol->target.path, strerror(errno));
+ goto cleanup;
+ }
+
+ if (close(fd) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot close file '%s': %s"),
+ vol->target.path, strerror(errno));
+ goto cleanup;
+ }
+ fd = -1;
+
+ /* Fill in data about this new vol */
+ if (virStorageBackendLogicalFindLVs(conn, pool, vol) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot find newly created volume '%s':
%s"),
+ vol->target.path, strerror(errno));
+ goto cleanup;
+ }
+
+ return 0;
+
+ cleanup:
+ if (fd != -1)
+ close(fd);
+ virStorageBackendLogicalDeleteVol(conn, pool, vol, 0);
+ return -1;
+}
+
+static int
+virStorageBackendLogicalDeleteVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ virStorageVolDefPtr vol,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ const char *cmdargv[] = {
+ LVREMOVE, "-f", vol->target.path, NULL
+ };
+
+ if (virRun(conn, (char**)cmdargv, NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+virStorageBackend virStorageBackendLogical = {
+ .type = VIR_STORAGE_POOL_LOGICAL,
+
+ .startPool = virStorageBackendLogicalStartPool,
+ .buildPool = virStorageBackendLogicalBuildPool,
+ .refreshPool = virStorageBackendLogicalRefreshPool,
+#if 0
+ .stopPool = virStorageBackendLogicalStopPool,
+#endif
+ .deletePool = virStorageBackendLogicalDeletePool,
+ .createVol = virStorageBackendLogicalCreateVol,
+ .deleteVol = virStorageBackendLogicalDeleteVol,
+
+ .poolOptions = {
+ .formatFromString = virStorageBackendLogicalPoolFormatFromString,
+ .formatToString = virStorageBackendLogicalPoolFormatToString,
+ },
+
+ .volType = VIR_STORAGE_VOL_BLOCK,
+};
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -r 555d6e919c35 src/storage_backend_logical.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_logical.h Tue Feb 19 17:31:03 2008 -0500
@@ -0,0 +1,45 @@
+/*
+ * storage_backend_logical.h: storage backend for logical volume handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#ifndef __VIR_STORAGE_BACKEND_LOGICAL_H__
+#define __VIR_STORAGE_BACKEND_LOGICAL_H__
+
+#include "storage_backend.h"
+
+extern virStorageBackend virStorageBackendLogical;
+
+#endif /* __VIR_STORAGE_BACKEND_LOGVOL_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules:
http://search.cpan.org/~danberr/ -=|
|=- Projects:
http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|