* [PATCH v3 1/4] iommu: Make @handle mandatory in iommu_{attach|replace}_group_handle()
2025-02-26 1:18 [PATCH v3 0/4] Misc iommu_attach_handle enhancements in iommu core Yi Liu
@ 2025-02-26 1:18 ` Yi Liu
2025-02-26 1:18 ` [PATCH v3 2/4] iommu: Drop iommu_group_replace_domain() Yi Liu
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Yi Liu @ 2025-02-26 1:18 UTC (permalink / raw)
To: joro, jgg
Cc: kevin.tian, baolu.lu, yi.l.liu, iommu, robin.murphy, nicolinc,
will
Caller of the two APIs always provide a valid handle, make @handle as
mandatory parameter. Take this chance incoporate the handle->domain
set under the protection of group->mutex in iommu_attach_group_handle().
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
---
drivers/iommu/iommu.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 870c3cdbd0f6..715bdb8af31b 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3511,10 +3511,11 @@ int iommu_attach_group_handle(struct iommu_domain *domain,
{
int ret;
- if (handle)
- handle->domain = domain;
+ if (!handle)
+ return -EINVAL;
mutex_lock(&group->mutex);
+ handle->domain = domain;
ret = xa_insert(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL);
if (ret)
goto err_unlock;
@@ -3568,16 +3569,14 @@ int iommu_replace_group_handle(struct iommu_group *group,
void *curr;
int ret;
- if (!new_domain)
+ if (!new_domain || !handle)
return -EINVAL;
mutex_lock(&group->mutex);
- if (handle) {
- ret = xa_reserve(&group->pasid_array, IOMMU_NO_PASID, GFP_KERNEL);
- if (ret)
- goto err_unlock;
- handle->domain = new_domain;
- }
+ handle->domain = new_domain;
+ ret = xa_reserve(&group->pasid_array, IOMMU_NO_PASID, GFP_KERNEL);
+ if (ret)
+ goto err_unlock;
ret = __iommu_group_set_domain(group, new_domain);
if (ret)
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v3 2/4] iommu: Drop iommu_group_replace_domain()
2025-02-26 1:18 [PATCH v3 0/4] Misc iommu_attach_handle enhancements in iommu core Yi Liu
2025-02-26 1:18 ` [PATCH v3 1/4] iommu: Make @handle mandatory in iommu_{attach|replace}_group_handle() Yi Liu
@ 2025-02-26 1:18 ` Yi Liu
2025-02-26 5:50 ` Baolu Lu
2025-02-26 1:18 ` [PATCH v3 3/4] iommu: Store either domain or handle in group->pasid_array Yi Liu
` (2 subsequent siblings)
4 siblings, 1 reply; 8+ messages in thread
From: Yi Liu @ 2025-02-26 1:18 UTC (permalink / raw)
To: joro, jgg
Cc: kevin.tian, baolu.lu, yi.l.liu, iommu, robin.murphy, nicolinc,
will
iommufd does not use it now, so drop it.
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
---
drivers/iommu/iommu-priv.h | 3 ---
drivers/iommu/iommu.c | 35 ++++++-----------------------------
2 files changed, 6 insertions(+), 32 deletions(-)
diff --git a/drivers/iommu/iommu-priv.h b/drivers/iommu/iommu-priv.h
index de5b54eaa8bf..b4508423e13b 100644
--- a/drivers/iommu/iommu-priv.h
+++ b/drivers/iommu/iommu-priv.h
@@ -24,9 +24,6 @@ static inline const struct iommu_ops *iommu_fwspec_ops(struct iommu_fwspec *fwsp
return iommu_ops_from_fwnode(fwspec ? fwspec->iommu_fwnode : NULL);
}
-int iommu_group_replace_domain(struct iommu_group *group,
- struct iommu_domain *new_domain);
-
int iommu_device_register_bus(struct iommu_device *iommu,
const struct iommu_ops *ops,
const struct bus_type *bus,
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 715bdb8af31b..bee3ebc91ae4 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2187,32 +2187,6 @@ int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group)
}
EXPORT_SYMBOL_GPL(iommu_attach_group);
-/**
- * iommu_group_replace_domain - replace the domain that a group is attached to
- * @group: IOMMU group that will be attached to the new domain
- * @new_domain: new IOMMU domain to replace with
- *
- * This API allows the group to switch domains without being forced to go to
- * the blocking domain in-between.
- *
- * If the currently attached domain is a core domain (e.g. a default_domain),
- * it will act just like the iommu_attach_group().
- */
-int iommu_group_replace_domain(struct iommu_group *group,
- struct iommu_domain *new_domain)
-{
- int ret;
-
- if (!new_domain)
- return -EINVAL;
-
- mutex_lock(&group->mutex);
- ret = __iommu_group_set_domain(group, new_domain);
- mutex_unlock(&group->mutex);
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(iommu_group_replace_domain, "IOMMUFD_INTERNAL");
-
static int __iommu_device_set_domain(struct iommu_group *group,
struct device *dev,
struct iommu_domain *new_domain,
@@ -3558,9 +3532,12 @@ EXPORT_SYMBOL_NS_GPL(iommu_detach_group_handle, "IOMMUFD_INTERNAL");
* @new_domain: new IOMMU domain to replace with
* @handle: attach handle
*
- * This is a variant of iommu_group_replace_domain(). It allows the caller to
- * provide an attach handle for the new domain and use it when the domain is
- * attached.
+ * This API allows the group to switch domains without being forced to go to
+ * the blocking domain in-between. It allows the caller to provide an attach
+ * handle for the new domain and use it when the domain is attached.
+ *
+ * If the currently attached domain is a core domain (e.g. a default_domain),
+ * it will act just like the iommu_attach_group_handle().
*/
int iommu_replace_group_handle(struct iommu_group *group,
struct iommu_domain *new_domain,
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v3 3/4] iommu: Store either domain or handle in group->pasid_array
2025-02-26 1:18 [PATCH v3 0/4] Misc iommu_attach_handle enhancements in iommu core Yi Liu
2025-02-26 1:18 ` [PATCH v3 1/4] iommu: Make @handle mandatory in iommu_{attach|replace}_group_handle() Yi Liu
2025-02-26 1:18 ` [PATCH v3 2/4] iommu: Drop iommu_group_replace_domain() Yi Liu
@ 2025-02-26 1:18 ` Yi Liu
2025-02-26 5:53 ` Baolu Lu
2025-02-26 1:18 ` [PATCH v3 4/4] iommu: Swap the order of setting group->pasid_array and calling attach op of iommu drivers Yi Liu
2025-02-28 14:30 ` [PATCH v3 0/4] Misc iommu_attach_handle enhancements in iommu core Jason Gunthorpe
4 siblings, 1 reply; 8+ messages in thread
From: Yi Liu @ 2025-02-26 1:18 UTC (permalink / raw)
To: joro, jgg
Cc: kevin.tian, baolu.lu, yi.l.liu, iommu, robin.murphy, nicolinc,
will
iommu_attach_device_pasid() only stores handle to group->pasid_array
when there is a valid handle input. However, it makes the
iommu_attach_device_pasid() unable to detect if the pasid has been
attached or not previously.
To be complete, let the iommu_attach_device_pasid() store the domain
to group->pasid_array if no valid handle. The other users of the
group->pasid_array should be updated to be consistent. e.g. the
iommu_attach_group_handle() and iommu_replace_group_handle().
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
---
drivers/iommu/iommu.c | 43 +++++++++++++++++++++++++++++++------------
1 file changed, 31 insertions(+), 12 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index bee3ebc91ae4..f9884a5cdeca 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -45,6 +45,9 @@ static unsigned int iommu_def_domain_type __read_mostly;
static bool iommu_dma_strict __read_mostly = IS_ENABLED(CONFIG_IOMMU_DEFAULT_DMA_STRICT);
static u32 iommu_cmd_line __read_mostly;
+/* Tags used with xa_tag_pointer() in group->pasid_array */
+enum { IOMMU_PASID_ARRAY_DOMAIN = 0, IOMMU_PASID_ARRAY_HANDLE = 1 };
+
struct iommu_group {
struct kobject kobj;
struct kobject *devices_kobj;
@@ -2147,6 +2150,17 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev)
return dev->iommu_group->default_domain;
}
+static void *iommu_make_pasid_array_entry(struct iommu_domain *domain,
+ struct iommu_attach_handle *handle)
+{
+ if (handle) {
+ handle->domain = domain;
+ return xa_tag_pointer(handle, IOMMU_PASID_ARRAY_HANDLE);
+ }
+
+ return xa_tag_pointer(domain, IOMMU_PASID_ARRAY_DOMAIN);
+}
+
static int __iommu_attach_group(struct iommu_domain *domain,
struct iommu_group *group)
{
@@ -3348,6 +3362,7 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
struct iommu_group *group = dev->iommu_group;
struct group_device *device;
const struct iommu_ops *ops;
+ void *entry;
int ret;
if (!group)
@@ -3371,10 +3386,9 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
}
}
- if (handle)
- handle->domain = domain;
+ entry = iommu_make_pasid_array_entry(domain, handle);
- ret = xa_insert(&group->pasid_array, pasid, handle, GFP_KERNEL);
+ ret = xa_insert(&group->pasid_array, pasid, entry, GFP_KERNEL);
if (ret)
goto out_unlock;
@@ -3454,13 +3468,17 @@ struct iommu_attach_handle *
iommu_attach_handle_get(struct iommu_group *group, ioasid_t pasid, unsigned int type)
{
struct iommu_attach_handle *handle;
+ void *entry;
xa_lock(&group->pasid_array);
- handle = xa_load(&group->pasid_array, pasid);
- if (!handle)
+ entry = xa_load(&group->pasid_array, pasid);
+ if (!entry || xa_pointer_tag(entry) != IOMMU_PASID_ARRAY_HANDLE) {
handle = ERR_PTR(-ENOENT);
- else if (type && handle->domain->type != type)
- handle = ERR_PTR(-EBUSY);
+ } else {
+ handle = xa_untag_pointer(entry);
+ if (type && handle->domain->type != type)
+ handle = ERR_PTR(-EBUSY);
+ }
xa_unlock(&group->pasid_array);
return handle;
@@ -3483,14 +3501,15 @@ int iommu_attach_group_handle(struct iommu_domain *domain,
struct iommu_group *group,
struct iommu_attach_handle *handle)
{
+ void *entry;
int ret;
if (!handle)
return -EINVAL;
mutex_lock(&group->mutex);
- handle->domain = domain;
- ret = xa_insert(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL);
+ entry = iommu_make_pasid_array_entry(domain, handle);
+ ret = xa_insert(&group->pasid_array, IOMMU_NO_PASID, entry, GFP_KERNEL);
if (ret)
goto err_unlock;
@@ -3543,14 +3562,14 @@ int iommu_replace_group_handle(struct iommu_group *group,
struct iommu_domain *new_domain,
struct iommu_attach_handle *handle)
{
- void *curr;
+ void *curr, *entry;
int ret;
if (!new_domain || !handle)
return -EINVAL;
mutex_lock(&group->mutex);
- handle->domain = new_domain;
+ entry = iommu_make_pasid_array_entry(new_domain, handle);
ret = xa_reserve(&group->pasid_array, IOMMU_NO_PASID, GFP_KERNEL);
if (ret)
goto err_unlock;
@@ -3559,7 +3578,7 @@ int iommu_replace_group_handle(struct iommu_group *group,
if (ret)
goto err_release;
- curr = xa_store(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL);
+ curr = xa_store(&group->pasid_array, IOMMU_NO_PASID, entry, GFP_KERNEL);
WARN_ON(xa_is_err(curr));
mutex_unlock(&group->mutex);
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v3 3/4] iommu: Store either domain or handle in group->pasid_array
2025-02-26 1:18 ` [PATCH v3 3/4] iommu: Store either domain or handle in group->pasid_array Yi Liu
@ 2025-02-26 5:53 ` Baolu Lu
0 siblings, 0 replies; 8+ messages in thread
From: Baolu Lu @ 2025-02-26 5:53 UTC (permalink / raw)
To: Yi Liu, joro, jgg; +Cc: kevin.tian, iommu, robin.murphy, nicolinc, will
On 2/26/25 09:18, Yi Liu wrote:
> iommu_attach_device_pasid() only stores handle to group->pasid_array
> when there is a valid handle input. However, it makes the
> iommu_attach_device_pasid() unable to detect if the pasid has been
> attached or not previously.
>
> To be complete, let the iommu_attach_device_pasid() store the domain
> to group->pasid_array if no valid handle. The other users of the
> group->pasid_array should be updated to be consistent. e.g. the
> iommu_attach_group_handle() and iommu_replace_group_handle().
>
> Suggested-by: Jason Gunthorpe<jgg@nvidia.com>
> Reviewed-by: Jason Gunthorpe<jgg@nvidia.com>
> Reviewed-by: Nicolin Chen<nicolinc@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>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 4/4] iommu: Swap the order of setting group->pasid_array and calling attach op of iommu drivers
2025-02-26 1:18 [PATCH v3 0/4] Misc iommu_attach_handle enhancements in iommu core Yi Liu
` (2 preceding siblings ...)
2025-02-26 1:18 ` [PATCH v3 3/4] iommu: Store either domain or handle in group->pasid_array Yi Liu
@ 2025-02-26 1:18 ` Yi Liu
2025-02-28 14:30 ` [PATCH v3 0/4] Misc iommu_attach_handle enhancements in iommu core Jason Gunthorpe
4 siblings, 0 replies; 8+ messages in thread
From: Yi Liu @ 2025-02-26 1:18 UTC (permalink / raw)
To: joro, jgg
Cc: kevin.tian, baolu.lu, yi.l.liu, iommu, robin.murphy, nicolinc,
will
The current implementation stores entry to the group->pasid_array before
the underlying iommu driver has successfully set the new domain. This can
lead to issues where PRIs are received on the new domain before the attach
operation is completed.
This patch swaps the order of operations to ensure that the domain is set
in the underlying iommu driver before updating the group->pasid_array.
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
---
drivers/iommu/iommu.c | 48 ++++++++++++++++++++++++++++++++-----------
1 file changed, 36 insertions(+), 12 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index f9884a5cdeca..73a3b20b2ef9 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3388,13 +3388,29 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
entry = iommu_make_pasid_array_entry(domain, handle);
- ret = xa_insert(&group->pasid_array, pasid, entry, GFP_KERNEL);
+ /*
+ * Entry present is a failure case. Use xa_insert() instead of
+ * xa_reserve().
+ */
+ ret = xa_insert(&group->pasid_array, pasid, XA_ZERO_ENTRY, GFP_KERNEL);
if (ret)
goto out_unlock;
ret = __iommu_set_group_pasid(domain, group, pasid);
- if (ret)
- xa_erase(&group->pasid_array, pasid);
+ if (ret) {
+ xa_release(&group->pasid_array, pasid);
+ goto out_unlock;
+ }
+
+ /*
+ * The xa_insert() above reserved the memory, and the group->mutex is
+ * held, this cannot fail. The new domain cannot be visible until the
+ * operation succeeds as we cannot tolerate PRIs becoming concurrently
+ * queued and then failing attach.
+ */
+ WARN_ON(xa_is_err(xa_store(&group->pasid_array,
+ pasid, entry, GFP_KERNEL)));
+
out_unlock:
mutex_unlock(&group->mutex);
return ret;
@@ -3509,19 +3525,27 @@ int iommu_attach_group_handle(struct iommu_domain *domain,
mutex_lock(&group->mutex);
entry = iommu_make_pasid_array_entry(domain, handle);
- ret = xa_insert(&group->pasid_array, IOMMU_NO_PASID, entry, GFP_KERNEL);
+ ret = xa_insert(&group->pasid_array,
+ IOMMU_NO_PASID, XA_ZERO_ENTRY, GFP_KERNEL);
if (ret)
- goto err_unlock;
+ goto out_unlock;
ret = __iommu_attach_group(domain, group);
- if (ret)
- goto err_erase;
- mutex_unlock(&group->mutex);
+ if (ret) {
+ xa_release(&group->pasid_array, IOMMU_NO_PASID);
+ goto out_unlock;
+ }
- return 0;
-err_erase:
- xa_erase(&group->pasid_array, IOMMU_NO_PASID);
-err_unlock:
+ /*
+ * The xa_insert() above reserved the memory, and the group->mutex is
+ * held, this cannot fail. The new domain cannot be visible until the
+ * operation succeeds as we cannot tolerate PRIs becoming concurrently
+ * queued and then failing attach.
+ */
+ WARN_ON(xa_is_err(xa_store(&group->pasid_array,
+ IOMMU_NO_PASID, entry, GFP_KERNEL)));
+
+out_unlock:
mutex_unlock(&group->mutex);
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v3 0/4] Misc iommu_attach_handle enhancements in iommu core
2025-02-26 1:18 [PATCH v3 0/4] Misc iommu_attach_handle enhancements in iommu core Yi Liu
` (3 preceding siblings ...)
2025-02-26 1:18 ` [PATCH v3 4/4] iommu: Swap the order of setting group->pasid_array and calling attach op of iommu drivers Yi Liu
@ 2025-02-28 14:30 ` Jason Gunthorpe
4 siblings, 0 replies; 8+ messages in thread
From: Jason Gunthorpe @ 2025-02-28 14:30 UTC (permalink / raw)
To: Yi Liu; +Cc: joro, kevin.tian, baolu.lu, iommu, robin.murphy, nicolinc, will
On Tue, Feb 25, 2025 at 05:18:45PM -0800, Yi Liu wrote:
>
> Yi Liu (4):
> iommu: Make @handle mandatory in iommu_{attach|replace}_group_handle()
> iommu: Drop iommu_group_replace_domain()
> iommu: Store either domain or handle in group->pasid_array
> iommu: Swap the order of setting group->pasid_array and calling attach
> op of iommu drivers
Applied to the shared branch
Thanks,
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread