From 445a9cd1f11dc8bc2a7061424004b7a15de3ba4c Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mon, 23 Jan 2023 09:32:06 -0500 Subject: [PATCH] import libvirt-8.5.0-7.3.el9_1 --- ...nt-QEMU-private-mount-NS-limitations.patch | 59 +++++++ ...it-a-bit-longer-for-new-node-devices.patch | 48 +++++ ...etStatsCpu-fallback-for-qemu-session.patch | 86 +++++++++ ...jectGetStringArray-for-optional-data.patch | 58 ++++++ ...ssReconnect-Don-t-build-memory-paths.patch | 57 ++++++ ...case-in-qemuDomainGetPreservedMounts.patch | 80 +++++++++ ...troduce-qemuDomainNamespaceSetupPath.patch | 68 ++++++++ ...Ls-when-creating-a-path-in-namespace.patch | 45 +++++ ...pagate-hugetlbfs-mounts-on-reconnect.patch | 73 ++++++++ ...GetStatInfo-for-sysTime-and-userTime.patch | 165 ++++++++++++++++++ ...rom-virJSONValueObjectGetStringArray.patch | 124 +++++++++++++ SPECS/libvirt.spec | 31 +++- 12 files changed, 893 insertions(+), 1 deletion(-) create mode 100644 SOURCES/libvirt-kbase-Document-QEMU-private-mount-NS-limitations.patch create mode 100644 SOURCES/libvirt-nodedev-wait-a-bit-longer-for-new-node-devices.patch create mode 100644 SOURCES/libvirt-qemu-Implement-qemuDomainGetStatsCpu-fallback-for-qemu-session.patch create mode 100644 SOURCES/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch create mode 100644 SOURCES/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch create mode 100644 SOURCES/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch create mode 100644 SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch create mode 100644 SOURCES/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch create mode 100644 SOURCES/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch create mode 100644 SOURCES/libvirt-util-Extend-virProcessGetStatInfo-for-sysTime-and-userTime.patch create mode 100644 SOURCES/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch diff --git a/SOURCES/libvirt-kbase-Document-QEMU-private-mount-NS-limitations.patch b/SOURCES/libvirt-kbase-Document-QEMU-private-mount-NS-limitations.patch new file mode 100644 index 0000000..2201756 --- /dev/null +++ b/SOURCES/libvirt-kbase-Document-QEMU-private-mount-NS-limitations.patch @@ -0,0 +1,59 @@ +From 332386ae7bc02618d1860f726065448324a6734a Mon Sep 17 00:00:00 2001 +Message-Id: <332386ae7bc02618d1860f726065448324a6734a@dist-git> +From: Michal Privoznik +Date: Mon, 5 Sep 2022 12:37:16 +0200 +Subject: [PATCH] kbase: Document QEMU private mount NS limitations + +There are two points I've taken for granted: + + 1) the mount points are set before starting a guest, + 2) the / and its submounts are marked as shared, so that mount + events propagate into child namespaces when assumption 1) is + not held. + +But what's obvious to me might not be obvious to our users. +Document these known limitations. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit d3397885d589c25b8962ae221fd0a71ced5597cb) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2152083 +Signed-off-by: Michal Privoznik +--- + docs/kbase/qemu-passthrough-security.rst | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/docs/kbase/qemu-passthrough-security.rst b/docs/kbase/qemu-passthrough-security.rst +index 4381d9f3a6..106c3cc5b9 100644 +--- a/docs/kbase/qemu-passthrough-security.rst ++++ b/docs/kbase/qemu-passthrough-security.rst +@@ -156,3 +156,25 @@ will affect all virtual machines. These settings are all made in + + * Cgroups - set ``cgroup_device_acl`` to include the desired device node, or + ``cgroup_controllers = [...]`` to exclude the ``devices`` controller. ++ ++Private monunt namespace ++---------------------------- ++ ++As mentioned above, libvirt launches each QEMU process in its own ``mount`` ++namespace. It's recommended that all mount points are set up prior starting any ++guest. For cases when that can't be assured, mount points in the namespace are ++marked as slave so that mount events happening in the parent namespace are ++propagated into this child namespace. But this may require an additional step: ++mounts in the parent namespace need to be marked as shared (if the distribution ++doesn't do that by default). This can be achieved by running the following ++command before any guest is started: ++ ++:: ++ ++ # mount --make-rshared / ++ ++Another requirement for dynamic mount point propagation is to not place ++``hugetlbfs`` mount points under ``/dev`` because these won't be propagated as ++corresponding directories do not exist in the private namespace. Or just use ++``memfd`` memory backend instead which does not require ``hugetlbfs`` mount ++points. +-- +2.39.0 + diff --git a/SOURCES/libvirt-nodedev-wait-a-bit-longer-for-new-node-devices.patch b/SOURCES/libvirt-nodedev-wait-a-bit-longer-for-new-node-devices.patch new file mode 100644 index 0000000..489bb0d --- /dev/null +++ b/SOURCES/libvirt-nodedev-wait-a-bit-longer-for-new-node-devices.patch @@ -0,0 +1,48 @@ +From 08c8ef5eb30983d6ca004e84a11fe7f2547f984e Mon Sep 17 00:00:00 2001 +Message-Id: <08c8ef5eb30983d6ca004e84a11fe7f2547f984e@dist-git> +From: Jonathon Jongsma +Date: Tue, 23 Aug 2022 12:28:02 -0500 +Subject: [PATCH] nodedev: wait a bit longer for new node devices + +Openstack developers reported that newly-created mdevs were not +recognized by libvirt until after a libvirt daemon restart. The source +of the problem appears to be that when libvirt gets the udev 'add' +event, the sysfs tree for that device might not be ready and so libvirt +waits 100ms for it to appear (max 100 waits of 1ms each). But in the +OpenStack environment, the sysfs tree for new mediated devices was +taking closer to 250ms to appear and therefore libvirt gave up waiting +and didn't add these new devices to its list of nodedevs. + +By changing the wait time to 1 second (max 100 waits of 10ms each), this +should provide enough time to enable these deployments to recognize +newly-created mediated devices, but it shouldn't increase the delay for +more traditional deployments too much. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2109450 + +Signed-off-by: Jonathon Jongsma +Reviewed-by: Erik Skultety +(cherry picked from commit e4f9682ebc442bb5dfee807ba618c8863355776d) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2141364 +Signed-off-by: Jonathon Jongsma +--- + src/node_device/node_device_udev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c +index 3d69bdedae..1f63162e23 100644 +--- a/src/node_device/node_device_udev.c ++++ b/src/node_device/node_device_udev.c +@@ -1036,7 +1036,7 @@ udevProcessMediatedDevice(struct udev_device *dev, + + linkpath = g_strdup_printf("%s/mdev_type", udev_device_get_syspath(dev)); + +- if (virFileWaitForExists(linkpath, 1, 100) < 0) { ++ if (virFileWaitForExists(linkpath, 10, 100) < 0) { + virReportSystemError(errno, + _("failed to wait for file '%s' to appear"), + linkpath); +-- +2.38.1 + diff --git a/SOURCES/libvirt-qemu-Implement-qemuDomainGetStatsCpu-fallback-for-qemu-session.patch b/SOURCES/libvirt-qemu-Implement-qemuDomainGetStatsCpu-fallback-for-qemu-session.patch new file mode 100644 index 0000000..fdbb8e4 --- /dev/null +++ b/SOURCES/libvirt-qemu-Implement-qemuDomainGetStatsCpu-fallback-for-qemu-session.patch @@ -0,0 +1,86 @@ +From 5da85fb944db3dd8213a7302deaffa3b294acd64 Mon Sep 17 00:00:00 2001 +Message-Id: <5da85fb944db3dd8213a7302deaffa3b294acd64@dist-git> +From: Michal Privoznik +Date: Tue, 9 Aug 2022 16:16:09 +0200 +Subject: [PATCH] qemu: Implement qemuDomainGetStatsCpu fallback for + qemu:///session +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For domains started under session URI, we don't set up CGroups +(well, how could we since we're not running as root anyways). +Nevertheless, fetching CPU statistics exits early because of +lacking cpuacct controller. But with recent extension to +virProcessGetStatInfo() we can get the values we need from the +proc filesystem. Implement the fallback for the session URI as +some of virt tools rely on cpu.* stats to be reported (virt-top, +virt-manager). + +Resolves: https://gitlab.com/libvirt/libvirt/-/issues/353 +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1693707 +Signed-off-by: Michal Privoznik +Reviewed-by: Ján Tomko +(cherry picked from commit 044b8744d65f8571038f85685b3c4b241162977b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2157094 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_driver.c | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 84cf2c6a4f..ac210d8069 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -18042,6 +18042,30 @@ qemuDomainGetStatsCpuCgroup(virDomainObj *dom, + return 0; + } + ++ ++static int ++qemuDomainGetStatsCpuProc(virDomainObj *vm, ++ virTypedParamList *params) ++{ ++ unsigned long long cpuTime = 0; ++ unsigned long long sysTime = 0; ++ unsigned long long userTime = 0; ++ ++ if (virProcessGetStatInfo(&cpuTime, &sysTime, &userTime, ++ NULL, NULL, vm->pid, 0) < 0) { ++ /* ignore error */ ++ return 0; ++ } ++ ++ if (virTypedParamListAddULLong(params, cpuTime, "cpu.time") < 0 || ++ virTypedParamListAddULLong(params, userTime, "cpu.user") < 0 || ++ virTypedParamListAddULLong(params, sysTime, "cpu.system") < 0) ++ return -1; ++ ++ return 0; ++} ++ ++ + static int + qemuDomainGetStatsCpuHaltPollTime(virDomainObj *dom, + virTypedParamList *params) +@@ -18066,8 +18090,15 @@ qemuDomainGetStatsCpu(virQEMUDriver *driver, + virTypedParamList *params, + unsigned int privflags G_GNUC_UNUSED) + { +- if (qemuDomainGetStatsCpuCgroup(dom, params) < 0) +- return -1; ++ qemuDomainObjPrivate *priv = dom->privateData; ++ ++ if (priv->cgroup) { ++ if (qemuDomainGetStatsCpuCgroup(dom, params) < 0) ++ return -1; ++ } else { ++ if (qemuDomainGetStatsCpuProc(dom, params) < 0) ++ return -1; ++ } + + if (qemuDomainGetStatsCpuCache(driver, dom, params) < 0) + return -1; +-- +2.39.0 + diff --git a/SOURCES/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch b/SOURCES/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch new file mode 100644 index 0000000..8a69de3 --- /dev/null +++ b/SOURCES/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch @@ -0,0 +1,58 @@ +From 198f38fa5540c7545607b9d1beb0bfb689d56c3d Mon Sep 17 00:00:00 2001 +Message-Id: <198f38fa5540c7545607b9d1beb0bfb689d56c3d@dist-git> +From: Peter Krempa +Date: Thu, 1 Dec 2022 17:02:42 +0100 +Subject: [PATCH] qemuAgentGetDisks: Don't use virJSONValueObjectGetStringArray + for optional data + +The 'dependencies' field in the return data may be missing in some +cases. Historically 'virJSONValueObjectGetStringArray' didn't report +error in such case, but later refactor (commit 043b50b948ef3c2 ) added +an error in order to use it in other places too. + +Unfortunately this results in the error log being spammed with an +irrelevant error in case when qemuAgentGetDisks is invoked on a VM +running windows. + +Replace the use of virJSONValueObjectGetStringArray by fetching the +array first and calling virJSONValueArrayToStringList only when we have +an array. + +Fixes: 043b50b948ef3c2a4adf5fa32a93ec2589851ac6 +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2149752 +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit 3b576601dfb924bb518870a01de5d1a421cbb467) +https://bugzilla.redhat.com/show_bug.cgi?id=2154410 +--- + src/qemu/qemu_agent.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c +index d81f01ba77..7afef06694 100644 +--- a/src/qemu/qemu_agent.c ++++ b/src/qemu/qemu_agent.c +@@ -2544,6 +2544,7 @@ int qemuAgentGetDisks(qemuAgent *agent, + for (i = 0; i < ndata; i++) { + virJSONValue *addr; + virJSONValue *entry = virJSONValueArrayGet(data, i); ++ virJSONValue *dependencies; + qemuAgentDiskInfo *disk; + + if (!entry) { +@@ -2569,7 +2570,11 @@ int qemuAgentGetDisks(qemuAgent *agent, + goto error; + } + +- disk->dependencies = virJSONValueObjectGetStringArray(entry, "dependencies"); ++ if ((dependencies = virJSONValueObjectGetArray(entry, "dependencies"))) { ++ if (!(disk->dependencies = virJSONValueArrayToStringList(dependencies))) ++ goto error; ++ } ++ + disk->alias = g_strdup(virJSONValueObjectGetString(entry, "alias")); + addr = virJSONValueObjectGetObject(entry, "address"); + if (addr) { +-- +2.39.0 + 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..519912e --- /dev/null +++ b/SOURCES/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch @@ -0,0 +1,57 @@ +From b76623b5921238c9a4db9b3e1958b51a4d7e8b52 Mon Sep 17 00:00:00 2001 +Message-Id: +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=2152083 +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 062a0b6dac..979ad99f5a 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -9004,9 +9004,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.39.0 + 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..736097e --- /dev/null +++ b/SOURCES/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch @@ -0,0 +1,80 @@ +From 6b3a0480cf2de402abce168aa0b093a8dc4f7a57 Mon Sep 17 00:00:00 2001 +Message-Id: <6b3a0480cf2de402abce168aa0b093a8dc4f7a57@dist-git> +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=2152083 +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 71e3366ca5..807ec37c91 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -109,6 +109,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) + */ +@@ -123,12 +125,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.39.0 + diff --git a/SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch b/SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch new file mode 100644 index 0000000..bb2bb4b --- /dev/null +++ b/SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch @@ -0,0 +1,68 @@ +From c8379fdd0f13af84f4b2ed449f8de77117fd8bc7 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=2152083 +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 807ec37c91..09e235e120 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -1424,6 +1424,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 fbea865c70..85d990f460 100644 +--- a/src/qemu/qemu_namespace.h ++++ b/src/qemu/qemu_namespace.h +@@ -48,6 +48,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.39.0 + 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..ca42fcc --- /dev/null +++ b/SOURCES/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch @@ -0,0 +1,45 @@ +From 1f0a6e441617da6a95e2188408ad1ed2dd4665e4 Mon Sep 17 00:00:00 2001 +Message-Id: <1f0a6e441617da6a95e2188408ad1ed2dd4665e4@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=2152083 +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 98cd794666..71e3366ca5 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -1040,8 +1040,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.39.0 + 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..a4d056f --- /dev/null +++ b/SOURCES/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch @@ -0,0 +1,73 @@ +From 9842eb7301f985e4cc08001aff48c269492b2456 Mon Sep 17 00:00:00 2001 +Message-Id: <9842eb7301f985e4cc08001aff48c269492b2456@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) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2152083 +Signed-off-by: Michal Privoznik +--- + docs/kbase/qemu-passthrough-security.rst | 6 ------ + src/qemu/qemu_process.c | 3 +++ + 2 files changed, 3 insertions(+), 6 deletions(-) + +diff --git a/docs/kbase/qemu-passthrough-security.rst b/docs/kbase/qemu-passthrough-security.rst +index 106c3cc5b9..ef10d8af9b 100644 +--- a/docs/kbase/qemu-passthrough-security.rst ++++ b/docs/kbase/qemu-passthrough-security.rst +@@ -172,9 +172,3 @@ command before any guest is started: + :: + + # mount --make-rshared / +- +-Another requirement for dynamic mount point propagation is to not place +-``hugetlbfs`` mount points under ``/dev`` because these won't be propagated as +-corresponding directories do not exist in the private namespace. Or just use +-``memfd`` memory backend instead which does not require ``hugetlbfs`` mount +-points. +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 4b52d664c7..062a0b6dac 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -4039,6 +4039,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.39.0 + diff --git a/SOURCES/libvirt-util-Extend-virProcessGetStatInfo-for-sysTime-and-userTime.patch b/SOURCES/libvirt-util-Extend-virProcessGetStatInfo-for-sysTime-and-userTime.patch new file mode 100644 index 0000000..a48639a --- /dev/null +++ b/SOURCES/libvirt-util-Extend-virProcessGetStatInfo-for-sysTime-and-userTime.patch @@ -0,0 +1,165 @@ +From b7a08f453fc448415ce320532907e61fa34f95b7 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Tue, 9 Aug 2022 16:15:55 +0200 +Subject: [PATCH] util: Extend virProcessGetStatInfo() for sysTime and userTime +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The virProcessGetStatInfo() helper parses /proc stat file for +given PID and/or TID and reports cumulative cpuTime which is just +a sum of user and sys times. But in near future, we'll need those +times separately, so make the function return them too (if caller +desires). + +Signed-off-by: Michal Privoznik +Reviewed-by: Ján Tomko +(cherry picked from commit cdc22d9a21e472a02dae8157e3cca5832f161feb) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2157094 +Signed-off-by: Michal Privoznik +--- + src/ch/ch_driver.c | 1 + + src/qemu/qemu_driver.c | 4 +++- + src/util/virprocess.c | 33 ++++++++++++++++++++++----------- + src/util/virprocess.h | 2 ++ + 4 files changed, 28 insertions(+), 12 deletions(-) + +diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c +index e7c172c894..bde148075d 100644 +--- a/src/ch/ch_driver.c ++++ b/src/ch/ch_driver.c +@@ -1075,6 +1075,7 @@ chDomainHelperGetVcpus(virDomainObj *vm, + vcpuinfo->number = i; + vcpuinfo->state = VIR_VCPU_RUNNING; + if (virProcessGetStatInfo(&vcpuinfo->cpuTime, ++ NULL, NULL, + &vcpuinfo->cpu, NULL, + vm->pid, vcpupid) < 0) { + virReportSystemError(errno, "%s", +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index ebd6365f52..84cf2c6a4f 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -1359,6 +1359,7 @@ qemuDomainHelperGetVcpus(virDomainObj *vm, + vcpuinfo->state = VIR_VCPU_RUNNING; + + if (virProcessGetStatInfo(&vcpuinfo->cpuTime, ++ NULL, NULL, + &vcpuinfo->cpu, NULL, + vm->pid, vcpupid) < 0) { + virReportSystemError(errno, "%s", +@@ -2528,6 +2529,7 @@ qemuDomainGetInfo(virDomainPtr dom, + + if (virDomainObjIsActive(vm)) { + if (virProcessGetStatInfo(&(info->cpuTime), NULL, NULL, ++ NULL, NULL, + vm->pid, 0) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("cannot read cputime for domain")); +@@ -10770,7 +10772,7 @@ qemuDomainMemoryStatsInternal(virQEMUDriver *driver, + ret = 0; + } + +- if (virProcessGetStatInfo(NULL, NULL, &rss, vm->pid, 0) < 0) { ++ if (virProcessGetStatInfo(NULL, NULL, NULL, NULL, &rss, vm->pid, 0) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("cannot get RSS for domain")); + } else { +diff --git a/src/util/virprocess.c b/src/util/virprocess.c +index 013afd91b4..11f36e00a8 100644 +--- a/src/util/virprocess.c ++++ b/src/util/virprocess.c +@@ -1737,32 +1737,37 @@ virProcessGetStat(pid_t pid, + #ifdef __linux__ + int + virProcessGetStatInfo(unsigned long long *cpuTime, ++ unsigned long long *userTime, ++ unsigned long long *sysTime, + int *lastCpu, + long *vm_rss, + pid_t pid, + pid_t tid) + { + g_auto(GStrv) proc_stat = virProcessGetStat(pid, tid); +- unsigned long long usertime = 0, systime = 0; ++ unsigned long long utime = 0; ++ unsigned long long stime = 0; ++ const unsigned long long jiff2nsec = 1000ull * 1000ull * 1000ull / ++ (unsigned long long) sysconf(_SC_CLK_TCK); + long rss = 0; + int cpu = 0; + + if (!proc_stat || +- virStrToLong_ullp(proc_stat[VIR_PROCESS_STAT_UTIME], NULL, 10, &usertime) < 0 || +- virStrToLong_ullp(proc_stat[VIR_PROCESS_STAT_STIME], NULL, 10, &systime) < 0 || ++ virStrToLong_ullp(proc_stat[VIR_PROCESS_STAT_UTIME], NULL, 10, &utime) < 0 || ++ virStrToLong_ullp(proc_stat[VIR_PROCESS_STAT_STIME], NULL, 10, &stime) < 0 || + virStrToLong_l(proc_stat[VIR_PROCESS_STAT_RSS], NULL, 10, &rss) < 0 || + virStrToLong_i(proc_stat[VIR_PROCESS_STAT_PROCESSOR], NULL, 10, &cpu) < 0) { + VIR_WARN("cannot parse process status data"); + } + +- /* We got jiffies +- * We want nanoseconds +- * _SC_CLK_TCK is jiffies per second +- * So calculate thus.... +- */ ++ utime *= jiff2nsec; ++ stime *= jiff2nsec; + if (cpuTime) +- *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) +- / (unsigned long long) sysconf(_SC_CLK_TCK); ++ *cpuTime = utime + stime; ++ if (userTime) ++ *userTime = utime; ++ if (sysTime) ++ *sysTime = stime; + if (lastCpu) + *lastCpu = cpu; + +@@ -1771,7 +1776,7 @@ virProcessGetStatInfo(unsigned long long *cpuTime, + + + VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d rss=%ld", +- (int) pid, tid, usertime, systime, cpu, rss); ++ (int) pid, tid, utime, stime, cpu, rss); + + return 0; + } +@@ -1844,6 +1849,8 @@ virProcessGetSchedInfo(unsigned long long *cpuWait, + #else + int + virProcessGetStatInfo(unsigned long long *cpuTime, ++ unsigned long long *userTime, ++ unsigned long long *sysTime, + int *lastCpu, + long *vm_rss, + pid_t pid G_GNUC_UNUSED, +@@ -1853,6 +1860,10 @@ virProcessGetStatInfo(unsigned long long *cpuTime, + * platforms, so just report neutral values */ + if (cpuTime) + *cpuTime = 0; ++ if (userTime) ++ *userTime = 0; ++ if (sysTime) ++ *sysTime = 0; + if (lastCpu) + *lastCpu = 0; + if (vm_rss) +diff --git a/src/util/virprocess.h b/src/util/virprocess.h +index 086fbe0e4d..f5a4a4e508 100644 +--- a/src/util/virprocess.h ++++ b/src/util/virprocess.h +@@ -195,6 +195,8 @@ typedef enum { + int virProcessNamespaceAvailable(unsigned int ns); + + int virProcessGetStatInfo(unsigned long long *cpuTime, ++ unsigned long long *userTime, ++ unsigned long long *sysTime, + int *lastCpu, + long *vm_rss, + pid_t pid, +-- +2.39.0 + diff --git a/SOURCES/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch b/SOURCES/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch new file mode 100644 index 0000000..5d6201f --- /dev/null +++ b/SOURCES/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch @@ -0,0 +1,124 @@ +From 38ad84afdbeab479d0beee24e7bef87a64db1ce3 Mon Sep 17 00:00:00 2001 +Message-Id: <38ad84afdbeab479d0beee24e7bef87a64db1ce3@dist-git> +From: Peter Krempa +Date: Thu, 1 Dec 2022 13:32:07 +0100 +Subject: [PATCH] util: json: Split out array->strinlist conversion from + virJSONValueObjectGetStringArray + +Introduce virJSONValueArrayToStringList which does only the conversion +from an array to a stringlist. + +This will allow refactoring the callers to be more careful in case when +they want to handle the existance of the member in the parent object +differently. + +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit 6765bdeaf7e9cbdb4c39d47f3b77fb28a498408a) +https://bugzilla.redhat.com/show_bug.cgi?id=2154410 +--- + src/libvirt_private.syms | 1 + + src/util/virjson.c | 43 ++++++++++++++++++++++------------------ + src/util/virjson.h | 2 ++ + 3 files changed, 27 insertions(+), 19 deletions(-) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 76bcc64eb0..288310b75a 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -2543,6 +2543,7 @@ virJSONValueArrayForeachSteal; + virJSONValueArrayGet; + virJSONValueArraySize; + virJSONValueArraySteal; ++virJSONValueArrayToStringList; + virJSONValueCopy; + virJSONValueFree; + virJSONValueFromString; +diff --git a/src/util/virjson.c b/src/util/virjson.c +index 53f8cdff95..fcbc173ffa 100644 +--- a/src/util/virjson.c ++++ b/src/util/virjson.c +@@ -1316,10 +1316,7 @@ virJSONValueObjectStealObject(virJSONValue *object, + char ** + virJSONValueObjectGetStringArray(virJSONValue *object, const char *key) + { +- g_auto(GStrv) ret = NULL; + virJSONValue *data; +- size_t n; +- size_t i; + + data = virJSONValueObjectGetArray(object, key); + if (!data) { +@@ -1329,32 +1326,40 @@ virJSONValueObjectGetStringArray(virJSONValue *object, const char *key) + return NULL; + } + +- n = virJSONValueArraySize(data); +- ret = g_new0(char *, n + 1); ++ return virJSONValueArrayToStringList(data); ++} ++ ++ ++/** ++ * virJSONValueArrayToStringList: ++ * @data: a JSON array containing strings to convert ++ * ++ * Converts @data a JSON array containing strings to a NULL-terminated string ++ * list. @data must be a JSON array. In case @data is doesn't contain only ++ * strings an error is reported. ++ */ ++char ** ++virJSONValueArrayToStringList(virJSONValue *data) ++{ ++ size_t n = virJSONValueArraySize(data); ++ g_auto(GStrv) ret = g_new0(char *, n + 1); ++ size_t i; ++ + for (i = 0; i < n; i++) { + virJSONValue *child = virJSONValueArrayGet(data, i); +- const char *tmp; + +- if (!child) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("%s array element is missing item %zu"), +- key, i); ++ if (!child || ++ !(ret[i] = g_strdup(virJSONValueGetString(child)))) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("JSON string array contains non-string element")); + return NULL; + } +- +- if (!(tmp = virJSONValueGetString(child))) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("%s array element does not contain a string"), +- key); +- return NULL; +- } +- +- ret[i] = g_strdup(tmp); + } + + return g_steal_pointer(&ret); + } + ++ + /** + * virJSONValueObjectForeachKeyValue: + * @object: JSON object to iterate +diff --git a/src/util/virjson.h b/src/util/virjson.h +index aced48a538..c9f83ab2bc 100644 +--- a/src/util/virjson.h ++++ b/src/util/virjson.h +@@ -172,6 +172,8 @@ virJSONValueObjectGetString(virJSONValue *object, + char ** + virJSONValueObjectGetStringArray(virJSONValue *object, + const char *key); ++char ** ++virJSONValueArrayToStringList(virJSONValue *data); + const char * + virJSONValueObjectGetStringOrNumber(virJSONValue *object, + const char *key); +-- +2.39.0 + diff --git a/SPECS/libvirt.spec b/SPECS/libvirt.spec index e3af6df..10590e3 100644 --- a/SPECS/libvirt.spec +++ b/SPECS/libvirt.spec @@ -231,7 +231,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 8.5.0 -Release: 7%{?dist}%{?extra_release} +Release: 7.3%{?dist}%{?extra_release} License: LGPLv2+ URL: https://libvirt.org/ @@ -274,6 +274,17 @@ Patch31: libvirt-qemu-don-t-call-qemuMigrationSrcIsAllowedHostdev-from-qemuMigra Patch32: libvirt-rpc-Pass-OPENSSL_CONF-through-to-ssh-invocations.patch Patch33: libvirt-qemu_process-Destroy-domain-s-namespace-after-killing-QEMU.patch Patch34: libvirt-security_selinux-Don-t-ignore-NVMe-disks-when-setting-image-label.patch +Patch35: libvirt-nodedev-wait-a-bit-longer-for-new-node-devices.patch +Patch36: libvirt-kbase-Document-QEMU-private-mount-NS-limitations.patch +Patch37: libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch +Patch38: libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch +Patch39: libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch +Patch40: libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch +Patch41: libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch +Patch42: libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch +Patch43: libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch +Patch44: libvirt-util-Extend-virProcessGetStatInfo-for-sysTime-and-userTime.patch +Patch45: libvirt-qemu-Implement-qemuDomainGetStatsCpu-fallback-for-qemu-session.patch Requires: libvirt-daemon = %{version}-%{release} @@ -2180,6 +2191,24 @@ exit 0 %changelog +* Thu Jan 5 2023 Jiri Denemark - 8.5.0-7.3.el9_1 +- util: json: Split out array->strinlist conversion from virJSONValueObjectGetStringArray (rhbz#2154410) +- qemuAgentGetDisks: Don't use virJSONValueObjectGetStringArray for optional data (rhbz#2154410) +- util: Extend virProcessGetStatInfo() for sysTime and userTime (rhbz#2157094) +- qemu: Implement qemuDomainGetStatsCpu fallback for qemu:///session (rhbz#2157094) +- RHEL: rpminspect: Disable abidiff inspection + +* Wed Dec 14 2022 Jiri Denemark - 8.5.0-7.2.el9_1 +- kbase: Document QEMU private mount NS limitations (rhbz#2152083) +- qemu_namespace: Tolerate missing ACLs when creating a path in namespace (rhbz#2152083) +- qemu_namespace: Fix a corner case in qemuDomainGetPreservedMounts() (rhbz#2152083) +- qemu_namespace: Introduce qemuDomainNamespaceSetupPath() (rhbz#2152083) +- qemu_process.c: Propagate hugetlbfs mounts on reconnect (rhbz#2152083) +- qemuProcessReconnect: Don't build memory paths (rhbz#2152083) + +* Fri Nov 11 2022 Jiri Denemark - 8.5.0-7.1.el9_1 +- nodedev: wait a bit longer for new node devices (rhbz#2141364) + * Mon Sep 26 2022 Jiri Denemark - 8.5.0-7 - security_selinux: Don't ignore NVMe disks when setting image label (rhbz#2121441)