]> www.infradead.org Git - users/hch/misc.git/commitdiff
drm/amdgpu: Use vmemdup_array_user in amdgpu_bo_create_list_entry_array
authorTvrtko Ursulin <tvrtko.ursulin@igalia.com>
Thu, 12 Jun 2025 10:44:26 +0000 (11:44 +0100)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 15 Sep 2025 20:51:34 +0000 (16:51 -0400)
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>
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c

index 702f6610d02435faa84a5853b6fed0491ea437c5..66fb37b643882c750f5f80078803628001507004 100644 (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,