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: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Tvrtko Ursulin 2025-06-12 11:44:26 +01:00 committed by Alex Deucher
parent 6530748485
commit c4ac100e9a

View File

@ -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,