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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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 -=| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list