Reviewed-by: Clement Mathieu--Drif <[email protected]>

Let's wait for Yi's review.  
Thanks for your efforts, Zhenzhong!

cmd

On Tue, 2026-10-20 at 17:19 +0800, Zhenzhong Duan 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.
> 
> 
> When a PASID entry becomes invalid, all resources allocated for that entry,  
> including the FAULTQ object and fault_fd, must be released.
> 
> Calling qemu_set_fd_handler() detaches the fault_fd I/O read handler and  
> wakes up the main loop thread from poll(). However, a race window exists  
> where iommufd_backend_free_id(fault_id) can be invoked before poll() exits  
> and releases its reference to the fault_fd file. In this scenario, freeing  
> the FAULTQ object returns -EBUSY because the opened fault_fd file still  
> holds an active reference to the FAULTQ object.
> 
> Defer FAULTQ resource teardown to a bottom half. This ensures poll() has  
> fully exited and dropped the file reference before the fault_fd is closed  
> and the FAULTQ object ID is freed. Additionally, keep the IOMMUFD backend  
> FD open via iommufd_backend_connect() across the asynchronous bottom half  
> execution to ensure FAULTQ object freed successfully.
> 
> Suggested-by: Shameer Kolothum 
> <[[email protected]](mailto:[email protected])>  
> Signed-off-by: Zhenzhong Duan 
> <[[email protected]](mailto:[email protected])>  
> Reviewed-by: Yi Liu <[[email protected]](mailto:[email protected])>  
> Tested-by: Xudong Hao <[[email protected]](mailto:[email protected])>  
> ---  
>  hw/i386/intel_iommu_accel.c | 59 +++++++++++++++++++++++++++++++++++--  
>  1 file changed, 56 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/i386/intel_iommu_accel.c b/hw/i386/intel_iommu_accel.c  
> index 243501f137..7db8319ad4 100644  
> --- a/hw/i386/intel_iommu_accel.c  
> +++ b/hw/i386/intel_iommu_accel.c  
> @@ -271,17 +271,70 @@ free_faultq:  
>      return false;  
>  }
> 
> +typedef struct IOMMUFaultQueue {  
> +    IOMMUFDBackend *iommufd;  
> +    uint32_t id;  
> +    int fd;  
> +    QLIST_HEAD(, VTDPRQEntry) vtd_prq_list;  
> +} IOMMUFaultQueue;  
> +  
> +static void faultq_teardown_bh(void *opaque)  
> +{  
> +    IOMMUFaultQueue *fq = opaque;  
> +    VTDPRQEntry *prqe, *next;  
> +  
> +    QLIST_FOREACH_SAFE(prqe, &fq->vtd_prq_list, next, next) {  
> +        QLIST_REMOVE(prqe, next);  
> +        g_free(prqe);  
> +    }  
> +  
> +    qemu_set_fd_handler(fq->fd, NULL, NULL, NULL);  
> +    close(fq->fd);  
> +    iommufd_backend_free_id(fq->iommufd, fq->id);  
> +    iommufd_backend_disconnect(fq->iommufd);  
> +  
> +    g_free(fq);  
> +}  
> +  
>  static void vtd_destroy_old_fs_faultq(VTDAccelPASIDCacheEntry *vtd_pce)  
>  {  
> +    HostIOMMUDeviceIOMMUFD *idev =  
> +        HOST_IOMMU_DEVICE_IOMMUFD(vtd_pce->vtd_hiod->hiod);  
> +    IOMMUFaultQueue *fq;  
> +  
>      if (vtd_pce->fault_fd < 0) {  
>          return;  
>      }
> 
> -    qemu_set_fd_handler(vtd_pce->fault_fd, NULL, NULL, NULL);  
> -    vtd_destroy_fs_faultq(vtd_pce->vtd_hiod, vtd_pce->fault_id,  
> -                          vtd_pce->fault_fd);  
> +    fq = g_malloc(sizeof(*fq));  
> +    fq->iommufd = idev->iommufd;  
> +    fq->fd = vtd_pce->fault_fd;  
> +    fq->id = vtd_pce->fault_id;  
>      vtd_pce->fault_id = 0;  
>      vtd_pce->fault_fd = -1;  
> +    fq->vtd_prq_list.lh_first = vtd_pce->vtd_prq_list.lh_first;  
> +    QLIST_INIT(&vtd_pce->vtd_prq_list);  
> +  
> +    /*  
> +     * During a VFIO device hot-unplug, if this is the last device connected 
>  
> +     * to the IOMMUFDBackend, the backend user count (iommufd->users) will  
> +     * drop to zero, triggering iommufd_backend_disconnect() which closes  
> +     * the backend's opened container FD.  
> +     *  
> +     * Since the teardown of this fault queue (faultq_teardown_bh) is  
> +     * scheduled asynchronously as a bottom half, we must temporarily  
> +     * increment the connection user count of the iommufd backend here.  
> +     * This guarantees the backend connection remains open and its opened  
> +     * FD remains active until the async BH completes.  
> +     *  
> +     * Incrementing the user count is guaranteed to succeed here because the 
>  
> +     * VFIO device is still registered as an active user of the backend at  
> +     * this point in the teardown sequence.  
> +     */  
> +    iommufd_backend_connect(fq->iommufd, &error_abort);  
> +  
> +    aio_bh_schedule_oneshot(iohandler_get_aio_context(),  
> +                            faultq_teardown_bh, fq);  
>  }
> 
>  static void vtd_setup_fs_faultq(VTDAccelPASIDCacheEntry *vtd_pce,  
> --  
> 2.52.0
> 

Reply via email to