Re: [PATCH 1/2] virpci: simplify virPCIDeviceBindToStub

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 07/11/2016 02:23 PM, Jim Fehlig wrote:
Early in virPCIDeviceBindToStub, there is a check to see if the
stub is already bound to the device, returning success with no
further actions if that is the case.

The same condition is unnecessarily checked later in the function.

Looking at the original code, the condition (whether the device is bound to the stub driver) is checked after writing the PCI ID of the device to the stub driver's "new_id" node. If you look here:

https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-pci

It says that when you write a PCI ID to a driver's "new_id", if there are any devices with the given PCI ID currently not bound to any driver, they will be immediately bound to the given driver. So I don't think the check is unnecessary - if the device wasn't bound to any driver to begin with (e.g. if the host driver for the device was blacklisted), it will be bound to the stub driver *immediately* after writing the PCI ID to new_id (ie before getting to the 2nd check).

So the condition isn't unnecessarily checked. It really can happen that we weren't bound to the stub in the first case, but were by the time we get to the 2nd.

On the other hand, this points out how utterly atrocious the new_id interface is - when I tested this by blacklisting the igbvf driver (so all the VFs of my 82576 card would have no driver bound to them), then started a domain that used a single VF, *all* of the VFs were suddenly bound to vfio-pci !!!

I also made a bunch of comments below before I noticed this part that I've put at the top, but in the end I think that especially since this whole bind/unbind/new_id interface is a dying thing, it would be better to leave it untouched (to avoid unexpected regressions) unless it's going to make a significant difference in how the driver_override stuff is added in.

Remove the unneeded checks to simplify the logic a bit.

Signed-off-by: Jim Fehlig <jfehlig@xxxxxxxx>
---
  src/util/virpci.c | 68 +++++++++++++++++++++++--------------------------------
  1 file changed, 28 insertions(+), 40 deletions(-)

diff --git a/src/util/virpci.c b/src/util/virpci.c
index 132948d..127b3b6 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -1196,7 +1196,6 @@ static int
  virPCIDeviceBindToStub(virPCIDevicePtr dev)
  {
      int result = -1;
-    bool reprobe = false;
      char *stubDriverPath = NULL;
      char *driverLink = NULL;
      char *path = NULL; /* reused for different purposes */
@@ -1225,10 +1224,16 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev)
              /* The device is already bound to the correct driver */
              VIR_DEBUG("Device %s is already bound to %s",
                        dev->name, stubDriverName);
+            dev->unbind_from_stub = true;
+            dev->remove_slot = true;

I understand where you got these two lines from (they were part of the 2nd "if (virFileLinkPointsTo(driverLink, stubDriverPath))" clause that you removed), but I don't think they should be put here - if we start out with the device already bound to the stub driver, then when we're finished we *won't* want to unbind_from_stub *or* remove_slot. To test this I commented them out and did several tests with three different builds:

A) a build without this patch
B) a build with this patch as-is
C) a build with this patch, but with the two lines above commented out.

With each libvirt build, I started then destroyed a domain with a <hostdev managed='yes'>, looking at the driver link in the devices sysfs directory before, during, and after the test. I did this with the following starting states:

1) device is bound to host driver before we start
2) device is bound to stub driver before we start
3) device isn't bound to *any* driver before we start

In all those (9) cases the device ends up bound to the same driver at the end as it was bound to at the beginning.

(I also tried starting the domain, then restarting libvirtd and then destroying the domain - both the old and new code have the same bug: even if the device was bound to the stub driver in the beginning, it ends up being bound to the host driver (or nothing, if the host driver has been blacklisted in modprobe.d) at the end.)

Result: I still believe those two lines above shouldn't be added.

              result = 0;
              goto cleanup;
          }
-        reprobe = true;
+        /*
+         * If the device is bound to a driver that is not the stub,  we'll
+         * need to reprobe later
+         */


Maybe instead of just "later" you could say "later when we unbind from the stub".


+        dev->reprobe = true;
      }
/* Add the PCI device ID to the stub's dynamic ID table;
@@ -1249,51 +1254,34 @@ virPCIDeviceBindToStub(virPCIDevicePtr dev)
          goto cleanup;
      }
- /* check whether the device is bound to pci-stub when we write dev->id to
-     * ${stubDriver}/new_id.
-     */
-    if (virFileLinkPointsTo(driverLink, stubDriverPath)) {
-        dev->unbind_from_stub = true;
-        dev->remove_slot = true;
-        result = 0;
-        goto remove_id;
-    }
-

As mentioned above, this really *could* happen -writing to new_id could immediately bind the device to the stub driver.

And if it wasn't immediately bound to the stub, that means it was already bound to something else, so we need to write the device's PCI address to the original driver's "unbind" (and *that* will cause it to be
      if (virPCIDeviceUnbind(dev) < 0)
          goto remove_id;
- /* If the device was bound to a driver we'll need to reprobe later */
-    dev->reprobe = reprobe;
+    /* Xen's pciback.ko wants you to use new_slot first */
+    VIR_FREE(path);
+    if (!(path = virPCIDriverFile(stubDriverName, "new_slot")))
+        goto remove_id;
- /* If the device isn't already bound to pci-stub, try binding it now.
-     */
-    if (!virFileLinkPointsTo(driverLink, stubDriverPath)) {

I think the above conditional also needs to stay - apparently it's possible that unbinding from the host driver still wouldn't be enough to get the device bound to the stuf, in which case you'd need to write the device's PCI address to the stub driver's "new_slot" in order to make it bind. But you don't want to do that unconditionally - I'd wager that it's more expenside to do the remove_slot later, and that's why the code is trying to avoid it.

-        /* Xen's pciback.ko wants you to use new_slot first */
-        VIR_FREE(path);
-        if (!(path = virPCIDriverFile(stubDriverName, "new_slot")))
-            goto remove_id;
-
-        if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) {
-            virReportSystemError(errno,
-                                 _("Failed to add slot for "
-                                   "PCI device '%s' to %s"),
-                                 dev->name, stubDriverName);
-            goto remove_id;
-        }
-        dev->remove_slot = true;
+    if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to add slot for "
+                               "PCI device '%s' to %s"),
+                             dev->name, stubDriverName);
+        goto remove_id;
+    }
+    dev->remove_slot = true;
- VIR_FREE(path);
-        if (!(path = virPCIDriverFile(stubDriverName, "bind")))
-            goto remove_id;
+    VIR_FREE(path);
+    if (!(path = virPCIDriverFile(stubDriverName, "bind")))
+        goto remove_id;
- if (virFileWriteStr(path, dev->name, 0) < 0) {
-            virReportSystemError(errno,
-                                 _("Failed to bind PCI device '%s' to %s"),
-                                 dev->name, stubDriverName);
-            goto remove_id;
-        }
-        dev->unbind_from_stub = true;
+    if (virFileWriteStr(path, dev->name, 0) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to bind PCI device '%s' to %s"),
+                             dev->name, stubDriverName);
+        goto remove_id;
      }
+    dev->unbind_from_stub = true;
result = 0;


In the end, I think this function should remain as it is.

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]