lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250423090149.2748ef62@collabora.com>
Date: Wed, 23 Apr 2025 09:01:49 +0200
From: Boris Brezillon <boris.brezillon@...labora.com>
To: Adrián Larumbe <adrian.larumbe@...labora.com>
Cc: linux-kernel@...r.kernel.org, dri-devel@...ts.freedesktop.org,
 kernel@...labora.com, Liviu Dudau <liviu.dudau@....com>, Steven Price
 <steven.price@....com>, Maarten Lankhorst
 <maarten.lankhorst@...ux.intel.com>, Maxime Ripard <mripard@...nel.org>,
 Thomas Zimmermann <tzimmermann@...e.de>, David Airlie <airlied@...il.com>,
 Simona Vetter <simona@...ll.ch>, Sumit Semwal <sumit.semwal@...aro.org>,
 Christian König <christian.koenig@....com>,
 linux-media@...r.kernel.org, linaro-mm-sig@...ts.linaro.org
Subject: Re: [PATCH v10 4/4] drm/panthor: show device-wide list of DRM GEM
 objects over DebugFS

On Wed, 23 Apr 2025 03:12:34 +0100
Adrián Larumbe <adrian.larumbe@...labora.com> wrote:

> Add a device DebugFS file that displays a complete list of all the DRM
> GEM objects that are exposed to UM through a DRM handle.
> 
> Since leaking object identifiers that might belong to a different NS is
> inadmissible, this functionality is only made available in debug builds
> with DEBUGFS support enabled.
> 
> File format is that of a table, with each entry displaying a variety of
> fields with information about each GEM object.
> 
> Each GEM object entry in the file displays the following information
> fields: Client PID, BO's global name, reference count, BO virtual size,
> BO resize size, VM address in its DRM-managed range, BO label and a GEM
> state flags.
> 
> There's also a usage flags field for the type of BO, which tells us
> whether it's a kernel BO and/or mapped onto the FW's address space.
> 
> GEM state and usage flag meanings are printed in the file prelude, so
> that UM parsing tools can interpret the numerical values in the table.
> 
> Signed-off-by: Adrián Larumbe <adrian.larumbe@...labora.com>
> Reviewed-by: Liviu Dudau <liviu.dudau@....com>
> Reviewed-by: Boris Brezillon <boris.brezillon@...labora.com>
> Reviewed-by: Steven Price <steven.price@....com>
> ---
>  drivers/gpu/drm/panthor/panthor_device.c |   5 +
>  drivers/gpu/drm/panthor/panthor_device.h |  11 ++
>  drivers/gpu/drm/panthor/panthor_drv.c    |  25 ++++
>  drivers/gpu/drm/panthor/panthor_gem.c    | 156 +++++++++++++++++++++++
>  drivers/gpu/drm/panthor/panthor_gem.h    |  65 ++++++++++
>  5 files changed, 262 insertions(+)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
> index a9da1d1eeb70..b776e1a2e4f3 100644
> --- a/drivers/gpu/drm/panthor/panthor_device.c
> +++ b/drivers/gpu/drm/panthor/panthor_device.c
> @@ -184,6 +184,11 @@ int panthor_device_init(struct panthor_device *ptdev)
>  	if (ret)
>  		return ret;
>  
> +#ifdef CONFIG_DEBUG_FS
> +	drmm_mutex_init(&ptdev->base, &ptdev->gems.lock);
> +	INIT_LIST_HEAD(&ptdev->gems.node);
> +#endif
> +
>  	atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_SUSPENDED);
>  	p = alloc_page(GFP_KERNEL | __GFP_ZERO);
>  	if (!p)
> diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
> index da6574021664..86206a961b38 100644
> --- a/drivers/gpu/drm/panthor/panthor_device.h
> +++ b/drivers/gpu/drm/panthor/panthor_device.h
> @@ -205,6 +205,17 @@ struct panthor_device {
>  
>  	/** @fast_rate: Maximum device clock frequency. Set by DVFS */
>  	unsigned long fast_rate;
> +
> +#ifdef CONFIG_DEBUG_FS
> +	/** @gems: Device-wide list of GEM objects owned by at least one file. */
> +	struct {
> +		/** @gems.lock: Protects the device-wide list of GEM objects. */
> +		struct mutex lock;
> +
> +		/** @node: Used to keep track of all the device's DRM objects */
> +		struct list_head node;
> +	} gems;
> +#endif
>  };
>  
>  struct panthor_gpu_usage {
> diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c
> index 7308fad02c9e..dfe2e89942a0 100644
> --- a/drivers/gpu/drm/panthor/panthor_drv.c
> +++ b/drivers/gpu/drm/panthor/panthor_drv.c
> @@ -1537,9 +1537,34 @@ static const struct file_operations panthor_drm_driver_fops = {
>  };
>  
>  #ifdef CONFIG_DEBUG_FS
> +static int panthor_gems_show(struct seq_file *m, void *data)
> +{
> +	struct drm_info_node *node = m->private;
> +	struct drm_device *dev = node->minor->dev;
> +	struct panthor_device *ptdev = container_of(dev, struct panthor_device, base);
> +
> +	panthor_gem_debugfs_print_bos(ptdev, m);
> +
> +	return 0;
> +}
> +
> +static struct drm_info_list panthor_debugfs_list[] = {
> +	{"gems", panthor_gems_show, 0, NULL},
> +};
> +
> +static int panthor_gems_debugfs_init(struct drm_minor *minor)
> +{
> +	drm_debugfs_create_files(panthor_debugfs_list,
> +				 ARRAY_SIZE(panthor_debugfs_list),
> +				 minor->debugfs_root, minor);
> +
> +	return 0;
> +}
> +
>  static void panthor_debugfs_init(struct drm_minor *minor)
>  {
>  	panthor_mmu_debugfs_init(minor);
> +	panthor_gems_debugfs_init(minor);
>  }
>  #endif
>  
> diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
> index 3f4ab5a2f2ae..fedb9697fe57 100644
> --- a/drivers/gpu/drm/panthor/panthor_gem.c
> +++ b/drivers/gpu/drm/panthor/panthor_gem.c
> @@ -11,14 +11,51 @@
>  #include <drm/panthor_drm.h>
>  
>  #include "panthor_device.h"
> +#include "panthor_fw.h"
>  #include "panthor_gem.h"
>  #include "panthor_mmu.h"
>  
> +#ifdef CONFIG_DEBUG_FS
> +static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev,
> +				       struct panthor_gem_object *bo)
> +{
> +	INIT_LIST_HEAD(&bo->debugfs.node);
> +
> +	bo->debugfs.creator.tgid = current->group_leader->pid;
> +	get_task_comm(bo->debugfs.creator.process_name, current->group_leader);
> +
> +	mutex_lock(&ptdev->gems.lock);
> +	list_add_tail(&bo->debugfs.node, &ptdev->gems.node);
> +	mutex_unlock(&ptdev->gems.lock);
> +}
> +
> +static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo)
> +{
> +	struct panthor_device *ptdev = container_of(bo->base.base.dev,
> +						    struct panthor_device, base);
> +
> +	if (list_empty(&bo->debugfs.node))
> +		return;
> +
> +	mutex_lock(&ptdev->gems.lock);
> +	list_del_init(&bo->debugfs.node);
> +	mutex_unlock(&ptdev->gems.lock);
> +}
> +
> +#else
> +static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev,
> +				       struct panthor_gem_object *bo)
> +{}
> +static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {}
> +#endif
> +
>  static void panthor_gem_free_object(struct drm_gem_object *obj)
>  {
>  	struct panthor_gem_object *bo = to_panthor_bo(obj);
>  	struct drm_gem_object *vm_root_gem = bo->exclusive_vm_root_gem;
>  
> +	panthor_gem_debugfs_bo_rm(bo);
> +
>  	/*
>  	 * Label might have been allocated with kstrdup_const(),
>  	 * we need to take that into account when freeing the memory
> @@ -88,6 +125,7 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm,
>  	struct drm_gem_shmem_object *obj;
>  	struct panthor_kernel_bo *kbo;
>  	struct panthor_gem_object *bo;
> +	u32 debug_flags = PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL;
>  	int ret;
>  
>  	if (drm_WARN_ON(&ptdev->base, !vm))
> @@ -107,7 +145,11 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm,
>  	kbo->obj = &obj->base;
>  	bo->flags = bo_flags;
>  
> +	if (vm == panthor_fw_vm(ptdev))
> +		debug_flags |= PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED;
> +
>  	panthor_gem_kernel_bo_set_label(kbo, name);
> +	panthor_gem_debugfs_set_usage_flags(to_panthor_bo(kbo->obj), debug_flags);
>  
>  	/* The system and GPU MMU page size might differ, which becomes a
>  	 * problem for FW sections that need to be mapped at explicit address
> @@ -210,6 +252,8 @@ struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t
>  	drm_gem_gpuva_set_lock(&obj->base.base, &obj->gpuva_list_lock);
>  	mutex_init(&obj->label.lock);
>  
> +	panthor_gem_debugfs_bo_add(ptdev, obj);
> +
>  	return &obj->base.base;
>  }
>  
> @@ -258,6 +302,12 @@ panthor_gem_create_with_handle(struct drm_file *file,
>  	/* drop reference from allocate - handle holds it now. */
>  	drm_gem_object_put(&shmem->base);
>  
> +	/*
> +	 * No explicit flags are needed in the call below, since the
> +	 * function internally sets the INITIALIZED bit for us.
> +	 */
> +	panthor_gem_debugfs_set_usage_flags(bo, 0);
> +
>  	return ret;
>  }
>  
> @@ -296,3 +346,109 @@ panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label)
>  
>  	panthor_gem_bo_set_label(bo->obj, str);
>  }
> +
> +#ifdef CONFIG_DEBUG_FS
> +struct gem_size_totals {
> +	size_t size;
> +	size_t resident;
> +	size_t reclaimable;
> +};
> +
> +static void panthor_gem_debugfs_print_flag_names(struct seq_file *m)
> +{
> +	int len;
> +	int i;
> +
> +	static const char * const gem_state_flags_names[] = {
> +		[PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT] = "imported",
> +		[PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT] = "exported",
> +	};
> +
> +	static const char * const gem_usage_flags_names[] = {
> +		[PANTHOR_DEBUGFS_GEM_USAGE_KERNEL_BIT] = "kernel",
> +		[PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT] = "fw-mapped",
> +	};
> +
> +	seq_puts(m, "GEM state flags: ");
> +	for (i = 0, len = ARRAY_SIZE(gem_state_flags_names); i < len; i++) {
> +		if (!gem_state_flags_names[i])
> +			continue;
> +		seq_printf(m, "%s (0x%x)%s", gem_state_flags_names[i],
> +			   (u32)BIT(i), (i < len - 1) ? ", " : "\n");
> +	}
> +
> +	seq_puts(m, "GEM usage flags: ");
> +	for (i = 0, len = ARRAY_SIZE(gem_usage_flags_names); i < len; i++) {
> +		if (!gem_usage_flags_names[i])
> +			continue;
> +		seq_printf(m, "%s (0x%x)%s", gem_usage_flags_names[i],
> +			   (u32)BIT(i), (i < len - 1) ? ", " : "\n\n");
> +	}
> +}
> +
> +static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
> +					 struct seq_file *m,
> +					 struct gem_size_totals *totals)
> +{
> +	unsigned int refcount = kref_read(&bo->base.base.refcount);
> +	char creator_info[32] = {};
> +	size_t resident_size;
> +	u32 gem_usage_flags = bo->debugfs.flags & (u32)~PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED;
> +	u32 gem_state_flags = 0;
> +
> +	/* Skip BOs being destroyed. */
> +	if (!refcount)
> +		return;
> +
> +	resident_size = bo->base.pages ? bo->base.base.size : 0;
> +
> +	snprintf(creator_info, sizeof(creator_info),
> +		 "%s/%d", bo->debugfs.creator.process_name, bo->debugfs.creator.tgid);
> +	seq_printf(m, "%-32s%-16d%-16d%-16zd%-16zd0x%-16lx",
> +		   creator_info,
> +		   bo->base.base.name,
> +		   refcount,
> +		   bo->base.base.size,
> +		   resident_size,
> +		   drm_vma_node_start(&bo->base.base.vma_node));
> +
> +	if (bo->base.base.import_attach)
> +		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED;
> +	if (bo->base.base.dma_buf)
> +		gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED;
> +
> +	seq_printf(m, "0x%-8x 0x%-10x", gem_state_flags, gem_usage_flags);
> +
> +	scoped_guard(mutex, &bo->label.lock) {
> +		seq_printf(m, "%s\n", bo->label.str ? : "");
> +	}
> +
> +	totals->size += bo->base.base.size;
> +	totals->resident += resident_size;
> +	if (bo->base.madv > 0)
> +		totals->reclaimable += resident_size;
> +}
> +
> +void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
> +				   struct seq_file *m)
> +{
> +	struct gem_size_totals totals = {0};
> +	struct panthor_gem_object *bo;
> +
> +	panthor_gem_debugfs_print_flag_names(m);
> +
> +	seq_puts(m, "created-by                      global-name     refcount        size            resident-size   file-offset       state      usage       label\n");
> +	seq_puts(m, "----------------------------------------------------------------------------------------------------------------------------------------------\n");
> +
> +	scoped_guard(mutex, &ptdev->gems.lock) {
> +		list_for_each_entry(bo, &ptdev->gems.node, debugfs.node) {
> +			if (bo->debugfs.flags & PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED)
> +				panthor_gem_debugfs_bo_print(bo, m, &totals);
> +		}
> +	}
> +
> +	seq_puts(m, "==============================================================================================================================================\n");
> +	seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
> +		   totals.size, totals.resident, totals.reclaimable);
> +}
> +#endif
> diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h
> index 3c09af568e47..4641994ddd7f 100644
> --- a/drivers/gpu/drm/panthor/panthor_gem.h
> +++ b/drivers/gpu/drm/panthor/panthor_gem.h
> @@ -15,6 +15,54 @@ struct panthor_vm;
>  
>  #define PANTHOR_BO_LABEL_MAXLEN	4096
>  
> +enum panthor_debugfs_gem_state_flags {
> +	PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT = 0,
> +	PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT = 1,
> +
> +	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED: GEM BO is PRIME imported. */
> +	PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT),
> +
> +	/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED: GEM BO is PRIME exported. */
> +	PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT),
> +};
> +
> +enum panthor_debugfs_gem_usage_flags {
> +	PANTHOR_DEBUGFS_GEM_USAGE_KERNEL_BIT = 0,
> +	PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT = 1,

Now that you print the flags as raw hex values, you don't need those
_BIT definitions.

> +
> +	/** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL: BO is for kernel use only. */
> +	PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL = BIT(PANTHOR_DEBUGFS_GEM_USAGE_KERNEL_BIT),
> +
> +	/** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED: BO is mapped on the FW VM. */
> +	PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED = BIT(PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT),
> +
> +	/** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED: BO is ready for DebugFS display. */
> +	PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED = BIT(31),
> +};
> +
> +/**
> + * struct panthor_gem_debugfs - GEM object's DebugFS list information
> + */
> +struct panthor_gem_debugfs {
> +	/**
> +	 * @node: Node used to insert the object in the device-wide list of
> +	 * GEM objects, to display information about it through a DebugFS file.
> +	 */
> +	struct list_head node;
> +
> +	/** @creator: Information about the UM process which created the GEM. */
> +	struct {
> +		/** @creator.process_name: Group leader name in owning thread's process */
> +		char process_name[TASK_COMM_LEN];
> +
> +		/** @creator.tgid: PID of the thread's group leader within its process */
> +		pid_t tgid;
> +	} creator;
> +
> +	/** @flags: Combination of panthor_debugfs_gem_usage_flags flags */
> +	u32 flags;
> +};
> +
>  /**
>   * struct panthor_gem_object - Driver specific GEM object.
>   */
> @@ -62,6 +110,10 @@ struct panthor_gem_object {
>  		/** @lock.str: Protects access to the @label.str field. */
>  		struct mutex lock;
>  	} label;
> +
> +#ifdef CONFIG_DEBUG_FS
> +	struct panthor_gem_debugfs debugfs;
> +#endif
>  };
>  
>  /**
> @@ -157,4 +209,17 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm,
>  
>  void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo);
>  
> +#ifdef CONFIG_DEBUG_FS
> +void panthor_gem_debugfs_print_bos(struct panthor_device *pfdev,
> +				   struct seq_file *m);
> +static inline void
> +panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags)
> +{
> +	bo->debugfs.flags = usage_flags | PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED;
> +}
> +
> +#else
> +void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {};
> +#endif
> +
>  #endif /* __PANTHOR_GEM_H__ */


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ