>-----Original Message-----
>From: CLEMENT MATHIEU--DRIF <clement.mathieu--d...@eviden.com>
>Subject: Re: [PATCH v4 3/3] intel_iommu: Take the VTD lock when looking for and
>creating address spaces
>
>Hi Zhenzhong,
>
>On 28/04/2025 10:55 am, Duan, Zhenzhong wrote:
>> Caution: External email. Do not open attachments or click links, unless this
>email comes from a known sender and you know the content is safe.
>>
>>
>> Hi Clement,
>>
>>> -----Original Message-----
>>> From: CLEMENT MATHIEU--DRIF <clement.mathieu--d...@eviden.com>
>>> Subject: [PATCH v4 3/3] intel_iommu: Take the VTD lock when looking for and
>>> creating address spaces
>>>
>>> vtd_find_add_as can be called by multiple threads which leads to a race
>>> condition on address space creation. The IOMMU lock must be taken to
>>> avoid such a race.
>>>
>>> Signed-off-by: Clement Mathieu--Drif <clement.mathieu--d...@eviden.com>
>>> ---
>>> hw/i386/intel_iommu.c | 28 ++++++++++++++++++++++++++--
>>> 1 file changed, 26 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
>>> index b7855f4b87..931ac01ef0 100644
>>> --- a/hw/i386/intel_iommu.c
>>> +++ b/hw/i386/intel_iommu.c
>>> @@ -4203,11 +4203,15 @@ VTDAddressSpace
>>> *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus,
>>>          .pasid = pasid,
>>>      };
>>>      VTDAddressSpace *vtd_dev_as;
>>> +    struct vtd_as_key *new_key = NULL;
>>>      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));
>>> +        new_key = g_malloc(sizeof(*new_key));
>>>
>>>          new_key->bus = bus;
>>>          new_key->devfn = devfn;
>>> @@ -4302,9 +4306,29 @@ VTDAddressSpace
>>> *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus,
>>>                                              &vtd_dev_as->nodmar, 0);
>>>
>>>          vtd_switch_address_space(vtd_dev_as);
>>> +    }
>>>
>>> -        g_hash_table_insert(s->vtd_address_spaces, new_key, vtd_dev_as);
>>> +    if (new_key != NULL) {
>>> +        VTDAddressSpace *second_vtd_dev_as;
>>> +
>>> +        /*
>>> +         * Take the lock again and recheck as the AS might have
>>> +         * been created in the meantime.
>>> +         */
>>> +        vtd_iommu_lock(s);
>>> +
>>> +        second_vtd_dev_as = g_hash_table_lookup(s->vtd_address_spaces,
>&key);
>>> +        if (!second_vtd_dev_as) {
>>> +            g_hash_table_insert(s->vtd_address_spaces, new_key, 
>>> vtd_dev_as);
>>> +        } else {
>>> +            vtd_dev_as = second_vtd_dev_as;
>>> +            g_free(vtd_dev_as);
>>> +            g_free(new_key);
>>
>> We need to release memory regions under this vtd_dev_as to avoid leak.
>
>
>Indeed, I'll have to take the BQL again.
>
>Is it ok for you if it look like this:
>
>vtd_iommu_lock(s);
>
>second_vtd_dev_as = g_hash_table_lookup(s->vtd_address_spaces, &key);
>if (!second_vtd_dev_as) {
>     g_hash_table_insert(s->vtd_address_spaces, new_key, vtd_dev_as);
>     vtd_iommu_unlock(s);
>} else {
>     vtd_iommu_unlock(s);
>     BQL_LOCK_GUARD();
>
>     memory_region_del_subregion(&vtd_dev_as->root, &vtd_dev_as->nodmar);
>     memory_region_del_subregion(&vtd_dev_as->root,
>                                 MEMORY_REGION(&vtd_dev_as->iommu));
>     memory_region_del_subregion(&vtd_dev_as->root,
>                                 &vtd_dev_as->iommu_ir_fault);
>     memory_region_del_subregion(&vtd_dev_as->root,
>                                 &vtd_dev_as->iommu_ir);
>
>     memory_region_unref(MEMORY_REGION(&vtd_dev_as->iommu));
>     memory_region_unref(&vtd_dev_as->iommu_ir_fault);
>     memory_region_unref(&vtd_dev_as->iommu_ir);
>     memory_region_unref(&vtd_dev_as->nodmar);

s/memory_region_unref/object_unparent?

>
>     address_space_destroy(&vtd_dev_as->as);

object_unparent(vtd_dev_as->root);

Thanks
Zhenzhong

Reply via email to