[Libvir] PATCH: 14/16: disk partition backend
Daniel P. Berrange
berrange at redhat.com
Wed Feb 20 04:05:40 UTC 2008
On Tue, Feb 12, 2008 at 04:40:26AM +0000, Daniel P. Berrange wrote:
> This implements a storage pool for partitioning local disks.
> It uses parted as the tool for reading & writing disk partitions.
> Since parted is GPLv3, we cannot link against the code directly.
> So, this driver calls out to the regular 'parted' command line
> tool for creationg/deletion. For listing of partiitons we have
> a trivial helper program '/usr/libexec/libvirt_parthelper'. This
> outputs partition listing in a easily parseable format - each
> partition, or free space extent is a record, containing 5 fields.
> Records and fields are separated by NULLs. The internal libvirt
> helper API virStorageBackendRunProgNul can reliably parse this
> data format (thanks to Jim for the suggestion of using NULLs
> instead of whitespace, since the latter is not so easy to protect
> against bogus files)
>
> Creating volumes from disk partitions is more complex than most
> of the drivers. This is because partition tables have quite
> strict placement constraints. There are free extent regions
> and a partition must fall within one, and further more be aligned
> to a suitable byte boundary. For this reason the pool XML format
> will contain information about the free extents on a disk. The
> volume XML will also detail the actual extents used by a partition
> on disk.
>
> All of the parted partition table types are supported. A new disk
> can be initialized with the 'build' operation which will write a
> new partition table. When creating volumes a partition entry type
> can be specified if required. For simply assigning volumes to guests
> though, it is not neccessary to use anything other than the default
> of 'none'.
.hgignore | 1
b/src/parthelper.c | 127 ++++++++++
b/src/storage_backend_disk.c | 537 +++++++++++++++++++++++++++++++++++++++++++
b/src/storage_backend_disk.h | 45 +++
configure.in | 48 +++
libvirt.spec.in | 5
po/POTFILES.in | 1
src/Makefile.am | 18 +
src/storage_backend.c | 14 +
9 files changed, 796 insertions(+)
diff -r f54c0eb07193 .hgignore
--- a/.hgignore Tue Feb 19 17:38:39 2008 -0500
+++ b/.hgignore Tue Feb 19 17:43:53 2008 -0500
@@ -18,6 +18,7 @@ Makefile\.in$
^src/virsh
^src/libvirt.la
^src/\.libs
+^src/parthelper
^aclocal.m4$
^docs/devhelp/libvirt.devhelp$
^libtool$
diff -r f54c0eb07193 configure.in
--- a/configure.in Tue Feb 19 17:38:39 2008 -0500
+++ b/configure.in Tue Feb 19 17:43:53 2008 -0500
@@ -27,6 +27,7 @@ GNUTLS_REQUIRED="1.0.25"
GNUTLS_REQUIRED="1.0.25"
AVAHI_REQUIRED="0.6.0"
POLKIT_REQUIRED="0.6"
+PARTED_REQUIRED="1.8.0"
dnl Checks for C compiler.
AC_PROG_CC
@@ -563,6 +564,8 @@ AC_ARG_WITH(storage-lvm,
[ --with-storage-lvm with LVM backend for the storage driver (on)],[],[with_storage_lvm=check])
AC_ARG_WITH(storage-iscsi,
[ --with-storage-iscsi with iSCSI backend for the storage driver (on)],[],[with_storage_iscsi=check])
+AC_ARG_WITH(storage-disk,
+[ --with-storage-disk with GPartd Disk backend for the storage driver (on)],[],[with_storage_disk=check])
if test "$with_storage_fs" = "yes" -o "$with_storage_fs" = "check"; then
AC_PATH_PROG(MOUNT, [mount], [], [$PATH:/sbin:/usr/sbin])
@@ -674,6 +677,50 @@ if test "$with_storage_iscsi" = "yes" -o
fi
fi
AM_CONDITIONAL(WITH_STORAGE_ISCSI, [test "$with_storage_iscsi" = "yes"])
+
+
+
+LIBPARTED_CFLAGS=
+LIBPARTED_LIBS=
+if test "$with_storage_disk" = "yes" -o "$with_storage_disk" = "check"; then
+ AC_PATH_PROG(PARTED, [parted], [], [$PATH:/sbin:/usr/sbin])
+ if test -z "$PARTED" ; then with_storage_disk=no ; fi
+
+ PARTED_FOUND=yes
+ if test "$with_storage_disk" != "no" -a "x$PKG_CONFIG" != "x" ; then
+ PKG_CHECK_MODULES(LIBPARTED, libparted >= $PARTED_REQUIRED, [], [PARTED_FOUND=no])
+ fi
+ if test "$PARTED_FOUND" = "no"; then
+ # RHEL-5 vintage parted is missing pkg-config files
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ PARTED_FOUND=yes
+ AC_CHECK_HEADER(parted/parted.h,,[PARTED_FOUND=no])
+ AC_CHECK_LIB(uuid, uuid_generate,,[PARTED_FOUND=no])
+ AC_CHECK_LIB(parted, ped_device_read,,[PARTED_FOUND=no])
+ LIBPARTED_LIBS="-luuid -lparted"
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ fi
+
+ if test "$PARTED_FOUND" = "no" ; then
+ if test "$with_storage_disk" = "yes" ; then
+ AC_MSG_ERROR(We need parted for disk storage driver)
+ else
+ with_storage_disk=no
+ fi
+ else
+ with_storage_disk=yes
+ fi
+
+ if test "$with_storage_disk" = "yes"; then
+ AC_DEFINE_UNQUOTED(WITH_STORAGE_DISK, 1, [whether Disk backend for storage driver is enabled])
+ AC_DEFINE_UNQUOTED([PARTED],["$PARTED"], [Location or name of the parted program])
+ fi
+fi
+AM_CONDITIONAL(WITH_STORAGE_DISK, [test "$with_storage_disk" = "yes"])
+AC_SUBST(LIBPARTED_CFLAGS)
+AC_SUBST(LIBPARTED_LIBS)
dnl
@@ -891,6 +938,7 @@ AC_MSG_NOTICE([ NetFS: $with_storage_f
AC_MSG_NOTICE([ NetFS: $with_storage_fs])
AC_MSG_NOTICE([ LVM: $with_storage_lvm])
AC_MSG_NOTICE([ iSCSI: $with_storage_iscsi])
+AC_MSG_NOTICE([ Disk: $with_storage_disk])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Libraries])
AC_MSG_NOTICE([])
diff -r f54c0eb07193 libvirt.spec.in
--- a/libvirt.spec.in Tue Feb 19 17:38:39 2008 -0500
+++ b/libvirt.spec.in Tue Feb 19 17:43:53 2008 -0500
@@ -53,6 +53,8 @@ Requires: lvm2
Requires: lvm2
# For ISCSI driver
Requires: iscsi-initiator-utils
+# For disk driver
+Requires: parted
BuildRequires: xen-devel
BuildRequires: libxml2-devel
BuildRequires: readline-devel
@@ -81,6 +83,8 @@ BuildRequires: lvm2
BuildRequires: lvm2
# For ISCSI driver
BuildRequires: iscsi-initiator-utils
+# For disk driver
+BuildRequires: parted-devel
Obsoletes: libvir
ExclusiveArch: i386 x86_64 ia64
@@ -203,6 +207,7 @@ fi
%if %{with_proxy} == "yes"
%attr(4755, root, root) %{_libexecdir}/libvirt_proxy
%endif
+%attr(0755, root, root) %{_libexecdir}/libvirt_parthelper
%attr(0755, root, root) %{_sbindir}/libvirtd
%doc docs/*.rng
%doc docs/*.xml
diff -r f54c0eb07193 po/POTFILES.in
--- a/po/POTFILES.in Tue Feb 19 17:38:39 2008 -0500
+++ b/po/POTFILES.in Tue Feb 19 17:43:53 2008 -0500
@@ -14,6 +14,7 @@ src/storage_backend_fs.c
src/storage_backend_fs.c
src/storage_backend_logical.c
src/storage_backend_iscsi.c
+src/storage_backend_disk.c
src/storage_conf.c
src/storage_driver.c
src/sexpr.c
diff -r f54c0eb07193 src/Makefile.am
--- a/src/Makefile.am Tue Feb 19 17:38:39 2008 -0500
+++ b/src/Makefile.am Tue Feb 19 17:43:53 2008 -0500
@@ -80,6 +80,13 @@ EXTRA_DIST += storage_backend_iscsi.h s
EXTRA_DIST += storage_backend_iscsi.h storage_backend_iscsi.c
endif
+if WITH_STORAGE_DISK
+CLIENT_SOURCES += storage_backend_disk.h storage_backend_disk.c
+else
+EXTRA_DIST += storage_backend_disk.h storage_backend_disk.c
+endif
+
+
libvirt_la_SOURCES = $(CLIENT_SOURCES) $(SERVER_SOURCES)
@@ -99,6 +106,17 @@ virsh_LDADD = $(LDADDS) $(VIRSH_LIBS)
virsh_LDADD = $(LDADDS) $(VIRSH_LIBS)
virsh_CFLAGS = $(COVERAGE_CFLAGS) $(READLINE_CFLAGS)
+if WITH_STORAGE_DISK
+libexec_PROGRAMS = libvirt_parthelper
+
+libvirt_parthelper_SOURCES = parthelper.c
+libvirt_parthelper_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS)
+libvirt_parthelper_LDADD = $(LIBPARTED_LIBS)
+libvirt_parthelper_CFLAGS = $(LIBPARTED_CFLAGS)
+else
+EXTRA_DIST += parthelper.c
+endif
+
#
# target to ease building test programs
#
diff -r f54c0eb07193 src/parthelper.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/parthelper.c Tue Feb 19 17:43:53 2008 -0500
@@ -0,0 +1,127 @@
+/*
+ * parthelper.c: Helper program to talk to parted with.
+ *
+ * This helper exists because parted is GPLv3+, while libvirt is LGPLv2+.
+ * Thus we can't link to parted in libvirt.so without the combined work
+ * being GPLv3+. Thus we separate via an external command. NB, this source
+ * code is still LGPLv2+, but the binary helper is effectively GPLv3+
+ *
+ * The existing 'parted' command line tool is also incredibly hard to parse
+ * in a reliable fashion if merely after a list of partitions & sizes,
+ * though it is fine for creating partitions.
+ *
+ * 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 <parted/parted.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ PedDevice *dev;
+ PedDisk *disk;
+ PedPartition *part;
+
+ if (argc != 2) {
+ fprintf(stderr, "syntax: %s DEVICE\n", argv[0]);
+ return 1;
+ }
+
+ if ((dev = ped_device_get(argv[1])) == NULL) {
+ fprintf(stderr, "unable to access device %s\n", argv[1]);
+ return 2;
+ }
+
+ if ((disk = ped_disk_new(dev)) == NULL) {
+ fprintf(stderr, "unable to access disk %s\n", argv[1]);
+ return 2;
+ }
+
+ /* Get the first partition, and then iterate over all */
+ part = ped_disk_get_partition(disk, 1);
+ while (part) {
+ const char *type;
+ const char *content;
+ if (part->type & PED_PARTITION_LOGICAL) {
+ type = "logical";
+ if (part->type & PED_PARTITION_FREESPACE)
+ content = "free";
+ else if (part->type & PED_PARTITION_METADATA)
+ content = "metadata";
+ else if (part->type & PED_PARTITION_PROTECTED)
+ content = "protected";
+ else
+ content = "data";
+ } else if (part->type == PED_PARTITION_EXTENDED) {
+ type = "extended";
+ content = "metadata";
+ } else {
+ type = "normal";
+ if (part->type & PED_PARTITION_FREESPACE)
+ content = "free";
+ else if (part->type & PED_PARTITION_METADATA)
+ content = "metadata";
+ else if (part->type & PED_PARTITION_PROTECTED)
+ content = "protected";
+ else
+ content = "data";
+ }
+
+ /* We do +1 on geom.end, because we want end of the last sector
+ * in bytes, not the last sector number
+ */
+ if (part->num != -1) {
+ printf("%s%d%c%s%c%s%c%llu%c%llu%c%llu%c",
+ part->geom.dev->path,
+ part->num, '\0',
+ type, '\0',
+ content, '\0',
+ part->geom.start * 512llu, '\0',
+ (part->geom.end + 1 ) * 512llu, '\0',
+ part->geom.length * 512llu, '\0');
+ } else {
+ printf("%s%c%s%c%s%c%llu%c%llu%c%llu%c",
+ "-", '\0',
+ type, '\0',
+ content, '\0',
+ part->geom.start * 512llu, '\0',
+ (part->geom.end + 1 ) * 512llu, '\0',
+ part->geom.length * 512llu, '\0');
+ }
+ part = ped_disk_next_partition(disk, part);
+ }
+
+ return 0;
+}
+/*
+ * 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 f54c0eb07193 src/storage_backend.c
--- a/src/storage_backend.c Tue Feb 19 17:38:39 2008 -0500
+++ b/src/storage_backend.c Tue Feb 19 17:43:53 2008 -0500
@@ -42,6 +42,9 @@
#if WITH_STORAGE_ISCSI
#include "storage_backend_iscsi.h"
#endif
+#if WITH_STORAGE_DISK
+#include "storage_backend_disk.h"
+#endif
#include "util.h"
@@ -60,6 +63,9 @@ static virStorageBackendPtr backends[] =
#endif
#if WITH_STORAGE_ISCSI
&virStorageBackendISCSI,
+#endif
+#if WITH_STORAGE_DISK
+ &virStorageBackendDisk,
#endif
};
@@ -110,6 +116,10 @@ virStorageBackendFromString(const char *
#if WITH_STORAGE_ISCSI
if (STREQ(type, "iscsi"))
return VIR_STORAGE_POOL_ISCSI;
+#endif
+#if WITH_STORAGE_DISK
+ if (STREQ(type, "disk"))
+ return VIR_STORAGE_POOL_DISK;
#endif
virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
@@ -135,6 +145,10 @@ virStorageBackendToString(int type) {
#if WITH_STORAGE_ISCSI
case VIR_STORAGE_POOL_ISCSI:
return "iscsi";
+#endif
+#if WITH_STORAGE_DISK
+ case VIR_STORAGE_POOL_DISK:
+ return "disk";
#endif
}
diff -r f54c0eb07193 src/storage_backend_disk.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_disk.c Tue Feb 19 17:43:53 2008 -0500
@@ -0,0 +1,537 @@
+/*
+ * storage_backend_disk.c: storage backend for disk 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 "storage_backend_disk.h"
+#include "util.h"
+
+enum {
+ VIR_STORAGE_POOL_DISK_DOS = 0,
+ VIR_STORAGE_POOL_DISK_DVH,
+ VIR_STORAGE_POOL_DISK_GPT,
+ VIR_STORAGE_POOL_DISK_MAC,
+ VIR_STORAGE_POOL_DISK_BSD,
+ VIR_STORAGE_POOL_DISK_PC98,
+ VIR_STORAGE_POOL_DISK_SUN,
+};
+
+/*
+ * XXX these are basically partition types.
+ *
+ * fdisk has a bazillion partition ID types
+ * parted has practically none, and splits the
+ * info across 3 different attributes.
+ *
+ * So this is a semi-generic set
+ */
+enum {
+ VIR_STORAGE_VOL_DISK_NONE = 0,
+ VIR_STORAGE_VOL_DISK_LINUX,
+ VIR_STORAGE_VOL_DISK_FAT16,
+ VIR_STORAGE_VOL_DISK_FAT32,
+ VIR_STORAGE_VOL_DISK_LINUX_SWAP,
+ VIR_STORAGE_VOL_DISK_LINUX_LVM,
+ VIR_STORAGE_VOL_DISK_LINUX_RAID,
+ VIR_STORAGE_VOL_DISK_EXTENDED,
+};
+
+#define PARTHELPER BINDIR "/libvirt_parthelper"
+
+static int
+virStorageBackendDiskPoolFormatFromString(virConnectPtr conn,
+ const char *format) {
+ if (format == NULL)
+ return VIR_STORAGE_POOL_DISK_DOS;
+
+ if (STREQ(format, "dos"))
+ return VIR_STORAGE_POOL_DISK_DOS;
+ if (STREQ(format, "dvh"))
+ return VIR_STORAGE_POOL_DISK_DVH;
+ if (STREQ(format, "gpt"))
+ return VIR_STORAGE_POOL_DISK_GPT;
+ if (STREQ(format, "mac"))
+ return VIR_STORAGE_POOL_DISK_MAC;
+ if (STREQ(format, "bsd"))
+ return VIR_STORAGE_POOL_DISK_BSD;
+ if (STREQ(format, "pc98"))
+ return VIR_STORAGE_POOL_DISK_PC98;
+ if (STREQ(format, "sun"))
+ return VIR_STORAGE_POOL_DISK_SUN;
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported pool format %s"), format);
+ return -1;
+}
+
+static const char *
+virStorageBackendDiskPoolFormatToString(virConnectPtr conn,
+ int format) {
+ switch (format) {
+ case VIR_STORAGE_POOL_DISK_DOS:
+ return "dos";
+ case VIR_STORAGE_POOL_DISK_DVH:
+ return "dvh";
+ case VIR_STORAGE_POOL_DISK_GPT:
+ return "gpt";
+ case VIR_STORAGE_POOL_DISK_MAC:
+ return "mac";
+ case VIR_STORAGE_POOL_DISK_BSD:
+ return "bsd";
+ case VIR_STORAGE_POOL_DISK_PC98:
+ return "pc98";
+ case VIR_STORAGE_POOL_DISK_SUN:
+ return "sun";
+ }
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported pool format %d"), format);
+ return NULL;
+}
+
+static int
+virStorageBackendDiskVolFormatFromString(virConnectPtr conn,
+ const char *format) {
+ if (format == NULL)
+ return VIR_STORAGE_VOL_DISK_NONE;
+
+ if (STREQ(format, "none"))
+ return VIR_STORAGE_VOL_DISK_NONE;
+ if (STREQ(format, "linux"))
+ return VIR_STORAGE_VOL_DISK_LINUX;
+ if (STREQ(format, "fat16"))
+ return VIR_STORAGE_VOL_DISK_FAT16;
+ if (STREQ(format, "fat32"))
+ return VIR_STORAGE_VOL_DISK_FAT32;
+ if (STREQ(format, "linux-swap"))
+ return VIR_STORAGE_VOL_DISK_LINUX_SWAP;
+ if (STREQ(format, "linux-lvm"))
+ return VIR_STORAGE_VOL_DISK_LINUX_LVM;
+ if (STREQ(format, "linux-raid"))
+ return VIR_STORAGE_VOL_DISK_LINUX_RAID;
+ if (STREQ(format, "extended"))
+ return VIR_STORAGE_VOL_DISK_EXTENDED;
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported volume format %s"), format);
+ return -1;
+}
+
+static const char *
+virStorageBackendDiskVolFormatToString(virConnectPtr conn,
+ int format) {
+ switch (format) {
+ case VIR_STORAGE_VOL_DISK_NONE:
+ return "none";
+ case VIR_STORAGE_VOL_DISK_LINUX:
+ return "linux";
+ case VIR_STORAGE_VOL_DISK_FAT16:
+ return "fat16";
+ case VIR_STORAGE_VOL_DISK_FAT32:
+ return "fat32";
+ case VIR_STORAGE_VOL_DISK_LINUX_SWAP:
+ return "linux-swap";
+ case VIR_STORAGE_VOL_DISK_LINUX_LVM:
+ return "linux-lvm";
+ case VIR_STORAGE_VOL_DISK_LINUX_RAID:
+ return "linux-raid";
+ case VIR_STORAGE_VOL_DISK_EXTENDED:
+ return "extended";
+ }
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported volume format %d"), format);
+ return NULL;
+}
+
+static int
+virStorageBackendDiskMakeDataVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ char **const groups,
+ virStorageVolDefPtr vol)
+{
+ char *tmp, *devpath;
+
+ if (vol == NULL) {
+ if ((vol = calloc(1, sizeof(virStorageVolDef))) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("volume"));
+ return -1;
+ }
+
+ vol->next = pool->volumes;
+ pool->volumes = vol;
+ pool->nvolumes++;
+
+ /* Prepended path will be same for all partitions, so we can
+ * strip the path to form a reasonable pool-unique name
+ */
+ tmp = strrchr(groups[0], '/');
+ if ((vol->name = strdup(tmp ? tmp + 1 : groups[0])) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("volume"));
+ return -1;
+ }
+ }
+
+ if (vol->target.path == NULL) {
+ if ((devpath = strdup(groups[0])) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("volume"));
+ return -1;
+ }
+
+ /* Now figure out the stable path
+ *
+ * XXX this method is O(N) because it scans the pool target
+ * dir every time its run. Should figure out a more efficient
+ * way of doing this...
+ */
+ if ((vol->target.path = virStorageBackendStablePath(conn,
+ pool,
+ devpath)) == NULL)
+ return -1;
+
+ if (devpath != vol->target.path)
+ free(devpath);
+ devpath = NULL;
+ }
+
+ if (vol->key == NULL) {
+ /* XXX base off a unique key of the underlying disk */
+ if ((vol->key = strdup(vol->target.path)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("volume"));
+ return -1;
+ }
+ }
+
+ if (vol->source.extents == NULL) {
+ if ((vol->source.extents =
+ calloc(1, sizeof(*(vol->source.extents)))) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("volume extents"));
+ return -1;
+ }
+ vol->source.nextent = 1;
+
+ if (virStrToLong_ull(groups[3], NULL, 10,
+ &vol->source.extents[0].start) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse device start location"));
+ return -1;
+ }
+
+ if (virStrToLong_ull(groups[4], NULL, 10,
+ &vol->source.extents[0].end) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse device end location"));
+ return -1;
+ }
+
+ if ((vol->source.extents[0].path =
+ strdup(pool->def->source.devices[0].path)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("extents"));
+ return -1;
+ }
+ }
+
+ /* Refresh allocation/capacity/perms */
+ if (virStorageBackendUpdateVolInfo(conn, vol, 1) < 0)
+ return -1;
+
+ /* The above gets allocation wrong for
+ * extended partitions, so overwrite it */
+ vol->allocation = vol->capacity =
+ (vol->source.extents[0].end - vol->source.extents[0].start);
+
+ if (STRNEQ(groups[2], "metadata"))
+ pool->def->allocation += vol->allocation;
+ if (vol->source.extents[0].end > pool->def->capacity)
+ pool->def->capacity = vol->source.extents[0].end;
+
+ return 0;
+}
+
+static int
+virStorageBackendDiskMakeFreeExtent(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool,
+ char **const groups)
+{
+ virStoragePoolSourceDeviceExtentPtr tmp;
+ virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];
+
+ if ((tmp = realloc(dev->freeExtents,
+ sizeof(*tmp) * (dev->nfreeExtent+1))) == NULL)
+ return -1;
+ dev->freeExtents = tmp;
+
+ memset(dev->freeExtents +
+ dev->nfreeExtent, 0, sizeof(*tmp));
+
+ if (virStrToLong_ull(groups[3], NULL, 10,
+ &dev->freeExtents[dev->nfreeExtent].start) < 0)
+ return -1; /* Don't bother to re-alloc freeExtents - it'll be free'd shortly */
+
+ if (virStrToLong_ull(groups[4], NULL, 10,
+ &dev->freeExtents[dev->nfreeExtent].end) < 0)
+ return -1; /* Don't bother to re-alloc freeExtents - it'll be free'd shortly */
+
+ pool->def->available +=
+ (dev->freeExtents[dev->nfreeExtent].end -
+ dev->freeExtents[dev->nfreeExtent].start);
+ if (dev->freeExtents[dev->nfreeExtent].end > pool->def->capacity)
+ pool->def->capacity = dev->freeExtents[dev->nfreeExtent].end;
+
+ dev->nfreeExtent++;
+
+ return 0;
+}
+
+
+static int
+virStorageBackendDiskMakeVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ size_t ntok ATTRIBUTE_UNUSED,
+ char **const groups,
+ void *data)
+{
+ /*
+ * Ignore normal+metadata, and logical+metadata partitions
+ * since they're basically internal book-keeping regions
+ * we have no control over. Do keep extended+metadata though
+ * because that's the MS-DOS extended partition region we
+ * need to be able to view/create/delete
+ */
+ if ((STREQ(groups[1], "normal") ||
+ STREQ(groups[1], "logical")) &&
+ STREQ(groups[2], "metadata"))
+ return 0;
+
+ /* Remaining data / metdata parts get turn into volumes... */
+ if (STREQ(groups[2], "metadata") ||
+ STREQ(groups[2], "data")) {
+ virStorageVolDefPtr vol = data;
+ /* We're searching for a specific vol only, so ignore others */
+ if (vol &&
+ STRNEQ(vol->name, groups[0]))
+ return 0;
+
+ return virStorageBackendDiskMakeDataVol(conn, pool, groups, vol);
+ } else if (STREQ(groups[2], "free")) {
+ /* ....or free space extents */
+ return virStorageBackendDiskMakeFreeExtent(conn, pool, groups);
+ } else {
+ /* This codepath should never happen unless someone changed
+ * libvirt_parthelper forgot to change this code */
+ return -1;
+ }
+}
+
+
+/* To get a list of partitions we run an external helper
+ * tool which then uses parted APIs. This is because
+ * parted's API is not compatible with libvirt's license
+ * but we really really want to use parted because the
+ * other options all suck :-)
+ *
+ * All the other storage backends run an external tool for
+ * listing volumes so this really isn't too much of a pain,
+ * and we can even ensure the output is friendly.
+ */
+static int
+virStorageBackendDiskReadPartitions(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol)
+{
+
+ /*
+ * # libvirt_parthelper DEVICE
+ * /dev/sda1 normal data 32256 106928128 106896384
+ * /dev/sda2 normal data 106928640 100027629568 99920701440
+ * - normal metadata 100027630080 100030242304 2612736
+ *
+ */
+ const char *prog[] = {
+ PARTHELPER, pool->def->source.devices[0].path, NULL,
+ };
+
+ pool->def->allocation = pool->def->capacity = pool->def->available = 0;
+
+ return virStorageBackendRunProgNul(conn,
+ pool,
+ prog,
+ 6,
+ virStorageBackendDiskMakeVol,
+ vol);
+}
+
+
+static int
+virStorageBackendDiskRefreshPool(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ free(pool->def->source.devices[0].freeExtents);
+ pool->def->source.devices[0].nfreeExtent = 0;
+ pool->def->source.devices[0].freeExtents = NULL;
+
+ return virStorageBackendDiskReadPartitions(conn, pool, NULL);
+}
+
+
+/**
+ * Write a new partition table header
+ */
+static int
+virStorageBackendDiskBuildPool(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ /* eg parted /dev/sda mklabel msdos */
+ const char *prog[] = {
+ PARTED,
+ pool->def->source.devices[0].path,
+ "mklabel",
+ virStorageBackendDiskPoolFormatToString(conn, pool->def->source.format),
+ NULL,
+ };
+
+ if (virRun(conn, (char**)prog, NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+virStorageBackendDiskDeleteVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ unsigned int flags);
+
+static int
+virStorageBackendDiskCreateVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol)
+{
+ int i;
+ char start[100], end[100];
+ unsigned long long startOffset, endOffset, smallestSize = 0;
+ int smallestExtent = -1;
+ virStoragePoolSourceDevicePtr dev = &pool->def->source.devices[0];
+ /* XXX customizable partition types */
+ const char *cmdargv[] = {
+ PARTED,
+ pool->def->source.devices[0].path,
+ "mkpart",
+ "--script",
+ "ext2",
+ start,
+ end,
+ NULL
+ };
+
+ for (i = 0 ; i < dev->nfreeExtent ; i++) {
+ unsigned long long size =
+ dev->freeExtents[i].end -
+ dev->freeExtents[i].start;
+ if (size > vol->allocation &&
+ (smallestSize == 0 ||
+ size < smallestSize)) {
+ smallestSize = size;
+ smallestExtent = i;
+ }
+ }
+ if (smallestExtent == -1) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("no large enough free extent"));
+ return -1;
+ }
+ startOffset = dev->freeExtents[smallestExtent].start;
+ endOffset = startOffset + vol->allocation;
+
+ snprintf(start, sizeof(start)-1, "%lluB", startOffset);
+ start[sizeof(start)-1] = '\0';
+ snprintf(end, sizeof(end)-1, "%lluB", endOffset);
+ end[sizeof(end)-1] = '\0';
+
+ if (virRun(conn, (char**)cmdargv, NULL) < 0)
+ return -1;
+
+ /* Blow away free extent info, as we're about to re-populate it */
+ free(pool->def->source.devices[0].freeExtents);
+ pool->def->source.devices[0].nfreeExtent = 0;
+ pool->def->source.devices[0].freeExtents = NULL;
+
+ /* Fetch actual extent info */
+ if (virStorageBackendDiskReadPartitions(conn, pool, vol) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+virStorageBackendDiskDeleteVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ virStorageVolDefPtr vol ATTRIBUTE_UNUSED,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ /* delete a partition */
+ virStorageReportError(conn, VIR_ERR_NO_SUPPORT,
+ _("Disk pools are not yet supported"));
+ return -1;
+}
+
+
+virStorageBackend virStorageBackendDisk = {
+ .type = VIR_STORAGE_POOL_DISK,
+
+ .buildPool = virStorageBackendDiskBuildPool,
+ .refreshPool = virStorageBackendDiskRefreshPool,
+
+ .createVol = virStorageBackendDiskCreateVol,
+ .deleteVol = virStorageBackendDiskDeleteVol,
+
+ .poolOptions = {
+ .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE),
+ .formatFromString = virStorageBackendDiskPoolFormatFromString,
+ .formatToString = virStorageBackendDiskPoolFormatToString,
+ },
+ .volOptions = {
+ .formatFromString = virStorageBackendDiskVolFormatFromString,
+ .formatToString = virStorageBackendDiskVolFormatToString,
+ },
+
+ .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 f54c0eb07193 src/storage_backend_disk.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_disk.h Tue Feb 19 17:43:53 2008 -0500
@@ -0,0 +1,45 @@
+/*
+ * storage_backend_disk.h: storage backend for disk 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_DISK_H__
+#define __VIR_STORAGE_BACKEND_DISK_H__
+
+#include "storage_backend.h"
+
+extern virStorageBackend virStorageBackendDisk;
+
+#endif /* __VIR_STORAGE_BACKEND_DISK_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