diff options
author | CLEMENT MATHIEU--DRIF <clement.mathieu--drif@eviden.com> | 2025-04-30 12:48:06 +0000 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2025-05-14 07:45:51 -0400 |
commit | 1b85dff5f0be30ddbcb7edbd3c084c9c5ee351ca (patch) | |
tree | 11ca344f5104cd0e6a298b2a005bea1c7e714ca1 | |
parent | b1c84782bfddeaa0070f5ae57ac2e4e3992f9f19 (diff) | |
download | qemu-1b85dff5f0be30ddbcb7edbd3c084c9c5ee351ca.zip qemu-1b85dff5f0be30ddbcb7edbd3c084c9c5ee351ca.tar.gz qemu-1b85dff5f0be30ddbcb7edbd3c084c9c5ee351ca.tar.bz2 |
intel_iommu: Take locks when looking for and creating address spaces
vtd_find_add_as can be called by multiple threads which leads to a race
condition. Taking the IOMMU lock ensures we avoid such a race.
Moreover we also need to take the bql to avoid an assert to fail in
memory_region_add_subregion_overlap when actually allocating a new
address space.
Signed-off-by: Clement Mathieu--Drif <clement.mathieu--drif@eviden.com>
Message-Id: <20250430124750.240412-3-clement.mathieu--drif@eviden.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r-- | hw/i386/intel_iommu.c | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index b925e65..69d72ad 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4205,9 +4205,30 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, VTDAddressSpace *vtd_dev_as; char name[128]; + vtd_iommu_lock(s); vtd_dev_as = g_hash_table_lookup(s->vtd_address_spaces, &key); + vtd_iommu_unlock(s); + if (!vtd_dev_as) { - struct vtd_as_key *new_key = g_malloc(sizeof(*new_key)); + struct vtd_as_key *new_key; + /* Slow path */ + + /* + * memory_region_add_subregion_overlap requires the bql, + * make sure we own it. + */ + BQL_LOCK_GUARD(); + vtd_iommu_lock(s); + + /* Check again as we released the lock for a moment */ + vtd_dev_as = g_hash_table_lookup(s->vtd_address_spaces, &key); + if (vtd_dev_as) { + vtd_iommu_unlock(s); + return vtd_dev_as; + } + + /* Still nothing, allocate a new address space */ + new_key = g_malloc(sizeof(*new_key)); new_key->bus = bus; new_key->devfn = devfn; @@ -4298,6 +4319,8 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, vtd_switch_address_space(vtd_dev_as); g_hash_table_insert(s->vtd_address_spaces, new_key, vtd_dev_as); + + vtd_iommu_unlock(s); } return vtd_dev_as; } |