[PATCH v12 1/3] drm/amdgpu: Add ioctl to get all gem handles for a process
Tvrtko Ursulin
tvrtko.ursulin at igalia.com
Tue Aug 12 09:28:21 UTC 2025
On 11/08/2025 16:05, David Francis wrote:
> Add new ioctl DRM_IOCTL_AMDGPU_GEM_LIST_HANDLES.
>
> This ioctl returns a list of bos with their handles, sizes,
> and flags and domains.
>
> This ioctl is meant to be used during CRIU checkpoint and
> provide information needed to reconstruct the bos
> in CRIU restore.
>
> Signed-off-by: David Francis <David.Francis at amd.com>
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 83 +++++++++++++++++++++++++
> drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h | 2 +
> include/uapi/drm/amdgpu_drm.h | 31 +++++++++
> 4 files changed, 117 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 4ff3a2eaaf55..f19795dddf9d 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -3031,6 +3031,7 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {
> DRM_IOCTL_DEF_DRV(AMDGPU_USERQ, amdgpu_userq_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
> DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_SIGNAL, amdgpu_userq_signal_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
> DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_WAIT, amdgpu_userq_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
> + DRM_IOCTL_DEF_DRV(AMDGPU_GEM_LIST_HANDLES, amdgpu_gem_list_handles_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
> };
>
> static const struct drm_driver amdgpu_kms_driver = {
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
> index e3f65977eeee..3873d2c19b4b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
> @@ -1032,6 +1032,89 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
> return r;
> }
>
> +/**
> + * drm_amdgpu_gem_list_handles_ioctl - get information about a process' buffer objects
> + *
> + * @dev: drm device pointer
> + * @data: drm_amdgpu_gem_list_handles
> + * @filp: drm file pointer
> + *
> + * num_bos is set as an input to the size of the bo_buckets array.
> + * num_bos is sent back as output as the number of bos in the process.
> + * If that number is larger than the size of the array, the ioctl must
> + * be retried.
> + *
> + * Returns:
> + * 0 for success, -errno for errors.
> + */
> +int amdgpu_gem_list_handles_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *filp)
> +{
> + struct drm_amdgpu_gem_list_handles *args = data;
> + struct drm_amdgpu_gem_list_handles_entry *bo_entries;
> + struct drm_gem_object *gobj;
> + int id, ret = 0;
> + int bo_index = 0;
> + int num_bos = 0;
> +
> + spin_lock(&filp->table_lock);
> + idr_for_each_entry(&filp->object_idr, gobj, id)
> + num_bos += 1;
> + spin_unlock(&filp->table_lock);
> +
> + if (args->num_entries < num_bos) {
> + args->num_entries = num_bos;
> + return 0;
> + }
> +
> + if (num_bos == 0) {
> + args->num_entries = 0;
> + return 0;
> + }
> +
> + bo_entries = kvcalloc(num_bos, sizeof(*bo_entries), GFP_KERNEL);
> + if (!bo_entries)
> + return -ENOMEM;
> +
> + spin_lock(&filp->table_lock);
> + idr_for_each_entry(&filp->object_idr, gobj, id) {
> + struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj);
> + struct drm_amdgpu_gem_list_handles_entry *bo_entry;
> +
> + if (bo_index >= num_bos) {
> + ret = -EAGAIN;
> + break;
> + }
> +
> + bo_entry = &bo_entries[bo_index];
> +
> + bo_entry->size = amdgpu_bo_size(bo);
> + bo_entry->alloc_flags = bo->flags & (~AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE);
> + /* WIPE_ON_RELEASE is set automatically in the driver; it is not permitted in
> + * BO creation. In the interest of giving the user exactly the flags they need
> + * to recreate the BO, clear it.
> + */
Ha, curious. What is the reason flags userspace cannot use are specified
in the uapi header?
> + bo_entry->preferred_domains = bo->preferred_domains;
> + bo_entry->gem_handle = id;
> +
> + if (bo->tbo.base.import_attach)
> + bo_entry->flags |= AMDGPU_GEM_LIST_HANDLES_FLAG_IS_IMPORT;
I had a question regarding this part in v11. Any comment on that?
Anyway, thanks for implementing the other changes I suggested, this one
LGTM now.
Regards,
Tvrtko
> +
> + bo_index += 1;
> + }
> + spin_unlock(&filp->table_lock);
> +
> + args->num_entries = bo_index;
> +
> + if (!ret)
> + ret = copy_to_user(u64_to_user_ptr(args->entries), bo_entries, num_bos * sizeof(*bo_entries));
> +
> + kvfree(bo_entries);
> +
> + return ret;
> +}
> +
> +
> static int amdgpu_gem_align_pitch(struct amdgpu_device *adev,
> int width,
> int cpp,
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h
> index b51e8f95ee86..7cdb6237bb92 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h
> @@ -67,6 +67,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
> struct drm_file *filp);
> int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
> struct drm_file *filp);
> +int amdgpu_gem_list_handles_ioctl(struct drm_device *dev, void *data,
> + struct drm_file *filp);
>
> int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data,
> struct drm_file *filp);
> diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h
> index bdedbaccf776..59b423883e91 100644
> --- a/include/uapi/drm/amdgpu_drm.h
> +++ b/include/uapi/drm/amdgpu_drm.h
> @@ -57,6 +57,7 @@ extern "C" {
> #define DRM_AMDGPU_USERQ 0x16
> #define DRM_AMDGPU_USERQ_SIGNAL 0x17
> #define DRM_AMDGPU_USERQ_WAIT 0x18
> +#define DRM_AMDGPU_GEM_LIST_HANDLES 0x19
>
> #define DRM_IOCTL_AMDGPU_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create)
> #define DRM_IOCTL_AMDGPU_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_MMAP, union drm_amdgpu_gem_mmap)
> @@ -77,6 +78,7 @@ extern "C" {
> #define DRM_IOCTL_AMDGPU_USERQ DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_USERQ, union drm_amdgpu_userq)
> #define DRM_IOCTL_AMDGPU_USERQ_SIGNAL DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_USERQ_SIGNAL, struct drm_amdgpu_userq_signal)
> #define DRM_IOCTL_AMDGPU_USERQ_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_USERQ_WAIT, struct drm_amdgpu_userq_wait)
> +#define DRM_IOCTL_AMDGPU_GEM_LIST_HANDLES DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_LIST_HANDLES, struct drm_amdgpu_gem_list_handles)
>
> /**
> * DOC: memory domains
> @@ -811,6 +813,35 @@ struct drm_amdgpu_gem_op {
> __u64 value;
> };
>
> +#define AMDGPU_GEM_LIST_HANDLES_FLAG_IS_IMPORT (1 << 0)
> +
> +struct drm_amdgpu_gem_list_handles {
> + /* User pointer to array of drm_amdgpu_gem_bo_info_entry */
> + __u64 entries;
> +
> + /* IN: Size of entries buffer. OUT: Number of handles in process (if larger than size of buffer, must retry) */
> + __u32 num_entries;
> +
> + __u32 padding;
> +};
> +
> +struct drm_amdgpu_gem_list_handles_entry {
> + /* gem handle of buffer object */
> + __u32 gem_handle;
> +
> + /* Currently just one flag: IS_IMPORT */
> + __u32 flags;
> +
> + /* Size of bo */
> + __u64 size;
> +
> + /* Preferred domains for GEM_CREATE */
> + __u64 preferred_domains;
> +
> + /* GEM_CREATE flags for re-creation of buffer */
> + __u64 alloc_flags;
> +};
> +
> #define AMDGPU_VA_OP_MAP 1
> #define AMDGPU_VA_OP_UNMAP 2
> #define AMDGPU_VA_OP_CLEAR 3
More information about the amd-gfx
mailing list