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>
This commit is contained in:
CLEMENT MATHIEU--DRIF 2025-04-30 12:48:06 +00:00 committed by Michael S. Tsirkin
parent b1c84782bf
commit 1b85dff5f0

View file

@ -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;
}