summaryrefslogtreecommitdiff
path: root/src/libvirt-nodedev.c
diff options
context:
space:
mode:
authorDaniel P. Berrange <berrange@redhat.com>2014-10-22 16:29:09 +0100
committerDaniel P. Berrange <berrange@redhat.com>2014-10-24 16:26:55 +0100
commite33ed8cdfefb901b24213f2f85b40ce31b6550a5 (patch)
treef9b43fd9bd97da57ba51eebef87af5e1aad8c547 /src/libvirt-nodedev.c
parent35ed98755fe8048a796ddf5b1c3cee73a4732731 (diff)
downloadlibvirt-e33ed8cdfefb901b24213f2f85b40ce31b6550a5.tar.gz
Move virNodeDevice related APIs out of libvirt.c
Introduce a src/libvirt-nodedev.c file to hold all the methods related to the virNodeDevice type.
Diffstat (limited to 'src/libvirt-nodedev.c')
-rw-r--r--src/libvirt-nodedev.c756
1 files changed, 756 insertions, 0 deletions
diff --git a/src/libvirt-nodedev.c b/src/libvirt-nodedev.c
new file mode 100644
index 0000000000..c19aeeff5b
--- /dev/null
+++ b/src/libvirt-nodedev.c
@@ -0,0 +1,756 @@
+/*
+ * libvirt-nodedev.c: entry points for virNodeDevPtr APIs
+ *
+ * Copyright (C) 2006-2014 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, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "datatypes.h"
+#include "virlog.h"
+
+VIR_LOG_INIT("libvirt.nodedev");
+
+#define VIR_FROM_THIS VIR_FROM_NODEDEV
+
+
+/**
+ * virNodeNumOfDevices:
+ * @conn: pointer to the hypervisor connection
+ * @cap: capability name
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Provides the number of node devices.
+ *
+ * If the optional 'cap' argument is non-NULL, then the count
+ * will be restricted to devices with the specified capability
+ *
+ * Returns the number of node devices or -1 in case of error
+ */
+int
+virNodeNumOfDevices(virConnectPtr conn, const char *cap, unsigned int flags)
+{
+ VIR_DEBUG("conn=%p, cap=%s, flags=%x", conn, NULLSTR(cap), flags);
+
+ virResetLastError();
+
+ virCheckConnectReturn(conn, -1);
+
+ if (conn->nodeDeviceDriver && conn->nodeDeviceDriver->nodeNumOfDevices) {
+ int ret;
+ ret = conn->nodeDeviceDriver->nodeNumOfDevices(conn, cap, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(conn);
+ return -1;
+}
+
+
+/**
+ * virConnectListAllNodeDevices:
+ * @conn: Pointer to the hypervisor connection.
+ * @devices: Pointer to a variable to store the array containing the node
+ * device objects or NULL if the list is not required (just returns
+ * number of node devices).
+ * @flags: bitwise-OR of virConnectListAllNodeDevices.
+ *
+ * Collect the list of node devices, and allocate an array to store those
+ * objects.
+ *
+ * Normally, all node devices are returned; however, @flags can be used to
+ * filter the results for a smaller list of targeted node devices. The valid
+ * flags are divided into groups, where each group contains bits that
+ * describe mutually exclusive attributes of a node device, and where all bits
+ * within a group describe all possible node devices.
+ *
+ * Only one group of the @flags is provided to filter the node devices by
+ * capability type, flags include:
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS
+ * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_GENERIC
+ *
+ * Returns the number of node devices found or -1 and sets @devices to NULL in
+ * case of error. On success, the array stored into @devices is guaranteed to
+ * have an extra allocated element set to NULL but not included in the return
+ * count, to make iteration easier. The caller is responsible for calling
+ * virNodeDeviceFree() on each array element, then calling free() on
+ * @devices.
+ */
+int
+virConnectListAllNodeDevices(virConnectPtr conn,
+ virNodeDevicePtr **devices,
+ unsigned int flags)
+{
+ VIR_DEBUG("conn=%p, devices=%p, flags=%x", conn, devices, flags);
+
+ virResetLastError();
+
+ if (devices)
+ *devices = NULL;
+
+ virCheckConnectReturn(conn, -1);
+
+ if (conn->nodeDeviceDriver &&
+ conn->nodeDeviceDriver->connectListAllNodeDevices) {
+ int ret;
+ ret = conn->nodeDeviceDriver->connectListAllNodeDevices(conn, devices, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(conn);
+ return -1;
+}
+
+
+/**
+ * virNodeListDevices:
+ * @conn: pointer to the hypervisor connection
+ * @cap: capability name
+ * @names: array to collect the list of node device names
+ * @maxnames: size of @names
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Collect the list of node devices, and store their names in @names
+ *
+ * For more control over the results, see virConnectListAllNodeDevices().
+ *
+ * If the optional 'cap' argument is non-NULL, then the count
+ * will be restricted to devices with the specified capability
+ *
+ * Returns the number of node devices found or -1 in case of error
+ */
+int
+virNodeListDevices(virConnectPtr conn,
+ const char *cap,
+ char **const names, int maxnames,
+ unsigned int flags)
+{
+ VIR_DEBUG("conn=%p, cap=%s, names=%p, maxnames=%d, flags=%x",
+ conn, cap, names, maxnames, flags);
+
+ virResetLastError();
+
+ virCheckConnectReturn(conn, -1);
+ virCheckNonNullArgGoto(names, error);
+ virCheckNonNegativeArgGoto(maxnames, error);
+
+ if (conn->nodeDeviceDriver && conn->nodeDeviceDriver->nodeListDevices) {
+ int ret;
+ ret = conn->nodeDeviceDriver->nodeListDevices(conn, cap, names, maxnames, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(conn);
+ return -1;
+}
+
+
+/**
+ * virNodeDeviceLookupByName:
+ * @conn: pointer to the hypervisor connection
+ * @name: unique device name
+ *
+ * Lookup a node device by its name.
+ *
+ * virNodeDeviceFree should be used to free the resources after the
+ * node device object is no longer needed.
+ *
+ * Returns a virNodeDevicePtr if found, NULL otherwise.
+ */
+virNodeDevicePtr
+virNodeDeviceLookupByName(virConnectPtr conn, const char *name)
+{
+ VIR_DEBUG("conn=%p, name=%p", conn, name);
+
+ virResetLastError();
+
+ virCheckConnectReturn(conn, NULL);
+ virCheckNonNullArgGoto(name, error);
+
+ if (conn->nodeDeviceDriver && conn->nodeDeviceDriver->nodeDeviceLookupByName) {
+ virNodeDevicePtr ret;
+ ret = conn->nodeDeviceDriver->nodeDeviceLookupByName(conn, name);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+
+/**
+ * virNodeDeviceLookupSCSIHostByWWN:
+ * @conn: pointer to the hypervisor connection
+ * @wwnn: WWNN of the SCSI Host.
+ * @wwpn: WWPN of the SCSI Host.
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Lookup SCSI Host which is capable with 'fc_host' by its WWNN and WWPN.
+ *
+ * virNodeDeviceFree should be used to free the resources after the
+ * node device object is no longer needed.
+ *
+ * Returns a virNodeDevicePtr if found, NULL otherwise.
+ */
+virNodeDevicePtr
+virNodeDeviceLookupSCSIHostByWWN(virConnectPtr conn,
+ const char *wwnn,
+ const char *wwpn,
+ unsigned int flags)
+{
+ VIR_DEBUG("conn=%p, wwnn=%p, wwpn=%p, flags=%x", conn, wwnn, wwpn, flags);
+
+ virResetLastError();
+
+ virCheckConnectReturn(conn, NULL);
+ virCheckNonNullArgGoto(wwnn, error);
+ virCheckNonNullArgGoto(wwpn, error);
+
+ if (conn->nodeDeviceDriver &&
+ conn->nodeDeviceDriver->nodeDeviceLookupSCSIHostByWWN) {
+ virNodeDevicePtr ret;
+ ret = conn->nodeDeviceDriver->nodeDeviceLookupSCSIHostByWWN(conn, wwnn,
+ wwpn, flags);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+
+/**
+ * virNodeDeviceGetXMLDesc:
+ * @dev: pointer to the node device
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Fetch an XML document describing all aspects of
+ * the device.
+ *
+ * Returns the XML document, or NULL on error
+ */
+char *
+virNodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags)
+{
+ VIR_DEBUG("dev=%p, conn=%p, flags=%x", dev, dev ? dev->conn : NULL, flags);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, NULL);
+
+ if (dev->conn->nodeDeviceDriver && dev->conn->nodeDeviceDriver->nodeDeviceGetXMLDesc) {
+ char *ret;
+ ret = dev->conn->nodeDeviceDriver->nodeDeviceGetXMLDesc(dev, flags);
+ if (!ret)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dev->conn);
+ return NULL;
+}
+
+
+/**
+ * virNodeDeviceGetName:
+ * @dev: the device
+ *
+ * Just return the device name
+ *
+ * Returns the device name or NULL in case of error
+ */
+const char *
+virNodeDeviceGetName(virNodeDevicePtr dev)
+{
+ VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, NULL);
+
+ return dev->name;
+}
+
+
+/**
+ * virNodeDeviceGetParent:
+ * @dev: the device
+ *
+ * Accessor for the parent of the device
+ *
+ * Returns the name of the device's parent, or NULL if an
+ * error occurred or when the device has no parent.
+ */
+const char *
+virNodeDeviceGetParent(virNodeDevicePtr dev)
+{
+ VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, NULL);
+
+ if (!dev->parent) {
+ if (dev->conn->nodeDeviceDriver && dev->conn->nodeDeviceDriver->nodeDeviceGetParent) {
+ dev->parent = dev->conn->nodeDeviceDriver->nodeDeviceGetParent(dev);
+ } else {
+ virReportUnsupportedError();
+ virDispatchError(dev->conn);
+ return NULL;
+ }
+ }
+ return dev->parent;
+}
+
+
+/**
+ * virNodeDeviceNumOfCaps:
+ * @dev: the device
+ *
+ * Accessor for the number of capabilities supported by the device.
+ *
+ * Returns the number of capabilities supported by the device or -1
+ * in case of error.
+ */
+int
+virNodeDeviceNumOfCaps(virNodeDevicePtr dev)
+{
+ VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, -1);
+
+ if (dev->conn->nodeDeviceDriver && dev->conn->nodeDeviceDriver->nodeDeviceNumOfCaps) {
+ int ret;
+ ret = dev->conn->nodeDeviceDriver->nodeDeviceNumOfCaps(dev);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dev->conn);
+ return -1;
+}
+
+
+/**
+ * virNodeDeviceListCaps:
+ * @dev: the device
+ * @names: array to collect the list of capability names
+ * @maxnames: size of @names
+ *
+ * Lists the names of the capabilities supported by the device.
+ *
+ * Returns the number of capability names listed in @names or -1
+ * in case of error.
+ */
+int
+virNodeDeviceListCaps(virNodeDevicePtr dev,
+ char **const names,
+ int maxnames)
+{
+ VIR_DEBUG("dev=%p, conn=%p, names=%p, maxnames=%d",
+ dev, dev ? dev->conn : NULL, names, maxnames);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, -1);
+ virCheckNonNullArgGoto(names, error);
+ virCheckNonNegativeArgGoto(maxnames, error);
+
+ if (dev->conn->nodeDeviceDriver && dev->conn->nodeDeviceDriver->nodeDeviceListCaps) {
+ int ret;
+ ret = dev->conn->nodeDeviceDriver->nodeDeviceListCaps(dev, names, maxnames);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dev->conn);
+ return -1;
+}
+
+
+/**
+ * virNodeDeviceFree:
+ * @dev: pointer to the node device
+ *
+ * Drops a reference to the node device, freeing it if
+ * this was the last reference.
+ *
+ * Returns the 0 for success, -1 for error.
+ */
+int
+virNodeDeviceFree(virNodeDevicePtr dev)
+{
+ VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, -1);
+
+ virObjectUnref(dev);
+ return 0;
+}
+
+
+/**
+ * virNodeDeviceRef:
+ * @dev: the dev to hold a reference on
+ *
+ * Increment the reference count on the dev. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virNodeDeviceFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using a dev would increment
+ * the reference count.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virNodeDeviceRef(virNodeDevicePtr dev)
+{
+ VIR_DEBUG("dev=%p refs=%d", dev, dev ? dev->object.u.s.refs : 0);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, -1);
+
+ virObjectRef(dev);
+ return 0;
+}
+
+
+/**
+ * virNodeDeviceDettach:
+ * @dev: pointer to the node device
+ *
+ * Dettach the node device from the node itself so that it may be
+ * assigned to a guest domain.
+ *
+ * Depending on the hypervisor, this may involve operations such
+ * as unbinding any device drivers from the device, binding the
+ * device to a dummy device driver and resetting the device.
+ *
+ * If the device is currently in use by the node, this method may
+ * fail.
+ *
+ * Once the device is not assigned to any guest, it may be re-attached
+ * to the node using the virNodeDeviceReattach() method.
+ *
+ * If the caller needs control over which backend driver will be used
+ * during PCI device assignment (to use something other than the
+ * default, for example VFIO), the newer virNodeDeviceDetachFlags()
+ * API should be used instead.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virNodeDeviceDettach(virNodeDevicePtr dev)
+{
+ VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, -1);
+ virCheckReadOnlyGoto(dev->conn->flags, error);
+
+ if (dev->conn->driver->nodeDeviceDettach) {
+ int ret;
+ ret = dev->conn->driver->nodeDeviceDettach(dev);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dev->conn);
+ return -1;
+}
+
+
+/**
+ * virNodeDeviceDetachFlags:
+ * @dev: pointer to the node device
+ * @driverName: name of backend driver that will be used
+ * for later device assignment to a domain. NULL
+ * means "use the hypervisor default driver"
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Detach the node device from the node itself so that it may be
+ * assigned to a guest domain.
+ *
+ * Depending on the hypervisor, this may involve operations such as
+ * unbinding any device drivers from the device, binding the device to
+ * a dummy device driver and resetting the device. Different backend
+ * drivers expect the device to be bound to different dummy
+ * devices. For example, QEMU's "kvm" backend driver (the default)
+ * expects the device to be bound to "pci-stub", but its "vfio"
+ * backend driver expects the device to be bound to "vfio-pci".
+ *
+ * If the device is currently in use by the node, this method may
+ * fail.
+ *
+ * Once the device is not assigned to any guest, it may be re-attached
+ * to the node using the virNodeDeviceReAttach() method.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virNodeDeviceDetachFlags(virNodeDevicePtr dev,
+ const char *driverName,
+ unsigned int flags)
+{
+ VIR_DEBUG("dev=%p, conn=%p driverName=%s flags=%x",
+ dev, dev ? dev->conn : NULL,
+ driverName ? driverName : "(default)", flags);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, -1);
+ virCheckReadOnlyGoto(dev->conn->flags, error);
+
+ if (dev->conn->driver->nodeDeviceDetachFlags) {
+ int ret;
+ ret = dev->conn->driver->nodeDeviceDetachFlags(dev, driverName, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dev->conn);
+ return -1;
+}
+
+
+/**
+ * virNodeDeviceReAttach:
+ * @dev: pointer to the node device
+ *
+ * Re-attach a previously dettached node device to the node so that it
+ * may be used by the node again.
+ *
+ * Depending on the hypervisor, this may involve operations such
+ * as resetting the device, unbinding it from a dummy device driver
+ * and binding it to its appropriate driver.
+ *
+ * If the device is currently in use by a guest, this method may fail.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virNodeDeviceReAttach(virNodeDevicePtr dev)
+{
+ VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, -1);
+ virCheckReadOnlyGoto(dev->conn->flags, error);
+
+ if (dev->conn->driver->nodeDeviceReAttach) {
+ int ret;
+ ret = dev->conn->driver->nodeDeviceReAttach(dev);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dev->conn);
+ return -1;
+}
+
+
+/**
+ * virNodeDeviceReset:
+ * @dev: pointer to the node device
+ *
+ * Reset a previously dettached node device to the node before or
+ * after assigning it to a guest.
+ *
+ * The exact reset semantics depends on the hypervisor and device
+ * type but, for example, KVM will attempt to reset PCI devices with
+ * a Function Level Reset, Secondary Bus Reset or a Power Management
+ * D-State reset.
+ *
+ * If the reset will affect other devices which are currently in use,
+ * this function may fail.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virNodeDeviceReset(virNodeDevicePtr dev)
+{
+ VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, -1);
+ virCheckReadOnlyGoto(dev->conn->flags, error);
+
+ if (dev->conn->driver->nodeDeviceReset) {
+ int ret;
+ ret = dev->conn->driver->nodeDeviceReset(dev);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dev->conn);
+ return -1;
+}
+
+
+/**
+ * virNodeDeviceCreateXML:
+ * @conn: pointer to the hypervisor connection
+ * @xmlDesc: string containing an XML description of the device to be created
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Create a new device on the VM host machine, for example, virtual
+ * HBAs created using vport_create.
+ *
+ * virNodeDeviceFree should be used to free the resources after the
+ * node device object is no longer needed.
+ *
+ * Returns a node device object if successful, NULL in case of failure
+ */
+virNodeDevicePtr
+virNodeDeviceCreateXML(virConnectPtr conn,
+ const char *xmlDesc,
+ unsigned int flags)
+{
+ VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%x", conn, xmlDesc, flags);
+
+ virResetLastError();
+
+ virCheckConnectReturn(conn, NULL);
+ virCheckReadOnlyGoto(conn->flags, error);
+ virCheckNonNullArgGoto(xmlDesc, error);
+
+ if (conn->nodeDeviceDriver &&
+ conn->nodeDeviceDriver->nodeDeviceCreateXML) {
+ virNodeDevicePtr dev = conn->nodeDeviceDriver->nodeDeviceCreateXML(conn, xmlDesc, flags);
+ if (dev == NULL)
+ goto error;
+ return dev;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(conn);
+ return NULL;
+}
+
+
+/**
+ * virNodeDeviceDestroy:
+ * @dev: a device object
+ *
+ * Destroy the device object. The virtual device (only works for vHBA
+ * currently) is removed from the host operating system. This function
+ * may require privileged access.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virNodeDeviceDestroy(virNodeDevicePtr dev)
+{
+ VIR_DEBUG("dev=%p", dev);
+
+ virResetLastError();
+
+ virCheckNodeDeviceReturn(dev, -1);
+ virCheckReadOnlyGoto(dev->conn->flags, error);
+
+ if (dev->conn->nodeDeviceDriver &&
+ dev->conn->nodeDeviceDriver->nodeDeviceDestroy) {
+ int retval = dev->conn->nodeDeviceDriver->nodeDeviceDestroy(dev);
+ if (retval < 0) {
+ goto error;
+ }
+
+ return 0;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dev->conn);
+ return -1;
+}