diff --git a/SOURCES/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch b/SOURCES/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch new file mode 100644 index 0000000..8f35b10 --- /dev/null +++ b/SOURCES/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch @@ -0,0 +1,57 @@ +From 9e5559fb4056507ecfc5e7dd758c3837283feb39 Mon Sep 17 00:00:00 2001 +Message-Id: <9e5559fb4056507ecfc5e7dd758c3837283feb39@dist-git> +From: Michal Privoznik +Date: Wed, 28 Sep 2022 10:12:36 +0200 +Subject: [PATCH] qemuProcessReconnect: Don't build memory paths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let me take you on a short trip to history. A long time ago, +libvirt would configure all QEMUs to use $hugetlbfs/libvirt/qemu +for their hugepages setup. This was problematic, because it did +not allow enough separation between guests. Therefore in +v3.0.0-rc1~367 the path changed to a per-domain basis: + + $hugetlbfs/libvirt/qemu/$domainShortName + +And to help with migration on daemon restart a call to +qemuProcessBuildDestroyMemoryPaths() was added to +qemuProcessReconnect() (well, it was named +qemuProcessBuildDestroyHugepagesPath() back then, see +v3.10.0-rc1~174). This was desirable then, because the memory +hotplug code did not call the function, it simply assumes +per-domain paths to exist. But this changed in v3.5.0-rc1~92 +after which the per-domain paths are created on memory hotplug +too. + +Therefore, it's no longer necessary to create these paths in +qemuProcessReconnect(). They are created exactly when needed +(domain startup and memory hotplug). + +Signed-off-by: Michal Privoznik +Reviewed-by: Ján Tomko +(cherry picked from commit 3478cca80ea7382cfdbff836d5d0b92aa014297b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132177 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 1164340aa9..0fb665bc82 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -8869,9 +8869,6 @@ qemuProcessReconnect(void *opaque) + goto cleanup; + } + +- if (qemuProcessBuildDestroyMemoryPaths(driver, obj, NULL, true) < 0) +- goto error; +- + if ((qemuDomainAssignAddresses(obj->def, priv->qemuCaps, + driver, obj, false)) < 0) { + goto error; +-- +2.37.2 + diff --git a/SOURCES/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch b/SOURCES/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch new file mode 100644 index 0000000..d7f692a --- /dev/null +++ b/SOURCES/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch @@ -0,0 +1,80 @@ +From d32d74310b652295fa23ccf8f096dd6c997dee05 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:43:22 +0200 +Subject: [PATCH] qemu_namespace: Fix a corner case in + qemuDomainGetPreservedMounts() + +When setting up namespace for QEMU we look at mount points under +/dev (like /dev/pts, /dev/mqueue/, etc.) because we want to +preserve those (which is done by moving them to a temp location, +unshare(), and then moving them back). We have a convenience +helper - qemuDomainGetPreservedMounts() - that processes the +mount table and (optionally) moves the other filesystems too. +This helper is also used when attempting to create a path in NS, +because the path, while starting with "/dev/" prefix, may +actually lead to one of those filesystems that we preserved. + +And here comes the corner case: while we require the parent mount +table to be in shared mode (equivalent of `mount --make-rshared /'), +these mount events propagate iff the target path exist inside the +slave mount table (= QEMU's private namespace). And since we +create only a subset of /dev nodes, well, that assumption is not +always the case. + +For instance, assume that a domain is already running, no +hugepages were configured for it nor any hugetlbfs is mounted. +Now, when a hugetlbfs is mounted into '/dev/hugepages', this is +propagated into the QEMU's namespace, but since the target dir +does not exist in the private /dev, the FS is not mounted in the +namespace. + +Fortunately, this difference between namespaces is visible when +comparing /proc/mounts and /proc/$PID/mounts (where PID is the +QEMU's PID). Therefore, if possible we should look at the latter. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 46b03819ae8d833b11c2aaccb2c2a0361727f51b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132177 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_namespace.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index 4bff325a2c..fc286ab0be 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -110,6 +110,8 @@ qemuDomainGetPreservedMountPath(virQEMUDriverConfig *cfg, + * b) generate backup path for all the entries in a) + * + * Any of the return pointers can be NULL. Both arrays are NULL-terminated. ++ * Get the mount table either from @vm's PID (if running), or from the ++ * namespace we're in (if @vm's not running). + * + * Returns 0 on success, -1 otherwise (with error reported) + */ +@@ -124,12 +126,18 @@ qemuDomainGetPreservedMounts(virQEMUDriverConfig *cfg, + size_t nmounts = 0; + g_auto(GStrv) paths = NULL; + g_auto(GStrv) savePaths = NULL; ++ g_autofree char *mountsPath = NULL; + size_t i; + + if (ndevPath) + *ndevPath = 0; + +- if (virFileGetMountSubtree(QEMU_PROC_MOUNTS, "/dev", &mounts, &nmounts) < 0) ++ if (vm->pid > 0) ++ mountsPath = g_strdup_printf("/proc/%lld/mounts", (long long) vm->pid); ++ else ++ mountsPath = g_strdup(QEMU_PROC_MOUNTS); ++ ++ if (virFileGetMountSubtree(mountsPath, "/dev", &mounts, &nmounts) < 0) + return -1; + + if (nmounts == 0) +-- +2.37.2 + diff --git a/SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch b/SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch new file mode 100644 index 0000000..5e2a39c --- /dev/null +++ b/SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch @@ -0,0 +1,68 @@ +From edca5497554ccf8016681884aa732156a9773061 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:43:58 +0200 +Subject: [PATCH] qemu_namespace: Introduce qemuDomainNamespaceSetupPath() + +Sometimes it may come handy to just bind mount a directory/file +into domain's namespace. Implement a thin wrapper over +qemuNamespaceMknodPaths() which has all the logic we need. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 5853d707189005a4ea5b2215e80853867b822fd9) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132177 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_namespace.c | 19 +++++++++++++++++++ + src/qemu/qemu_namespace.h | 4 ++++ + 2 files changed, 23 insertions(+) + +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index fc286ab0be..74ffd6fb90 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -1398,6 +1398,25 @@ qemuNamespaceUnlinkPaths(virDomainObj *vm, + } + + ++int ++qemuDomainNamespaceSetupPath(virDomainObj *vm, ++ const char *path, ++ bool *created) ++{ ++ g_autoptr(virGSListString) paths = NULL; ++ ++ if (!qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT)) ++ return 0; ++ ++ paths = g_slist_prepend(paths, g_strdup(path)); ++ ++ if (qemuNamespaceMknodPaths(vm, paths, created) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++ + int + qemuDomainNamespaceSetupDisk(virDomainObj *vm, + virStorageSource *src, +diff --git a/src/qemu/qemu_namespace.h b/src/qemu/qemu_namespace.h +index 020aca13d8..1ab9322061 100644 +--- a/src/qemu/qemu_namespace.h ++++ b/src/qemu/qemu_namespace.h +@@ -49,6 +49,10 @@ void qemuDomainDestroyNamespace(virQEMUDriver *driver, + + bool qemuDomainNamespaceAvailable(qemuDomainNamespace ns); + ++int qemuDomainNamespaceSetupPath(virDomainObj *vm, ++ const char *path, ++ bool *created); ++ + int qemuDomainNamespaceSetupDisk(virDomainObj *vm, + virStorageSource *src, + bool *created); +-- +2.37.2 + diff --git a/SOURCES/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch b/SOURCES/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch new file mode 100644 index 0000000..6159834 --- /dev/null +++ b/SOURCES/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch @@ -0,0 +1,45 @@ +From 8806d4dd0f0c7c20a42513b2a1ff310455decdc6 Mon Sep 17 00:00:00 2001 +Message-Id: <8806d4dd0f0c7c20a42513b2a1ff310455decdc6@dist-git> +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:37:23 +0200 +Subject: [PATCH] qemu_namespace: Tolerate missing ACLs when creating a path in + namespace + +When creating a path in a domain's mount namespace we try to set +ACLs on it, so that it's a verbatim copy of the path in parent's +namespace. The ACLs are queried upfront (by +qemuNamespaceMknodItemInit()) but this is fault tolerant so the +pointer to ACLs might be NULL (meaning no ACLs were queried, for +instance because the underlying filesystem does not support +them). But then we take this NULL and pass it to virFileSetACLs() +which immediately returns an error because NULL is invalid value. + +Mimic what we do with SELinux label - only set ACLs if they are +non-NULL which includes symlinks. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 687374959e160dc566bd4b6d43c7bf1beb470c59) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132177 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_namespace.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index 94453033f5..4bff325a2c 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -1023,8 +1023,7 @@ qemuNamespaceMknodOne(qemuNamespaceMknodItem *data) + goto cleanup; + } + +- /* Symlinks don't have ACLs. */ +- if (!isLink && ++ if (data->acl && + virFileSetACLs(data->file, data->acl) < 0 && + errno != ENOTSUP) { + virReportSystemError(errno, +-- +2.37.2 + diff --git a/SOURCES/libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch b/SOURCES/libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch new file mode 100644 index 0000000..4d4314f --- /dev/null +++ b/SOURCES/libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch @@ -0,0 +1,50 @@ +From a2cb0eca44996e1a7a397f028d44994f2e402a2e Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Mon, 5 Sep 2022 10:34:44 +0200 +Subject: [PATCH] qemu_process: Don't require a hugetlbfs mount for memfd + +The aim of qemuProcessNeedHugepagesPath() is to determine whether +a hugetlbfs mount point is required for given domain (as in +whether qemuBuildMemoryBackendProps() picks up +memory-backend-file pointing to a hugetlbfs mount point). Well, +when domain is configured to use memfd backend then that +condition can never be true. Therefore, skip creating domain's +private path under hugetlbfs mount points. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit f14f8dff9330ed51d817f190a2ee9ac76dfac00b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132177 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 5c6657a876..540eee9ff0 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3810,8 +3810,18 @@ qemuProcessNeedHugepagesPath(virDomainDef *def, + const long system_pagesize = virGetSystemPageSizeKB(); + size_t i; + +- if (def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) ++ switch ((virDomainMemorySource)def->mem.source) { ++ case VIR_DOMAIN_MEMORY_SOURCE_FILE: ++ /* This needs a hugetlbfs mount. */ + return true; ++ case VIR_DOMAIN_MEMORY_SOURCE_MEMFD: ++ /* memfd works without a hugetlbfs mount */ ++ return false; ++ case VIR_DOMAIN_MEMORY_SOURCE_NONE: ++ case VIR_DOMAIN_MEMORY_SOURCE_ANONYMOUS: ++ case VIR_DOMAIN_MEMORY_SOURCE_LAST: ++ break; ++ } + + for (i = 0; i < def->mem.nhugepages; i++) { + if (def->mem.hugepages[i].size != system_pagesize) +-- +2.37.2 + diff --git a/SOURCES/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch b/SOURCES/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch new file mode 100644 index 0000000..1fe77c7 --- /dev/null +++ b/SOURCES/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch @@ -0,0 +1,65 @@ +From 347606bc80f40c22712d0ffe61a149c3266bf131 Mon Sep 17 00:00:00 2001 +Message-Id: <347606bc80f40c22712d0ffe61a149c3266bf131@dist-git> +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:45:51 +0200 +Subject: [PATCH] qemu_process.c: Propagate hugetlbfs mounts on reconnect + +When reconnecting to a running QEMU process, we construct the +per-domain path in all hugetlbfs mounts. This is a relict from +the past (v3.4.0-100-g5b24d25062) where we switched to a +per-domain path and we want to create those paths when libvirtd +restarts on upgrade. + +And with namespaces enabled there is one corner case where the +path is not created. In fact an error is reported and the +reconnect fails. Ideally, all mount events are propagated into +the QEMU's namespace. And they probably are, except when the +target path does not exist inside the namespace. Now, it's pretty +common for users to mount hugetlbfs under /dev (e.g. +/dev/hugepages), but if domain is started without hugepages (or +more specifically - private hugetlbfs path wasn't created on +domain startup), then the reconnect code tries to create it. +But it fails to do so, well, it fails to set seclabels on the +path because, because the path does not exist in the private +namespace. And it doesn't exist because we specifically create +only a subset of all possible /dev nodes. Therefore, the mount +event, whilst propagated, is not successful and hence the +filesystem is not mounted. We have to do it ourselves. + +If hugetlbfs is mount anywhere else there's no problem and this +is effectively a dead code. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 0377177c7856bb87a9d8aa1324b54f5fbe9f1e5b) + +Conflicts: +- docs/kbase/qemu-passthrough-security.rst: Well, v8.8.0-rc1~32 + isn't backported, thus we can't remove a paragraph that the + backported commit did. It's a documentation after all, so no + harm. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2132177 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 540eee9ff0..1164340aa9 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3906,6 +3906,9 @@ qemuProcessBuildDestroyMemoryPathsImpl(virQEMUDriver *driver, + return -1; + } + ++ if (qemuDomainNamespaceSetupPath(vm, path, NULL) < 0) ++ return -1; ++ + if (qemuSecurityDomainSetPathLabel(driver, vm, path, true) < 0) + return -1; + } else { +-- +2.37.2 + diff --git a/SPECS/libvirt.spec b/SPECS/libvirt.spec index 3d6c119..e2e621b 100644 --- a/SPECS/libvirt.spec +++ b/SPECS/libvirt.spec @@ -210,7 +210,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 8.0.0 -Release: 5.4%{?dist}%{?extra_release} +Release: 5.5%{?dist}%{?extra_release} License: LGPLv2+ URL: https://libvirt.org/ @@ -262,6 +262,12 @@ Patch39: libvirt-qemu_migration-Restore-original-memory-locking-limit.patch Patch40: libvirt-Add-VIR_MIGRATE_ZEROCOPY-flag.patch Patch41: libvirt-virsh-Add-support-for-VIR_MIGRATE_ZEROCOPY-flag.patch Patch42: libvirt-qemu_migration-Implement-VIR_MIGRATE_ZEROCOPY-flag.patch +Patch43: libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch +Patch44: libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch +Patch45: libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch +Patch46: libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch +Patch47: libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch +Patch48: libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2135,6 +2141,14 @@ exit 0 %changelog +* Thu Oct 6 2022 Jiri Denemark - 8.0.0-5.5.el8 +- qemu_process: Don't require a hugetlbfs mount for memfd (rhbz#2132177) +- qemu_namespace: Tolerate missing ACLs when creating a path in namespace (rhbz#2132177) +- qemu_namespace: Fix a corner case in qemuDomainGetPreservedMounts() (rhbz#2132177) +- qemu_namespace: Introduce qemuDomainNamespaceSetupPath() (rhbz#2132177) +- qemu_process.c: Propagate hugetlbfs mounts on reconnect (rhbz#2132177) +- qemuProcessReconnect: Don't build memory paths (rhbz#2132177) + * Thu Aug 18 2022 Jiri Denemark - 8.0.0-5.4.el8 - conf: Move virDomainObj::originalMemlock into qemuDomainObjPrivate (rhbz#2117272) - qemu_domain: Format qemuDomainObjPrivate::originalMemlock (rhbz#2117272)