All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
@ 2022-05-04  0:11 Jason Gunthorpe via iommu
  2022-05-04  8:22 ` Nicolin Chen via iommu
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-05-04  0:11 UTC (permalink / raw)
  To: iommu, Nicolin Chen, Will Deacon, Robin Murphy; +Cc: Kevin Tian, Qian Cai

Once the group enters 'owned' mode it can never be assigned back to the
default_domain or to a NULL domain. It must always be actively assigned to
a current domain. If the caller hasn't provided a domain then the core
must provide an explicit DMA blocking domain that has no DMA map.

Lazily create a group-global blocking DMA domain when
iommu_group_claim_dma_owner is first called and immediately assign the
group to it. This ensures that DMA is immediately fully isolated on all
IOMMU drivers.

If the user attaches/detaches while owned then detach will set the group
back to the blocking domain.

Slightly reorganize the call chains so that
__iommu_group_attach_core_domain() is the function that removes any caller
configured domain and sets the domains back a core owned domain with an
appropriate lifetime.

__iommu_group_attach_domain() is the worker function that can change the
domain assigned to a group to any target domain, including NULL.

Add comments clarifying how the NULL vs detach_dev vs default_domain works
based on Robin's remarks.

This fixes an oops with VFIO and SMMUv3 because VFIO will call
iommu_detach_group() and then immediately iommu_domain_free(), but
SMMUv3 has no way to know that the domain it is holding a pointer to
has been freed. Now the iommu_detach_group() will assign the blocking
domain and SMMUv3 will no longer hold a stale domain reference.

Fixes: 1ea2a07a532b ("iommu: Add DMA ownership management interfaces")
Reported-by: Qian Cai <quic_qiancai@quicinc.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/iommu/iommu.c | 112 +++++++++++++++++++++++++++++++-----------
 1 file changed, 82 insertions(+), 30 deletions(-)

This is based on Robins draft here:

https://lore.kernel.org/linux-iommu/18831161-473f-e04f-4a81-1c7062ad192d@arm.com/

With some rework. I re-organized the call chains instead of introducing
iommu_group_user_attached(), fixed a recursive locking for
iommu_group_get_purgatory(), and made a proper commit message.

Still only compile tested, so RFCish.

Nicolin/Lu? What do you think, can you check it?

Jason

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 0c42ece2585406..94d99768023c94 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -44,6 +44,7 @@ struct iommu_group {
 	char *name;
 	int id;
 	struct iommu_domain *default_domain;
+	struct iommu_domain *blocking_domain;
 	struct iommu_domain *domain;
 	struct list_head entry;
 	unsigned int owner_cnt;
@@ -82,8 +83,7 @@ static int __iommu_attach_device(struct iommu_domain *domain,
 				 struct device *dev);
 static int __iommu_attach_group(struct iommu_domain *domain,
 				struct iommu_group *group);
-static void __iommu_detach_group(struct iommu_domain *domain,
-				 struct iommu_group *group);
+static void __iommu_group_attach_core_domain(struct iommu_group *group);
 static int iommu_create_device_direct_mappings(struct iommu_group *group,
 					       struct device *dev);
 static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
@@ -596,6 +596,8 @@ static void iommu_group_release(struct kobject *kobj)
 
 	if (group->default_domain)
 		iommu_domain_free(group->default_domain);
+	if (group->blocking_domain)
+		iommu_domain_free(group->blocking_domain);
 
 	kfree(group->name);
 	kfree(group);
@@ -1979,12 +1981,10 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
 		return;
 
 	mutex_lock(&group->mutex);
-	if (iommu_group_device_count(group) != 1) {
-		WARN_ON(1);
+	if (WARN_ON(domain != group->domain) ||
+	    WARN_ON(iommu_group_device_count(group) != 1))
 		goto out_unlock;
-	}
-
-	__iommu_detach_group(domain, group);
+	__iommu_group_attach_core_domain(group);
 
 out_unlock:
 	mutex_unlock(&group->mutex);
@@ -2072,38 +2072,66 @@ static int iommu_group_do_detach_device(struct device *dev, void *data)
 	return 0;
 }
 
-static void __iommu_detach_group(struct iommu_domain *domain,
-				 struct iommu_group *group)
+static int __iommu_group_attach_domain(struct iommu_group *group,
+				       struct iommu_domain *new_domain)
 {
 	int ret;
 
+	if (group->domain == new_domain)
+		return 0;
+
 	/*
-	 * If the group has been claimed already, do not re-attach the default
-	 * domain.
+	 * A NULL domain means to call the detach_dev() op. New drivers should
+	 * use a IOMMU_DOMAIN_IDENTITY domain instead of a NULL default_domain
+	 * and detatch_dev().
 	 */
-	if (!group->default_domain || group->owner) {
-		__iommu_group_for_each_dev(group, domain,
+	if (!new_domain) {
+		WARN_ON(!group->domain->ops->detach_dev);
+		__iommu_group_for_each_dev(group, group->domain,
 					   iommu_group_do_detach_device);
 		group->domain = NULL;
-		return;
+		return 0;
 	}
 
-	if (group->domain == group->default_domain)
-		return;
-
-	/* Detach by re-attaching to the default domain */
+	/*
+	 * New drivers do not implement detach_dev, so changing the domain is
+	 * done by calling attach on the new domain. Drivers should implement
+	 * this so that DMA is always translated by either the new, old, or a
+	 * blocking domain. DMA should never become untranslated.
+	 *
+	 * Note that this is called in error unwind paths, attaching to a
+	 * domain that has already been attached cannot fail.
+	 */
 	ret = __iommu_group_for_each_dev(group, group->default_domain,
 					 iommu_group_do_attach_device);
-	if (ret != 0)
-		WARN_ON(1);
+	if (ret)
+		return ret;
+	group->domain = new_domain;
+	return 0;
+}
+
+/*
+ * Put the group's domain back to the appropriate core-owned domain - either the
+ * standard kernel-mode DMA configuration or an all-DMA-blocked domain.
+ */
+static void __iommu_group_attach_core_domain(struct iommu_group *group)
+{
+	struct iommu_domain *new_domain;
+	int ret;
+
+	if (group->owner)
+		new_domain = group->blocking_domain;
 	else
-		group->domain = group->default_domain;
+		new_domain = group->default_domain;
+
+	ret = __iommu_group_attach_domain(group, new_domain);
+	WARN(ret, "iommu driver failed to attach the default/blocking domain");
 }
 
 void iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group)
 {
 	mutex_lock(&group->mutex);
-	__iommu_detach_group(domain, group);
+	__iommu_group_attach_core_domain(group);
 	mutex_unlock(&group->mutex);
 }
 EXPORT_SYMBOL_GPL(iommu_detach_group);
@@ -3088,6 +3116,29 @@ void iommu_device_unuse_default_domain(struct device *dev)
 	iommu_group_put(group);
 }
 
+static int __iommu_group_alloc_blocking_domain(struct iommu_group *group)
+{
+	struct group_device *dev =
+		list_first_entry(&group->devices, struct group_device, list);
+
+	if (group->blocking_domain)
+		return 0;
+
+	group->blocking_domain =
+		__iommu_domain_alloc(dev->dev->bus, IOMMU_DOMAIN_BLOCKED);
+	if (!group->blocking_domain) {
+		/*
+		 * For drivers that do not yet understand IOMMU_DOMAIN_BLOCKED
+		 * create an empty domain instead.
+		 */
+		group->blocking_domain = __iommu_domain_alloc(
+			dev->dev->bus, IOMMU_DOMAIN_UNMANAGED);
+		if (!group->blocking_domain)
+			return -EINVAL;
+	}
+	return 0;
+}
+
 /**
  * iommu_group_claim_dma_owner() - Set DMA ownership of a group
  * @group: The group.
@@ -3111,9 +3162,15 @@ int iommu_group_claim_dma_owner(struct iommu_group *group, void *owner)
 			goto unlock_out;
 		}
 
+		ret = __iommu_group_alloc_blocking_domain(group);
+		if (ret)
+			goto unlock_out;
+
+		ret = __iommu_group_attach_domain(group,
+						  group->blocking_domain);
+		if (ret)
+			goto unlock_out;
 		group->owner = owner;
-		if (group->domain)
-			__iommu_detach_group(group->domain, group);
 	}
 
 	group->owner_cnt++;
@@ -3137,13 +3194,8 @@ void iommu_group_release_dma_owner(struct iommu_group *group)
 		goto unlock_out;
 
 	group->owner_cnt = 0;
-	/*
-	 * The UNMANAGED domain should be detached before all USER
-	 * owners have been released.
-	 */
-	if (!WARN_ON(group->domain) && group->default_domain)
-		__iommu_attach_group(group->default_domain, group);
 	group->owner = NULL;
+	__iommu_group_attach_core_domain(group);
 unlock_out:
 	mutex_unlock(&group->mutex);
 }

base-commit: dc7afe17339c2f5de8c377aaa0b976139a19e158
-- 
2.36.0

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04  0:11 [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain Jason Gunthorpe via iommu
@ 2022-05-04  8:22 ` Nicolin Chen via iommu
  2022-05-04 11:57   ` Jason Gunthorpe via iommu
  2022-05-04 11:48 ` Baolu Lu
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Nicolin Chen via iommu @ 2022-05-04  8:22 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: Kevin Tian, Will Deacon, Qian Cai, iommu, Robin Murphy

On Tue, May 03, 2022 at 09:11:02PM -0300, Jason Gunthorpe wrote:

> This is based on Robins draft here:
> 
> https://lore.kernel.org/linux-iommu/18831161-473f-e04f-4a81-1c7062ad192d@arm.com/
> 
> With some rework. I re-organized the call chains instead of introducing
> iommu_group_user_attached(), fixed a recursive locking for
> iommu_group_get_purgatory(), and made a proper commit message.
> 
> Still only compile tested, so RFCish.
> 
> Nicolin/Lu? What do you think, can you check it?

I am able to repro the issue on ARM64 and give this a quick try.
But the patch seems to need to include the following change too.

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 94d99768023c..9bb108d01baa 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2040,7 +2040,8 @@ static int __iommu_attach_group(struct iommu_domain *domain,
 {
 	int ret;
 
-	if (group->domain && group->domain != group->default_domain)
+	if (group->domain && group->domain != group->default_domain &&
+	    group->domain != group->blocking_domain)
 		return -EBUSY;
 
 	ret = __iommu_group_for_each_dev(group, domain,

> @@ -2072,38 +2072,66 @@ static int iommu_group_do_detach_device(struct device *dev, void *data)
>  	return 0;
>  }
>  
> -static void __iommu_detach_group(struct iommu_domain *domain,
> -				 struct iommu_group *group)
> +static int __iommu_group_attach_domain(struct iommu_group *group,
> +				       struct iommu_domain *new_domain)
>  {
>  	int ret;
>  
> +	if (group->domain == new_domain)
> +		return 0;
> +
>  	/*
> -	 * If the group has been claimed already, do not re-attach the default
> -	 * domain.
> +	 * A NULL domain means to call the detach_dev() op. New drivers should
> +	 * use a IOMMU_DOMAIN_IDENTITY domain instead of a NULL default_domain

an IOMMU_DOMAIN_IDENTITY?

Just a nit here. I will take a closer look at the change tomorrow.

Thanks
Nic
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04  0:11 [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain Jason Gunthorpe via iommu
  2022-05-04  8:22 ` Nicolin Chen via iommu
@ 2022-05-04 11:48 ` Baolu Lu
  2022-05-04 11:53   ` Jason Gunthorpe via iommu
  2022-05-04 14:35 ` Baolu Lu
  2022-05-04 14:42 ` Robin Murphy
  3 siblings, 1 reply; 13+ messages in thread
From: Baolu Lu @ 2022-05-04 11:48 UTC (permalink / raw)
  To: Jason Gunthorpe, iommu, Nicolin Chen, Will Deacon, Robin Murphy
  Cc: Kevin Tian, Qian Cai

Hi Jason,

On 2022/5/4 08:11, Jason Gunthorpe wrote:
> +static int __iommu_group_attach_domain(struct iommu_group *group,
> +				       struct iommu_domain *new_domain)
>   {
>   	int ret;
>   
> +	if (group->domain == new_domain)
> +		return 0;
> +
>   	/*
> -	 * If the group has been claimed already, do not re-attach the default
> -	 * domain.
> +	 * A NULL domain means to call the detach_dev() op. New drivers should
> +	 * use a IOMMU_DOMAIN_IDENTITY domain instead of a NULL default_domain
> +	 * and detatch_dev().
>   	 */
> -	if (!group->default_domain || group->owner) {
> -		__iommu_group_for_each_dev(group, domain,
> +	if (!new_domain) {
> +		WARN_ON(!group->domain->ops->detach_dev);
> +		__iommu_group_for_each_dev(group, group->domain,
>   					   iommu_group_do_detach_device);
>   		group->domain = NULL;
> -		return;
> +		return 0;
>   	}
>   
> -	if (group->domain == group->default_domain)
> -		return;
> -
> -	/* Detach by re-attaching to the default domain */
> +	/*
> +	 * New drivers do not implement detach_dev, so changing the domain is
> +	 * done by calling attach on the new domain. Drivers should implement
> +	 * this so that DMA is always translated by either the new, old, or a
> +	 * blocking domain. DMA should never become untranslated.
> +	 *
> +	 * Note that this is called in error unwind paths, attaching to a
> +	 * domain that has already been attached cannot fail.
> +	 */
>   	ret = __iommu_group_for_each_dev(group, group->default_domain,
						^^^^^^^^^^^^^^^^^^^^^^

I suppose this should be @new_domain, right?

>   					 iommu_group_do_attach_device);
> -	if (ret != 0)
> -		WARN_ON(1);
> +	if (ret)
> +		return ret;
> +	group->domain = new_domain;
> +	return 0;
> +}

Best regards,
baolu
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04 11:48 ` Baolu Lu
@ 2022-05-04 11:53   ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-05-04 11:53 UTC (permalink / raw)
  To: Baolu Lu; +Cc: Kevin Tian, Robin Murphy, Qian Cai, iommu, Will Deacon

On Wed, May 04, 2022 at 07:48:58PM +0800, Baolu Lu wrote:

> > +	/*
> > +	 * New drivers do not implement detach_dev, so changing the domain is
> > +	 * done by calling attach on the new domain. Drivers should implement
> > +	 * this so that DMA is always translated by either the new, old, or a
> > +	 * blocking domain. DMA should never become untranslated.
> > +	 *
> > +	 * Note that this is called in error unwind paths, attaching to a
> > +	 * domain that has already been attached cannot fail.
> > +	 */
> >   	ret = __iommu_group_for_each_dev(group, group->default_domain,
> 						^^^^^^^^^^^^^^^^^^^^^^
> 
> I suppose this should be @new_domain, right?

Yes, thank you

Jason
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04  8:22 ` Nicolin Chen via iommu
@ 2022-05-04 11:57   ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-05-04 11:57 UTC (permalink / raw)
  To: Nicolin Chen; +Cc: Kevin Tian, Will Deacon, Qian Cai, iommu, Robin Murphy

On Wed, May 04, 2022 at 01:22:00AM -0700, Nicolin Chen wrote:

> I am able to repro the issue on ARM64 and give this a quick try.
> But the patch seems to need to include the following change too.
> 
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 94d99768023c..9bb108d01baa 100644
> +++ b/drivers/iommu/iommu.c
> @@ -2040,7 +2040,8 @@ static int __iommu_attach_group(struct iommu_domain *domain,
>  {
>  	int ret;
>  
> -	if (group->domain && group->domain != group->default_domain)
> +	if (group->domain && group->domain != group->default_domain &&
> +	    group->domain != group->blocking_domain)
>  		return -EBUSY;
>  
>  	ret = __iommu_group_for_each_dev(group, domain,

Make sense, thanks

> >  	/*
> > -	 * If the group has been claimed already, do not re-attach the default
> > -	 * domain.
> > +	 * A NULL domain means to call the detach_dev() op. New drivers should
> > +	 * use a IOMMU_DOMAIN_IDENTITY domain instead of a NULL default_domain
> 
> an IOMMU_DOMAIN_IDENTITY?

Done

Jason
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04  0:11 [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain Jason Gunthorpe via iommu
  2022-05-04  8:22 ` Nicolin Chen via iommu
  2022-05-04 11:48 ` Baolu Lu
@ 2022-05-04 14:35 ` Baolu Lu
  2022-05-04 14:38   ` Jason Gunthorpe via iommu
  2022-05-04 14:42 ` Robin Murphy
  3 siblings, 1 reply; 13+ messages in thread
From: Baolu Lu @ 2022-05-04 14:35 UTC (permalink / raw)
  To: Jason Gunthorpe, iommu, Nicolin Chen, Will Deacon, Robin Murphy
  Cc: Kevin Tian, Qian Cai

Hi Jason,

On 2022/5/4 08:11, Jason Gunthorpe wrote:
> Once the group enters 'owned' mode it can never be assigned back to the
> default_domain or to a NULL domain. It must always be actively assigned to
> a current domain. If the caller hasn't provided a domain then the core
> must provide an explicit DMA blocking domain that has no DMA map.
> 
> Lazily create a group-global blocking DMA domain when
> iommu_group_claim_dma_owner is first called and immediately assign the
> group to it. This ensures that DMA is immediately fully isolated on all
> IOMMU drivers.
> 
> If the user attaches/detaches while owned then detach will set the group
> back to the blocking domain.
> 
> Slightly reorganize the call chains so that
> __iommu_group_attach_core_domain() is the function that removes any caller
> configured domain and sets the domains back a core owned domain with an
> appropriate lifetime.
> 
> __iommu_group_attach_domain() is the worker function that can change the
> domain assigned to a group to any target domain, including NULL.
> 
> Add comments clarifying how the NULL vs detach_dev vs default_domain works
> based on Robin's remarks.
> 
> This fixes an oops with VFIO and SMMUv3 because VFIO will call
> iommu_detach_group() and then immediately iommu_domain_free(), but
> SMMUv3 has no way to know that the domain it is holding a pointer to
> has been freed. Now the iommu_detach_group() will assign the blocking
> domain and SMMUv3 will no longer hold a stale domain reference.
> 
> Fixes: 1ea2a07a532b ("iommu: Add DMA ownership management interfaces")
> Reported-by: Qian Cai <quic_qiancai@quicinc.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> ---
>   drivers/iommu/iommu.c | 112 +++++++++++++++++++++++++++++++-----------
>   1 file changed, 82 insertions(+), 30 deletions(-)
> 
> This is based on Robins draft here:
> 
> https://lore.kernel.org/linux-iommu/18831161-473f-e04f-4a81-1c7062ad192d@arm.com/
> 
> With some rework. I re-organized the call chains instead of introducing
> iommu_group_user_attached(), fixed a recursive locking for
> iommu_group_get_purgatory(), and made a proper commit message.
> 
> Still only compile tested, so RFCish.
> 
> Nicolin/Lu? What do you think, can you check it?

Thank you for the patch.

With below additional changes, this patch works on my Intel test
machine.

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 513da82f2ed1..7c415e9b6906 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2063,7 +2063,8 @@ static int __iommu_attach_group(struct 
iommu_domain *domain,
  {
         int ret;

-       if (group->domain && group->domain != group->default_domain)
+       if (group->domain && group->domain != group->default_domain &&
+           group->domain != group->blocking_domain)
                 return -EBUSY;

         ret = __iommu_group_for_each_dev(group, domain,
@@ -2125,7 +2126,7 @@ static int __iommu_group_attach_domain(struct 
iommu_group *group,
          * Note that this is called in error unwind paths, attaching to a
          * domain that has already been attached cannot fail.
          */
-       ret = __iommu_group_for_each_dev(group, group->default_domain,
+       ret = __iommu_group_for_each_dev(group, new_domain,
                                          iommu_group_do_attach_device);
         if (ret)
                 return ret;
@@ -3180,7 +3181,9 @@ int iommu_group_claim_dma_owner(struct iommu_group 
*group, void *owner)
                 ret = -EPERM;
                 goto unlock_out;
         } else {
-               if (group->domain && group->domain != 
group->default_domain) {
+               if (group->domain &&
+                   group->domain != group->default_domain &&
+                   group->domain != group->blocking_domain) {
                         ret = -EBUSY;
                         goto unlock_out;

Best regards,
baolu
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04 14:35 ` Baolu Lu
@ 2022-05-04 14:38   ` Jason Gunthorpe via iommu
  2022-05-04 14:55     ` Baolu Lu
  0 siblings, 1 reply; 13+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-05-04 14:38 UTC (permalink / raw)
  To: Baolu Lu; +Cc: Kevin Tian, Robin Murphy, Qian Cai, iommu, Will Deacon

On Wed, May 04, 2022 at 10:35:12PM +0800, Baolu Lu wrote:

> With below additional changes, this patch works on my Intel test
> machine.

Thanks!
 
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 513da82f2ed1..7c415e9b6906 100644
> +++ b/drivers/iommu/iommu.c
> @@ -2063,7 +2063,8 @@ static int __iommu_attach_group(struct iommu_domain
> *domain,
>  {
>         int ret;
> 
> -       if (group->domain && group->domain != group->default_domain)
> +       if (group->domain && group->domain != group->default_domain &&
> +           group->domain != group->blocking_domain)
>                 return -EBUSY;
> 
>         ret = __iommu_group_for_each_dev(group, domain,
> @@ -2125,7 +2126,7 @@ static int __iommu_group_attach_domain(struct
> iommu_group *group,
>          * Note that this is called in error unwind paths, attaching to a
>          * domain that has already been attached cannot fail.
>          */
> -       ret = __iommu_group_for_each_dev(group, group->default_domain,
> +       ret = __iommu_group_for_each_dev(group, new_domain,
>                                          iommu_group_do_attach_device);
>         if (ret)
>                 return ret;

Done

> @@ -3180,7 +3181,9 @@ int iommu_group_claim_dma_owner(struct iommu_group
> *group, void *owner)
>                 ret = -EPERM;
>                 goto unlock_out;
>         } else {
> -               if (group->domain && group->domain != group->default_domain)
> {
> +               if (group->domain &&
> +                   group->domain != group->default_domain &&
> +                   group->domain != group->blocking_domain) {

Why do we need this hunk? This is just trying to check if there is
some conflict with some other domain attach, group->domain can never
be blocking_domain here.

Jason
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04  0:11 [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain Jason Gunthorpe via iommu
                   ` (2 preceding siblings ...)
  2022-05-04 14:35 ` Baolu Lu
@ 2022-05-04 14:42 ` Robin Murphy
  2022-05-04 14:54   ` Jason Gunthorpe via iommu
  3 siblings, 1 reply; 13+ messages in thread
From: Robin Murphy @ 2022-05-04 14:42 UTC (permalink / raw)
  To: Jason Gunthorpe, iommu, Nicolin Chen, Will Deacon; +Cc: Kevin Tian, Qian Cai

On 2022-05-04 01:11, Jason Gunthorpe wrote:
> Once the group enters 'owned' mode it can never be assigned back to the
> default_domain or to a NULL domain. It must always be actively assigned to
> a current domain. If the caller hasn't provided a domain then the core
> must provide an explicit DMA blocking domain that has no DMA map.
> 
> Lazily create a group-global blocking DMA domain when
> iommu_group_claim_dma_owner is first called and immediately assign the
> group to it. This ensures that DMA is immediately fully isolated on all
> IOMMU drivers.
> 
> If the user attaches/detaches while owned then detach will set the group
> back to the blocking domain.
> 
> Slightly reorganize the call chains so that
> __iommu_group_attach_core_domain() is the function that removes any caller
> configured domain and sets the domains back a core owned domain with an
> appropriate lifetime.
> 
> __iommu_group_attach_domain() is the worker function that can change the
> domain assigned to a group to any target domain, including NULL.
> 
> Add comments clarifying how the NULL vs detach_dev vs default_domain works
> based on Robin's remarks.
> 
> This fixes an oops with VFIO and SMMUv3 because VFIO will call
> iommu_detach_group() and then immediately iommu_domain_free(), but
> SMMUv3 has no way to know that the domain it is holding a pointer to
> has been freed. Now the iommu_detach_group() will assign the blocking
> domain and SMMUv3 will no longer hold a stale domain reference.

Thanks for taking this on! I do like the overall structure and naming 
much more than my initial sketch :)

> Fixes: 1ea2a07a532b ("iommu: Add DMA ownership management interfaces")
> Reported-by: Qian Cai <quic_qiancai@quicinc.com>

Co-developed-by: Robin Murphy <robin.murphy@arm.com>

(so the sign-off chain makes sense - you deserve overall authorship here)

> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> ---
[...]
> @@ -2072,38 +2072,66 @@ static int iommu_group_do_detach_device(struct device *dev, void *data)
>   	return 0;
>   }
>   
> -static void __iommu_detach_group(struct iommu_domain *domain,
> -				 struct iommu_group *group)
> +static int __iommu_group_attach_domain(struct iommu_group *group,
> +				       struct iommu_domain *new_domain)
>   {
>   	int ret;
>   
> +	if (group->domain == new_domain)
> +		return 0;
> +
>   	/*
> -	 * If the group has been claimed already, do not re-attach the default
> -	 * domain.
> +	 * A NULL domain means to call the detach_dev() op. New drivers should
> +	 * use a IOMMU_DOMAIN_IDENTITY domain instead of a NULL default_domain

Nit: IOMMU_DOMAIN_DMA is the baseline of default domain support, 
passthrough is more of an optional extra.

> +	 * and detatch_dev().

Nit: detach_dev

Otherwise, modulo the other things already pointed out, this looks OK to me.

Cheers,
Robin.
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04 14:42 ` Robin Murphy
@ 2022-05-04 14:54   ` Jason Gunthorpe via iommu
  2022-05-04 15:29     ` Robin Murphy
  0 siblings, 1 reply; 13+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-05-04 14:54 UTC (permalink / raw)
  To: Robin Murphy; +Cc: Kevin Tian, Qian Cai, iommu, Will Deacon

On Wed, May 04, 2022 at 03:42:09PM +0100, Robin Murphy wrote:

> > This fixes an oops with VFIO and SMMUv3 because VFIO will call
> > iommu_detach_group() and then immediately iommu_domain_free(), but
> > SMMUv3 has no way to know that the domain it is holding a pointer to
> > has been freed. Now the iommu_detach_group() will assign the blocking
> > domain and SMMUv3 will no longer hold a stale domain reference.
> 
> Thanks for taking this on! I do like the overall structure and naming much
> more than my initial sketch :)

Thanks, no problem!
 
> >   	/*
> > -	 * If the group has been claimed already, do not re-attach the default
> > -	 * domain.
> > +	 * A NULL domain means to call the detach_dev() op. New drivers should
> > +	 * use a IOMMU_DOMAIN_IDENTITY domain instead of a NULL default_domain
> 
> Nit: IOMMU_DOMAIN_DMA is the baseline of default domain support, passthrough
> is more of an optional extra.

Can you elaborate on this a bit more for the comment, I'm not sure I
understand all the historical stuff here.

Here we are looking at a case where group->domain becomes NULL - what
does this mean in the historical world? ie what should the iommu
driver do when detach_dev is called?

I had guessed it was remove all translation - ie IOMMU_DOMAIN_IDENTITY?

> > +	 * and detatch_dev().
> 
> Nit: detach_dev
> 
> Otherwise, modulo the other things already pointed out, this looks OK to me.

Done, thanks

Jason 
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04 14:38   ` Jason Gunthorpe via iommu
@ 2022-05-04 14:55     ` Baolu Lu
  2022-05-04 15:00       ` Jason Gunthorpe via iommu
  0 siblings, 1 reply; 13+ messages in thread
From: Baolu Lu @ 2022-05-04 14:55 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: Kevin Tian, Robin Murphy, Qian Cai, iommu, Will Deacon

On 2022/5/4 22:38, Jason Gunthorpe wrote:
>> @@ -3180,7 +3181,9 @@ int iommu_group_claim_dma_owner(struct iommu_group
>> *group, void *owner)
>>                  ret = -EPERM;
>>                  goto unlock_out;
>>          } else {
>> -               if (group->domain && group->domain != group->default_domain)
>> {
>> +               if (group->domain &&
>> +                   group->domain != group->default_domain &&
>> +                   group->domain != group->blocking_domain) {
> Why do we need this hunk? This is just trying to check if there is
> some conflict with some other domain attach, group->domain can never
> be blocking_domain here.
This is *not* needed. Also verified with real hardware.

Sorry for the noise.

Best regards,
baolu
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04 14:55     ` Baolu Lu
@ 2022-05-04 15:00       ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-05-04 15:00 UTC (permalink / raw)
  To: Baolu Lu; +Cc: Kevin Tian, Robin Murphy, Qian Cai, iommu, Will Deacon

On Wed, May 04, 2022 at 10:55:00PM +0800, Baolu Lu wrote:
> On 2022/5/4 22:38, Jason Gunthorpe wrote:
> > > @@ -3180,7 +3181,9 @@ int iommu_group_claim_dma_owner(struct iommu_group
> > > *group, void *owner)
> > >                  ret = -EPERM;
> > >                  goto unlock_out;
> > >          } else {
> > > -               if (group->domain && group->domain != group->default_domain)
> > > {
> > > +               if (group->domain &&
> > > +                   group->domain != group->default_domain &&
> > > +                   group->domain != group->blocking_domain) {
> > Why do we need this hunk? This is just trying to check if there is
> > some conflict with some other domain attach, group->domain can never
> > be blocking_domain here.
> This is *not* needed. Also verified with real hardware.
> 
> Sorry for the noise.

Okay, great, I'll add your tested-by, thanks

Jason
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04 14:54   ` Jason Gunthorpe via iommu
@ 2022-05-04 15:29     ` Robin Murphy
  2022-05-04 18:20       ` Jason Gunthorpe via iommu
  0 siblings, 1 reply; 13+ messages in thread
From: Robin Murphy @ 2022-05-04 15:29 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: Kevin Tian, Qian Cai, iommu, Will Deacon

On 2022-05-04 15:54, Jason Gunthorpe wrote:
> On Wed, May 04, 2022 at 03:42:09PM +0100, Robin Murphy wrote:
> 
>>> This fixes an oops with VFIO and SMMUv3 because VFIO will call
>>> iommu_detach_group() and then immediately iommu_domain_free(), but
>>> SMMUv3 has no way to know that the domain it is holding a pointer to
>>> has been freed. Now the iommu_detach_group() will assign the blocking
>>> domain and SMMUv3 will no longer hold a stale domain reference.
>>
>> Thanks for taking this on! I do like the overall structure and naming much
>> more than my initial sketch :)
> 
> Thanks, no problem!
>   
>>>    	/*
>>> -	 * If the group has been claimed already, do not re-attach the default
>>> -	 * domain.
>>> +	 * A NULL domain means to call the detach_dev() op. New drivers should
>>> +	 * use a IOMMU_DOMAIN_IDENTITY domain instead of a NULL default_domain
>>
>> Nit: IOMMU_DOMAIN_DMA is the baseline of default domain support, passthrough
>> is more of an optional extra.
> 
> Can you elaborate on this a bit more for the comment, I'm not sure I
> understand all the historical stuff here.

Well, the comment could effectively just be "New drivers should support 
default domains."

What supporting default domains means in practice is two things: that 
.attach_dev handles moving directly between domains without .detach_dev 
being called, and that .domain_alloc supports at least IOMMU_DOMAIN_DMA 
- other unsupported default domain types can fall back to that, but not 
vice versa, see iommu_group_alloc_default_domain().

> Here we are looking at a case where group->domain becomes NULL - what
> does this mean in the historical world? ie what should the iommu
> driver do when detach_dev is called?
> 
> I had guessed it was remove all translation - ie IOMMU_DOMAIN_IDENTITY?

Historically, whatever a NULL domain means is mostly between the IOMMU 
driver and the platform DMA ops - I honestly have no idea what the likes 
of s390 and fsl-pamu do, for example. For SMMUv3 it was always configurable.

Cheers,
Robin.
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain
  2022-05-04 15:29     ` Robin Murphy
@ 2022-05-04 18:20       ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-05-04 18:20 UTC (permalink / raw)
  To: Robin Murphy; +Cc: Kevin Tian, Qian Cai, iommu, Will Deacon

On Wed, May 04, 2022 at 04:29:24PM +0100, Robin Murphy wrote:
> On 2022-05-04 15:54, Jason Gunthorpe wrote:
> > On Wed, May 04, 2022 at 03:42:09PM +0100, Robin Murphy wrote:
> > 
> > > > This fixes an oops with VFIO and SMMUv3 because VFIO will call
> > > > iommu_detach_group() and then immediately iommu_domain_free(), but
> > > > SMMUv3 has no way to know that the domain it is holding a pointer to
> > > > has been freed. Now the iommu_detach_group() will assign the blocking
> > > > domain and SMMUv3 will no longer hold a stale domain reference.
> > > 
> > > Thanks for taking this on! I do like the overall structure and naming much
> > > more than my initial sketch :)
> > 
> > Thanks, no problem!
> > > >    	/*
> > > > -	 * If the group has been claimed already, do not re-attach the default
> > > > -	 * domain.
> > > > +	 * A NULL domain means to call the detach_dev() op. New drivers should
> > > > +	 * use a IOMMU_DOMAIN_IDENTITY domain instead of a NULL default_domain
> > > 
> > > Nit: IOMMU_DOMAIN_DMA is the baseline of default domain support, passthrough
> > > is more of an optional extra.
> > 
> > Can you elaborate on this a bit more for the comment, I'm not sure I
> > understand all the historical stuff here.
> 
> Well, the comment could effectively just be "New drivers should support
> default domains."

I made it this:

	/*
	 * New drivers should support default domains and so the detach_dev() op
	 * will never be called. Otheriwse the NULL domain indicates the
	 * translation for the group should be set so it will work with the
	 * platform DMA ops.
	 */

It also seems clear to me we should delete a bunch of detach_dev ops
from drivers?

I naively see that these drivers have the word IOMMU_DOMAIN_DMA in
them and also define detach_dev:
 amd iommu
 apple-dart
 qcom_iommu
 exynos-iommu
 intel iommu
 ipmmu-vmsa
 mtk_iommu
 rockchip-iommu
 sprd-iommu
 sun50i-iommu

These ones have IOMMU_DOMAIN_DMA but don't define detach_dev:
 arm-smmuv3
 arm-smmu
 virtio-iommu

And I suppose these are the 'old' drivers:
 fsl_pamu
 omap-iommu
 tegra-gart
 tegra-smmu

I can get a patch for this as well, I think it will be clarifying to
remove this cruft.

Thanks
Jason
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-05-04 18:20 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-04  0:11 [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain Jason Gunthorpe via iommu
2022-05-04  8:22 ` Nicolin Chen via iommu
2022-05-04 11:57   ` Jason Gunthorpe via iommu
2022-05-04 11:48 ` Baolu Lu
2022-05-04 11:53   ` Jason Gunthorpe via iommu
2022-05-04 14:35 ` Baolu Lu
2022-05-04 14:38   ` Jason Gunthorpe via iommu
2022-05-04 14:55     ` Baolu Lu
2022-05-04 15:00       ` Jason Gunthorpe via iommu
2022-05-04 14:42 ` Robin Murphy
2022-05-04 14:54   ` Jason Gunthorpe via iommu
2022-05-04 15:29     ` Robin Murphy
2022-05-04 18:20       ` Jason Gunthorpe via iommu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.