Commit 4f2e59cc authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

iommu: Add iommu_copy_struct_from_full_user_array helper

The iommu_copy_struct_from_user_array helper can be used to copy a single
entry from a user array which might not be efficient if the array is big.

Add a new iommu_copy_struct_from_full_user_array to copy the entire user
array at once. Update the existing iommu_copy_struct_from_user_array kdoc
accordingly.

Link: https://patch.msgid.link/r/5cd773d9c26920c5807d232b21d415ea79172e49.1730836308.git.nicolinc@nvidia.com


Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Signed-off-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 54ce69e3
Loading
Loading
Loading
Loading
+47 −1
Original line number Diff line number Diff line
@@ -493,7 +493,9 @@ static inline int __iommu_copy_struct_from_user_array(
 * @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.
 *
 * Copy a single entry from a user array. Return 0 for success, otherwise
 * -error.
 */
#define iommu_copy_struct_from_user_array(kdst, user_array, data_type, index, \
					  min_last)                           \
@@ -501,6 +503,50 @@ static inline int __iommu_copy_struct_from_user_array(
		kdst, user_array, data_type, index, sizeof(*(kdst)),          \
		offsetofend(typeof(*(kdst)), min_last))

/**
 * iommu_copy_struct_from_full_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
 * @kdst_entry_size: sizeof(*kdst)
 * @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
 *
 * Copy the entire user array. kdst must have room for kdst_entry_size *
 * user_array->entry_num bytes. Return 0 for success, otherwise -error.
 */
static inline int
iommu_copy_struct_from_full_user_array(void *kdst, size_t kdst_entry_size,
				       struct iommu_user_data_array *user_array,
				       unsigned int data_type)
{
	unsigned int i;
	int ret;

	if (user_array->type != data_type)
		return -EINVAL;
	if (!user_array->entry_num)
		return -EINVAL;
	if (likely(user_array->entry_len == kdst_entry_size)) {
		if (copy_from_user(kdst, user_array->uptr,
				   user_array->entry_num *
					   user_array->entry_len))
			return -EFAULT;
	}

	/* Copy item by item */
	for (i = 0; i != user_array->entry_num; i++) {
		ret = copy_struct_from_user(
			kdst + kdst_entry_size * i, kdst_entry_size,
			user_array->uptr + user_array->entry_len * i,
			user_array->entry_len);
		if (ret)
			return ret;
	}
	return 0;
}

/**
 * struct iommu_ops - iommu ops and capabilities
 * @capable: check capability