[libvirt] [PATCH 2/2] Implement destroy API

David Allan dallan at redhat.com
Fri May 8 21:41:09 UTC 2009


---
 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




More information about the libvir-list mailing list