Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Jason Gunthorpe via iommu
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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Robin Murphy

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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Jason Gunthorpe via iommu
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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Baolu Lu

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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Jason Gunthorpe via iommu
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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Robin Murphy

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 


Co-developed-by: Robin Murphy 

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


Signed-off-by: Robin Murphy 
Signed-off-by: Jason Gunthorpe 
---

[...]

@@ -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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Jason Gunthorpe via iommu
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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Baolu Lu

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 
Signed-off-by: Robin Murphy 
Signed-off-by: Jason Gunthorpe 
---
  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-1c7062ad1...@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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Jason Gunthorpe via iommu
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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Jason Gunthorpe via iommu
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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Baolu Lu

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


Re: [PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-04 Thread Nicolin Chen via iommu
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-1c7062ad1...@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


[PATCH] iommu: iommu_group_claim_dma_owner() must always assign a domain

2022-05-03 Thread Jason Gunthorpe via iommu
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 
Signed-off-by: Robin Murphy 
Signed-off-by: Jason Gunthorpe 
---
 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-1c7062ad1...@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(>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(>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);