mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
Added disk partition storage pool backend
This commit is contained in:
parent
8ec1fcd925
commit
b7db975135
@ -1,3 +1,12 @@
|
||||
Wed Feb 20 10:46:27 EST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* configure.in: Added check for parted tool & libraries
|
||||
* libvirt.spec.in: Added dep on parted
|
||||
* po/POTFILES.in: Added storage_backend_disk.c
|
||||
* src/Makefile.am, src/storage_backend.c, src/parthelper.c,
|
||||
src/storage_backend_disk.c, src/storage_backend_disk.h: Added
|
||||
disk partition storage pool backend
|
||||
|
||||
Wed Feb 20 10:44:27 EST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* configure.in: Added check for iscsiadm tool
|
||||
|
48
configure.in
48
configure.in
@ -27,6 +27,7 @@ LIBXML_REQUIRED="2.5.0"
|
||||
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])
|
||||
@ -676,6 +679,50 @@ 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
|
||||
dnl check for python
|
||||
dnl
|
||||
@ -891,6 +938,7 @@ AC_MSG_NOTICE([ FS: $with_storage_fs])
|
||||
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([])
|
||||
|
@ -53,6 +53,8 @@ Requires: /usr/sbin/qcow-create
|
||||
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: /usr/sbin/qcow-create
|
||||
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
|
||||
|
@ -14,6 +14,7 @@ src/storage_backend.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
|
||||
|
@ -80,6 +80,13 @@ else
|
||||
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_DEPENDENCIES = $(DEPS)
|
||||
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
|
||||
#
|
||||
|
127
src/parthelper.c
Normal file
127
src/parthelper.c
Normal file
@ -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@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:
|
||||
*/
|
@ -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"
|
||||
@ -61,6 +64,9 @@ static virStorageBackendPtr backends[] = {
|
||||
#if WITH_STORAGE_ISCSI
|
||||
&virStorageBackendISCSI,
|
||||
#endif
|
||||
#if WITH_STORAGE_DISK
|
||||
&virStorageBackendDisk,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -111,6 +117,10 @@ virStorageBackendFromString(const char *type) {
|
||||
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,
|
||||
_("unknown storage backend type %s"), type);
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
537
src/storage_backend_disk.c
Normal file
537
src/storage_backend_disk.c
Normal file
@ -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@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:
|
||||
*/
|
45
src/storage_backend_disk.h
Normal file
45
src/storage_backend_disk.h
Normal file
@ -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@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:
|
||||
*/
|
Loading…
Reference in New Issue
Block a user