mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-26 23:55:23 +00:00
1173 lines
34 KiB
Diff
1173 lines
34 KiB
Diff
|
From 04d20a662109de6727232eb1213627877bb9662f Mon Sep 17 00:00:00 2001
|
||
|
From: David Allan <dallan@redhat.com>
|
||
|
Date: Tue, 19 May 2009 16:35:15 -0400
|
||
|
Subject: [PATCH] Step 7 of 8 Implement the driver methods
|
||
|
|
||
|
---
|
||
|
src/Makefile.am | 4 +-
|
||
|
src/node_device.c | 430 +++++++++++++++++++++++++++++++++++++++++++
|
||
|
src/node_device.h | 13 ++
|
||
|
src/node_device_conf.c | 136 ++++++++++++--
|
||
|
src/node_device_conf.h | 22 ++-
|
||
|
src/node_device_hal.c | 5 +
|
||
|
src/node_device_hal.h | 40 ++++
|
||
|
src/node_device_hal_linux.c | 170 +++++++++++++++++
|
||
|
src/qemu_driver.c | 2 +-
|
||
|
src/storage_backend.c | 24 +--
|
||
|
src/xen_unified.c | 2 +-
|
||
|
tests/nodedevxml2xmltest.c | 2 +-
|
||
|
12 files changed, 810 insertions(+), 40 deletions(-)
|
||
|
create mode 100644 src/node_device_hal.h
|
||
|
create mode 100644 src/node_device_hal_linux.c
|
||
|
|
||
|
diff --git a/src/Makefile.am b/src/Makefile.am
|
||
|
index fd692b4..39fabce 100644
|
||
|
--- a/src/Makefile.am
|
||
|
+++ b/src/Makefile.am
|
||
|
@@ -188,7 +188,9 @@ NODE_DEVICE_DRIVER_SOURCES = \
|
||
|
node_device.c node_device.h
|
||
|
|
||
|
NODE_DEVICE_DRIVER_HAL_SOURCES = \
|
||
|
- node_device_hal.c
|
||
|
+ node_device_hal.c \
|
||
|
+ node_device_hal_linux.c
|
||
|
+
|
||
|
NODE_DEVICE_DRIVER_DEVKIT_SOURCES = \
|
||
|
node_device_devkit.c
|
||
|
|
||
|
diff --git a/src/node_device.c b/src/node_device.c
|
||
|
index b84729f..4f73baf 100644
|
||
|
--- a/src/node_device.c
|
||
|
+++ b/src/node_device.c
|
||
|
@@ -25,6 +25,8 @@
|
||
|
|
||
|
#include <unistd.h>
|
||
|
#include <errno.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <time.h>
|
||
|
|
||
|
#include "virterror_internal.h"
|
||
|
#include "datatypes.h"
|
||
|
@@ -133,6 +135,53 @@ cleanup:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+static virNodeDevicePtr
|
||
|
+nodeDeviceLookupByWWN(virConnectPtr conn,
|
||
|
+ const char *wwnn,
|
||
|
+ const char *wwpn)
|
||
|
+{
|
||
|
+ unsigned int i;
|
||
|
+ virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
|
||
|
+ virNodeDeviceObjListPtr devs = &driver->devs;
|
||
|
+ virNodeDevCapsDefPtr cap = NULL;
|
||
|
+ virNodeDeviceObjPtr obj = NULL;
|
||
|
+ virNodeDevicePtr dev = NULL;
|
||
|
+
|
||
|
+ nodeDeviceLock(driver);
|
||
|
+
|
||
|
+ for (i = 0; i < devs->count; i++) {
|
||
|
+
|
||
|
+ obj = devs->objs[i];
|
||
|
+ virNodeDeviceObjLock(obj);
|
||
|
+ cap = obj->def->caps;
|
||
|
+
|
||
|
+ while (cap) {
|
||
|
+
|
||
|
+ if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) {
|
||
|
+ if (cap->data.scsi_host.flags &
|
||
|
+ VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
|
||
|
+
|
||
|
+ if (STREQ(cap->data.scsi_host.wwnn, wwnn) &&
|
||
|
+ STREQ(cap->data.scsi_host.wwpn, wwpn)) {
|
||
|
+ dev = virGetNodeDevice(conn, obj->def->name);
|
||
|
+ virNodeDeviceObjUnlock(obj);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ cap = cap->next;
|
||
|
+ }
|
||
|
+
|
||
|
+ virNodeDeviceObjUnlock(obj);
|
||
|
+ }
|
||
|
+
|
||
|
+out:
|
||
|
+ nodeDeviceUnlock(driver);
|
||
|
+ return dev;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
static char *nodeDeviceDumpXML(virNodeDevicePtr dev,
|
||
|
unsigned int flags ATTRIBUTE_UNUSED)
|
||
|
{
|
||
|
@@ -258,6 +307,385 @@ cleanup:
|
||
|
}
|
||
|
|
||
|
|
||
|
+static int
|
||
|
+nodeDeviceVportCreateDelete(virConnectPtr conn,
|
||
|
+ const int parent_host,
|
||
|
+ const char *wwpn,
|
||
|
+ const char *wwnn,
|
||
|
+ int operation)
|
||
|
+{
|
||
|
+ int fd = -1;
|
||
|
+ int retval = 0;
|
||
|
+ char *operation_path = NULL, *vport_name = NULL;
|
||
|
+ const char *operation_file = NULL;
|
||
|
+ size_t towrite = 0;
|
||
|
+ unsigned int written = 0;
|
||
|
+
|
||
|
+ switch (operation) {
|
||
|
+ case VPORT_CREATE:
|
||
|
+ operation_file = LINUX_SYSFS_VPORT_CREATE_POSTFIX;
|
||
|
+ break;
|
||
|
+ case VPORT_DELETE:
|
||
|
+ operation_file = LINUX_SYSFS_VPORT_DELETE_POSTFIX;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||
|
+ _("Invalid vport operation (%d)"), operation);
|
||
|
+ retval = -1;
|
||
|
+ goto cleanup;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (virAsprintf(&operation_path,
|
||
|
+ "%shost%d%s",
|
||
|
+ LINUX_SYSFS_FC_HOST_PREFIX,
|
||
|
+ parent_host,
|
||
|
+ operation_file) < 0) {
|
||
|
+
|
||
|
+ virReportOOMError(conn);
|
||
|
+ retval = -1;
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ VIR_DEBUG(_("Vport operation path is '%s'"), operation_path);
|
||
|
+
|
||
|
+ fd = open(operation_path, O_WRONLY);
|
||
|
+
|
||
|
+ if (fd < 0) {
|
||
|
+ virReportSystemError(conn, errno,
|
||
|
+ _("Could not open '%s' for vport operation"),
|
||
|
+ operation_path);
|
||
|
+ retval = -1;
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (virAsprintf(&vport_name,
|
||
|
+ "%s:%s",
|
||
|
+ wwpn,
|
||
|
+ wwnn) < 0) {
|
||
|
+
|
||
|
+ virReportOOMError(conn);
|
||
|
+ retval = -1;
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ towrite = strlen(vport_name);
|
||
|
+ written = safewrite(fd, vport_name, towrite);
|
||
|
+ if (written != towrite) {
|
||
|
+ virReportSystemError(conn, errno,
|
||
|
+ _("Write of '%s' to '%s' during "
|
||
|
+ "vport create/delete failed "
|
||
|
+ "(towrite: %lu written: %d)"),
|
||
|
+ vport_name, operation_path,
|
||
|
+ towrite, written);
|
||
|
+ retval = -1;
|
||
|
+ }
|
||
|
+
|
||
|
+cleanup:
|
||
|
+ if (fd != -1) {
|
||
|
+ close(fd);
|
||
|
+ }
|
||
|
+ VIR_FREE(vport_name);
|
||
|
+ VIR_FREE(operation_path);
|
||
|
+ VIR_DEBUG("%s", _("Vport operation complete"));
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int
|
||
|
+get_wwns(virConnectPtr conn,
|
||
|
+ virNodeDeviceDefPtr def,
|
||
|
+ char **wwnn,
|
||
|
+ char **wwpn)
|
||
|
+{
|
||
|
+ virNodeDevCapsDefPtr cap = NULL;
|
||
|
+ int ret = 0;
|
||
|
+
|
||
|
+ cap = def->caps;
|
||
|
+ while (cap != NULL) {
|
||
|
+ if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST &&
|
||
|
+ cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
|
||
|
+ *wwnn = strdup(cap->data.scsi_host.wwnn);
|
||
|
+ *wwpn = strdup(cap->data.scsi_host.wwpn);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ cap = cap->next;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (cap == NULL) {
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_NO_SUPPORT,
|
||
|
+ "%s", _("Device is not a fibre channel HBA"));
|
||
|
+ ret = -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (*wwnn == NULL || *wwpn == NULL) {
|
||
|
+ /* Free the other one, if allocated... */
|
||
|
+ VIR_FREE(wwnn);
|
||
|
+ VIR_FREE(wwpn);
|
||
|
+ ret = -1;
|
||
|
+ virReportOOMError(conn);
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int
|
||
|
+get_parent_host(virConnectPtr conn,
|
||
|
+ virDeviceMonitorStatePtr driver,
|
||
|
+ const char *dev_name,
|
||
|
+ const char *parent_name,
|
||
|
+ int *parent_host)
|
||
|
+{
|
||
|
+ virNodeDeviceObjPtr parent = NULL;
|
||
|
+ virNodeDevCapsDefPtr cap = NULL;
|
||
|
+ int ret = 0;
|
||
|
+
|
||
|
+ parent = virNodeDeviceFindByName(&driver->devs, parent_name);
|
||
|
+ if (parent == NULL) {
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
|
||
|
+ _("Could not find parent device for '%s'"),
|
||
|
+ dev_name);
|
||
|
+ ret = -1;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ cap = parent->def->caps;
|
||
|
+ while (cap != NULL) {
|
||
|
+ if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST &&
|
||
|
+ (cap->data.scsi_host.flags &
|
||
|
+ VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS)) {
|
||
|
+ *parent_host = cap->data.scsi_host.host;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ cap = cap->next;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (cap == NULL) {
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
|
||
|
+ _("Device %s is not capable of vport operations"),
|
||
|
+ parent->def->name);
|
||
|
+ ret = -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ virNodeDeviceObjUnlock(parent);
|
||
|
+
|
||
|
+out:
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int
|
||
|
+get_time(virConnectPtr conn, time_t *t)
|
||
|
+{
|
||
|
+ int ret = 0;
|
||
|
+
|
||
|
+ *t = time(NULL);
|
||
|
+ if (*t == (time_t)-1) {
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||
|
+ "%s", _("Could not get current time"));
|
||
|
+
|
||
|
+ *t = 0;
|
||
|
+ ret = -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* When large numbers of devices are present on the host, it's
|
||
|
+ * possible for udev not to realize that it has work to do before we
|
||
|
+ * get here. We thus keep trying to find the new device we just
|
||
|
+ * created for up to LINUX_NEW_DEVICE_WAIT_TIME. Note that udev's
|
||
|
+ * default settle time is 180 seconds, so once udev realizes that it
|
||
|
+ * has work to do, it might take that long for the udev wait to
|
||
|
+ * return. Thus the total maximum time for this function to return is
|
||
|
+ * the udev settle time plus LINUX_NEW_DEVICE_WAIT_TIME.
|
||
|
+ *
|
||
|
+ * This whole area is a race, but if we retry the udev wait for
|
||
|
+ * LINUX_NEW_DEVICE_WAIT_TIME seconds and there's still no device,
|
||
|
+ * it's probably safe to assume it's not going to appear.
|
||
|
+ */
|
||
|
+static virNodeDevicePtr
|
||
|
+find_new_device(virConnectPtr conn, const char *wwnn, const char *wwpn)
|
||
|
+{
|
||
|
+ virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
|
||
|
+ virNodeDevicePtr dev = NULL;
|
||
|
+ time_t start = 0, now = 0;
|
||
|
+
|
||
|
+ /* The thread that creates the device takes the driver lock, so we
|
||
|
+ * must release it in order to allow the device to be created.
|
||
|
+ * We're not doing anything with the driver pointer at this point,
|
||
|
+ * so it's safe to release it, assuming that the pointer itself
|
||
|
+ * doesn't become invalid. */
|
||
|
+ nodeDeviceUnlock(driver);
|
||
|
+
|
||
|
+ get_time(conn, &start);
|
||
|
+
|
||
|
+ while ((now - start) < LINUX_NEW_DEVICE_WAIT_TIME) {
|
||
|
+
|
||
|
+ virNodeDeviceWaitForDevices(conn);
|
||
|
+
|
||
|
+ dev = nodeDeviceLookupByWWN(conn, wwnn, wwpn);
|
||
|
+
|
||
|
+ if (dev != NULL) {
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ sleep(5);
|
||
|
+ if (get_time(conn, &now) == -1) {
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ nodeDeviceLock(driver);
|
||
|
+
|
||
|
+ return dev;
|
||
|
+}
|
||
|
+
|
||
|
+static virNodeDevicePtr
|
||
|
+nodeDeviceCreateXML(virConnectPtr conn,
|
||
|
+ const char *xmlDesc,
|
||
|
+ unsigned int flags ATTRIBUTE_UNUSED)
|
||
|
+{
|
||
|
+ virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
|
||
|
+ virNodeDeviceDefPtr def = NULL;
|
||
|
+ char *wwnn = NULL, *wwpn = NULL;
|
||
|
+ int parent_host = -1;
|
||
|
+ virNodeDevicePtr dev = NULL;
|
||
|
+
|
||
|
+ nodeDeviceLock(driver);
|
||
|
+
|
||
|
+ def = virNodeDeviceDefParseString(conn, xmlDesc, CREATE_DEVICE);
|
||
|
+ if (def == NULL) {
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (get_wwns(conn, def, &wwnn, &wwpn) == -1) {
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (get_parent_host(conn,
|
||
|
+ driver,
|
||
|
+ def->name,
|
||
|
+ def->parent,
|
||
|
+ &parent_host) == -1) {
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (nodeDeviceVportCreateDelete(conn,
|
||
|
+ parent_host,
|
||
|
+ wwpn,
|
||
|
+ wwnn,
|
||
|
+ VPORT_CREATE) == -1) {
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ dev = find_new_device(conn, wwnn, wwpn);
|
||
|
+ /* We don't check the return value, because one way or another,
|
||
|
+ * we're returning what we get... */
|
||
|
+
|
||
|
+ if (dev == NULL) {
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_NO_NODE_DEVICE, NULL);
|
||
|
+ }
|
||
|
+
|
||
|
+cleanup:
|
||
|
+ nodeDeviceUnlock(driver);
|
||
|
+ virNodeDeviceDefFree(def);
|
||
|
+ VIR_FREE(wwnn);
|
||
|
+ VIR_FREE(wwpn);
|
||
|
+ return dev;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int
|
||
|
+nodeDeviceDestroy(virNodeDevicePtr dev)
|
||
|
+{
|
||
|
+ int ret = 0;
|
||
|
+ virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData;
|
||
|
+ virNodeDeviceObjPtr obj = NULL;
|
||
|
+ char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL;
|
||
|
+ int parent_host = -1;
|
||
|
+
|
||
|
+ nodeDeviceLock(driver);
|
||
|
+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
|
||
|
+ nodeDeviceUnlock(driver);
|
||
|
+
|
||
|
+ if (!obj) {
|
||
|
+ virNodeDeviceReportError(dev->conn, VIR_ERR_NO_NODE_DEVICE, NULL);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (get_wwns(dev->conn, obj->def, &wwnn, &wwpn) == -1) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ parent_name = strdup(obj->def->parent);
|
||
|
+
|
||
|
+ /* get_parent_host will cause the device object's lock to be
|
||
|
+ * taken, so we have to dup the parent's name and drop the lock
|
||
|
+ * before calling it. We don't need the reference to the object
|
||
|
+ * any more once we have the parent's name. */
|
||
|
+ virNodeDeviceObjUnlock(obj);
|
||
|
+ obj = NULL;
|
||
|
+
|
||
|
+ if (parent_name == NULL) {
|
||
|
+ virReportOOMError(dev->conn);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (get_parent_host(dev->conn,
|
||
|
+ driver,
|
||
|
+ dev->name,
|
||
|
+ parent_name,
|
||
|
+ &parent_host) == -1) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (nodeDeviceVportCreateDelete(dev->conn,
|
||
|
+ parent_host,
|
||
|
+ wwpn,
|
||
|
+ wwnn,
|
||
|
+ VPORT_DELETE) == -1) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+out:
|
||
|
+ VIR_FREE(parent_name);
|
||
|
+ VIR_FREE(wwnn);
|
||
|
+ VIR_FREE(wwpn);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+#if defined(UDEVADM) || defined(UDEVSETTLE)
|
||
|
+void virNodeDeviceWaitForDevices(virConnectPtr conn)
|
||
|
+{
|
||
|
+#ifdef UDEVADM
|
||
|
+ const char *const settleprog[] = { UDEVADM, "settle", NULL };
|
||
|
+#else
|
||
|
+ const char *const settleprog[] = { UDEVSETTLE, NULL };
|
||
|
+#endif
|
||
|
+ int exitstatus;
|
||
|
+
|
||
|
+ if (access(settleprog[0], X_OK) != 0)
|
||
|
+ return;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * NOTE: we ignore errors here; this is just to make sure that any device
|
||
|
+ * nodes that are being created finish before we try to scan them.
|
||
|
+ * If this fails for any reason, we still have the backup of polling for
|
||
|
+ * 5 seconds for device nodes.
|
||
|
+ */
|
||
|
+ virRun(conn, settleprog, &exitstatus);
|
||
|
+}
|
||
|
+#else
|
||
|
+void virNodeDeviceWaitForDevices(virConnectPtr conn ATTRIBUTE_UNUSED) {}
|
||
|
+#endif
|
||
|
+
|
||
|
+
|
||
|
void registerCommonNodeFuncs(virDeviceMonitorPtr driver)
|
||
|
{
|
||
|
driver->numOfDevices = nodeNumOfDevices;
|
||
|
@@ -267,6 +695,8 @@ void registerCommonNodeFuncs(virDeviceMonitorPtr driver)
|
||
|
driver->deviceGetParent = nodeDeviceGetParent;
|
||
|
driver->deviceNumOfCaps = nodeDeviceNumOfCaps;
|
||
|
driver->deviceListCaps = nodeDeviceListCaps;
|
||
|
+ driver->deviceCreateXML = nodeDeviceCreateXML;
|
||
|
+ driver->deviceDestroy = nodeDeviceDestroy;
|
||
|
}
|
||
|
|
||
|
|
||
|
diff --git a/src/node_device.h b/src/node_device.h
|
||
|
index 9496120..882ba0f 100644
|
||
|
--- a/src/node_device.h
|
||
|
+++ b/src/node_device.h
|
||
|
@@ -28,6 +28,17 @@
|
||
|
#include "driver.h"
|
||
|
#include "node_device_conf.h"
|
||
|
|
||
|
+#define LINUX_SYSFS_SCSI_HOST_PREFIX "/sys/class/scsi_host"
|
||
|
+#define LINUX_SYSFS_SCSI_HOST_POSTFIX "device"
|
||
|
+#define LINUX_SYSFS_FC_HOST_PREFIX "/sys/class/fc_host/"
|
||
|
+
|
||
|
+#define VPORT_CREATE 0
|
||
|
+#define VPORT_DELETE 1
|
||
|
+#define LINUX_SYSFS_VPORT_CREATE_POSTFIX "/vport_create"
|
||
|
+#define LINUX_SYSFS_VPORT_DELETE_POSTFIX "/vport_delete"
|
||
|
+
|
||
|
+#define LINUX_NEW_DEVICE_WAIT_TIME 60
|
||
|
+
|
||
|
#ifdef HAVE_HAL
|
||
|
int halNodeRegister(void);
|
||
|
#endif
|
||
|
@@ -42,4 +53,6 @@ void registerCommonNodeFuncs(virDeviceMonitorPtr mon);
|
||
|
|
||
|
int nodedevRegister(void);
|
||
|
|
||
|
+void virNodeDeviceWaitForDevices(virConnectPtr conn);
|
||
|
+
|
||
|
#endif /* __VIR_NODE_DEVICE_H__ */
|
||
|
diff --git a/src/node_device_conf.c b/src/node_device_conf.c
|
||
|
index 6e04112..5b35b60 100644
|
||
|
--- a/src/node_device_conf.c
|
||
|
+++ b/src/node_device_conf.c
|
||
|
@@ -53,9 +53,34 @@ VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST,
|
||
|
"80203",
|
||
|
"80211")
|
||
|
|
||
|
+VIR_ENUM_IMPL(virNodeDevHBACap, VIR_NODE_DEV_CAP_HBA_LAST,
|
||
|
+ "fc_host",
|
||
|
+ "vport_ops")
|
||
|
|
||
|
#define virNodeDeviceLog(msg...) fprintf(stderr, msg)
|
||
|
|
||
|
+static int
|
||
|
+virNodeDevCapsDefParseString(virConnectPtr conn,
|
||
|
+ const char *xpath,
|
||
|
+ xmlXPathContextPtr ctxt,
|
||
|
+ char **string,
|
||
|
+ virNodeDeviceDefPtr def,
|
||
|
+ const char *missing_error_fmt)
|
||
|
+{
|
||
|
+ char *s;
|
||
|
+
|
||
|
+ s = virXPathString(conn, xpath, ctxt);
|
||
|
+ if (s == NULL) {
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||
|
+ missing_error_fmt,
|
||
|
+ def->name);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ *string = s;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
virNodeDeviceObjPtr virNodeDeviceFindByName(const virNodeDeviceObjListPtr devs,
|
||
|
const char *name)
|
||
|
{
|
||
|
@@ -302,6 +327,18 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
|
||
|
case VIR_NODE_DEV_CAP_SCSI_HOST:
|
||
|
virBufferVSprintf(&buf, " <host>%d</host>\n",
|
||
|
data->scsi_host.host);
|
||
|
+ if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
|
||
|
+ virBufferAddLit(&buf, " <capability type='fc_host'>\n");
|
||
|
+ virBufferVSprintf(&buf,
|
||
|
+ " <wwnn>%s</wwnn>\n", data->scsi_host.wwnn);
|
||
|
+ virBufferVSprintf(&buf,
|
||
|
+ " <wwpn>%s</wwpn>\n", data->scsi_host.wwpn);
|
||
|
+ virBufferAddLit(&buf, " </capability>\n");
|
||
|
+ }
|
||
|
+ if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
|
||
|
+ virBufferAddLit(&buf, " <capability type='vport_ops' />\n");
|
||
|
+ }
|
||
|
+
|
||
|
break;
|
||
|
case VIR_NODE_DEV_CAP_SCSI:
|
||
|
virBufferVSprintf(&buf, " <host>%d</host>\n", data->scsi.host);
|
||
|
@@ -561,26 +598,91 @@ virNodeDevCapScsiHostParseXML(virConnectPtr conn,
|
||
|
xmlXPathContextPtr ctxt,
|
||
|
virNodeDeviceDefPtr def,
|
||
|
xmlNodePtr node,
|
||
|
- union _virNodeDevCapData *data)
|
||
|
+ union _virNodeDevCapData *data,
|
||
|
+ int create)
|
||
|
{
|
||
|
- xmlNodePtr orignode;
|
||
|
- int ret = -1;
|
||
|
+ xmlNodePtr orignode, *nodes = NULL;
|
||
|
+ int ret = -1, n = 0, i;
|
||
|
+ char *type = NULL;
|
||
|
|
||
|
orignode = ctxt->node;
|
||
|
ctxt->node = node;
|
||
|
|
||
|
- if (virNodeDevCapsDefParseULong(conn, "number(./host[1])", ctxt,
|
||
|
+ if (create == EXISTING_DEVICE &&
|
||
|
+ virNodeDevCapsDefParseULong(conn, "number(./host[1])", ctxt,
|
||
|
&data->scsi_host.host, def,
|
||
|
_("no SCSI host ID supplied for '%s'"),
|
||
|
- _("invalid SCSI host ID supplied for '%s'")) < 0)
|
||
|
+ _("invalid SCSI host ID supplied for '%s'")) < 0) {
|
||
|
goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ((n = virXPathNodeSet(conn, "./capability", ctxt, &nodes)) < 0) {
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||
|
+ _("error parsing SCSI host capabilities for '%s'"),
|
||
|
+ def->name);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0 ; i < n ; i++) {
|
||
|
+ type = virXMLPropString(nodes[i], "type");
|
||
|
+
|
||
|
+ if (!type) {
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||
|
+ _("missing SCSI host capability type for '%s'"),
|
||
|
+ def->name);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (STREQ(type, "vport_ops")) {
|
||
|
+
|
||
|
+ data->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS;
|
||
|
+
|
||
|
+ } else if (STREQ(type, "fc_host")) {
|
||
|
+
|
||
|
+ xmlNodePtr orignode2;
|
||
|
+
|
||
|
+ data->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST;
|
||
|
+
|
||
|
+ orignode2 = ctxt->node;
|
||
|
+ ctxt->node = nodes[i];
|
||
|
+
|
||
|
+ if (virNodeDevCapsDefParseString(conn, "string(./wwnn[1])",
|
||
|
+ ctxt,
|
||
|
+ &data->scsi_host.wwnn,
|
||
|
+ def,
|
||
|
+ _("no WWNN supplied for '%s'")) < 0) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (virNodeDevCapsDefParseString(conn, "string(./wwpn[1])",
|
||
|
+ ctxt,
|
||
|
+ &data->scsi_host.wwpn,
|
||
|
+ def,
|
||
|
+ _("no WWPN supplied for '%s'")) < 0) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ ctxt->node = orignode2;
|
||
|
+
|
||
|
+ } else {
|
||
|
+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||
|
+ _("unknown SCSI host capability type '%s' for '%s'"),
|
||
|
+ type, def->name);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ VIR_FREE(type);
|
||
|
+ }
|
||
|
|
||
|
ret = 0;
|
||
|
+
|
||
|
out:
|
||
|
+ VIR_FREE(type);
|
||
|
ctxt->node = orignode;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
static int
|
||
|
virNodeDevCapNetParseXML(virConnectPtr conn,
|
||
|
xmlXPathContextPtr ctxt,
|
||
|
@@ -848,7 +950,8 @@ static virNodeDevCapsDefPtr
|
||
|
virNodeDevCapsDefParseXML(virConnectPtr conn,
|
||
|
xmlXPathContextPtr ctxt,
|
||
|
virNodeDeviceDefPtr def,
|
||
|
- xmlNodePtr node)
|
||
|
+ xmlNodePtr node,
|
||
|
+ int create)
|
||
|
{
|
||
|
virNodeDevCapsDefPtr caps;
|
||
|
char *tmp;
|
||
|
@@ -892,7 +995,7 @@ virNodeDevCapsDefParseXML(virConnectPtr conn,
|
||
|
ret = virNodeDevCapNetParseXML(conn, ctxt, def, node, &caps->data);
|
||
|
break;
|
||
|
case VIR_NODE_DEV_CAP_SCSI_HOST:
|
||
|
- ret = virNodeDevCapScsiHostParseXML(conn, ctxt, def, node, &caps->data);
|
||
|
+ ret = virNodeDevCapScsiHostParseXML(conn, ctxt, def, node, &caps->data, create);
|
||
|
break;
|
||
|
case VIR_NODE_DEV_CAP_SCSI:
|
||
|
ret = virNodeDevCapScsiParseXML(conn, ctxt, def, node, &caps->data);
|
||
|
@@ -918,7 +1021,7 @@ error:
|
||
|
}
|
||
|
|
||
|
static virNodeDeviceDefPtr
|
||
|
-virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt)
|
||
|
+virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt, int create)
|
||
|
{
|
||
|
virNodeDeviceDefPtr def;
|
||
|
virNodeDevCapsDefPtr *next_cap;
|
||
|
@@ -931,7 +1034,12 @@ virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt)
|
||
|
}
|
||
|
|
||
|
/* Extract device name */
|
||
|
- def->name = virXPathString(conn, "string(./name[1])", ctxt);
|
||
|
+ if (create == EXISTING_DEVICE) {
|
||
|
+ def->name = virXPathString(conn, "string(./name[1])", ctxt);
|
||
|
+ } else {
|
||
|
+ def->name = strdup("new device");
|
||
|
+ }
|
||
|
+
|
||
|
if (!def->name) {
|
||
|
virNodeDeviceReportError(conn, VIR_ERR_NO_NAME, NULL);
|
||
|
goto error;
|
||
|
@@ -951,7 +1059,7 @@ virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt)
|
||
|
|
||
|
next_cap = &def->caps;
|
||
|
for (i = 0 ; i < n ; i++) {
|
||
|
- *next_cap = virNodeDevCapsDefParseXML(conn, ctxt, def, nodes[i]);
|
||
|
+ *next_cap = virNodeDevCapsDefParseXML(conn, ctxt, def, nodes[i], create);
|
||
|
if (!*next_cap) {
|
||
|
VIR_FREE(nodes);
|
||
|
goto error;
|
||
|
@@ -969,7 +1077,7 @@ virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt)
|
||
|
}
|
||
|
|
||
|
static virNodeDeviceDefPtr
|
||
|
-virNodeDeviceDefParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root)
|
||
|
+virNodeDeviceDefParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root, int create)
|
||
|
{
|
||
|
xmlXPathContextPtr ctxt = NULL;
|
||
|
virNodeDeviceDefPtr def = NULL;
|
||
|
@@ -987,7 +1095,7 @@ virNodeDeviceDefParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root)
|
||
|
}
|
||
|
|
||
|
ctxt->node = root;
|
||
|
- def = virNodeDeviceDefParseXML(conn, ctxt);
|
||
|
+ def = virNodeDeviceDefParseXML(conn, ctxt, create);
|
||
|
|
||
|
cleanup:
|
||
|
xmlXPathFreeContext(ctxt);
|
||
|
@@ -1015,7 +1123,7 @@ catchXMLError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
||
|
}
|
||
|
|
||
|
virNodeDeviceDefPtr
|
||
|
-virNodeDeviceDefParseString(virConnectPtr conn, const char *str)
|
||
|
+virNodeDeviceDefParseString(virConnectPtr conn, const char *str, int create)
|
||
|
{
|
||
|
xmlParserCtxtPtr pctxt;
|
||
|
xmlDocPtr xml = NULL;
|
||
|
@@ -1046,7 +1154,7 @@ virNodeDeviceDefParseString(virConnectPtr conn, const char *str)
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
- def = virNodeDeviceDefParseNode(conn, xml, root);
|
||
|
+ def = virNodeDeviceDefParseNode(conn, xml, root, create);
|
||
|
|
||
|
cleanup:
|
||
|
xmlFreeParserCtxt(pctxt);
|
||
|
diff --git a/src/node_device_conf.h b/src/node_device_conf.h
|
||
|
index 26e5558..62b4e71 100644
|
||
|
--- a/src/node_device_conf.h
|
||
|
+++ b/src/node_device_conf.h
|
||
|
@@ -28,6 +28,9 @@
|
||
|
#include "util.h"
|
||
|
#include "threads.h"
|
||
|
|
||
|
+#define CREATE_DEVICE 1
|
||
|
+#define EXISTING_DEVICE 0
|
||
|
+
|
||
|
enum virNodeDevCapType {
|
||
|
/* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */
|
||
|
VIR_NODE_DEV_CAP_SYSTEM, /* System capability */
|
||
|
@@ -48,8 +51,16 @@ enum virNodeDevNetCapType {
|
||
|
VIR_NODE_DEV_CAP_NET_LAST
|
||
|
};
|
||
|
|
||
|
+enum virNodeDevHBACapType {
|
||
|
+ /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */
|
||
|
+ VIR_NODE_DEV_CAP_HBA_FC_HOST, /* fibre channel HBA */
|
||
|
+ VIR_NODE_DEV_CAP_HBA_VPORT_OPS, /* capable of vport operations */
|
||
|
+ VIR_NODE_DEV_CAP_HBA_LAST
|
||
|
+};
|
||
|
+
|
||
|
VIR_ENUM_DECL(virNodeDevCap)
|
||
|
VIR_ENUM_DECL(virNodeDevNetCap)
|
||
|
+VIR_ENUM_DECL(virNodeDevHBACap)
|
||
|
|
||
|
enum virNodeDevStorageCapFlags {
|
||
|
VIR_NODE_DEV_CAP_STORAGE_REMOVABLE = (1 << 0),
|
||
|
@@ -57,6 +68,11 @@ enum virNodeDevStorageCapFlags {
|
||
|
VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE = (1 << 2),
|
||
|
};
|
||
|
|
||
|
+enum virNodeDevScsiHostCapFlags {
|
||
|
+ VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST = (1 << 0),
|
||
|
+ VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS = (1 << 1),
|
||
|
+};
|
||
|
+
|
||
|
typedef struct _virNodeDevCapsDef virNodeDevCapsDef;
|
||
|
typedef virNodeDevCapsDef *virNodeDevCapsDefPtr;
|
||
|
struct _virNodeDevCapsDef {
|
||
|
@@ -108,6 +124,9 @@ struct _virNodeDevCapsDef {
|
||
|
} net;
|
||
|
struct {
|
||
|
unsigned host;
|
||
|
+ char *wwnn;
|
||
|
+ char *wwpn;
|
||
|
+ unsigned flags;
|
||
|
} scsi_host;
|
||
|
struct {
|
||
|
unsigned host;
|
||
|
@@ -185,7 +204,8 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
|
||
|
const virNodeDeviceDefPtr def);
|
||
|
|
||
|
virNodeDeviceDefPtr virNodeDeviceDefParseString(virConnectPtr conn,
|
||
|
- const char *str);
|
||
|
+ const char *str,
|
||
|
+ int create);
|
||
|
|
||
|
void virNodeDeviceDefFree(virNodeDeviceDefPtr def);
|
||
|
|
||
|
diff --git a/src/node_device_hal.c b/src/node_device_hal.c
|
||
|
index b214f60..5927ba1 100644
|
||
|
--- a/src/node_device_hal.c
|
||
|
+++ b/src/node_device_hal.c
|
||
|
@@ -28,6 +28,7 @@
|
||
|
#include <libhal.h>
|
||
|
|
||
|
#include "node_device_conf.h"
|
||
|
+#include "node_device_hal.h"
|
||
|
#include "virterror_internal.h"
|
||
|
#include "driver.h"
|
||
|
#include "datatypes.h"
|
||
|
@@ -37,6 +38,8 @@
|
||
|
#include "logging.h"
|
||
|
#include "node_device.h"
|
||
|
|
||
|
+#define VIR_FROM_THIS VIR_FROM_NODEDEV
|
||
|
+
|
||
|
/*
|
||
|
* Host device enumeration (HAL implementation)
|
||
|
*/
|
||
|
@@ -215,6 +218,8 @@ static int gather_scsi_host_cap(LibHalContext *ctx, const char *udi,
|
||
|
union _virNodeDevCapData *d)
|
||
|
{
|
||
|
(void)get_int_prop(ctx, udi, "scsi_host.host", (int *)&d->scsi_host.host);
|
||
|
+ (void)check_fc_host(d);
|
||
|
+ (void)check_vport_capable(d);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/src/node_device_hal.h b/src/node_device_hal.h
|
||
|
new file mode 100644
|
||
|
index 0000000..0b4a2ef
|
||
|
--- /dev/null
|
||
|
+++ b/src/node_device_hal.h
|
||
|
@@ -0,0 +1,40 @@
|
||
|
+/*
|
||
|
+ * node_device_hal.h: node device enumeration - HAL-based implementation
|
||
|
+ *
|
||
|
+ * Copyright (C) 2009 Red Hat, Inc.
|
||
|
+ *
|
||
|
+ * 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
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef __VIR_NODE_DEVICE_HAL_H__
|
||
|
+#define __VIR_NODE_DEVICE_HAL_H__
|
||
|
+
|
||
|
+#ifdef __linux__
|
||
|
+
|
||
|
+#define check_fc_host(d) check_fc_host_linux(d)
|
||
|
+int check_fc_host_linux(union _virNodeDevCapData *d);
|
||
|
+
|
||
|
+#define check_vport_capable(d) check_vport_capable_linux(d)
|
||
|
+int check_vport_capable_linux(union _virNodeDevCapData *d);
|
||
|
+
|
||
|
+#else /* __linux__ */
|
||
|
+
|
||
|
+#define check_fc_host(d)
|
||
|
+#define check_vport_capable(d)
|
||
|
+
|
||
|
+#endif /* __linux__ */
|
||
|
+
|
||
|
+#endif /* __VIR_NODE_DEVICE_HAL_H__ */
|
||
|
diff --git a/src/node_device_hal_linux.c b/src/node_device_hal_linux.c
|
||
|
new file mode 100644
|
||
|
index 0000000..1deb6d2
|
||
|
--- /dev/null
|
||
|
+++ b/src/node_device_hal_linux.c
|
||
|
@@ -0,0 +1,170 @@
|
||
|
+/*
|
||
|
+ * node_device_hal_linuc.c: Linux specific code to gather device data
|
||
|
+ * not available through HAL.
|
||
|
+ *
|
||
|
+ * Copyright (C) 2009 Red Hat, Inc.
|
||
|
+ *
|
||
|
+ * 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
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+#include <config.h>
|
||
|
+
|
||
|
+#include <fcntl.h>
|
||
|
+
|
||
|
+#include "node_device.h"
|
||
|
+#include "node_device_hal.h"
|
||
|
+#include "virterror_internal.h"
|
||
|
+#include "memory.h"
|
||
|
+#include "logging.h"
|
||
|
+
|
||
|
+#define VIR_FROM_THIS VIR_FROM_NODEDEV
|
||
|
+
|
||
|
+#ifdef __linux__
|
||
|
+
|
||
|
+int check_fc_host_linux(union _virNodeDevCapData *d)
|
||
|
+{
|
||
|
+ char *sysfs_path = NULL;
|
||
|
+ char *wwnn_path = NULL;
|
||
|
+ char *wwpn_path = NULL;
|
||
|
+ char *p = NULL;
|
||
|
+ int fd = -1;
|
||
|
+ char buf[64];
|
||
|
+ struct stat st;
|
||
|
+
|
||
|
+ VIR_DEBUG(_("Checking if host%d is an FC HBA"), d->scsi_host.host);
|
||
|
+
|
||
|
+ if (virAsprintf(&sysfs_path, "%s/host%d",
|
||
|
+ LINUX_SYSFS_FC_HOST_PREFIX,
|
||
|
+ d->scsi_host.host) < 0) {
|
||
|
+ virReportOOMError(NULL);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (stat(sysfs_path, &st) != 0) {
|
||
|
+ /* Not an FC HBA */
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST;
|
||
|
+
|
||
|
+ if (virAsprintf(&wwnn_path, "%s/node_name",
|
||
|
+ sysfs_path) < 0) {
|
||
|
+ virReportOOMError(NULL);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ((fd = open(wwnn_path, O_RDONLY)) < 0) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ memset(buf, 0, sizeof(buf));
|
||
|
+ if (saferead(fd, buf, sizeof(buf)) < 0) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ close(fd);
|
||
|
+ fd = -1;
|
||
|
+
|
||
|
+ p = strstr(buf, "0x");
|
||
|
+ if (p != NULL) {
|
||
|
+ p += strlen("0x");
|
||
|
+ } else {
|
||
|
+ p = buf;
|
||
|
+ }
|
||
|
+
|
||
|
+ d->scsi_host.wwnn = strndup(p, sizeof(buf));
|
||
|
+ if (d->scsi_host.wwnn == NULL) {
|
||
|
+ virReportOOMError(NULL);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ p = strchr(d->scsi_host.wwnn, '\n');
|
||
|
+ if (p != NULL) {
|
||
|
+ *p = '\0';
|
||
|
+ }
|
||
|
+
|
||
|
+ if (virAsprintf(&wwpn_path, "%s/port_name",
|
||
|
+ sysfs_path) < 0) {
|
||
|
+ virReportOOMError(NULL);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ((fd = open(wwpn_path, O_RDONLY)) < 0) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ memset(buf, 0, sizeof(buf));
|
||
|
+ if (saferead(fd, buf, sizeof(buf)) < 0) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ close(fd);
|
||
|
+ fd = -1;
|
||
|
+
|
||
|
+ p = strstr(buf, "0x");
|
||
|
+ if (p != NULL) {
|
||
|
+ p += strlen("0x");
|
||
|
+ } else {
|
||
|
+ p = buf;
|
||
|
+ }
|
||
|
+
|
||
|
+ d->scsi_host.wwpn = strndup(p, sizeof(buf));
|
||
|
+ if (d->scsi_host.wwpn == NULL) {
|
||
|
+ virReportOOMError(NULL);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ p = strchr(d->scsi_host.wwpn, '\n');
|
||
|
+ if (p != NULL) {
|
||
|
+ *p = '\0';
|
||
|
+ }
|
||
|
+
|
||
|
+out:
|
||
|
+ if (fd != -1) {
|
||
|
+ close(fd);
|
||
|
+ }
|
||
|
+ VIR_FREE(sysfs_path);
|
||
|
+ VIR_FREE(wwnn_path);
|
||
|
+ VIR_FREE(wwpn_path);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+int check_vport_capable_linux(union _virNodeDevCapData *d)
|
||
|
+{
|
||
|
+ char *sysfs_path = NULL;
|
||
|
+ struct stat st;
|
||
|
+
|
||
|
+ if (virAsprintf(&sysfs_path, "%s/host%d/vport_create",
|
||
|
+ LINUX_SYSFS_FC_HOST_PREFIX,
|
||
|
+ d->scsi_host.host) < 0) {
|
||
|
+ virReportOOMError(NULL);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (stat(sysfs_path, &st) != 0) {
|
||
|
+ /* Not a vport capable HBA */
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS;
|
||
|
+
|
||
|
+out:
|
||
|
+ VIR_FREE(sysfs_path);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+#endif /* __linux__ */
|
||
|
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
|
||
|
index bd60b29..057e97b 100644
|
||
|
--- a/src/qemu_driver.c
|
||
|
+++ b/src/qemu_driver.c
|
||
|
@@ -5089,7 +5089,7 @@ qemudNodeDeviceGetPciInfo (virNodeDevicePtr dev,
|
||
|
if (!xml)
|
||
|
goto out;
|
||
|
|
||
|
- def = virNodeDeviceDefParseString(dev->conn, xml);
|
||
|
+ def = virNodeDeviceDefParseString(dev->conn, xml, EXISTING_DEVICE);
|
||
|
if (!def)
|
||
|
goto out;
|
||
|
|
||
|
diff --git a/src/storage_backend.c b/src/storage_backend.c
|
||
|
index b154140..74759cf 100644
|
||
|
--- a/src/storage_backend.c
|
||
|
+++ b/src/storage_backend.c
|
||
|
@@ -46,6 +46,7 @@
|
||
|
#include "virterror_internal.h"
|
||
|
#include "util.h"
|
||
|
#include "memory.h"
|
||
|
+#include "node_device.h"
|
||
|
|
||
|
#include "storage_backend.h"
|
||
|
|
||
|
@@ -245,30 +246,11 @@ virStorageBackendUpdateVolTargetInfoFD(virConnectPtr conn,
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-#if defined(UDEVADM) || defined(UDEVSETTLE)
|
||
|
void virStorageBackendWaitForDevices(virConnectPtr conn)
|
||
|
{
|
||
|
-#ifdef UDEVADM
|
||
|
- const char *const settleprog[] = { UDEVADM, "settle", NULL };
|
||
|
-#else
|
||
|
- const char *const settleprog[] = { UDEVSETTLE, NULL };
|
||
|
-#endif
|
||
|
- int exitstatus;
|
||
|
-
|
||
|
- if (access(settleprog[0], X_OK) != 0)
|
||
|
- return;
|
||
|
-
|
||
|
- /*
|
||
|
- * NOTE: we ignore errors here; this is just to make sure that any device
|
||
|
- * nodes that are being created finish before we try to scan them.
|
||
|
- * If this fails for any reason, we still have the backup of polling for
|
||
|
- * 5 seconds for device nodes.
|
||
|
- */
|
||
|
- virRun(conn, settleprog, &exitstatus);
|
||
|
+ virNodeDeviceWaitForDevices(conn);
|
||
|
+ return;
|
||
|
}
|
||
|
-#else
|
||
|
-void virStorageBackendWaitForDevices(virConnectPtr conn ATTRIBUTE_UNUSED) {}
|
||
|
-#endif
|
||
|
|
||
|
/*
|
||
|
* Given a volume path directly in /dev/XXX, iterate over the
|
||
|
diff --git a/src/xen_unified.c b/src/xen_unified.c
|
||
|
index e708980..8da4e23 100644
|
||
|
--- a/src/xen_unified.c
|
||
|
+++ b/src/xen_unified.c
|
||
|
@@ -1439,7 +1439,7 @@ xenUnifiedNodeDeviceGetPciInfo (virNodeDevicePtr dev,
|
||
|
if (!xml)
|
||
|
goto out;
|
||
|
|
||
|
- def = virNodeDeviceDefParseString(dev->conn, xml);
|
||
|
+ def = virNodeDeviceDefParseString(dev->conn, xml, EXISTING_DEVICE);
|
||
|
if (!def)
|
||
|
goto out;
|
||
|
|
||
|
diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
|
||
|
index 29cdb9e..7621212 100644
|
||
|
--- a/tests/nodedevxml2xmltest.c
|
||
|
+++ b/tests/nodedevxml2xmltest.c
|
||
|
@@ -29,7 +29,7 @@ static int testCompareXMLToXMLFiles(const char *xml) {
|
||
|
if (virtTestLoadFile(xml, &xmlPtr, MAX_FILE) < 0)
|
||
|
goto fail;
|
||
|
|
||
|
- if (!(dev = virNodeDeviceDefParseString(NULL, xmlData)))
|
||
|
+ if (!(dev = virNodeDeviceDefParseString(NULL, xmlData, EXISTING_DEVICE)))
|
||
|
goto fail;
|
||
|
|
||
|
if (!(actual = virNodeDeviceDefFormat(NULL, dev)))
|
||
|
--
|
||
|
1.6.0.6
|
||
|
|