Message ID | 20240327125433.248946-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 Wed, Mar 27, 2024 at 05:54:32AM -0700, Yi Liu wrote: > Existing remove_dev_pasid() callbacks of the underlying iommu drivers get > the attached domain from the group->pasid_array. However, the domains > stored in group->pasid_array are not always correct. For example, the > set_dev_pasid() path updates group->pasid_array first and then invoke > remove_dev_pasid() callback when error happened. The remove_dev_pasid() > callback would get the updated domain. This is not correct for the > devices that are still attached with an old domain or just no attached > domain. > > To avoid the above problem, passing the attached domain to the > remove_dev_pasid() callback is more reliable. I've relaized we have the same issue with set_dev_pasid, there is no way for the driver to get the old domain since the xarray was updated before calling set_dev_pasid. This is unlike the RID path. Meaning drivers can't implement PASID replace. So we need another patch to pass the old domain into set_dev_pasid too... This looks fine Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Jason
On 2024/3/27 21:02, Jason Gunthorpe wrote: > On Wed, Mar 27, 2024 at 05:54:32AM -0700, Yi Liu wrote: >> Existing remove_dev_pasid() callbacks of the underlying iommu drivers get >> the attached domain from the group->pasid_array. However, the domains >> stored in group->pasid_array are not always correct. For example, the >> set_dev_pasid() path updates group->pasid_array first and then invoke >> remove_dev_pasid() callback when error happened. The remove_dev_pasid() >> callback would get the updated domain. This is not correct for the >> devices that are still attached with an old domain or just no attached >> domain. >> >> To avoid the above problem, passing the attached domain to the >> remove_dev_pasid() callback is more reliable. > > I've relaized we have the same issue with set_dev_pasid, there is no > way for the driver to get the old domain since the xarray was updated > before calling set_dev_pasid. This is unlike the RID path. Meaning > drivers can't implement PASID replace. > > So we need another patch to pass the old domain into set_dev_pasid > too... yes. you've given this suggestion in below. :) I've already in this way. Will send it out together with other iommufd pasid attach/replace/detach patches. https://lore.kernel.org/linux-iommu/20240318165247.GD5825@nvidia.com/ > > This looks fine > > Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> thanks.
> From: Liu, Yi L <yi.l.liu@intel.com> > Sent: Wednesday, March 27, 2024 8:55 PM > > @@ -3375,7 +3376,7 @@ 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); > + __iommu_remove_group_pasid(group, pasid, domain); > xa_erase(&group->pasid_array, pasid); I didn't get why this patch alone fixes anything. You are passing the new domain which is same as original code which gets it from xarray. so it is at most a non-functional refactoring with the next patch doing real fix?
On 2024/3/28 11:12, Tian, Kevin wrote: >> From: Liu, Yi L <yi.l.liu@intel.com> >> Sent: Wednesday, March 27, 2024 8:55 PM >> >> @@ -3375,7 +3376,7 @@ 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); >> + __iommu_remove_group_pasid(group, pasid, domain); >> xa_erase(&group->pasid_array, pasid); > > I didn't get why this patch alone fixes anything. You are passing the > new domain which is same as original code which gets it from > xarray. you are right. This is to avoid getting domain from xarray in remove_dev_pasid(). But this part is still the same with the original code. > so it is at most a non-functional refactoring with the next patch > doing real fix? yes. let me make it clearer.
On 2024/3/27 21:02, Jason Gunthorpe wrote: > On Wed, Mar 27, 2024 at 05:54:32AM -0700, Yi Liu wrote: >> Existing remove_dev_pasid() callbacks of the underlying iommu drivers get >> the attached domain from the group->pasid_array. However, the domains >> stored in group->pasid_array are not always correct. For example, the >> set_dev_pasid() path updates group->pasid_array first and then invoke >> remove_dev_pasid() callback when error happened. The remove_dev_pasid() >> callback would get the updated domain. This is not correct for the >> devices that are still attached with an old domain or just no attached >> domain. >> >> To avoid the above problem, passing the attached domain to the >> remove_dev_pasid() callback is more reliable. > > I've relaized we have the same issue with set_dev_pasid, there is no > way for the driver to get the old domain since the xarray was updated > before calling set_dev_pasid. This is unlike the RID path. Meaning > drivers can't implement PASID replace. > > So we need another patch to pass the old domain into set_dev_pasid > too... > > This looks fine > > Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> I dropped your r-b as the description changed. Please have another look at the v2 of this patch. :) [1] https://lore.kernel.org/linux-iommu/20240328122958.83332-3-yi.l.liu@intel.com/
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 5ed036225e69..ced041777ec0 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -3044,14 +3044,9 @@ static int arm_smmu_def_domain_type(struct device *dev) return 0; } -static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid) +static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid, + struct iommu_domain *domain) { - struct iommu_domain *domain; - - domain = iommu_get_domain_for_dev_pasid(dev, pasid, IOMMU_DOMAIN_SVA); - if (WARN_ON(IS_ERR(domain)) || !domain) - return; - arm_smmu_sva_remove_dev_pasid(domain, dev, pasid); } diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 50eb9aed47cc..45c75a8a0ef5 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -4587,19 +4587,15 @@ static int intel_iommu_iotlb_sync_map(struct iommu_domain *domain, return 0; } -static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) +static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, + struct iommu_domain *domain) { struct device_domain_info *info = dev_iommu_priv_get(dev); + struct dmar_domain *dmar_domain = to_dmar_domain(domain); struct dev_pasid_info *curr, *dev_pasid = NULL; struct intel_iommu *iommu = info->iommu; - struct dmar_domain *dmar_domain; - struct iommu_domain *domain; unsigned long flags; - domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0); - if (WARN_ON_ONCE(!domain)) - goto out_tear_down; - /* * The SVA implementation needs to handle its own stuffs like the mm * notification. Before consolidating that code into iommu core, let @@ -4610,7 +4606,6 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) goto out_tear_down; } - dmar_domain = to_dmar_domain(domain); spin_lock_irqsave(&dmar_domain->lock, flags); list_for_each_entry(curr, &dmar_domain->dev_pasids, link_domain) { if (curr->dev == dev && curr->pasid == pasid) { diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 098869007c69..681e916d285b 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -3330,14 +3330,15 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain, } static void __iommu_remove_group_pasid(struct iommu_group *group, - ioasid_t pasid) + ioasid_t pasid, + struct iommu_domain *domain) { struct group_device *device; const struct iommu_ops *ops; for_each_group_device(group, device) { ops = dev_iommu_ops(device->dev); - ops->remove_dev_pasid(device->dev, pasid); + ops->remove_dev_pasid(device->dev, pasid, domain); } } @@ -3375,7 +3376,7 @@ 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); + __iommu_remove_group_pasid(group, pasid, domain); xa_erase(&group->pasid_array, pasid); } out_unlock: @@ -3400,7 +3401,7 @@ void iommu_detach_device_pasid(struct iommu_domain *domain, struct device *dev, struct iommu_group *group = dev->iommu_group; mutex_lock(&group->mutex); - __iommu_remove_group_pasid(group, pasid); + __iommu_remove_group_pasid(group, pasid, domain); WARN_ON(xa_erase(&group->pasid_array, pasid) != domain); mutex_unlock(&group->mutex); } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 2e925b5eba53..40dd439307e8 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -578,7 +578,8 @@ struct iommu_ops { struct iommu_page_response *msg); int (*def_domain_type)(struct device *dev); - void (*remove_dev_pasid)(struct device *dev, ioasid_t pasid); + void (*remove_dev_pasid)(struct device *dev, ioasid_t pasid, + struct iommu_domain *domain); const struct iommu_domain_ops *default_domain_ops; unsigned long pgsize_bitmap;
Existing remove_dev_pasid() callbacks of the underlying iommu drivers get the attached domain from the group->pasid_array. However, the domains stored in group->pasid_array are not always correct. For example, the set_dev_pasid() path updates group->pasid_array first and then invoke remove_dev_pasid() callback when error happened. The remove_dev_pasid() callback would get the updated domain. This is not correct for the devices that are still attached with an old domain or just no attached domain. To avoid the above problem, passing the attached domain to the remove_dev_pasid() callback is more reliable. Fixes: 386fa64fd52baadb ("arm-smmu-v3/sva: Add SVA domain support") Suggested-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Yi Liu <yi.l.liu@intel.com> --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 9 ++------- drivers/iommu/intel/iommu.c | 11 +++-------- drivers/iommu/iommu.c | 9 +++++---- include/linux/iommu.h | 3 ++- 4 files changed, 12 insertions(+), 20 deletions(-)