[Libvir] PATCH: 12/16: logical volume backend

Daniel P. Berrange berrange at redhat.com
Tue Feb 12 04:38:39 UTC 2008


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 |    6 
 b/src/storage_backend_logical.c |  497 ++++++++++++++++++++++++++++++++++++++++
 b/src/storage_backend_logical.h |   45 +++
 configure.in                    |   58 ++++
 libvirt.spec.in                 |    4 
 qemud/qemud.c                   |    4 
 src/Makefile.am                 |    8 
 src/storage_backend.c           |   14 +
 8 files changed, 635 insertions(+), 1 deletion(-)

diff -r 31abfd8687b3 configure.in
--- a/configure.in	Thu Feb 07 13:44:25 2008 -0500
+++ b/configure.in	Thu Feb 07 14:17:16 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 31abfd8687b3 docs/storage/pool-logical.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/pool-logical.xml	Thu Feb 07 14:17:16 2008 -0500
@@ -0,0 +1,6 @@
+<pool type="logical">
+  <name>HostVG</name>
+  <source>
+    <device>/dev/sda1</device>
+  </source>
+</pool>
diff -r 31abfd8687b3 libvirt.spec.in
--- a/libvirt.spec.in	Thu Feb 07 13:44:25 2008 -0500
+++ b/libvirt.spec.in	Thu Feb 07 14:17:16 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 31abfd8687b3 qemud/qemud.c
--- a/qemud/qemud.c	Thu Feb 07 13:44:25 2008 -0500
+++ b/qemud/qemud.c	Thu Feb 07 14:17:16 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 31abfd8687b3 src/Makefile.am
--- a/src/Makefile.am	Thu Feb 07 13:44:25 2008 -0500
+++ b/src/Makefile.am	Thu Feb 07 14:17:16 2008 -0500
@@ -69,6 +69,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 31abfd8687b3 src/storage_backend.c
--- a/src/storage_backend.c	Thu Feb 07 13:44:25 2008 -0500
+++ b/src/storage_backend.c	Thu Feb 07 14:17:16 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
 };
 
@@ -84,6 +90,10 @@ int virStorageBackendFromString(const ch
         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, "unknown storage backend type %s", type);
     return -1;
@@ -98,6 +108,10 @@ const char *virStorageBackendToString(in
         return "fs";
     case VIR_STORAGE_POOL_NETFS:
         return "netfs";
+#endif
+#if WITH_STORAGE_LVM
+    case VIR_STORAGE_POOL_LOGICAL:
+        return "logical";
 #endif
     }
 
diff -r 31abfd8687b3 src/storage_backend_logical.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_logical.c	Thu Feb 07 14:17:16 2008 -0500
@@ -0,0 +1,497 @@
+/*
+ * 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"
+
+
+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 (xstrtol_ull(groups[3], NULL, 10, &offset) < 0)
+        return -1;
+    if (xstrtol_ull(groups[4], NULL, 10, &length) < 0)
+        return -1;
+    if (xstrtol_ull(groups[5], NULL, 10, &size) < 0)
+        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 (xstrtol_ull(groups[0], NULL, 10, &pool->def->capacity) < 0)
+        return -1;
+    if (xstrtol_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;
+
+    /* XXX multiple pvs */
+    if ((vgargv = malloc(sizeof(char*) * (1))) == NULL) {
+        virStorageReportError(conn, VIR_ERR_NO_MEMORY, "argv");
+        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++) {
+        int fd;
+        char zeros[512];
+        memset(zeros, 0, sizeof(zeros));
+
+        /*
+         * LVM requires that the first 512 bytes are 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 (%d)",
+                                  strerror(errno), errno);
+            goto cleanup;
+        }
+        if (write(fd, zeros, sizeof(zeros)) != sizeof(zeros)) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  "cannot clear device header %s (%d)",
+                                  strerror(errno), errno);
+            close(fd);
+            goto cleanup;
+        }
+        if (close(fd) < 0) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  "cannot close device %s (%d)",
+                                  strerror(errno), 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': %d (%s)",
+                              vol->target.path, errno, 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': %d (%s)",
+                                  vol->target.path, errno, strerror(errno));
+            goto cleanup;
+        }
+    }
+    if (fchmod(fd, vol->target.perms.mode) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "cannot set file mode '%s': %d (%s)",
+                              vol->target.path, errno, strerror(errno));
+        goto cleanup;
+    }
+
+    if (close(fd) < 0) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "cannot close file '%s': %d (%s)",
+                              vol->target.path, errno, 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': %d (%s)",
+                              vol->target.path, errno, 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 31abfd8687b3 src/storage_backend_logical.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_logical.h	Thu Feb 07 14:17:16 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