Message ID | 20240328122958.83332-2-yi.l.liu@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Two enhancements to iommu_at[de]tach_device_pasid() | expand |
On 3/28/24 8:29 PM, Yi Liu wrote: > There is no error handling now in __iommu_set_group_pasid(), it relies on > its caller to loop all the devices to undo the pasid attachment. This is > not self-contained and has drawbacks. It would result in unnecessary > remove_dev_pasid() calls on the devices that have not been attached to the > new domain. But the remove_dev_pasid() callback would get the new domain > from the group->pasid_array. So for such devices, the iommu driver won't > find the attachment under the domain, hence unable to do cleanup. This may > not be a real problem today. But it depends on the implementation of the > underlying iommu driver. e.g. the intel iommu driver would warn for such > devices. Such warnings are unnecessary. > > To solve the above problem, it is necessary to handle the error within > __iommu_set_group_pasid(). It only loops the devices that have attached > to the new domain, and undo it. > > Fixes: 16603704559c ("iommu: Add attach/detach_dev_pasid iommu interfaces") > Suggested-by: Jason Gunthorpe<jgg@nvidia.com> > Reviewed-by: Jason Gunthorpe<jgg@nvidia.com> > Reviewed-by: Kevin Tian<kevin.tian@intel.com> > Signed-off-by: Yi Liu<yi.l.liu@intel.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Best regards, baolu
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 098869007c69..bb3244df525e 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -3317,15 +3317,26 @@ EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed); static int __iommu_set_group_pasid(struct iommu_domain *domain, struct iommu_group *group, ioasid_t pasid) { - struct group_device *device; - int ret = 0; + struct group_device *device, *last_gdev; + int ret; for_each_group_device(group, device) { ret = domain->ops->set_dev_pasid(domain, device->dev, pasid); if (ret) - break; + goto err_revert; } + return 0; + +err_revert: + last_gdev = device; + for_each_group_device(group, device) { + const struct iommu_ops *ops = dev_iommu_ops(device->dev); + + if (device == last_gdev) + break; + ops->remove_dev_pasid(device->dev, pasid); + } return ret; } @@ -3374,10 +3385,8 @@ int iommu_attach_device_pasid(struct iommu_domain *domain, } ret = __iommu_set_group_pasid(domain, group, pasid); - if (ret) { - __iommu_remove_group_pasid(group, pasid); + if (ret) xa_erase(&group->pasid_array, pasid); - } out_unlock: mutex_unlock(&group->mutex); return ret;