Blame SOURCES/libvirt-hostdev-mdev-Lookup-mdevs-by-sysfs-path-rather-than-mdev-struct.patch

b35f2b
From 9e97e35031572e0f6ace32e2fb094f0f358f0391 Mon Sep 17 00:00:00 2001
b35f2b
Message-Id: <9e97e35031572e0f6ace32e2fb094f0f358f0391@dist-git>
b35f2b
From: Thomas Huth <thuth@redhat.com>
b35f2b
Date: Tue, 11 May 2021 14:10:28 +0200
b35f2b
Subject: [PATCH] hostdev: mdev: Lookup mdevs by sysfs path rather than mdev
b35f2b
 struct
b35f2b
MIME-Version: 1.0
b35f2b
Content-Type: text/plain; charset=UTF-8
b35f2b
Content-Transfer-Encoding: 8bit
b35f2b
b35f2b
The lookup didn't do anything apart from comparing the sysfs paths
b35f2b
anyway since that's what makes each mdev unique.
b35f2b
The most ridiculous usage of the old logic was in
b35f2b
virHostdevReAttachMediatedDevices where in order to drop an mdev
b35f2b
hostdev from the list of active devices we first had to create a new
b35f2b
mdev and use it in the lookup call. Why couldn't we have used the
b35f2b
hostdev directly? Because the hostdev and mdev structures are
b35f2b
incompatible.
b35f2b
b35f2b
The way mdevs are currently removed is via a write to a specific sysfs
b35f2b
attribute. If you do it while the machine which has the mdev assigned
b35f2b
is running, the write call may block (with a new enough kernel, with
b35f2b
older kernels it would return a write error!) until the device
b35f2b
is no longer in use which is when the QEMU process exits.
b35f2b
b35f2b
The interesting part here comes afterwards when we're cleaning up and
b35f2b
call virHostdevReAttachMediatedDevices. The domain doesn't exist
b35f2b
anymore, so the list of active hostdevs needs to be updated and the
b35f2b
respective hostdevs removed from the list, but remember we had to
b35f2b
create an mdev object in the memory in order to find it in the list
b35f2b
first which will fail because the write to sysfs had already removed
b35f2b
the mdev instance from the host system.
b35f2b
And so the next time you try to start the same domain you'll get:
b35f2b
b35f2b
"Requested operation is not valid: mediated device <path> is in use by
b35f2b
driver QEMU, domain <name>"
b35f2b
b35f2b
Fixes: https://gitlab.com/libvirt/libvirt/-/issues/119
b35f2b
b35f2b
Signed-off-by: Erik Skultety <eskultet@redhat.com>
b35f2b
Reviewed-by: Ján Tomko <jtomko@redhat.com>
b35f2b
(cherry picked from commit 49cb59778a4e6c2d04bb9383a9d97fbbc83f9fce)
b35f2b
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1940449
b35f2b
Signed-off-by: Thomas Huth <thuth@redhat.com>
b35f2b
Message-Id: <20210511121028.304070-3-thuth@redhat.com>
b35f2b
Reviewed-by: Erik Skultety <eskultet@redhat.com>
b35f2b
---
b35f2b
 src/util/virhostdev.c | 10 ++++------
b35f2b
 src/util/virmdev.c    | 16 ++++++++--------
b35f2b
 src/util/virmdev.h    |  4 ++--
b35f2b
 3 files changed, 14 insertions(+), 16 deletions(-)
b35f2b
b35f2b
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
b35f2b
index b7050e99e4..392e94307c 100644
b35f2b
--- a/src/util/virhostdev.c
b35f2b
+++ b/src/util/virhostdev.c
b35f2b
@@ -2025,7 +2025,7 @@ virHostdevReAttachMediatedDevices(virHostdevManagerPtr mgr,
b35f2b
 
b35f2b
     virObjectLock(mgr->activeMediatedHostdevs);
b35f2b
     for (i = 0; i < nhostdevs; i++) {
b35f2b
-        g_autoptr(virMediatedDevice) mdev = NULL;
b35f2b
+        g_autofree char *sysfspath = NULL;
b35f2b
         virMediatedDevicePtr tmp;
b35f2b
         virDomainHostdevSubsysMediatedDevPtr mdevsrc;
b35f2b
         virDomainHostdevDefPtr hostdev = hostdevs[i];
b35f2b
@@ -2034,14 +2034,12 @@ virHostdevReAttachMediatedDevices(virHostdevManagerPtr mgr,
b35f2b
             continue;
b35f2b
 
b35f2b
         mdevsrc = &hostdev->source.subsys.u.mdev;
b35f2b
-
b35f2b
-        if (!(mdev = virMediatedDeviceNew(mdevsrc->uuidstr,
b35f2b
-                                          mdevsrc->model)))
b35f2b
-            continue;
b35f2b
+        sysfspath = virMediatedDeviceGetSysfsPath(mdevsrc->uuidstr);
b35f2b
 
b35f2b
         /* Remove from the list only mdevs assigned to @drv_name/@dom_name */
b35f2b
 
b35f2b
-        tmp = virMediatedDeviceListFind(mgr->activeMediatedHostdevs, mdev);
b35f2b
+        tmp = virMediatedDeviceListFind(mgr->activeMediatedHostdevs,
b35f2b
+                                        sysfspath);
b35f2b
 
b35f2b
         /* skip inactive devices */
b35f2b
         if (!tmp)
b35f2b
diff --git a/src/util/virmdev.c b/src/util/virmdev.c
b35f2b
index c2499c0a20..bae4a7d2c1 100644
b35f2b
--- a/src/util/virmdev.c
b35f2b
+++ b/src/util/virmdev.c
b35f2b
@@ -312,7 +312,7 @@ int
b35f2b
 virMediatedDeviceListAdd(virMediatedDeviceListPtr list,
b35f2b
                          virMediatedDevicePtr *dev)
b35f2b
 {
b35f2b
-    if (virMediatedDeviceListFind(list, *dev)) {
b35f2b
+    if (virMediatedDeviceListFind(list, (*dev)->path)) {
b35f2b
         virReportError(VIR_ERR_INTERNAL_ERROR,
b35f2b
                        _("device %s is already in use"), (*dev)->path);
b35f2b
         return -1;
b35f2b
@@ -358,7 +358,7 @@ virMediatedDevicePtr
b35f2b
 virMediatedDeviceListSteal(virMediatedDeviceListPtr list,
b35f2b
                            virMediatedDevicePtr dev)
b35f2b
 {
b35f2b
-    int idx = virMediatedDeviceListFindIndex(list, dev);
b35f2b
+    int idx = virMediatedDeviceListFindIndex(list, dev->path);
b35f2b
 
b35f2b
     return virMediatedDeviceListStealIndex(list, idx);
b35f2b
 }
b35f2b
@@ -374,13 +374,13 @@ virMediatedDeviceListDel(virMediatedDeviceListPtr list,
b35f2b
 
b35f2b
 int
b35f2b
 virMediatedDeviceListFindIndex(virMediatedDeviceListPtr list,
b35f2b
-                               virMediatedDevicePtr dev)
b35f2b
+                               const char *sysfspath)
b35f2b
 {
b35f2b
     size_t i;
b35f2b
 
b35f2b
     for (i = 0; i < list->count; i++) {
b35f2b
-        virMediatedDevicePtr other = list->devs[i];
b35f2b
-        if (STREQ(other->path, dev->path))
b35f2b
+        virMediatedDevicePtr dev = list->devs[i];
b35f2b
+        if (STREQ(sysfspath, dev->path))
b35f2b
             return i;
b35f2b
     }
b35f2b
     return -1;
b35f2b
@@ -389,11 +389,11 @@ virMediatedDeviceListFindIndex(virMediatedDeviceListPtr list,
b35f2b
 
b35f2b
 virMediatedDevicePtr
b35f2b
 virMediatedDeviceListFind(virMediatedDeviceListPtr list,
b35f2b
-                          virMediatedDevicePtr dev)
b35f2b
+                          const char *sysfspath)
b35f2b
 {
b35f2b
     int idx;
b35f2b
 
b35f2b
-    if ((idx = virMediatedDeviceListFindIndex(list, dev)) >= 0)
b35f2b
+    if ((idx = virMediatedDeviceListFindIndex(list, sysfspath)) >= 0)
b35f2b
         return list->devs[idx];
b35f2b
     else
b35f2b
         return NULL;
b35f2b
@@ -407,7 +407,7 @@ virMediatedDeviceIsUsed(virMediatedDevicePtr dev,
b35f2b
     const char *drvname, *domname;
b35f2b
     virMediatedDevicePtr tmp = NULL;
b35f2b
 
b35f2b
-    if ((tmp = virMediatedDeviceListFind(list, dev))) {
b35f2b
+    if ((tmp = virMediatedDeviceListFind(list, dev->path))) {
b35f2b
         virMediatedDeviceGetUsedBy(tmp, &drvname, &domname);
b35f2b
         virReportError(VIR_ERR_OPERATION_INVALID,
b35f2b
                        _("mediated device %s is in use by "
b35f2b
diff --git a/src/util/virmdev.h b/src/util/virmdev.h
b35f2b
index e0905a3f6e..3022ab9948 100644
b35f2b
--- a/src/util/virmdev.h
b35f2b
+++ b/src/util/virmdev.h
b35f2b
@@ -120,11 +120,11 @@ virMediatedDeviceListDel(virMediatedDeviceListPtr list,
b35f2b
 
b35f2b
 virMediatedDevicePtr
b35f2b
 virMediatedDeviceListFind(virMediatedDeviceListPtr list,
b35f2b
-                          virMediatedDevicePtr dev);
b35f2b
+                          const char *sysfspath);
b35f2b
 
b35f2b
 int
b35f2b
 virMediatedDeviceListFindIndex(virMediatedDeviceListPtr list,
b35f2b
-                               virMediatedDevicePtr dev);
b35f2b
+                               const char *sysfspath);
b35f2b
 
b35f2b
 int
b35f2b
 virMediatedDeviceListMarkDevices(virMediatedDeviceListPtr dst,
b35f2b
-- 
b35f2b
2.31.1
b35f2b