c401cc
From c5a1547cc5aa9fed95f2bb48d9dcb4c659e640d1 Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <c5a1547cc5aa9fed95f2bb48d9dcb4c659e640d1.1390394206.git.jdenemar@redhat.com>
c401cc
From: Jiri Denemark <jdenemar@redhat.com>
c401cc
Date: Mon, 20 Jan 2014 14:41:12 +0100
c401cc
Subject: [PATCH] pci: Fix failure paths in detach
c401cc
c401cc
https://bugzilla.redhat.com/show_bug.cgi?id=1046919
c401cc
c401cc
Since commit v0.9.0-47-g4e8969e (released in 0.9.1) some failures during
c401cc
device detach were reported to callers of virPCIDeviceBindToStub as
c401cc
success. For example, even though a device seemed to be detached
c401cc
c401cc
    virsh # nodedev-detach pci_0000_07_05_0 --driver vfio
c401cc
    Device pci_0000_07_05_0 detached
c401cc
c401cc
one could find similar message in libvirt logs:
c401cc
c401cc
    Failed to bind PCI device '0000:07:05.0' to vfio-pci: No such device
c401cc
c401cc
This patch fixes these paths and also avoids overwriting real errors
c401cc
with errors encountered during a cleanup phase.
c401cc
c401cc
(cherry picked from commit d8ab981bdd137f15675ee0d101abeabf42680cc1)
c401cc
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
---
c401cc
 src/util/virpci.c | 39 +++++++++++++++++++++++----------------
c401cc
 1 file changed, 23 insertions(+), 16 deletions(-)
c401cc
c401cc
diff --git a/src/util/virpci.c b/src/util/virpci.c
c401cc
index b48e433..f689961 100644
c401cc
--- a/src/util/virpci.c
c401cc
+++ b/src/util/virpci.c
c401cc
@@ -1091,16 +1091,17 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
c401cc
 {
c401cc
     int result = -1;
c401cc
     int reprobe = false;
c401cc
-
c401cc
     char *stubDriverPath = NULL;
c401cc
     char *driverLink = NULL;
c401cc
     char *oldDriverPath = NULL;
c401cc
     char *oldDriverName = NULL;
c401cc
     char *path = NULL; /* reused for different purposes */
c401cc
-    const char *newDriverName = NULL;
c401cc
+    char *newDriverName = NULL;
c401cc
+    virErrorPtr err = NULL;
c401cc
 
c401cc
     if (virPCIDriverDir(&stubDriverPath, stubDriverName) < 0 ||
c401cc
-        virPCIFile(&driverLink, dev->name, "driver") < 0)
c401cc
+        virPCIFile(&driverLink, dev->name, "driver") < 0 ||
c401cc
+        VIR_STRDUP(newDriverName, stubDriverName) < 0)
c401cc
         goto cleanup;
c401cc
 
c401cc
     if (virFileExists(driverLink)) {
c401cc
@@ -1108,7 +1109,6 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
c401cc
             /* The device is already bound to the correct driver */
c401cc
             VIR_DEBUG("Device %s is already bound to %s",
c401cc
                       dev->name, stubDriverName);
c401cc
-            newDriverName = stubDriverName;
c401cc
             result = 0;
c401cc
             goto cleanup;
c401cc
         }
c401cc
@@ -1140,6 +1140,7 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
c401cc
     if (virFileLinkPointsTo(driverLink, stubDriverPath)) {
c401cc
         dev->unbind_from_stub = true;
c401cc
         dev->remove_slot = true;
c401cc
+        result = 0;
c401cc
         goto remove_id;
c401cc
     }
c401cc
 
c401cc
@@ -1148,16 +1149,15 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
c401cc
      * PCI device happens to be IDE controller for the disk hosting
c401cc
      * your root filesystem.
c401cc
      */
c401cc
-    if (virPCIFile(&path, dev->name, "driver/unbind") < 0) {
c401cc
-        goto cleanup;
c401cc
-    }
c401cc
+    if (virPCIFile(&path, dev->name, "driver/unbind") < 0)
c401cc
+        goto remove_id;
c401cc
 
c401cc
     if (virFileExists(path)) {
c401cc
         if (virFileWriteStr(path, dev->name, 0) < 0) {
c401cc
             virReportSystemError(errno,
c401cc
                                  _("Failed to unbind PCI device '%s'"),
c401cc
                                  dev->name);
c401cc
-            goto cleanup;
c401cc
+            goto remove_id;
c401cc
         }
c401cc
         dev->reprobe = reprobe;
c401cc
     }
c401cc
@@ -1192,7 +1192,11 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev,
c401cc
         dev->unbind_from_stub = true;
c401cc
     }
c401cc
 
c401cc
+    result = 0;
c401cc
+
c401cc
 remove_id:
c401cc
+    err = virSaveLastError();
c401cc
+
c401cc
     /* If 'remove_id' exists, remove the device id from pci-stub's dynamic
c401cc
      * ID table so that 'drivers_probe' works below.
c401cc
      */
c401cc
@@ -1203,6 +1207,7 @@ remove_id:
c401cc
                      "cannot be probed again.", dev->id, stubDriverName);
c401cc
         }
c401cc
         dev->reprobe = false;
c401cc
+        result = -1;
c401cc
         goto cleanup;
c401cc
     }
c401cc
 
c401cc
@@ -1217,12 +1222,10 @@ remove_id:
c401cc
                      "cannot be probed again.", dev->id, stubDriverName);
c401cc
         }
c401cc
         dev->reprobe = false;
c401cc
+        result = -1;
c401cc
         goto cleanup;
c401cc
     }
c401cc
 
c401cc
-    newDriverName = stubDriverName;
c401cc
-    result = 0;
c401cc
-
c401cc
 cleanup:
c401cc
     VIR_FREE(stubDriverPath);
c401cc
     VIR_FREE(driverLink);
c401cc
@@ -1230,13 +1233,17 @@ cleanup:
c401cc
     VIR_FREE(oldDriverName);
c401cc
     VIR_FREE(path);
c401cc
 
c401cc
-    if (newDriverName &&
c401cc
-        STRNEQ_NULLABLE(dev->stubDriver, newDriverName)) {
c401cc
+    if (result < 0) {
c401cc
+        VIR_FREE(newDriverName);
c401cc
+        virPCIDeviceUnbindFromStub(dev);
c401cc
+    } else {
c401cc
         VIR_FREE(dev->stubDriver);
c401cc
-        result = VIR_STRDUP(dev->stubDriver, newDriverName);
c401cc
+        dev->stubDriver = newDriverName;
c401cc
     }
c401cc
-    if (result < 0)
c401cc
-        virPCIDeviceUnbindFromStub(dev);
c401cc
+
c401cc
+    if (err)
c401cc
+        virSetError(err);
c401cc
+    virFreeError(err);
c401cc
 
c401cc
     return result;
c401cc
 }
c401cc
-- 
c401cc
1.8.5.3
c401cc