---
src/Makefile.am | 4 +-
src/node_device.c | 123 ++++++++++++++++++++++++--------
src/node_device.h | 1 -
src/node_device_conf.c | 30 +++++---
src/node_device_conf.h | 6 ++-
src/node_device_hal.c | 131 +----------------------------------
src/node_device_hal.h | 40 ++++++++++
src/node_device_hal_linux.c | 165 +++++++++++++++++++++++++++++++++++++++++++
src/qemu_driver.c | 2 +-
src/remote_internal.c | 2 +-
src/virsh.c | 56 ++++++++++++++-
src/xen_unified.c | 2 +-
tests/nodedevxml2xmltest.c | 2 +-
13 files changed, 384 insertions(+), 180 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 25d3251..41a7fd9 100644
--- a/src/node_device.c
+++ b/src/node_device.c
@@ -316,9 +316,8 @@ nodeDeviceVportCreateDelete(virConnectPtr conn,
{
int fd = -1;
int retval = 0;
- char *operation_path;
+ char *operation_path = NULL, *vport_name = NULL;
const char *operation_file;
- char *vport_name;
size_t towrite = 0;
unsigned int written = 0;
@@ -333,7 +332,7 @@ nodeDeviceVportCreateDelete(virConnectPtr conn,
virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("Invalid vport operation (%d)"),
operation);
retval = -1;
- goto no_unwind;
+ goto cleanup;
break;
}
@@ -345,7 +344,7 @@ nodeDeviceVportCreateDelete(virConnectPtr conn,
virReportOOMError(conn);
retval = -1;
- goto no_unwind;
+ goto cleanup;
}
VIR_DEBUG(_("Vport operation path is '%s'"), operation_path);
@@ -357,7 +356,7 @@ nodeDeviceVportCreateDelete(virConnectPtr conn,
_("Could not open '%s' for vport
operation"),
operation_path);
retval = -1;
- goto free_path;
+ goto cleanup;
}
if (virAsprintf(&vport_name,
@@ -367,7 +366,7 @@ nodeDeviceVportCreateDelete(virConnectPtr conn,
virReportOOMError(conn);
retval = -1;
- goto close_fd;
+ goto cleanup;
}
towrite = strlen(vport_name);
@@ -382,12 +381,12 @@ nodeDeviceVportCreateDelete(virConnectPtr conn,
retval = -1;
}
+cleanup:
+ if (fd != -1) {
+ close(fd);
+ }
VIR_FREE(vport_name);
-close_fd:
- close(fd);
-free_path:
VIR_FREE(operation_path);
-no_unwind:
VIR_DEBUG("%s", _("Vport operation complete"));
return retval;
}
@@ -406,8 +405,8 @@ get_wwns(virConnectPtr conn,
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 = cap->data.scsi_host.wwnn;
- *wwpn = cap->data.scsi_host.wwnn;
+ *wwnn = strdup(cap->data.scsi_host.wwnn);
+ *wwpn = strdup(cap->data.scsi_host.wwpn);
break;
}
@@ -415,13 +414,17 @@ get_wwns(virConnectPtr conn,
}
if (cap == NULL) {
- /* XXX This error code is wrong--it results in errors of the form:
- "error: invalid node device pointer in Device foo is not a fibre channel
HBA"
- */
- virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
- _("Device %s is not a fibre channel HBA"),
- def->name);
+ 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;
@@ -431,27 +434,30 @@ get_wwns(virConnectPtr conn,
static int
get_parent_host(virConnectPtr conn,
virDeviceMonitorStatePtr driver,
- virNodeDeviceDefPtr def,
+ const char *dev_name,
+ const char *parent_name,
int *parent_host)
{
virNodeDeviceObjPtr parent = NULL;
virNodeDevCapsDefPtr cap = NULL;
int ret = 0;
- parent = virNodeDeviceFindByName(&driver->devs, def->parent);
+ parent = virNodeDeviceFindByName(&driver->devs, parent_name);
if (parent == NULL) {
virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
_("Could not find parent device for
'%s'"),
- def->name);
+ dev_name);
ret = -1;
goto out;
}
cap = parent->def->caps;
while (cap != NULL) {
- if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) {
- *parent_host = cap->data.scsi_host.host;
- break;
+ 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;
@@ -459,7 +465,7 @@ get_parent_host(virConnectPtr conn,
if (cap == NULL) {
virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
- _("Device %s is not a SCSI host"),
+ _("Device %s is not capable of vport
operations"),
parent->def->name);
ret = -1;
}
@@ -542,7 +548,7 @@ nodeDeviceCreateXML(virConnectPtr conn,
nodeDeviceLock(driver);
- def = virNodeDeviceDefParseString(conn, xmlDesc);
+ def = virNodeDeviceDefParseString(conn, xmlDesc, CREATE_DEVICE);
if (def == NULL) {
goto cleanup;
}
@@ -551,7 +557,11 @@ nodeDeviceCreateXML(virConnectPtr conn,
goto cleanup;
}
- if (get_parent_host(conn, driver, def, &parent_host) == -1) {
+ if (get_parent_host(conn,
+ driver,
+ def->name,
+ def->parent,
+ &parent_host) == -1) {
goto cleanup;
}
@@ -574,14 +584,69 @@ nodeDeviceCreateXML(virConnectPtr conn,
cleanup:
nodeDeviceUnlock(driver);
virNodeDeviceDefFree(def);
+ VIR_FREE(wwnn);
+ VIR_FREE(wwpn);
return dev;
}
static int
-nodeDeviceDestroy(virNodeDevicePtr dev ATTRIBUTE_UNUSED)
+nodeDeviceDestroy(virNodeDevicePtr dev)
{
- return 0;
+ 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;
}
diff --git a/src/node_device.h b/src/node_device.h
index 59cd5f5..882ba0f 100644
--- a/src/node_device.h
+++ b/src/node_device.h
@@ -28,7 +28,6 @@
#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/"
diff --git a/src/node_device_conf.c b/src/node_device_conf.c
index 6c74551..5b35b60 100644
--- a/src/node_device_conf.c
+++ b/src/node_device_conf.c
@@ -598,7 +598,8 @@ virNodeDevCapScsiHostParseXML(virConnectPtr conn,
xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
xmlNodePtr node,
- union _virNodeDevCapData *data)
+ union _virNodeDevCapData *data,
+ int create)
{
xmlNodePtr orignode, *nodes = NULL;
int ret = -1, n = 0, i;
@@ -607,7 +608,8 @@ virNodeDevCapScsiHostParseXML(virConnectPtr conn,
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) {
@@ -948,7 +950,8 @@ static virNodeDevCapsDefPtr
virNodeDevCapsDefParseXML(virConnectPtr conn,
xmlXPathContextPtr ctxt,
virNodeDeviceDefPtr def,
- xmlNodePtr node)
+ xmlNodePtr node,
+ int create)
{
virNodeDevCapsDefPtr caps;
char *tmp;
@@ -992,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);
@@ -1018,7 +1021,7 @@ error:
}
static virNodeDeviceDefPtr
-virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt)
+virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt, int create)
{
virNodeDeviceDefPtr def;
virNodeDevCapsDefPtr *next_cap;
@@ -1031,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;
@@ -1051,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;
@@ -1069,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;
@@ -1087,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);
@@ -1115,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;
@@ -1146,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 8233a91..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 */
@@ -201,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 5e54044..5927ba1 100644
--- a/src/node_device_hal.c
+++ b/src/node_device_hal.c
@@ -26,9 +26,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <libhal.h>
-#include <fcntl.h>
#include "node_device_conf.h"
+#include "node_device_hal.h"
#include "virterror_internal.h"
#include "driver.h"
#include "datatypes.h"
@@ -214,135 +214,6 @@ static int gather_net_cap(LibHalContext *ctx, const char *udi,
}
-static int check_fc_host(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);
-
- 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);
-
- 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:
- VIR_FREE(sysfs_path);
- VIR_FREE(wwnn_path);
- VIR_FREE(wwpn_path);
- return 0;
-}
-
-
-static int check_vport_capable(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;
-}
-
-
static int gather_scsi_host_cap(LibHalContext *ctx, const char *udi,
union _virNodeDevCapData *d)
{
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..37b385b
--- /dev/null
+++ b/src/node_device_hal_linux.c
@@ -0,0 +1,165 @@
+/*
+ * 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);
+
+ 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);
+
+ 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:
+ 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 acf08d4..bcc7518 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -5006,7 +5006,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/remote_internal.c b/src/remote_internal.c
index 24226e5..dd46e2f 100644
--- a/src/remote_internal.c
+++ b/src/remote_internal.c
@@ -5027,7 +5027,7 @@ remoteNodeDeviceDestroy(virNodeDevicePtr dev)
args.name = dev->name;
- if (call(dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_RESET,
+ if (call(dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_DESTROY,
(xdrproc_t) xdr_remote_node_device_destroy_args, (char *) &args,
(xdrproc_t) xdr_void, (char *) NULL) == -1)
goto done;
diff --git a/src/virsh.c b/src/virsh.c
index 1a094eb..427d97f 100644
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -2984,7 +2984,7 @@ cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
{
virNodeDevicePtr dev = NULL;
char *from;
- int found;
+ int found = 0;
int ret = TRUE;
char *buffer;
@@ -2992,11 +2992,13 @@ cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
return FALSE;
from = vshCommandOptString(cmd, "file", &found);
- if (!found)
+ if (!found) {
return FALSE;
+ }
- if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
+ if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
return FALSE;
+ }
dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0);
free (buffer);
@@ -3014,6 +3016,53 @@ cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
/*
+ * "nodedev-destroy" command
+ */
+static const vshCmdInfo info_node_device_destroy[] = {
+ {"help", gettext_noop("destroy a device on the node")},
+ {"desc", gettext_noop("Destroy a device on the node. Note that this
"
+ "command destroys devices on the physical host ")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_node_device_destroy[] = {
+ {"name", VSH_OT_DATA, VSH_OFLAG_REQ,
+ gettext_noop("name of the device to be destroyed")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd)
+{
+ virNodeDevicePtr dev = NULL;
+ int ret = TRUE;
+ int found = 0;
+ char *name;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) {
+ return FALSE;
+ }
+
+ name = vshCommandOptString(cmd, "name", &found);
+ if (!found) {
+ return FALSE;
+ }
+
+ dev = virNodeDeviceLookupByName(ctl->conn, name);
+
+ if (virNodeDeviceDestroy(dev) == 0) {
+ vshPrint(ctl, _("Destroyed node device '%s'\n"), name);
+ } else {
+ vshError(ctl, FALSE, _("Failed to destroy node device '%s'"),
name);
+ ret = FALSE;
+ }
+
+ virNodeDeviceFree(dev);
+ return ret;
+}
+
+
+/*
* XML Building helper for pool-define-as and pool-create-as
*/
static const vshCmdOptDef opts_pool_X_as[] = {
@@ -5948,6 +5997,7 @@ static const vshCmdDef commands[] = {
{"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach,
info_node_device_reattach},
{"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset,
info_node_device_reset},
{"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create,
info_node_device_create},
+ {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy,
info_node_device_destroy},
{"pool-autostart", cmdPoolAutostart, opts_pool_autostart,
info_pool_autostart},
{"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build},
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