Last March, DanPB posted code to create pools from SCSI HBAs. This patch is simply
bringing that code into the current tree.
* src/storage_backend_scsi.[ch] contain the pool implementataion
* There are small changes to several other source files to integrate the new pool type.
---
configure.in | 13 ++-
po/POTFILES.in | 1 +
src/Makefile.am | 9 +
src/storage_backend.c | 6 +
src/storage_backend_scsi.c | 471 ++++++++++++++++++++++++++++++++++++++++++++
src/storage_backend_scsi.h | 45 +++++
src/storage_conf.c | 18 ++
7 files changed, 562 insertions(+), 1 deletions(-)
create mode 100644 src/storage_backend_scsi.c
create mode 100644 src/storage_backend_scsi.h
diff --git a/configure.in b/configure.in
index d2e8252..b88a7d5 100644
--- a/configure.in
+++ b/configure.in
@@ -739,6 +739,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-scsi],
+[ --with-storage-scsi with SCSI backend for the storage driver
(on)],[],[with_storage_scsi=check])
AC_ARG_WITH([storage-disk],
[ --with-storage-disk with GPartd Disk backend for the storage driver
(on)],[],[with_storage_disk=check])
@@ -748,6 +750,7 @@ if test "$with_libvirtd" = "no"; then
with_storage_fs=no
with_storage_lvm=no
with_storage_iscsi=no
+ with_storage_scsi=no
with_storage_disk=no
fi
if test "$with_storage_dir" = "yes" ; then
@@ -876,6 +879,13 @@ if test "$with_storage_iscsi" = "yes" -o
"$with_storage_iscsi" = "check"; then
fi
AM_CONDITIONAL([WITH_STORAGE_ISCSI], [test "$with_storage_iscsi" =
"yes"])
+if test "$with_storage_scsi" = "check"; then
+ with_storage_scsi=yes
+
+ AC_DEFINE_UNQUOTED([WITH_STORAGE_SCSI], 1,
+ [whether SCSI backend for storage driver is enabled])
+ AM_CONDITIONAL([WITH_STORAGE_SCSI], [test "$with_storage_scsi" =
"yes"])
+fi
LIBPARTED_CFLAGS=
@@ -1158,7 +1168,7 @@ LV_LIBTOOL_OBJDIR=${lt_cv_objdir-.}
AC_SUBST([LV_LIBTOOL_OBJDIR])
dnl HAL or DeviceKit library for host device enumeration
-HAL_REQUIRED=0.0
+HAL_REQUIRED=0.5.0
HAL_CFLAGS=
HAL_LIBS=
AC_ARG_WITH([hal],
@@ -1312,6 +1322,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([ SCSI: $with_storage_scsi])
AC_MSG_NOTICE([ Disk: $with_storage_disk])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Driver Loadable Modules])
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7461f93..4433183 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -27,6 +27,7 @@ src/storage_backend_disk.c
src/storage_backend_fs.c
src/storage_backend_iscsi.c
src/storage_backend_logical.c
+src/storage_backend_scsi.c
src/storage_conf.c
src/storage_driver.c
src/test.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 3a798d2..f1dd789 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,6 +9,7 @@ INCLUDES = \
$(XEN_CFLAGS) \
$(SELINUX_CFLAGS) \
$(DRIVER_MODULE_CFLAGS) \
+ $(POLKIT_CFLAGS) \
-DLIBDIR=\""$(libdir)"\" \
-DBINDIR=\""$(libexecdir)"\" \
-DSBINDIR=\""$(sbindir)"\" \
@@ -158,6 +159,9 @@ STORAGE_DRIVER_LVM_SOURCES = \
STORAGE_DRIVER_ISCSI_SOURCES = \
storage_backend_iscsi.h storage_backend_iscsi.c
+STORAGE_DRIVER_SCSI_SOURCES = \
+ storage_backend_scsi.h storage_backend_scsi.c
+
STORAGE_DRIVER_DISK_SOURCES = \
storage_backend_disk.h storage_backend_disk.c
@@ -344,6 +348,10 @@ if WITH_STORAGE_ISCSI
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_ISCSI_SOURCES)
endif
+if WITH_STORAGE_SCSI
+libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_SCSI_SOURCES)
+endif
+
if WITH_STORAGE_DISK
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES)
endif
@@ -392,6 +400,7 @@ EXTRA_DIST += \
$(STORAGE_DRIVER_FS_SOURCES) \
$(STORAGE_DRIVER_LVM_SOURCES) \
$(STORAGE_DRIVER_ISCSI_SOURCES) \
+ $(STORAGE_DRIVER_SCSI_SOURCES) \
$(STORAGE_DRIVER_DISK_SOURCES) \
$(NODE_DEVICE_DRIVER_SOURCES) \
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
diff --git a/src/storage_backend.c b/src/storage_backend.c
index 8408f34..95173fa 100644
--- a/src/storage_backend.c
+++ b/src/storage_backend.c
@@ -54,6 +54,9 @@
#if WITH_STORAGE_ISCSI
#include "storage_backend_iscsi.h"
#endif
+#if WITH_STORAGE_SCSI
+#include "storage_backend_scsi.h"
+#endif
#if WITH_STORAGE_DISK
#include "storage_backend_disk.h"
#endif
@@ -78,6 +81,9 @@ static virStorageBackendPtr backends[] = {
#if WITH_STORAGE_ISCSI
&virStorageBackendISCSI,
#endif
+#if WITH_STORAGE_SCSI
+ &virStorageBackendSCSI,
+#endif
#if WITH_STORAGE_DISK
&virStorageBackendDisk,
#endif
diff --git a/src/storage_backend_scsi.c b/src/storage_backend_scsi.c
new file mode 100644
index 0000000..236d894
--- /dev/null
+++ b/src/storage_backend_scsi.c
@@ -0,0 +1,471 @@
+/*
+ * storage_backend_scsi.c: storage backend for SCSI 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 <c-ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <hal/libhal.h>
+
+#include "virterror_internal.h"
+#include "storage_backend_scsi.h"
+#include "memory.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+#define LINUX_SYSFS_SCSI_HOST_PREFIX "/sys/class/scsi_host/"
+#define LINUX_SYSFS_SCSI_HOST_POSTFIX "/device"
+
+
+/**
+ * virStorageBackendSCSIMakeHostDevice:
+ * @conn: report errors agains
+ * @pool: pool to resolve
+ * @buf: pre-allocated buffer to fill with path name
+ * @buflen: size of buffer
+ *
+ * Resolve a HBA name to HBA device path
+ *
+ * Given a pool object configured for a SCSI HBA, resolve the HBA name
+ * into the canonical sysfs path for the HBA device. This can then be
+ * used to lookup the device in HAL.
+ *
+ * Returns 0 on success, -1 on failure
+ */
+static int virStorageBackendSCSIMakeHostDevice(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ char *buf,
+ size_t buflen)
+{
+ char *dev = NULL;
+ char *tmp = pool->def->source.adapter;
+ char relLink[PATH_MAX], absLink[PATH_MAX];
+ ssize_t len;
+
+ if (!tmp) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Missing adapter name for pool"));
+ return -1;
+ }
+
+ /* Sanity check host adapter name - should only be 0-9, a-z.
+ * Anything else is bogus & so we reject it, to prevent them
+ * making us read arbitrary paths on host
+ */
+ while (*tmp) {
+ if (!c_isalnum(*tmp)) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid character in pool adapter name
'%s'"),
+ pool->def->source.adapter);
+ return -1;
+ }
+ tmp++;
+ }
+
+ /*
+ * First get the class based path eg
+ *
+ * /sys/class/scsi_host/host1/device
+ */
+ if ((dev = malloc(sizeof(LINUX_SYSFS_SCSI_HOST_PREFIX) +
+ strlen(pool->def->source.adapter) +
+ sizeof(LINUX_SYSFS_SCSI_HOST_POSTFIX) +
+ 1)) == NULL) {
+ virReportOOMError(conn);
+ return -1;
+ }
+
+ strcpy(dev, LINUX_SYSFS_SCSI_HOST_PREFIX);
+ strcat(dev, pool->def->source.adapter);
+ strcat(dev, LINUX_SYSFS_SCSI_HOST_POSTFIX);
+
+ /*
+ * Now resolve the class based path symlink to the real
+ * device path, which is likely under PCI bus hierarchy
+ * and is the path tracked by HAL
+ */
+ /* Readlink does not null terminate, so we reserve one byte */
+ if ((len = readlink(dev, relLink, sizeof(relLink)-1)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot find SCSI host adapter '%s' at
'%s'"),
+ pool->def->source.adapter, dev);
+ free(dev);
+ return -1;
+ }
+ relLink[len] = '\0';
+
+
+ /*
+ * The symlink is relative, so now we have to turn it
+ * into a absolute path
+ */
+ if ((tmp = realloc(dev,
+ sizeof(LINUX_SYSFS_SCSI_HOST_PREFIX) +
+ strlen(pool->def->source.adapter) +
+ 1 +
+ strlen(relLink) +
+ 1)) == NULL) {
+ virReportOOMError(conn);
+ free(dev);
+ return -1;
+ }
+ dev = tmp;
+
+ strcpy(dev, LINUX_SYSFS_SCSI_HOST_PREFIX);
+ strcat(dev, pool->def->source.adapter);
+ strcat(dev, "/");
+ strcat(dev, relLink);
+
+ /*
+ * And finally canonicalize the absolute path to remove the
+ * copious .. components
+ */
+ if (!realpath(dev, absLink)) {
+ char ebuf[1024];
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot canonicalize link: %s"),
+ virStrerror(errno, ebuf, sizeof ebuf));
+ free(dev);
+ return -1;
+ }
+ free(dev);
+
+ if (strlen(absLink) >= buflen) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("link too long for buffer"));
+ return -1;
+ }
+ strcpy(buf, absLink);
+
+ return 0;
+}
+
+
+/**
+ * virStorageBackendSCSICreateVol
+ *
+ * Allocate a virStorageVolDef object for the specified
+ * metadata and hook it into the pool
+ *
+ * Returns 0 on success, -1 on failure
+ */
+static int
+virStorageBackendSCSICreateVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ const char *name,
+ const char *path,
+ const char *key,
+ unsigned long long size)
+{
+ virStorageVolDefPtr vol;
+ char *tmppath;
+
+ if (VIR_ALLOC(vol) < 0) {
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+
+ vol->type = VIR_STORAGE_VOL_BLOCK;
+
+ tmppath = strdup(path);
+ vol->name = strdup(name);
+ vol->key = strdup(key);
+ vol->allocation = vol->capacity = size;
+
+ if ((vol->name == NULL) ||
+ (vol->key == NULL) ||
+ (tmppath == NULL)) {
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+
+ /* 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,
+ tmppath)) == NULL)
+ goto cleanup;
+
+ if (tmppath != vol->target.path)
+ free(tmppath);
+ tmppath = NULL;
+
+ if (virStorageBackendUpdateVolInfo(conn, vol, 1) < 0)
+ goto cleanup;
+
+ pool->def->capacity += vol->capacity;
+ pool->def->allocation += vol->allocation;
+
+ if (VIR_REALLOC_N(pool->volumes.objs,
+ pool->volumes.count+1) < 0) {
+ virReportOOMError(conn);
+ virStorageVolDefFree(vol);
+ goto cleanup;
+ }
+ pool->volumes.objs[pool->volumes.count++] = vol;
+
+ return 0;
+
+cleanup:
+ free(tmppath);
+ virStorageVolDefFree(vol);
+ return -1;
+}
+
+
+/**
+ * virStorageBackendSCSIAddLUN:
+ *
+ * @conn: connection to report errors against
+ * @pool: pool to register volume with
+ * @ctx: HAL context
+ * @devname: HAL device name for LUN
+ *
+ * Given a HAL device supported 'block' and 'storage' capabilities
+ * register it as a volume in the pool
+ *
+ * Returns 0 on success, -1 on error
+ */
+static int
+virStorageBackendSCSIAddLUN(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ LibHalContext *ctx,
+ const char *devname)
+{
+ char **strdevs = NULL;
+ int numstrdevs = 0;
+ char *dev = NULL, *key = NULL;
+ unsigned long long size;
+ int host, bus, target, lun;
+ int n = -1, i;
+ int ret = -1;
+ char name[100];
+ DBusError derr = DBUS_ERROR_INIT;
+
+ if ((strdevs = libhal_manager_find_device_string_match(ctx,
+ "info.parent",
+ devname,
+ &numstrdevs,
+ &derr)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("HAL failed to lookup LUNs for '%s':
%s"),
+ devname, derr.message);
+ goto cleanup;
+ }
+ for (i = 0 ; i < numstrdevs && n == -1 ; i++) {
+ char *cat = libhal_device_get_property_string(ctx,
+ strdevs[0],
+ "info.category",
+ NULL);
+ /* XXX derr */
+ if (cat != NULL) {
+ if (STREQ(cat, "storage"))
+ n = i;
+ free(cat);
+ }
+ }
+ /* No storage vol for device - probably a removable vol so ignore */
+ if (n == -1) {
+ ret = 0;
+ goto cleanup;
+ }
+
+#define HAL_GET_PROPERTY(path, name, err, type, value) \
+ (value) = libhal_device_get_property_ ## type(ctx, (path), (name), (err)); \
+ if (dbus_error_is_set((err))) { \
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, \
+ "unable to lookup '%s' property on %s:
%s", \
+ (name), (path), derr.message); \
+ goto cleanup; \
+ }
+
+ /* These are props of the physical device */
+ HAL_GET_PROPERTY(devname, "scsi.host", &derr, int, host);
+ HAL_GET_PROPERTY(devname, "scsi.bus", &derr, int, bus);
+ HAL_GET_PROPERTY(devname, "scsi.target", &derr, int, target);
+ HAL_GET_PROPERTY(devname, "scsi.lun", &derr, int, lun);
+
+ /* These are props of the logic device */
+ HAL_GET_PROPERTY(strdevs[0], "block.device", &derr, string, dev);
+ /*
+ * XXX storage.serial is not actually unique if they have
+ * multipath on the fibre channel adapter
+ */
+ HAL_GET_PROPERTY(strdevs[0], "storage.serial", &derr, string, key);
+ HAL_GET_PROPERTY(strdevs[0], "storage.size", &derr, uint64, size);
+
+#undef HAL_GET_PROPERTY
+
+ snprintf(name, sizeof(name), "%d:%d:%d:%d", host, bus, target, lun);
+ name[sizeof(name)-1] = '\0';
+
+ if (virStorageBackendSCSICreateVol(conn, pool, name, dev, key, size) < 0)
+ goto cleanup;
+ ret = 0;
+
+cleanup:
+ for (i = 0 ; strdevs && i < numstrdevs ; i++)
+ free(strdevs[i]);
+ free(strdevs);
+ free(dev);
+ free(key);
+ if (dbus_error_is_set(&derr))
+ dbus_error_free(&derr);
+ return ret;
+}
+
+
+/**
+ * virStorageBackendSCSIRefreshPool:
+ *
+ * Query HAL for all storage devices associated with a specific
+ * SCSI HBA.
+ *
+ * XXX, currently we only support regular devices in /dev/,
+ * or /dev/disk/by-XXX. In future we also need to be able to
+ * map to multipath devices setup under /dev/mpath/XXXX.
+ */
+static int
+virStorageBackendSCSIRefreshPool(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ char hostdevice[PATH_MAX];
+ LibHalContext *ctx = NULL;
+ DBusConnection *sysbus = NULL;
+ DBusError derr = DBUS_ERROR_INIT;
+ char **hbadevs = NULL, **blkdevs = NULL;
+ int numhbadevs = 0, numblkdevs = 0;
+ int i, ret = -1;
+
+ /* Get the canonical sysfs path for the HBA device */
+ if (virStorageBackendSCSIMakeHostDevice(conn, pool,
+ hostdevice, sizeof(hostdevice)) < 0)
+ goto cleanup;
+
+ if ((ctx = libhal_ctx_new()) == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("failed to allocate HAL context"));
+ goto cleanup;
+ }
+
+ sysbus = dbus_bus_get(DBUS_BUS_SYSTEM, &derr);
+ if (sysbus == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("failed to get dbus system bus:
'%s'"),
+ derr.message);
+ goto cleanup;
+ }
+
+ if (!libhal_ctx_set_dbus_connection(ctx, sysbus)) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("failed to set HAL dbus connection"));
+ goto cleanup;
+ }
+
+
+ if (!libhal_ctx_init(ctx, &derr)) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("failed to initialize HAL context:
'%s'"),
+ derr.message);
+ goto cleanup;
+ }
+
+ if ((hbadevs = libhal_manager_find_device_string_match(ctx,
+ "linux.sysfs_path",
+ hostdevice,
+ &numhbadevs,
+ &derr)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("HAL failed to lookup device '%s':
%s"),
+ hostdevice, derr.message);
+ goto cleanup;
+ }
+
+ if (numhbadevs != 1) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected number of HBA devices from HAL "
+ "(expected 1, got %d) when looking up device "
+ "'%s'"), numhbadevs, hostdevice);
+ goto cleanup;
+ }
+
+ if ((blkdevs = libhal_manager_find_device_string_match(ctx,
+ "info.parent",
+ hbadevs[0],
+ &numblkdevs,
+ &derr)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("failed to lookup LUNs for %s with HAL: %s"),
+ hbadevs[0], derr.message);
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < numblkdevs ; i++)
+ virStorageBackendSCSIAddLUN(conn,
+ pool,
+ ctx,
+ blkdevs[i]);
+
+ ret = 0;
+
+cleanup:
+ for (i = 0 ; hbadevs && i < numhbadevs ; i++)
+ free(hbadevs[i]);
+ free(hbadevs);
+ for (i = 0 ; blkdevs && i < numblkdevs ; i++)
+ free(blkdevs[i]);
+ free(blkdevs);
+ libhal_ctx_shutdown(ctx, NULL);
+ libhal_ctx_free(ctx);
+ if (sysbus)
+ dbus_connection_unref(sysbus);
+ if (dbus_error_is_set(&derr))
+ dbus_error_free(&derr);
+ return ret;
+}
+
+
+
+virStorageBackend virStorageBackendSCSI = {
+ .type = VIR_STORAGE_POOL_SCSI,
+ .refreshPool = virStorageBackendSCSIRefreshPool,
+};
+
+/*
+ * 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 --git a/src/storage_backend_scsi.h b/src/storage_backend_scsi.h
new file mode 100644
index 0000000..c912269
--- /dev/null
+++ b/src/storage_backend_scsi.h
@@ -0,0 +1,45 @@
+/*
+ * storage_backend_scsi.h: storage backend for SCSI 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_SCSI_H__
+#define __VIR_STORAGE_BACKEND_SCSI_H__
+
+#include "storage_backend.h"
+
+extern virStorageBackend virStorageBackendSCSI;
+
+#endif /* __VIR_STORAGE_BACKEND_SCSI_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:
+ */
diff --git a/src/storage_conf.c b/src/storage_conf.c
index 70107a2..2ea6f8e 100644
--- a/src/storage_conf.c
+++ b/src/storage_conf.c
@@ -187,6 +187,14 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
.formatToString = virStoragePoolFormatDiskTypeToString,
}
},
+ { .poolType = VIR_STORAGE_POOL_SCSI,
+ .poolOptions = {
+ .flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER),
+ },
+ .volOptions = {
+ .formatToString = virStoragePoolFormatDiskTypeToString,
+ }
+ },
{ .poolType = VIR_STORAGE_POOL_DISK,
.poolOptions = {
.flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
@@ -269,6 +277,7 @@ virStoragePoolSourceFree(virStoragePoolSourcePtr source) {
VIR_FREE(source->devices);
VIR_FREE(source->dir);
VIR_FREE(source->name);
+ VIR_FREE(source->adapter);
if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
VIR_FREE(source->auth.chap.login);
@@ -550,6 +559,15 @@ virStoragePoolDefParseDoc(virConnectPtr conn,
}
}
+ if (options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) {
+ if ((ret->source.adapter = virXPathString(conn,
+
"string(/pool/source/adapter/@name)",
+ ctxt)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("missing storage pool source adapter
name"));
+ goto cleanup;
+ }
+ }
authType = virXPathString(conn, "string(/pool/source/auth/@type)", ctxt);
if (authType == NULL) {
--
1.6.0.6