[RFC PATCH v2 01/32] iommufd: Allow HWPTs to have a NULL IOAS
From: Samiullah Khawaja
Date: Tue Dec 02 2025 - 18:03:22 EST
From: YiFei Zhu <zhuyifei@xxxxxxxxxx>
Normally HWPTs are created with a parent IOAS to allow the mappings
to be modified. For liveupdate we want an immutable HWPT upon restore,
so no IOAS is needed. This patch prepares iommufd so it would not
crash on a NULL hwpt_paging->ioas.
Signed-off-by: YiFei Zhu <zhuyifei@xxxxxxxxxx>
---
drivers/iommu/iommufd/device.c | 11 ++++++++---
drivers/iommu/iommufd/hw_pagetable.c | 15 +++++++++++++--
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 4c842368289f..ba4d9c3cfa8b 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -418,6 +418,7 @@ iommufd_device_attach_reserved_iova(struct iommufd_device *idev,
lockdep_assert_held(&igroup->lock);
+ /* unreachable if !hwpt_paging->ioas */
rc = iopt_table_enforce_dev_resv_regions(&hwpt_paging->ioas->iopt,
idev->dev,
&igroup->sw_msi_start);
@@ -603,7 +604,7 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
struct iommufd_device *idev, ioasid_t pasid)
{
struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);
- bool attach_resv = hwpt_paging && pasid == IOMMU_NO_PASID;
+ bool attach_resv = hwpt_paging && pasid == IOMMU_NO_PASID && hwpt_paging->ioas;
struct iommufd_group *igroup = idev->igroup;
struct iommufd_hw_pagetable *old_hwpt;
struct iommufd_attach *attach;
@@ -707,7 +708,7 @@ iommufd_hw_pagetable_detach(struct iommufd_device *idev, ioasid_t pasid)
xa_erase(&igroup->pasid_attach, pasid);
kfree(attach);
}
- if (hwpt_paging && pasid == IOMMU_NO_PASID)
+ if (hwpt_paging && pasid == IOMMU_NO_PASID && hwpt_paging->ioas)
iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, idev->dev);
mutex_unlock(&igroup->lock);
@@ -739,6 +740,9 @@ iommufd_group_remove_reserved_iova(struct iommufd_group *igroup,
lockdep_assert_held(&igroup->lock);
+ if (!hwpt_paging->ioas)
+ return;
+
attach = xa_load(&igroup->pasid_attach, IOMMU_NO_PASID);
xa_for_each(&attach->device_array, index, cur)
iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, cur->dev);
@@ -756,6 +760,7 @@ iommufd_group_do_replace_reserved_iova(struct iommufd_group *igroup,
lockdep_assert_held(&igroup->lock);
+ /* unreachable if !hwpt_paging->ioas */
attach = xa_load(&igroup->pasid_attach, IOMMU_NO_PASID);
old_hwpt_paging = find_hwpt_paging(attach->hwpt);
if (!old_hwpt_paging || hwpt_paging->ioas != old_hwpt_paging->ioas) {
@@ -782,7 +787,7 @@ iommufd_device_do_replace(struct iommufd_device *idev, ioasid_t pasid,
struct iommufd_hw_pagetable *hwpt)
{
struct iommufd_hwpt_paging *hwpt_paging = find_hwpt_paging(hwpt);
- bool attach_resv = hwpt_paging && pasid == IOMMU_NO_PASID;
+ bool attach_resv = hwpt_paging && pasid == IOMMU_NO_PASID && hwpt_paging->ioas;
struct iommufd_hwpt_paging *old_hwpt_paging;
struct iommufd_group *igroup = idev->igroup;
struct iommufd_hw_pagetable *old_hwpt;
diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
index fe789c2dc0c9..78d2130e0061 100644
--- a/drivers/iommu/iommufd/hw_pagetable.c
+++ b/drivers/iommu/iommufd/hw_pagetable.c
@@ -23,6 +23,7 @@ void iommufd_hwpt_paging_destroy(struct iommufd_object *obj)
container_of(obj, struct iommufd_hwpt_paging, common.obj);
if (!list_empty(&hwpt_paging->hwpt_item)) {
+ /* unreachable if !hwpt_paging->ioas */
mutex_lock(&hwpt_paging->ioas->mutex);
list_del(&hwpt_paging->hwpt_item);
mutex_unlock(&hwpt_paging->ioas->mutex);
@@ -32,7 +33,9 @@ void iommufd_hwpt_paging_destroy(struct iommufd_object *obj)
}
__iommufd_hwpt_destroy(&hwpt_paging->common);
- refcount_dec(&hwpt_paging->ioas->obj.users);
+
+ if (hwpt_paging->ioas)
+ refcount_dec(&hwpt_paging->ioas->obj.users);
}
void iommufd_hwpt_paging_abort(struct iommufd_object *obj)
@@ -41,9 +44,11 @@ void iommufd_hwpt_paging_abort(struct iommufd_object *obj)
container_of(obj, struct iommufd_hwpt_paging, common.obj);
/* The ioas->mutex must be held until finalize is called. */
- lockdep_assert_held(&hwpt_paging->ioas->mutex);
+ if (hwpt_paging->ioas)
+ lockdep_assert_held(&hwpt_paging->ioas->mutex);
if (!list_empty(&hwpt_paging->hwpt_item)) {
+ /* unreachable if !hwpt_paging->ioas */
list_del_init(&hwpt_paging->hwpt_item);
iopt_table_remove_domain(&hwpt_paging->ioas->iopt,
hwpt_paging->common.domain);
@@ -457,6 +462,9 @@ int iommufd_hwpt_set_dirty_tracking(struct iommufd_ucmd *ucmd)
return PTR_ERR(hwpt_paging);
ioas = hwpt_paging->ioas;
+ if (!ioas)
+ return -EINVAL;
+
enable = cmd->flags & IOMMU_HWPT_DIRTY_TRACKING_ENABLE;
rc = iopt_set_dirty_tracking(&ioas->iopt, hwpt_paging->common.domain,
@@ -482,6 +490,9 @@ int iommufd_hwpt_get_dirty_bitmap(struct iommufd_ucmd *ucmd)
return PTR_ERR(hwpt_paging);
ioas = hwpt_paging->ioas;
+ if (!ioas)
+ return -EINVAL;
+
rc = iopt_read_and_clear_dirty_data(
&ioas->iopt, hwpt_paging->common.domain, cmd->flags, cmd);
--
2.52.0.158.g65b55ccf14-goog