pci: Fix failure paths in detach

https://bugzilla.redhat.com/show_bug.cgi?id=1046919

Since commit v0.9.0-47-g4e8969e (released in 0.9.1) some failures during
device detach were reported to callers of virPCIDeviceBindToStub as
success. For example, even though a device seemed to be detached

    virsh # nodedev-detach pci_0000_07_05_0 --driver vfio
    Device pci_0000_07_05_0 detached

one could find similar message in libvirt logs:

    Failed to bind PCI device '0000:07:05.0' to vfio-pci: No such device

This patch fixes these paths and also avoids overwriting real errors
with errors encountered during a cleanup phase.
This commit is contained in:
Jiri Denemark 2014-01-16 20:08:00 +01:00
parent c982e5e84f
commit d8ab981bdd

View File

@ -1123,14 +1123,15 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
{ {
int result = -1; int result = -1;
int reprobe = false; int reprobe = false;
char *stubDriverPath = NULL; char *stubDriverPath = NULL;
char *driverLink = NULL; char *driverLink = NULL;
char *path = NULL; /* reused for different purposes */ char *path = NULL; /* reused for different purposes */
const char *newDriverName = NULL; char *newDriverName = NULL;
virErrorPtr err = NULL;
if (virPCIDriverDir(&stubDriverPath, stubDriverName) < 0 || if (virPCIDriverDir(&stubDriverPath, stubDriverName) < 0 ||
virPCIFile(&driverLink, dev->name, "driver") < 0) virPCIFile(&driverLink, dev->name, "driver") < 0 ||
VIR_STRDUP(newDriverName, stubDriverName) < 0)
goto cleanup; goto cleanup;
if (virFileExists(driverLink)) { if (virFileExists(driverLink)) {
@ -1138,7 +1139,6 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
/* The device is already bound to the correct driver */ /* The device is already bound to the correct driver */
VIR_DEBUG("Device %s is already bound to %s", VIR_DEBUG("Device %s is already bound to %s",
dev->name, stubDriverName); dev->name, stubDriverName);
newDriverName = stubDriverName;
result = 0; result = 0;
goto cleanup; goto cleanup;
} }
@ -1170,6 +1170,7 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
if (virFileLinkPointsTo(driverLink, stubDriverPath)) { if (virFileLinkPointsTo(driverLink, stubDriverPath)) {
dev->unbind_from_stub = true; dev->unbind_from_stub = true;
dev->remove_slot = true; dev->remove_slot = true;
result = 0;
goto remove_id; goto remove_id;
} }
@ -1178,16 +1179,15 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
* PCI device happens to be IDE controller for the disk hosting * PCI device happens to be IDE controller for the disk hosting
* your root filesystem. * your root filesystem.
*/ */
if (virPCIFile(&path, dev->name, "driver/unbind") < 0) { if (virPCIFile(&path, dev->name, "driver/unbind") < 0)
goto cleanup; goto remove_id;
}
if (virFileExists(path)) { if (virFileExists(path)) {
if (virFileWriteStr(path, dev->name, 0) < 0) { if (virFileWriteStr(path, dev->name, 0) < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("Failed to unbind PCI device '%s'"), _("Failed to unbind PCI device '%s'"),
dev->name); dev->name);
goto cleanup; goto remove_id;
} }
dev->reprobe = reprobe; dev->reprobe = reprobe;
} }
@ -1222,7 +1222,11 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
dev->unbind_from_stub = true; dev->unbind_from_stub = true;
} }
result = 0;
remove_id: remove_id:
err = virSaveLastError();
/* If 'remove_id' exists, remove the device id from pci-stub's dynamic /* If 'remove_id' exists, remove the device id from pci-stub's dynamic
* ID table so that 'drivers_probe' works below. * ID table so that 'drivers_probe' works below.
*/ */
@ -1233,6 +1237,7 @@ remove_id:
"cannot be probed again.", dev->id, stubDriverName); "cannot be probed again.", dev->id, stubDriverName);
} }
dev->reprobe = false; dev->reprobe = false;
result = -1;
goto cleanup; goto cleanup;
} }
@ -1247,24 +1252,26 @@ remove_id:
"cannot be probed again.", dev->id, stubDriverName); "cannot be probed again.", dev->id, stubDriverName);
} }
dev->reprobe = false; dev->reprobe = false;
result = -1;
goto cleanup; goto cleanup;
} }
newDriverName = stubDriverName;
result = 0;
cleanup: cleanup:
VIR_FREE(stubDriverPath); VIR_FREE(stubDriverPath);
VIR_FREE(driverLink); VIR_FREE(driverLink);
VIR_FREE(path); VIR_FREE(path);
if (newDriverName && if (result < 0) {
STRNEQ_NULLABLE(dev->stubDriver, newDriverName)) { VIR_FREE(newDriverName);
VIR_FREE(dev->stubDriver);
result = VIR_STRDUP(dev->stubDriver, newDriverName);
}
if (result < 0)
virPCIDeviceUnbindFromStub(dev); virPCIDeviceUnbindFromStub(dev);
} else {
VIR_FREE(dev->stubDriver);
dev->stubDriver = newDriverName;
}
if (err)
virSetError(err);
virFreeError(err);
return result; return result;
} }