An object allocator needs to call either iommufd_object_finalize() upon a
success or iommufd_object_abort_and_destroy() upon an error code.

To reduce duplication, store a new_obj in the struct iommufd_ucmd and call
iommufd_object_finalize/iommufd_object_abort_and_destroy() accordingly in
the main function.

This will also ease a driver-allocated object so that a driver can simply
return with an error code to trigger an iommufd_object_abort_and_destroy()
instead of doing an abort itself.

Similar to iommufd_object_alloc() and __iommufd_object_alloc(), add a pair
of helpers: __iommufd_object_alloc_ucmd() and iommufd_object_alloc_ucmd().

Suggested-by: Jason Gunthorpe <j...@nvidia.com>
Signed-off-by: Nicolin Chen <nicol...@nvidia.com>
---
 drivers/iommu/iommufd/iommufd_private.h |  1 +
 include/linux/iommufd.h                 | 23 +++++++++++++++++++++++
 drivers/iommu/iommufd/driver.c          | 18 ++++++++++++++++++
 drivers/iommu/iommufd/main.c            |  7 +++++++
 4 files changed, 49 insertions(+)

diff --git a/drivers/iommu/iommufd/iommufd_private.h 
b/drivers/iommu/iommufd/iommufd_private.h
index 10899e2cd34a..16767c231580 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -135,6 +135,7 @@ struct iommufd_ucmd {
        void __user *ubuffer;
        u32 user_size;
        void *cmd;
+       struct iommufd_object *new_obj;
 };
 
 int iommufd_vfio_ioctl(struct iommufd_ctx *ictx, unsigned int cmd,
diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h
index 498c9a768506..47f38034f5e7 100644
--- a/include/linux/iommufd.h
+++ b/include/linux/iommufd.h
@@ -22,6 +22,7 @@ struct iommu_user_data_array;
 struct iommufd_access;
 struct iommufd_ctx;
 struct iommufd_device;
+struct iommufd_ucmd;
 struct iommufd_viommu_ops;
 struct page;
 
@@ -51,6 +52,18 @@ struct iommufd_object {
        unsigned int id;
 };
 
+#define __iommufd_object_alloc_ucmd(ucmd, ptr, type, obj)                      
\
+       container_of(_iommufd_object_alloc_ucmd(                               \
+                            ucmd,                                             \
+                            sizeof(*(ptr)) + BUILD_BUG_ON_ZERO(               \
+                                                     offsetof(typeof(*(ptr)), \
+                                                              obj) != 0),     \
+                            type),                                            \
+                    typeof(*(ptr)), obj)
+
+#define iommufd_object_alloc_ucmd(ucmd, ptr, type) \
+       __iommufd_object_alloc_ucmd(ucmd, ptr, type, obj)
+
 struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,
                                           struct device *dev, u32 *id);
 void iommufd_device_unbind(struct iommufd_device *idev);
@@ -193,6 +206,9 @@ static inline int iommufd_vfio_compat_set_no_iommu(struct 
iommufd_ctx *ictx)
 struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
                                             size_t size,
                                             enum iommufd_object_type type);
+struct iommufd_object *
+_iommufd_object_alloc_ucmd(struct iommufd_ucmd *ucmd, size_t size,
+                          enum iommufd_object_type type);
 struct device *iommufd_viommu_find_dev(struct iommufd_viommu *viommu,
                                       unsigned long vdev_id);
 int iommufd_viommu_get_vdev_id(struct iommufd_viommu *viommu,
@@ -208,6 +224,13 @@ _iommufd_object_alloc(struct iommufd_ctx *ictx, size_t 
size,
        return ERR_PTR(-EOPNOTSUPP);
 }
 
+static inline struct iommufd_object *
+_iommufd_object_alloc_ucmd(struct iommufd_ucmd *ucmd, size_t size,
+                          enum iommufd_object_type type)
+{
+       return ERR_PTR(-EOPNOTSUPP);
+}
+
 static inline struct device *
 iommufd_viommu_find_dev(struct iommufd_viommu *viommu, unsigned long vdev_id)
 {
diff --git a/drivers/iommu/iommufd/driver.c b/drivers/iommu/iommufd/driver.c
index 922cd1fe7ec2..28dec9e09720 100644
--- a/drivers/iommu/iommufd/driver.c
+++ b/drivers/iommu/iommufd/driver.c
@@ -36,6 +36,24 @@ struct iommufd_object *_iommufd_object_alloc(struct 
iommufd_ctx *ictx,
 }
 EXPORT_SYMBOL_NS_GPL(_iommufd_object_alloc, "IOMMUFD");
 
+struct iommufd_object *_iommufd_object_alloc_ucmd(struct iommufd_ucmd *ucmd,
+                                                 size_t size,
+                                                 enum iommufd_object_type type)
+{
+       struct iommufd_object *new_obj;
+
+       if (ucmd->new_obj)
+               return ERR_PTR(-EBUSY);
+
+       new_obj = _iommufd_object_alloc(ucmd->ictx, size, type);
+       if (IS_ERR(new_obj))
+               return new_obj;
+
+       ucmd->new_obj = new_obj;
+       return new_obj;
+}
+EXPORT_SYMBOL_NS_GPL(_iommufd_object_alloc_ucmd, "IOMMUFD");
+
 /* Caller should xa_lock(&viommu->vdevs) to protect the return value */
 struct device *iommufd_viommu_find_dev(struct iommufd_viommu *viommu,
                                       unsigned long vdev_id)
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
index 347c56ef44d8..c6d0b446e632 100644
--- a/drivers/iommu/iommufd/main.c
+++ b/drivers/iommu/iommufd/main.c
@@ -416,6 +416,13 @@ static long iommufd_fops_ioctl(struct file *filp, unsigned 
int cmd,
        if (ret)
                return ret;
        ret = op->execute(&ucmd);
+
+       if (ucmd.new_obj) {
+               if (ret)
+                       iommufd_object_abort_and_destroy(ictx, ucmd.new_obj);
+               else
+                       iommufd_object_finalize(ictx, ucmd.new_obj);
+       }
        return ret;
 }
 
-- 
2.43.0


Reply via email to