diff mbox series

[1/2] iommu: Pass domain to remove_dev_pasid() op

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

Commit Message

Yi Liu March 27, 2024, 12:54 p.m. UTC
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(-)

Comments

Jason Gunthorpe March 27, 2024, 1:02 p.m. UTC | #1
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
Yi Liu March 27, 2024, 1:10 p.m. UTC | #2
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.
Tian, Kevin March 28, 2024, 3:12 a.m. UTC | #3
> 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?
Yi Liu March 28, 2024, 6:28 a.m. UTC | #4
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.
Yi Liu March 28, 2024, 12:38 p.m. UTC | #5
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 mbox series

Patch

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;