Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
src/libvirt_private.syms | 2 ++
src/util/virpci.c | 71 ++++++++++++++++++++++++++++--------------------
src/util/virpci.h | 5 ++++
3 files changed, 49 insertions(+), 29 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 91d1304..68140e6 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1581,6 +1581,7 @@ virPCIDeviceCopy;
virPCIDeviceDetach;
virPCIDeviceFileIterate;
virPCIDeviceFree;
+virPCIDeviceGetDriverPathAndName;
virPCIDeviceGetIOMMUGroupDev;
virPCIDeviceGetIOMMUGroupList;
virPCIDeviceGetManaged;
@@ -1612,6 +1613,7 @@ virPCIDeviceSetReprobe;
virPCIDeviceSetStubDriver;
virPCIDeviceSetUnbindFromStub;
virPCIDeviceSetUsedBy;
+virPCIDeviceUnbind;
virPCIDeviceWaitForCleanup;
virPCIGetNetName;
virPCIGetPhysicalFunction;
diff --git a/src/util/virpci.c b/src/util/virpci.c
index f6ab794..e2d222e 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -225,7 +225,7 @@ virPCIFile(char **buffer, const char *device, const char *file)
*
* Return 0 for success, -1 for error.
*/
-static int
+int
virPCIDeviceGetDriverPathAndName(virPCIDevicePtr dev, char **path, char **name)
{
int ret = -1;
@@ -1005,6 +1005,44 @@ recheck:
return -1;
}
+int
+virPCIDeviceUnbind(virPCIDevicePtr dev, bool reprobe)
+{
+ char *path = NULL;
+ char *drvpath = NULL;
+ char *driver = NULL;
+ int ret = -1;
+
+ if (virPCIDeviceGetDriverPathAndName(dev, &drvpath, &driver) < 0)
+ goto cleanup;
+
+ if (!driver) {
+ /* The device is not bound to any driver */
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (virPCIFile(&path, dev->name, "driver/unbind") < 0)
+ goto cleanup;
+
+ if (virFileExists(path)) {
+ if (virFileWriteStr(path, dev->name, 0) < 0) {
+ virReportSystemError(errno,
+ _("Failed to unbind PCI device '%s' from
%s"),
+ dev->name, driver);
+ goto cleanup;
+ }
+ dev->reprobe = reprobe;
+ }
+
+ ret = 0;
+cleanup:
+ VIR_FREE(path);
+ VIR_FREE(drvpath);
+ VIR_FREE(driver);
+ return ret;
+}
+
static const char *virPCIKnownStubs[] = {
"pciback", /* used by xen */
"pci-stub", /* used by kvm legacy passthrough */
@@ -1047,18 +1085,8 @@ virPCIDeviceUnbindFromStub(virPCIDevicePtr dev)
if (!isStub)
goto remove_slot;
- if (virFileExists(drvdir)) {
- if (virPCIDriverFile(&path, driver, "unbind") < 0) {
- goto cleanup;
- }
-
- if (virFileWriteStr(path, dev->name, 0) < 0) {
- virReportSystemError(errno,
- _("Failed to unbind PCI device '%s' from
%s"),
- dev->name, driver);
- goto cleanup;
- }
- }
+ if (virPCIDeviceUnbind(dev, dev->reprobe) < 0)
+ goto cleanup;
dev->unbind_from_stub = false;
remove_slot:
@@ -1174,24 +1202,9 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
goto remove_id;
}
- /* If the device is already bound to a driver, unbind it.
- * Note, this will have rather unpleasant side effects if this
- * PCI device happens to be IDE controller for the disk hosting
- * your root filesystem.
- */
- if (virPCIFile(&path, dev->name, "driver/unbind") < 0)
+ if (virPCIDeviceUnbind(dev, reprobe) < 0)
goto remove_id;
- if (virFileExists(path)) {
- if (virFileWriteStr(path, dev->name, 0) < 0) {
- virReportSystemError(errno,
- _("Failed to unbind PCI device
'%s'"),
- dev->name);
- goto remove_id;
- }
- dev->reprobe = reprobe;
- }
-
/* If the device isn't already bound to pci-stub, try binding it now.
*/
if (!virFileLinkPointsTo(driverLink, stubDriverPath)) {
diff --git a/src/util/virpci.h b/src/util/virpci.h
index 08bf4c3..42c3c95 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -167,4 +167,9 @@ int virPCIDeviceAddressParse(char *address, virPCIDeviceAddressPtr
bdf);
int virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path,
char **pfname, int *vf_index);
+int virPCIDeviceUnbind(virPCIDevicePtr dev, bool reprobe);
+int virPCIDeviceGetDriverPathAndName(virPCIDevicePtr dev,
+ char **path,
+ char **name);
+
#endif /* __VIR_PCI_H__ */
--
1.8.5.3