All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jani Nikula <jani.nikula@linux.intel.com>
To: Anusha Srivatsa <asrivats@redhat.com>,
	Neil Armstrong <neil.armstrong@linaro.org>,
	Jessica Zhang <quic_jesszhan@quicinc.com>,
	Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	Maxime Ripard <mripard@kernel.org>,
	Thomas Zimmermann <tzimmermann@suse.de>,
	David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>
Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	Luca Ceresoli <luca.ceresoli@bootlin.com>,
	Anusha Srivatsa <asrivats@redhat.com>
Subject: Re: [PATCH v4 2/4] drm/panel: Add refcount support
Date: Mon, 28 Apr 2025 19:31:50 +0300	[thread overview]
Message-ID: <87y0vkw8ll.fsf@intel.com> (raw)
In-Reply-To: <20250331-b4-panel-refcounting-v4-2-dad50c60c6c9@redhat.com>

On Mon, 31 Mar 2025, Anusha Srivatsa <asrivats@redhat.com> wrote:
> Allocate panel via reference counting. Add _get() and _put() helper
> functions to ensure panel allocations are refcounted. Avoid use after
> free by ensuring panel pointer is valid and can be usable till the last
> reference is put.
>
> Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
> Reviewed-by: Maxime Ripard <mripard@kernel.org>
> Signed-off-by: Anusha Srivatsa <asrivats@redhat.com>
>
> ---
> v4: Add refcounting documentation in this patch (Maxime)
>
> v3: Add include in this patch (Luca)
>
> v2: Export drm_panel_put/get() (Maxime)
> - Change commit log with better workding (Luca, Maxime)
> - Change drm_panel_put() to return void (Luca)
> - Code Cleanups - add return in documentation, replace bridge to
> panel (Luca)
> ---
>  drivers/gpu/drm/drm_panel.c | 64 ++++++++++++++++++++++++++++++++++++++++++++-
>  include/drm/drm_panel.h     | 19 ++++++++++++++
>  2 files changed, 82 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> index bdeab5710ee324dc1742fbc77582250960556308..7b17531d85a4dc3031709919564d2e4d8332f748 100644
> --- a/drivers/gpu/drm/drm_panel.c
> +++ b/drivers/gpu/drm/drm_panel.c
> @@ -355,24 +355,86 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
>  }
>  EXPORT_SYMBOL(of_drm_find_panel);
>  
> +static void __drm_panel_free(struct kref *kref)
> +{
> +	struct drm_panel *panel = container_of(kref, struct drm_panel, refcount);
> +
> +	kfree(panel->container);
> +}
> +
> +/**
> + * drm_panel_get - Acquire a panel reference
> + * @panel: DRM panel
> + *
> + * This function increments the panel's refcount.
> + * Returns:
> + * Pointer to @panel
> + */
> +struct drm_panel *drm_panel_get(struct drm_panel *panel)
> +{
> +	if (!panel)
> +		return panel;
> +
> +	kref_get(&panel->refcount);
> +
> +	return panel;
> +}
> +EXPORT_SYMBOL(drm_panel_get);
> +
> +/**
> + * drm_panel_put - Release a panel reference
> + * @panel: DRM panel
> + *
> + * This function decrements the panel's reference count and frees the
> + * object if the reference count drops to zero.
> + */
> +void drm_panel_put(struct drm_panel *panel)
> +{
> +	if (panel)
> +		kref_put(&panel->refcount, __drm_panel_free);
> +}
> +EXPORT_SYMBOL(drm_panel_put);
> +
> +/**
> + * drm_panel_put_void - wrapper to drm_panel_put() taking a void pointer
> + *
> + * @data: pointer to @struct drm_panel, cast to a void pointer
> + *
> + * Wrapper of drm_panel_put() to be used when a function taking a void
> + * pointer is needed, for example as a devm action.
> + */
> +static void drm_panel_put_void(void *data)
> +{
> +	struct drm_panel *panel = (struct drm_panel *)data;
> +
> +	drm_panel_put(panel);
> +}
> +
>  void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
>  			     const struct drm_panel_funcs *funcs,
>  			     int connector_type)
>  {
>  	void *container;
>  	struct drm_panel *panel;
> +	int err;
>  
>  	if (!funcs) {
>  		dev_warn(dev, "Missing funcs pointer\n");
>  		return ERR_PTR(-EINVAL);
>  	}
>  
> -	container = devm_kzalloc(dev, size, GFP_KERNEL);
> +	container = kzalloc(size, GFP_KERNEL);
>  	if (!container)
>  		return ERR_PTR(-ENOMEM);
>  
>  	panel = container + offset;
> +	panel->container = container;
>  	panel->funcs = funcs;
> +	kref_init(&panel->refcount);

Hi Anusha, this should be done in drm_panel_init() instead.

There are many users of drm_panel that don't use devm_drm_panel_alloc()
but allocate separately, and call drm_panel_init() only. They'll all
have refcount set to 0 instead of 1 like kref_init() does.

This means all subsequent get/put pairs on such panels will lead to
__drm_panel_free() being called! But through a lucky coincidence, that
will be a nop because panel->container is also not initialized...

I'm sorry to say, the drm refcounting interface is quite broken for such
use cases.


BR,
Jani.


> +
> +	err = devm_add_action_or_reset(dev, drm_panel_put_void, panel);
> +	if (err)
> +		return ERR_PTR(err);
>  
>  	drm_panel_init(panel, dev, funcs, connector_type);
>  
> diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
> index 415e85e8b76a15679f59c944ea152367dc3e0488..31d84f901c514c93ab6cbc09f445853ef897bc95 100644
> --- a/include/drm/drm_panel.h
> +++ b/include/drm/drm_panel.h
> @@ -28,6 +28,7 @@
>  #include <linux/errno.h>
>  #include <linux/list.h>
>  #include <linux/mutex.h>
> +#include <linux/kref.h>
>  
>  struct backlight_device;
>  struct dentry;
> @@ -266,6 +267,17 @@ struct drm_panel {
>  	 * If true then the panel has been enabled.
>  	 */
>  	bool enabled;
> +
> +	/**
> +	 * @container: Pointer to the private driver struct embedding this
> +	 * @struct drm_panel.
> +	 */
> +	void *container;
> +
> +	/**
> +	 * @refcount: reference count of users referencing this panel.
> +	 */
> +	struct kref refcount;
>  };
>  
>  void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
> @@ -282,6 +294,10 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
>   * @connector_type: the connector type (DRM_MODE_CONNECTOR_*) corresponding to
>   * the panel interface
>   *
> + * The reference count of the returned panel is initialized to 1. This
> + * reference will be automatically dropped via devm (by calling
> + * drm_panel_put()) when @dev is removed.
> + *
>   * Returns:
>   * Pointer to container structure embedding the panel, ERR_PTR on failure.
>   */
> @@ -294,6 +310,9 @@ void drm_panel_init(struct drm_panel *panel, struct device *dev,
>  		    const struct drm_panel_funcs *funcs,
>  		    int connector_type);
>  
> +struct drm_panel *drm_panel_get(struct drm_panel *panel);
> +void drm_panel_put(struct drm_panel *panel);
> +
>  void drm_panel_add(struct drm_panel *panel);
>  void drm_panel_remove(struct drm_panel *panel);

-- 
Jani Nikula, Intel

  reply	other threads:[~2025-04-28 16:32 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-31 15:15 [PATCH v4 0/4] drm/panel: Panel Refcounting infrastructure Anusha Srivatsa
2025-03-31 15:15 ` [PATCH v4 1/4] drm/panel: Add new helpers for refcounted panel allocatons Anusha Srivatsa
2025-03-31 15:15 ` [PATCH v4 2/4] drm/panel: Add refcount support Anusha Srivatsa
2025-04-28 16:31   ` Jani Nikula [this message]
2025-04-29  9:00     ` Maxime Ripard
2025-04-29  9:22       ` Jani Nikula
2025-05-05  6:53         ` Maxime Ripard
2025-05-05 18:52           ` Anusha Srivatsa
2025-05-08 14:27             ` Jani Nikula
2025-05-08 21:48               ` Anusha Srivatsa
2025-05-09  9:24                 ` Jani Nikula
2025-05-09 11:41               ` Maxime Ripard
2025-05-09 12:45                 ` Jani Nikula
2025-05-13  2:40                   ` Anusha Srivatsa
2025-05-13 12:19                     ` Jani Nikula
2025-05-13 13:06                   ` Maxime Ripard
2025-05-14  9:22                     ` Jani Nikula
2025-05-16 19:43                       ` Anusha Srivatsa
2025-05-19 12:23                         ` Jani Nikula
2025-05-19 16:05                       ` Maxime Ripard
2025-05-20 10:09                         ` Jani Nikula
2025-05-23 11:34                           ` Jani Nikula
2025-05-27 15:04                             ` Maxime Ripard
2025-05-27 19:24                               ` Jani Nikula
2025-05-27 14:57                           ` Maxime Ripard
2025-05-27 19:40                             ` Jani Nikula
2025-06-06  7:33                               ` Maxime Ripard
2025-06-06  9:11                                 ` Jani Nikula
2025-03-31 15:15 ` [PATCH v4 3/4] drm/panel: deprecate old-style panel allocation Anusha Srivatsa
2025-03-31 15:15 ` [PATCH v4 4/4] drm/panel/panel-simple: Use the new allocation in place of devm_kzalloc() Anusha Srivatsa
2025-04-01 15:05 ` [PATCH v4 0/4] drm/panel: Panel Refcounting infrastructure Maxime Ripard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87y0vkw8ll.fsf@intel.com \
    --to=jani.nikula@linux.intel.com \
    --cc=airlied@gmail.com \
    --cc=asrivats@redhat.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luca.ceresoli@bootlin.com \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mripard@kernel.org \
    --cc=neil.armstrong@linaro.org \
    --cc=quic_jesszhan@quicinc.com \
    --cc=simona@ffwll.ch \
    --cc=tzimmermann@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.