Enable building for ppc64le

This commit is contained in:
Eduard Abdullin 2025-12-19 02:28:43 +00:00 committed by root
commit b525ab970d
8 changed files with 864 additions and 2 deletions

View File

@ -0,0 +1,69 @@
From 933524784d813b24aa0970992b820698f1e03180 Mon Sep 17 00:00:00 2001
Message-ID: <933524784d813b24aa0970992b820698f1e03180.1766070439.git.jdenemar@redhat.com>
From: Nathan Chen via Devel <devel@lists.libvirt.org>
Date: Tue, 2 Dec 2025 11:59:47 -0800
Subject: [PATCH] qemu: Use pci_bus to identify multi-smmuv3 model
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Use presence of non-negative pci_bus to identify multi-smmuv3
IOMMU model, instead of the niommus attribute. This allows for
specifying a single arm-smmuv3 on the qemu command line,
instead of both the virt-machine smmuv3 and arm-smmuv3
being specified at the same time.
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
Fixes: e70c4d54d365 conf: Support multiple device-pluggable smmuv3 IOMMUs
Reviewed-by: Ján Tomko <jtomko@redhat.com>
(cherry picked from commit da4305b7bc8d3bd52c60db1905db88e43ebd9868)
https://issues.redhat.com/browse/RHEL-74200
Signed-off-by: Ján Tomko <jtomko@redhat.com>
---
src/qemu/qemu_command.c | 2 +-
src/qemu/qemu_postparse.c | 2 +-
.../iommu-smmuv3-pci-bus-single.aarch64-latest.args | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index b69fe23236..fb89dbec27 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -7192,7 +7192,7 @@ qemuBuildMachineCommandLine(virCommand *cmd,
if (qemuAppendDomainFeaturesMachineParam(&buf, def, qemuCaps) < 0)
return -1;
- if (def->niommus == 1) {
+ if (def->iommus && def->iommus[0]->pci_bus < 0) {
switch (def->iommus[0]->model) {
case VIR_DOMAIN_IOMMU_MODEL_SMMUV3:
virBufferAddLit(&buf, ",iommu=smmuv3");
diff --git a/src/qemu/qemu_postparse.c b/src/qemu/qemu_postparse.c
index dc5ade829a..840d6a1174 100644
--- a/src/qemu/qemu_postparse.c
+++ b/src/qemu/qemu_postparse.c
@@ -1559,7 +1559,7 @@ qemuDomainDefEnableDefaultFeatures(virDomainDef *def,
* domain already has IOMMU without inremap. This will be fixed in
* qemuDomainIOMMUDefPostParse() but there domain definition can't be
* modified so change it now. */
- if (def->iommus && def->niommus == 1 &&
+ if (def->iommus && def->iommus[0]->pci_bus < 0 &&
(def->iommus[0]->intremap == VIR_TRISTATE_SWITCH_ON ||
qemuDomainNeedsIOMMUWithEIM(def)) &&
def->features[VIR_DOMAIN_FEATURE_IOAPIC] == VIR_DOMAIN_IOAPIC_NONE) {
diff --git a/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.args b/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.args
index 976467e641..34e7bda1c5 100644
--- a/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.args
+++ b/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.args
@@ -10,7 +10,7 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-guest/.config \
-name guest=guest,debug-threads=on \
-S \
-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-guest/master-key.aes"}' \
--machine virt,usb=off,gic-version=2,iommu=smmuv3,dump-guest-core=off,memory-backend=mach-virt.ram,acpi=off \
+-machine virt,usb=off,gic-version=2,dump-guest-core=off,memory-backend=mach-virt.ram,acpi=off \
-accel tcg \
-cpu cortex-a15 \
-m size=1048576k \
--
2.52.0

View File

@ -0,0 +1,119 @@
From 8e9dc8aed52c98c3683949dfe1127061bd9df47a Mon Sep 17 00:00:00 2001
Message-ID: <8e9dc8aed52c98c3683949dfe1127061bd9df47a.1766070439.git.jdenemar@redhat.com>
From: Peter Krempa <pkrempa@redhat.com>
Date: Mon, 1 Dec 2025 11:35:32 +0100
Subject: [PATCH] qemu: tpm: Account for possible migration without actually
sharing storage
The current logic in 'qemuTPMEmulatorBuildCommand' skips all setup if
the *location* of the data is on what we'd consider shared storage.
This means that if the location is not actually shared (e.g. it's shared
betweeh some other hosts than the two doing the migration) and the path
wasn't ever used (e.g. by migrating out) from the host where we're
migrating into the complete setup of the location would be skipped even
when it doesn't exist.
Fix the logic by skipping only some of the setup steps so that
'qemuTPMEmulatorCreateStorage' can still create the storage if it
doesn't exist.
The rest of the code then needs to take the 'created' flag returned from
'qemuTPMEmulatorCreateStorage' into account.
Fixes: 68103e9daf633b789428fedef56f816c92f6ee75
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
(cherry picked from commit d56d0560946770d4364a4918cc289e6a7fe5d15c)
https://issues.redhat.com/browse/RHEL-132534
---
src/qemu/qemu_tpm.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c
index 4c9445d72c..660410bcba 100644
--- a/src/qemu/qemu_tpm.c
+++ b/src/qemu/qemu_tpm.c
@@ -158,6 +158,7 @@ qemuTPMEmulatorGetPid(const char *swtpmStateDir,
/**
* qemuTPMEmulatorCreateStorage:
* @tpm: TPM definition for an emulator type
+ * @sharedStorageMigration: VM is being migrated with possibly shared storage
* @created: a pointer to a bool that will be set to true if the
* storage was created because it did not exist yet
* @swtpm_user: The uid that needs to be able to access the directory
@@ -169,6 +170,7 @@ qemuTPMEmulatorGetPid(const char *swtpmStateDir,
*/
static int
qemuTPMEmulatorCreateStorage(virDomainTPMDef *tpm,
+ bool sharedStorageMigration,
bool *created,
uid_t swtpm_user,
gid_t swtpm_group)
@@ -187,8 +189,17 @@ qemuTPMEmulatorCreateStorage(virDomainTPMDef *tpm,
*created = false;
if (!virFileExists(source_path) ||
- virDirIsEmpty(source_path, true) > 0)
+ virDirIsEmpty(source_path, true) > 0) {
*created = true;
+ } else {
+ /* If the location exists and is shared, we don't need to create it
+ * during migration */
+ if (sharedStorageMigration) {
+ VIR_DEBUG("Skipping TPM storage creation. Path '%s' already exists and is on shared storage.",
+ source_path);
+ return 0;
+ }
+ }
if (virDirCreate(source_path, 0700, swtpm_user, swtpm_group,
VIR_DIR_CREATE_ALLOW_EXIST) < 0) {
@@ -809,16 +820,13 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
run_setup = true;
}
- /* Do not create storage and run swtpm_setup on incoming migration over
- * shared storage
- */
on_shared_storage = virFileIsSharedFS(tpm->data.emulator.source_path,
cfg->sharedFilesystems) == 1;
- if (incomingMigration && on_shared_storage)
- create_storage = false;
if (create_storage) {
- if (qemuTPMEmulatorCreateStorage(tpm, &created,
+ if (qemuTPMEmulatorCreateStorage(tpm,
+ incomingMigration && on_shared_storage,
+ &created,
cfg->swtpm_user, cfg->swtpm_group) < 0)
return NULL;
run_setup = created;
@@ -885,6 +893,9 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
/* If swtpm supports it and the TPM state is stored on shared storage,
* start swtpm with --migration release-lock-outgoing so it can migrate
* across shared storage if needed.
+ *
+ * Note that if 'created' is true, the location didn't exist so the storage
+ * is not actually shared.
*/
QEMU_DOMAIN_TPM_PRIVATE(tpm)->swtpm.can_migrate_shared_storage = false;
if (on_shared_storage &&
@@ -892,13 +903,13 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
virCommandAddArg(cmd, "--migration");
virCommandAddArgFormat(cmd, "release-lock-outgoing%s",
- incomingMigration ? ",incoming": "");
+ incomingMigration && !created ? ",incoming": "");
QEMU_DOMAIN_TPM_PRIVATE(tpm)->swtpm.can_migrate_shared_storage = true;
} else {
/* Report an error if there's an incoming migration across shared
* storage and swtpm does not support the --migration option.
*/
- if (incomingMigration && on_shared_storage) {
+ if (incomingMigration && on_shared_storage && !created) {
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
_("%1$s (on destination side) does not support the --migration option needed for migration with shared storage"),
swtpm);
--
2.52.0

View File

@ -0,0 +1,111 @@
From 0bb3bb84670dbd45c6eca2d108b2d4d5a7754ef4 Mon Sep 17 00:00:00 2001
Message-ID: <0bb3bb84670dbd45c6eca2d108b2d4d5a7754ef4.1766070439.git.jdenemar@redhat.com>
From: Jiri Denemark <jdenemar@redhat.com>
Date: Fri, 5 Dec 2025 15:09:15 +0100
Subject: [PATCH] tests: Test virFileIsSharedFSOverride
Technically virFileIsSharedFSOverride is available on any OS, but we
need a mocked realpath() to test it. Because the virfilemock library
also mocks statfs() which is only available on Linux, we don't even try
to load the library anywhere else. Thus we need to skip testing
virFileIsSharedFSOverride on non-Linux too.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
(cherry picked from commit 121d179e068b584f62ea2c029d89a44e67c909c0)
https://issues.redhat.com/browse/RHEL-102925
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
tests/virfiletest.c | 69 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/tests/virfiletest.c b/tests/virfiletest.c
index e05925a321..ccd76a3fac 100644
--- a/tests/virfiletest.c
+++ b/tests/virfiletest.c
@@ -329,6 +329,55 @@ testFileIsSharedFSType(const void *opaque G_GNUC_UNUSED)
}
+static const char *shared_filesystems[] = {
+ "/run/user/501/gvfs",
+ "/nfs",
+ "/gluster",
+ "/ceph/multi",
+ "/gpfs/data/blaf",
+ "/quobyte",
+ NULL,
+};
+
+static int
+testFileIsSharedFSOverride(const void *opaque G_GNUC_UNUSED)
+{
+#ifndef __linux__
+ return EXIT_AM_SKIP;
+#else
+ const struct testFileIsSharedFSType *data = opaque;
+ g_autofree char *mtabFile = NULL;
+ bool actual;
+ int ret = -1;
+
+ /* mtab is used by mocked realpath to decide whether a given path exists */
+ mtabFile = g_strdup_printf(abs_srcdir "/virfiledata/%s", data->mtabFile);
+
+ if (!g_setenv("LIBVIRT_MTAB", mtabFile, true)) {
+ fprintf(stderr, "Unable to set env variable\n");
+ goto cleanup;
+ }
+
+ actual = virFileIsSharedFSOverride(data->filename,
+ (char * const *) shared_filesystems);
+
+ if (actual != data->expected) {
+ fprintf(stderr, "FS of '%s' is %s. Expected: %s\n",
+ data->filename,
+ actual ? "shared" : "not shared",
+ data->expected ? "shared" : "not shared");
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ g_unsetenv("LIBVIRT_MTAB");
+ return ret;
+#endif
+}
+
+
static int
mymain(void)
{
@@ -439,6 +488,26 @@ mymain(void)
DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/gpfs/data", true);
DO_TEST_FILE_IS_SHARED_FS_TYPE("mounts3.txt", "/quobyte", true);
+#define DO_TEST_FILE_IS_SHARED_FS_OVERRIDE(mtab, file, exp) \
+ do { \
+ struct testFileIsSharedFSType data = { \
+ .mtabFile = mtab, .filename = file, .expected = exp \
+ }; \
+ if (virTestRun(virTestCounterNext(), testFileIsSharedFSOverride, &data) < 0) \
+ ret = -1; \
+ } while (0)
+
+ virTestCounterReset("testFileIsSharedFSOverride ");
+ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts2.txt", "/boot/vmlinuz", false);
+ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts2.txt", "/run/user/501/gvfs/some/file", true);
+ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/nfs/file", true);
+ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/gluster/file", true);
+ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/some/symlink/file", true);
+ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/ceph/file", false);
+ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/ceph/multi/file", true);
+ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/gpfs/data", false);
+ DO_TEST_FILE_IS_SHARED_FS_OVERRIDE("mounts3.txt", "/quobyte", true);
+
return ret != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
--
2.52.0

View File

@ -0,0 +1,201 @@
From d30c21439f3847ecc229db9355eb802f0256a3f0 Mon Sep 17 00:00:00 2001
Message-ID: <d30c21439f3847ecc229db9355eb802f0256a3f0.1766070438.git.jdenemar@redhat.com>
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
Date: Fri, 5 Dec 2025 08:50:51 +0100
Subject: [PATCH] tests: add test for a single per-device smmuv3
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Ján Tomko <jtomko@redhat.com>
(cherry picked from commit 45ff1c002629dadd9d94b91742ffb985b0fe027f)
https://issues.redhat.com/browse/RHEL-74200
Signed-off-by: Ján Tomko <jtomko@redhat.com>
---
...-smmuv3-pci-bus-single.aarch64-latest.args | 40 +++++++++++++
...u-smmuv3-pci-bus-single.aarch64-latest.xml | 59 +++++++++++++++++++
.../iommu-smmuv3-pci-bus-single.xml | 46 +++++++++++++++
tests/qemuxmlconftest.c | 1 +
4 files changed, 146 insertions(+)
create mode 100644 tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.args
create mode 100644 tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.xml
create mode 100644 tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.xml
diff --git a/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.args b/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.args
new file mode 100644
index 0000000000..976467e641
--- /dev/null
+++ b/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.args
@@ -0,0 +1,40 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/var/lib/libvirt/qemu/domain--1-guest \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-guest/.local/share \
+XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-guest/.cache \
+XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-guest/.config \
+/usr/bin/qemu-system-aarch64 \
+-name guest=guest,debug-threads=on \
+-S \
+-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-guest/master-key.aes"}' \
+-machine virt,usb=off,gic-version=2,iommu=smmuv3,dump-guest-core=off,memory-backend=mach-virt.ram,acpi=off \
+-accel tcg \
+-cpu cortex-a15 \
+-m size=1048576k \
+-object '{"qom-type":"memory-backend-ram","id":"mach-virt.ram","size":1073741824}' \
+-overcommit mem-lock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-boot strict=on \
+-device '{"driver":"pxb-pcie","bus_nr":252,"id":"pci.1","bus":"pcie.0","addr":"0x1"}' \
+-device '{"driver":"pxb-pcie","bus_nr":248,"id":"pci.2","bus":"pcie.0","addr":"0x2"}' \
+-device '{"driver":"pcie-root-port","port":0,"chassis":21,"id":"pci.3","bus":"pci.1","addr":"0x0"}' \
+-device '{"driver":"pcie-root-port","port":168,"chassis":22,"id":"pci.4","bus":"pci.2","addr":"0x0"}' \
+-device '{"driver":"arm-smmuv3","primary-bus":"pci.1","id":"iommu0"}' \
+-audiodev '{"id":"audio1","driver":"none"}' \
+-object '{"qom-type":"rng-random","id":"objrng0","filename":"/dev/urandom"}' \
+-device '{"driver":"virtio-rng-pci","rng":"objrng0","id":"rng0","bus":"pci.3","addr":"0x0"}' \
+-object '{"qom-type":"rng-random","id":"objrng1","filename":"/dev/urandom"}' \
+-device '{"driver":"virtio-rng-pci","rng":"objrng1","id":"rng1","bus":"pci.4","addr":"0x0"}' \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.xml b/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.xml
new file mode 100644
index 0000000000..e6071fd71b
--- /dev/null
+++ b/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.aarch64-latest.xml
@@ -0,0 +1,59 @@
+<domain type='qemu'>
+ <name>guest</name>
+ <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <currentMemory unit='KiB'>1048576</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <gic version='2'/>
+ </features>
+ <cpu mode='custom' match='exact' check='none'>
+ <model fallback='forbid'>cortex-a15</model>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-aarch64</emulator>
+ <controller type='usb' index='0' model='none'/>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-expander-bus'>
+ <model name='pxb-pcie'/>
+ <target busNr='252'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-expander-bus'>
+ <model name='pxb-pcie'/>
+ <target busNr='248'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </controller>
+ <controller type='pci' index='3' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='21' port='0x0'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='pci' index='4' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='22' port='0xa8'/>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </controller>
+ <audio id='1' type='none'/>
+ <memballoon model='none'/>
+ <rng model='virtio'>
+ <backend model='random'>/dev/urandom</backend>
+ <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </rng>
+ <rng model='virtio'>
+ <backend model='random'>/dev/urandom</backend>
+ <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
+ </rng>
+ <iommu model='smmuv3'>
+ <driver pciBus='1'/>
+ </iommu>
+ </devices>
+</domain>
diff --git a/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.xml b/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.xml
new file mode 100644
index 0000000000..6f40a19740
--- /dev/null
+++ b/tests/qemuxmlconfdata/iommu-smmuv3-pci-bus-single.xml
@@ -0,0 +1,46 @@
+<domain type='qemu'>
+ <name>guest</name>
+ <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid>
+ <memory unit='KiB'>1048576</memory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='aarch64' machine='virt'>hvm</type>
+ </os>
+ <devices>
+ <emulator>/usr/bin/qemu-system-aarch64</emulator>
+ <controller type='usb' model='none'/>
+ <memballoon model='none'/>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='pci' index='1' model='pcie-expander-bus'>
+ <model name='pxb-pcie'/>
+ <target busNr='252'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-expander-bus'>
+ <model name='pxb-pcie'/>
+ <target busNr='248'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </controller>
+ <controller type='pci' index='3' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='21' port='0x0'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='pci' index='4' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='22' port='0xa8'/>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </controller>
+ <rng model='virtio'>
+ <backend model='random'>/dev/urandom</backend>
+ <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </rng>
+ <rng model='virtio'>
+ <backend model='random'>/dev/urandom</backend>
+ <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
+ </rng>
+ <iommu model='smmuv3'>
+ <driver pciBus='1'/>
+ </iommu>
+ </devices>
+</domain>
diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
index de03c58c8a..9a3257ea55 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -3039,6 +3039,7 @@ mymain(void)
DO_TEST_CAPS_LATEST_ABI_UPDATE("intel-iommu-eim-autoadd-v2");
DO_TEST_CAPS_ARCH_LATEST("iommu-smmuv3", "aarch64");
DO_TEST_CAPS_ARCH_LATEST("iommu-smmuv3-pci-bus", "aarch64");
+ DO_TEST_CAPS_ARCH_LATEST("iommu-smmuv3-pci-bus-single", "aarch64");
DO_TEST_CAPS_LATEST("virtio-iommu-x86_64");
DO_TEST_CAPS_ARCH_LATEST("virtio-iommu-aarch64", "aarch64");
DO_TEST_CAPS_LATEST_PARSE_ERROR("virtio-iommu-wrong-machine");
--
2.52.0

View File

@ -0,0 +1,114 @@
From bcf71678b891cb8862b85be2fd44d2dc61686f94 Mon Sep 17 00:00:00 2001
Message-ID: <bcf71678b891cb8862b85be2fd44d2dc61686f94.1766070439.git.jdenemar@redhat.com>
From: Jiri Denemark <jdenemar@redhat.com>
Date: Fri, 5 Dec 2025 16:51:25 +0100
Subject: [PATCH] util: Fix race condition in virFileIsSharedFSOverride
Switch virFileIsSharedFSOverride to use virFileCheckParents to avoid a
race which could result in virFileCanonicalizePath to be called on a
path that does not exist anymore.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
(cherry picked from commit 3a44f0c23d75519a9a374f790f4b91ab7b65a138)
https://issues.redhat.com/browse/RHEL-102925
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/util/virfile.c | 59 +++++++++++++++++-----------------------------
1 file changed, 22 insertions(+), 37 deletions(-)
diff --git a/src/util/virfile.c b/src/util/virfile.c
index 95fc8ff0e6..52d711d2a9 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -3502,33 +3502,6 @@ virFileCheckParents(const char *path,
}
-static char *
-virFileGetExistingParent(const char *path)
-{
- g_autofree char *dirpath = g_strdup(path);
- char *p = NULL;
-
- /* Try less and less of the path until we get to a directory we can access.
- * Even if we don't have 'x' permission on any directory in the path on the
- * NFS server (assuming it's NFS), we will be able to stat the mount point.
- */
- while (!virFileExists(dirpath) && p != dirpath) {
- if (!(p = strrchr(dirpath, '/'))) {
- virReportSystemError(EINVAL,
- _("Invalid relative path '%1$s'"), path);
- return NULL;
- }
-
- if (p == dirpath)
- *(p + 1) = '\0';
- else
- *p = '\0';
- }
-
- return g_steal_pointer(&dirpath);
-}
-
-
#ifdef __linux__
# ifndef NFS_SUPER_MAGIC
@@ -3875,6 +3848,17 @@ virFileGetDefaultHugepage(virHugeTLBFS *fs,
}
+static bool
+virFileCheckParentsCanonicalize(const char *path,
+ void *opaque)
+{
+ char **canonical = opaque;
+
+ *canonical = virFileCanonicalizePath(path);
+ return !!*canonical;
+}
+
+
/**
* virFileIsSharedFSOverride:
* @path: Path to check
@@ -3888,24 +3872,25 @@ virFileIsSharedFSOverride(const char *path,
char *const *overrides)
{
g_autofree char *dirpath = NULL;
- g_autofree char *existing = NULL;
char *p = NULL;
+ int rc;
if (!path || path[0] != '/' || !overrides)
return false;
/* We only care about the longest existing sub-path. Further components
- * may will later be created by libvirt will not magically become a shared
- * filesystem. */
- if (!(existing = virFileGetExistingParent(path)))
+ * that may later be created by libvirt will not magically become a shared
+ * filesystem. Overrides have been canonicalized ahead of time, so we need
+ * to do the same for the provided path or we'll never be able to find a
+ * match if symlinks are involved.
+ */
+ rc = virFileCheckParents(path, NULL,
+ virFileCheckParentsCanonicalize, &dirpath);
+ if (rc == -1)
return false;
- /* Overrides have been canonicalized ahead of time, so we need to
- * do the same for the provided path or we'll never be able to
- * find a match if symlinks are involved */
- if (!(dirpath = virFileCanonicalizePath(existing))) {
- VIR_DEBUG("Cannot canonicalize parent '%s' of path '%s'",
- existing, path);
+ if (rc != 0) {
+ VIR_DEBUG("Cannot canonicalize path '%s'", path);
return false;
}
--
2.52.0

View File

@ -0,0 +1,144 @@
From 0ef9c539a38510d35daec578dae8491f8a1c651c Mon Sep 17 00:00:00 2001
Message-ID: <0ef9c539a38510d35daec578dae8491f8a1c651c.1766070439.git.jdenemar@redhat.com>
From: Jiri Denemark <jdenemar@redhat.com>
Date: Fri, 5 Dec 2025 16:47:14 +0100
Subject: [PATCH] util: Fix race condition in virFileIsSharedFSType
virFileIsSharedFSType could end up calling statfs on a path that no
longer exists and return an error. If this happens for a path on a
shared filesystem, the caller may incorrectly consider the path as
non-shared.
Specifically, when starting a domain with TPM enabled and deciding
whether its vTPM state is stored on a shared storage, the race could
cause qemuTPMEmulatorBuildCommand to consider the state to be
non-shared. This means swtpm would be started without --migration even
when the state is actually stored on a shared storage and any attempt to
migrate such domain would fail with
Operation not supported: the running swtpm does not support
migration with shared storage
In fact, any caller of virFileGetExistingParent contained an inherent
TOCTOU race condition as the existing parent of a given path return by
virFileGetExistingParent may no longer exist at the time the caller
wants to check it.
This patch introduces a new virFileCheckParents API which is almost
identical to virFileGetExistingParent, but uses a supplied callback to
check each path. This new API is used in virFileIsSharedFSType to avoid
the race. The old function will later be completely removed once all
callers are switched to the new one.
Fixes: 05526b50909ff50c16e13a0b5580d41de74e3d59
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
(cherry picked from commit b6addd42bece693debbf2e95551a2b4d2e1b453f)
https://issues.redhat.com/browse/RHEL-102925
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/util/virfile.c | 71 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 69 insertions(+), 2 deletions(-)
diff --git a/src/util/virfile.c b/src/util/virfile.c
index a5c9fbe0d9..95fc8ff0e6 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -3445,6 +3445,63 @@ virFileRemoveLastComponent(char *path)
}
+/* Check callback for virFileCheckParents */
+typedef bool (*virFileCheckParentsCallback)(const char *dirpath,
+ void *opaque);
+
+/**
+ * virFileCheckParents:
+ * @path: path to check
+ * @parent: where to store the closest parent satisfying the check
+ * @check: callback called on parent paths
+ * @opaque: data for the @check callback
+ *
+ * Calls @check on the @path and its parent paths until it returns true or a
+ * root directory is reached. When @check returns true, the @parent (if
+ * non-NULL) will be set to a copy of the corresponding path. The caller is
+ * responsible for freeing it.
+ *
+ * Returns 0 on success (@parent set),
+ * -1 on invalid input,
+ * -2 when no path (including "/") satisfies the @check.
+ */
+static int
+virFileCheckParents(const char *path,
+ char **parent,
+ virFileCheckParentsCallback check,
+ void *opaque)
+{
+ g_autofree char *dirpath = g_strdup(path);
+ char *p = NULL;
+ bool checkOK;
+
+ checkOK = check(dirpath, opaque);
+
+ while (!checkOK && p != dirpath) {
+ if (!(p = strrchr(dirpath, G_DIR_SEPARATOR))) {
+ virReportSystemError(EINVAL,
+ _("Invalid absolute path '%1$s'"), path);
+ return -1;
+ }
+
+ if (p == dirpath)
+ *(p + 1) = '\0';
+ else
+ *p = '\0';
+
+ checkOK = check(dirpath, opaque);
+ }
+
+ if (!checkOK)
+ return -2;
+
+ if (parent)
+ *parent = g_steal_pointer(&dirpath);
+
+ return 0;
+}
+
+
static char *
virFileGetExistingParent(const char *path)
{
@@ -3599,6 +3656,14 @@ static const struct virFileSharedFsData virFileSharedFs[] = {
};
+static bool
+virFileCheckParentsStatFS(const char *path,
+ void *opaque)
+{
+ return statfs(path, (struct statfs *) opaque) == 0;
+}
+
+
int
virFileIsSharedFSType(const char *path,
unsigned int fstypes)
@@ -3607,11 +3672,13 @@ virFileIsSharedFSType(const char *path,
struct statfs sb;
long long f_type = 0;
size_t i;
+ int rc;
- if (!(dirpath = virFileGetExistingParent(path)))
+ if ((rc = virFileCheckParents(path, &dirpath,
+ virFileCheckParentsStatFS, &sb)) == -1)
return -1;
- if (statfs(dirpath, &sb) < 0) {
+ if (rc != 0) {
virReportSystemError(errno,
_("cannot determine filesystem for '%1$s'"),
path);
--
2.52.0

View File

@ -0,0 +1,84 @@
From 9a8eedf3c0eca3075cf27ebae2d872df6627f3dd Mon Sep 17 00:00:00 2001
Message-ID: <9a8eedf3c0eca3075cf27ebae2d872df6627f3dd.1766070439.git.jdenemar@redhat.com>
From: Jiri Denemark <jdenemar@redhat.com>
Date: Fri, 5 Dec 2025 16:52:32 +0100
Subject: [PATCH] util: Rework virFileIsSharedFSOverride using
virFileCheckParents
The newly introduced virFileCheckParents is generic enough to be used
for checking whether a specific path or any of its parents is included
in the overrides array.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
(cherry picked from commit eedf9ed68b45585569865604bf2a403670feaf3e)
https://issues.redhat.com/browse/RHEL-102925
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/util/virfile.c | 35 ++++++++++++-----------------------
1 file changed, 12 insertions(+), 23 deletions(-)
diff --git a/src/util/virfile.c b/src/util/virfile.c
index 52d711d2a9..05b2fa8168 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -3859,6 +3859,14 @@ virFileCheckParentsCanonicalize(const char *path,
}
+static bool
+virFileCheckParentsInOverrides(const char *path,
+ void *opaque)
+{
+ return g_strv_contains((const char *const *) opaque, path);
+}
+
+
/**
* virFileIsSharedFSOverride:
* @path: Path to check
@@ -3872,7 +3880,6 @@ virFileIsSharedFSOverride(const char *path,
char *const *overrides)
{
g_autofree char *dirpath = NULL;
- char *p = NULL;
int rc;
if (!path || path[0] != '/' || !overrides)
@@ -3894,29 +3901,11 @@ virFileIsSharedFSOverride(const char *path,
return false;
}
- if (g_strv_contains((const char *const *) overrides, dirpath))
- return true;
+ if (virFileCheckParents(dirpath, NULL, virFileCheckParentsInOverrides,
+ (void *) overrides) < 0)
+ return false;
- /* Continue until we've scanned the entire path */
- while (p != dirpath) {
-
- /* Find the last slash */
- if ((p = strrchr(dirpath, '/')) == NULL)
- break;
-
- /* Truncate the path by overwriting the slash that we've just
- * found with a null byte. If it is the very first slash in
- * the path, we need to handle things slightly differently */
- if (p == dirpath)
- *(p+1) = '\0';
- else
- *p = '\0';
-
- if (g_strv_contains((const char *const *) overrides, dirpath))
- return true;
- }
-
- return false;
+ return true;
}
--
2.52.0

View File

@ -298,7 +298,7 @@
Summary: Library providing a simple virtualization API
Name: libvirt
Version: 11.10.0
Release: 1%{?dist}%{?extra_release}.alma.1
Release: 2%{?dist}%{?extra_release}.alma.1
License: GPL-2.0-or-later AND LGPL-2.1-only AND LGPL-2.1-or-later AND OFL-1.1
URL: https://libvirt.org/
@ -306,6 +306,14 @@ URL: https://libvirt.org/
%define mainturl stable_updates/
%endif
Source: https://download.libvirt.org/%{?mainturl}libvirt-%{version}.tar.xz
Patch1: libvirt-tests-add-test-for-a-single-per-device-smmuv3.patch
Patch2: libvirt-qemu-Use-pci_bus-to-identify-multi-smmuv3-model.patch
Patch3: libvirt-qemu-tpm-Account-for-possible-migration-without-actually-sharing-storage.patch
Patch4: libvirt-tests-Test-virFileIsSharedFSOverride.patch
Patch5: libvirt-util-Fix-race-condition-in-virFileIsSharedFSType.patch
Patch6: libvirt-util-Fix-race-condition-in-virFileIsSharedFSOverride.patch
Patch7: libvirt-util-Rework-virFileIsSharedFSOverride-using-virFileCheckParents.patch
Requires: libvirt-daemon = %{version}-%{release}
Requires: libvirt-daemon-config-network = %{version}-%{release}
@ -1172,6 +1180,9 @@ MinGW Windows libvirt virtualization library.
%prep
%autosetup -S git_am -N
%autopatch
%build
%if 0%{?fedora} >= %{min_fedora} || 0%{?rhel} >= %{min_rhel}
%define supported_platform 1
@ -2693,9 +2704,18 @@ exit 0
%endif
%changelog
* Thu Dec 04 2025 Eduard Abdullin <eabdullin@almalinux.org> - 11.10.0-1.alma.1
* Fri Dec 19 2025 Eduard Abdullin <eabdullin@almalinux.org> - 11.10.0-2.alma.1
- Enable building for ppc64le
* Thu Dec 18 2025 Jiri Denemark <jdenemar@redhat.com> - 11.10.0-2
- tests: add test for a single per-device smmuv3 (RHEL-74200)
- qemu: Use pci_bus to identify multi-smmuv3 model (RHEL-74200)
- qemu: tpm: Account for possible migration without actually sharing storage (RHEL-132534)
- tests: Test virFileIsSharedFSOverride (RHEL-102925)
- util: Fix race condition in virFileIsSharedFSType (RHEL-102925)
- util: Fix race condition in virFileIsSharedFSOverride (RHEL-102925)
- util: Rework virFileIsSharedFSOverride using virFileCheckParents (RHEL-102925)
* Mon Dec 1 2025 Jiri Denemark <jdenemar@redhat.com> - 11.10.0-1
- Rebased to libvirt-11.10.0 (RHEL-104238)
- The rebase also fixes the following bugs: