[RFC PATCH v2 29/32] iommufd: Handle the iommufd can_finish properly

From: Samiullah Khawaja
Date: Tue Dec 02 2025 - 18:08:29 EST


IOMMUFD cannot finish until the restored domains have attachments. The
devices attached to the restored domains should be detached or
hotswapped to different iommu domains before the finish can happen.

Signed-off-by: Samiullah Khawaja <skhawaja@xxxxxxxxxx>
---
drivers/iommu/iommufd/iommufd_private.h | 4 +-
drivers/iommu/iommufd/liveupdate.c | 55 ++++++++++++++++++++-----
2 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index 0d358e5486d0..3ae324d7da14 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -383,6 +383,7 @@ struct iommufd_hwpt_paging {
bool nest_parent : 1;
#ifdef CONFIG_LIVEUPDATE
bool lu_preserved : 1;
+ bool lu_restored : 1;
u32 lu_token;
#endif
/* Head at iommufd_ioas::hwpt_list */
@@ -728,9 +729,6 @@ int iommufd_liveupdate_unregister_lufs(void);

int iommufd_hwpt_lu_set_preserved(struct iommufd_ucmd *ucmd);
int iommufd_hwpt_lu_restore(struct iommufd_ucmd *ucmd);
-
-/* TODO */
-#define iommu_domain_has_attachments(x) (false)
#else
static inline int iommufd_liveupdate_register_lufs(void)
{
diff --git a/drivers/iommu/iommufd/liveupdate.c b/drivers/iommu/iommufd/liveupdate.c
index 5b45071d7dd2..fe4c514811a4 100644
--- a/drivers/iommu/iommufd/liveupdate.c
+++ b/drivers/iommu/iommufd/liveupdate.c
@@ -265,16 +265,6 @@ static int iommufd_liveupdate_retrieve(struct liveupdate_file_op_args *args)
return rc;
}

-static bool iommufd_liveupdate_can_finish(struct liveupdate_file_op_args *args)
-{
- if (!args->retrieved || !args->file) {
- pr_warn("%s: fd not reclaimed\n", __func__);
- return false;
- }
-
- return true;
-}
-
int iommufd_hwpt_lu_restore(struct iommufd_ucmd *ucmd)
{
struct iommu_hwpt_lu_restore *cmd = ucmd->cmd;
@@ -319,6 +309,7 @@ int iommufd_hwpt_lu_restore(struct iommufd_ucmd *ucmd)
iommufd_object_finalize(ictx, &hwpt->common.obj);

hwpt_lu->reclaimed = true;
+ hwpt->lu_restored = true;
cmd->pt_id = hwpt->common.obj.id;
return 0;

@@ -327,6 +318,50 @@ int iommufd_hwpt_lu_restore(struct iommufd_ucmd *ucmd)
return rc;
}

+static bool iommufd_liveupdate_can_finish(struct liveupdate_file_op_args *args)
+{
+ struct iommufd_hwpt_paging *hwpt;
+ struct iommufd_hwpt_lu *hwpt_lu;
+ struct iommufd_lu *iommufd_lu;
+ struct iommufd_object *obj;
+ struct iommufd_ctx *ictx;
+ unsigned long index;
+ unsigned int i;
+
+ if (!args->retrieved || !args->file) {
+ pr_warn("%s: fd not reclaimed\n", __func__);
+ return false;
+ }
+
+ ictx = iommufd_ctx_from_file(args->file);
+ iommufd_lu = ictx->lu;
+
+ for (i = 0; i < iommufd_lu->nr_hwpts; i++) {
+ hwpt_lu = &iommufd_lu->hwpts[i];
+
+ if (!hwpt_lu->reclaimed)
+ return false;
+ }
+
+ xa_lock(&ictx->objects);
+ xa_for_each(&ictx->objects, index, obj) {
+ if (obj->type != IOMMUFD_OBJ_HWPT_PAGING)
+ continue;
+
+ hwpt = container_of(obj, struct iommufd_hwpt_paging, common.obj);
+ if (!hwpt->lu_restored)
+ continue;
+
+ if (!hwpt->common.domain || iommu_domain_has_attachments(hwpt->common.domain)) {
+ xa_unlock(&ictx->objects);
+ return false;
+ }
+ }
+ xa_unlock(&ictx->objects);
+
+ return true;
+}
+
static void iommufd_liveupdate_finish(struct liveupdate_file_op_args *args)
{
struct iommufd_lu *iommufd_lu;
--
2.52.0.158.g65b55ccf14-goog