iommu: Add iommu_copy_struct_from_user_array helper
authorNicolin Chen <nicolinc@nvidia.com>
Thu, 11 Jan 2024 04:10:10 +0000 (20:10 -0800)
committerJason Gunthorpe <jgg@nvidia.com>
Thu, 11 Jan 2024 17:01:25 +0000 (13:01 -0400)
Wrap up the data pointer/num sanity and __iommu_copy_struct_from_user()
call for iommu drivers to copy driver specific data at a specific location
in the struct iommu_user_data_array.

And expect it to be used in cache_invalidate_user ops for example.

Link: https://lore.kernel.org/r/20240111041015.47920-4-yi.l.liu@intel.com
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Co-developed-by: Yi Liu <yi.l.liu@intel.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
include/linux/iommu.h

index 93c0d12dd047cb839a713deccbc7bf08ff9b695f..9dbadf74a3a1e2f33a1154b95dbbf4f1094dbfd9 100644 (file)
@@ -341,6 +341,57 @@ static inline int __iommu_copy_struct_from_user(
                                      sizeof(*kdst),                      \
                                      offsetofend(typeof(*kdst), min_last))
 
+/**
+ * __iommu_copy_struct_from_user_array - Copy iommu driver specific user space
+ *                                       data from an iommu_user_data_array
+ * @dst_data: Pointer to an iommu driver specific user data that is defined in
+ *            include/uapi/linux/iommufd.h
+ * @src_array: Pointer to a struct iommu_user_data_array for a user space array
+ * @data_type: The data type of the @dst_data. Must match with @src_array.type
+ * @index: Index to the location in the array to copy user data from
+ * @data_len: Length of current user data structure, i.e. sizeof(struct _dst)
+ * @min_len: Initial length of user data structure for backward compatibility.
+ *           This should be offsetofend using the last member in the user data
+ *           struct that was initially added to include/uapi/linux/iommufd.h
+ */
+static inline int __iommu_copy_struct_from_user_array(
+       void *dst_data, const struct iommu_user_data_array *src_array,
+       unsigned int data_type, unsigned int index, size_t data_len,
+       size_t min_len)
+{
+       struct iommu_user_data src_data;
+
+       if (WARN_ON(!src_array || index >= src_array->entry_num))
+               return -EINVAL;
+       if (!src_array->entry_num)
+               return -EINVAL;
+       src_data.uptr = src_array->uptr + src_array->entry_len * index;
+       src_data.len = src_array->entry_len;
+       src_data.type = src_array->type;
+
+       return __iommu_copy_struct_from_user(dst_data, &src_data, data_type,
+                                            data_len, min_len);
+}
+
+/**
+ * iommu_copy_struct_from_user_array - Copy iommu driver specific user space
+ *                                     data from an iommu_user_data_array
+ * @kdst: Pointer to an iommu driver specific user data that is defined in
+ *        include/uapi/linux/iommufd.h
+ * @user_array: Pointer to a struct iommu_user_data_array for a user space
+ *              array
+ * @data_type: The data type of the @kdst. Must match with @user_array->type
+ * @index: Index to the location in the array to copy user data from
+ * @min_last: The last member of the data structure @kdst points in the
+ *            initial version.
+ * Return 0 for success, otherwise -error.
+ */
+#define iommu_copy_struct_from_user_array(kdst, user_array, data_type, index, \
+                                         min_last)                           \
+       __iommu_copy_struct_from_user_array(                                  \
+               kdst, user_array, data_type, index, sizeof(*(kdst)),          \
+               offsetofend(typeof(*(kdst)), min_last))
+
 /**
  * struct iommu_ops - iommu ops and capabilities
  * @capable: check capability