Commit c4ac100e authored by Tvrtko Ursulin's avatar Tvrtko Ursulin Committed by Alex Deucher
Browse files

drm/amdgpu: Use vmemdup_array_user in amdgpu_bo_create_list_entry_array



Replace kvmalloc_array() + copy_from_user() with vmemdup_array_user() on
the fast path.

This shrinks the source code and improves separation between the kernel
and userspace slabs.

Signed-off-by: default avatarTvrtko Ursulin <tvrtko.ursulin@igalia.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 65307484
Loading
Loading
Loading
Loading
+17 −24
Original line number Diff line number Diff line
@@ -184,43 +184,36 @@ void amdgpu_bo_list_put(struct amdgpu_bo_list *list)
int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in,
				      struct drm_amdgpu_bo_list_entry **info_param)
{
	const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr);
	const uint32_t info_size = sizeof(struct drm_amdgpu_bo_list_entry);
	const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr);
	const uint32_t bo_info_size = in->bo_info_size;
	const uint32_t bo_number = in->bo_number;
	struct drm_amdgpu_bo_list_entry *info;
	int r;

	info = kvmalloc_array(in->bo_number, info_size, GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	/* copy the handle array from userspace to a kernel buffer */
	r = -EFAULT;
	if (likely(info_size == in->bo_info_size)) {
		unsigned long bytes = in->bo_number *
			in->bo_info_size;

		if (copy_from_user(info, uptr, bytes))
			goto error_free;

	if (likely(info_size == bo_info_size)) {
		info = vmemdup_array_user(uptr, bo_number, info_size);
		if (IS_ERR(info))
			return PTR_ERR(info);
	} else {
		unsigned long bytes = min(in->bo_info_size, info_size);
		const uint32_t bytes = min(bo_info_size, info_size);
		unsigned i;

		memset(info, 0, in->bo_number * info_size);
		for (i = 0; i < in->bo_number; ++i) {
			if (copy_from_user(&info[i], uptr, bytes))
				goto error_free;
		info = kvmalloc_array(bo_number, info_size, GFP_KERNEL);
		if (!info)
			return -ENOMEM;

			uptr += in->bo_info_size;
		memset(info, 0, bo_number * info_size);
		for (i = 0; i < bo_number; ++i, uptr += bo_info_size) {
			if (copy_from_user(&info[i], uptr, bytes)) {
				kvfree(info);
				return -EFAULT;
			}
		}
	}

	*info_param = info;
	return 0;

error_free:
	kvfree(info);
	return r;
}

int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,