Blame SOURCES/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch

dc2b6e
From 215adedb16aa082d052f84705338de0d77721fe0 Mon Sep 17 00:00:00 2001
dc2b6e
Message-Id: <215adedb16aa082d052f84705338de0d77721fe0@dist-git>
dc2b6e
From: Michal Privoznik <mprivozn@redhat.com>
dc2b6e
Date: Tue, 6 Sep 2022 13:43:22 +0200
dc2b6e
Subject: [PATCH] qemu_namespace: Fix a corner case in
dc2b6e
 qemuDomainGetPreservedMounts()
dc2b6e
dc2b6e
When setting up namespace for QEMU we look at mount points under
dc2b6e
/dev (like /dev/pts, /dev/mqueue/, etc.) because we want to
dc2b6e
preserve those (which is done by moving them to a temp location,
dc2b6e
unshare(), and then moving them back). We have a convenience
dc2b6e
helper - qemuDomainGetPreservedMounts() - that processes the
dc2b6e
mount table and (optionally) moves the other filesystems too.
dc2b6e
This helper is also used when attempting to create a path in NS,
dc2b6e
because the path, while starting with "/dev/" prefix, may
dc2b6e
actually lead to one of those filesystems that we preserved.
dc2b6e
dc2b6e
And here comes the corner case: while we require the parent mount
dc2b6e
table to be in shared mode (equivalent of `mount --make-rshared /'),
dc2b6e
these mount events propagate iff the target path exist inside the
dc2b6e
slave mount table (= QEMU's private namespace). And since we
dc2b6e
create only a subset of /dev nodes, well, that assumption is not
dc2b6e
always the case.
dc2b6e
dc2b6e
For instance, assume that a domain is already running, no
dc2b6e
hugepages were configured for it nor any hugetlbfs is mounted.
dc2b6e
Now, when a hugetlbfs is mounted into '/dev/hugepages', this is
dc2b6e
propagated into the QEMU's namespace, but since the target dir
dc2b6e
does not exist in the private /dev, the FS is not mounted in the
dc2b6e
namespace.
dc2b6e
dc2b6e
Fortunately, this difference between namespaces is visible when
dc2b6e
comparing /proc/mounts and /proc/$PID/mounts (where PID is the
dc2b6e
QEMU's PID). Therefore, if possible we should look at the latter.
dc2b6e
dc2b6e
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
dc2b6e
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
dc2b6e
(cherry picked from commit 46b03819ae8d833b11c2aaccb2c2a0361727f51b)
dc2b6e
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196
dc2b6e
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
dc2b6e
---
dc2b6e
 src/qemu/qemu_namespace.c | 10 +++++++++-
dc2b6e
 1 file changed, 9 insertions(+), 1 deletion(-)
dc2b6e
dc2b6e
diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c
dc2b6e
index 4bff325a2c..fc286ab0be 100644
dc2b6e
--- a/src/qemu/qemu_namespace.c
dc2b6e
+++ b/src/qemu/qemu_namespace.c
dc2b6e
@@ -110,6 +110,8 @@ qemuDomainGetPreservedMountPath(virQEMUDriverConfig *cfg,
dc2b6e
  * b) generate backup path for all the entries in a)
dc2b6e
  *
dc2b6e
  * Any of the return pointers can be NULL. Both arrays are NULL-terminated.
dc2b6e
+ * Get the mount table either from @vm's PID (if running), or from the
dc2b6e
+ * namespace we're in (if @vm's not running).
dc2b6e
  *
dc2b6e
  * Returns 0 on success, -1 otherwise (with error reported)
dc2b6e
  */
dc2b6e
@@ -124,12 +126,18 @@ qemuDomainGetPreservedMounts(virQEMUDriverConfig *cfg,
dc2b6e
     size_t nmounts = 0;
dc2b6e
     g_auto(GStrv) paths = NULL;
dc2b6e
     g_auto(GStrv) savePaths = NULL;
dc2b6e
+    g_autofree char *mountsPath = NULL;
dc2b6e
     size_t i;
dc2b6e
 
dc2b6e
     if (ndevPath)
dc2b6e
         *ndevPath = 0;
dc2b6e
 
dc2b6e
-    if (virFileGetMountSubtree(QEMU_PROC_MOUNTS, "/dev", &mounts, &nmounts) < 0)
dc2b6e
+    if (vm->pid > 0)
dc2b6e
+        mountsPath = g_strdup_printf("/proc/%lld/mounts", (long long) vm->pid);
dc2b6e
+    else
dc2b6e
+        mountsPath = g_strdup(QEMU_PROC_MOUNTS);
dc2b6e
+
dc2b6e
+    if (virFileGetMountSubtree(mountsPath, "/dev", &mounts, &nmounts) < 0)
dc2b6e
         return -1;
dc2b6e
 
dc2b6e
     if (nmounts == 0)
dc2b6e
-- 
dc2b6e
2.38.0
dc2b6e