[Libvir] PATCH: 12/16: logical volume backend
Daniel P. Berrange
berrange at redhat.com
Wed Feb 20 04:04:31 UTC 2008
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 at 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 at 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 -=|
More information about the libvir-list
mailing list