linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] drm/framebuffer: Acquire internal references on GEM handles
@ 2025-07-04  8:53 Thomas Zimmermann
  2025-07-04 12:06 ` Christian König
  2025-07-06 13:21 ` Mario Limonciello
  0 siblings, 2 replies; 5+ messages in thread
From: Thomas Zimmermann @ 2025-07-04  8:53 UTC (permalink / raw)
  To: christian.koenig, asrivats, maarten.lankhorst, mripard, airlied,
	simona, patrik.r.jakobsson
  Cc: dri-devel, Thomas Zimmermann, Bert Karwatzki, Sumit Semwal,
	linux-media, linaro-mm-sig, stable

Acquire GEM handles in drm_framebuffer_init() and release them in
the corresponding drm_framebuffer_cleanup(). Ties the handle's
lifetime to the framebuffer. Not all GEM buffer objects have GEM
handles. If not set, no refcounting takes place. This is the case
for some fbdev emulation. This is not a problem as these GEM objects
do not use dma-bufs and drivers will not release them while fbdev
emulation is running.

As all drivers use drm_framebuffer_init(), they will now all hold
dma-buf references as fixed in commit 5307dce878d4 ("drm/gem: Acquire
references on GEM handles for framebuffers").

In the GEM framebuffer helpers, restore the original ref counting
on buffer objects. As the helpers for handle refcounting are now
no longer called from outside the DRM core, unexport the symbols.

Gma500 (unnecessarily) clears the framebuffer's GEM-object pointer
before calling drm_framebuffer_cleanup(). Remove these lines to
make it consistent with the rest of the drivers. It's one of the
fbdev emulations with no GEM handle on their buffers. The change
to gma500 is therefore rather cosmetic.

Tested on i915, amdgpu (by Bert) and gma500. Also tested on i915
plus udl for the original problem with dma-buf sharing.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Fixes: 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers")
Reported-by: Bert Karwatzki <spasswolf@web.de>
Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/
Tested-by: Bert Karwatzki <spasswolf@web.de>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Anusha Srivatsa <asrivats@redhat.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: "Christian König" <christian.koenig@amd.com>
Cc: linux-media@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: linaro-mm-sig@lists.linaro.org
Cc: <stable@vger.kernel.org>
---
 drivers/gpu/drm/drm_framebuffer.c            | 23 +++++++-
 drivers/gpu/drm/drm_gem.c                    | 59 +++++++++++++-------
 drivers/gpu/drm/drm_gem_framebuffer_helper.c | 16 +++---
 drivers/gpu/drm/drm_internal.h               |  4 +-
 drivers/gpu/drm/gma500/fbdev.c               |  2 -
 5 files changed, 69 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index b781601946db..e4a10dd053fc 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -862,11 +862,17 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_framebuffer_free);
 int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
 			 const struct drm_framebuffer_funcs *funcs)
 {
+	unsigned int i;
 	int ret;
 
 	if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
 		return -EINVAL;
 
+	for (i = 0; i < fb->format->num_planes; i++) {
+		if (fb->obj[i])
+			drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
+	}
+
 	INIT_LIST_HEAD(&fb->filp_head);
 
 	fb->funcs = funcs;
@@ -875,7 +881,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
 	ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
 				    false, drm_framebuffer_free);
 	if (ret)
-		goto out;
+		goto err;
 
 	mutex_lock(&dev->mode_config.fb_lock);
 	dev->mode_config.num_fb++;
@@ -883,7 +889,14 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
 	mutex_unlock(&dev->mode_config.fb_lock);
 
 	drm_mode_object_register(dev, &fb->base);
-out:
+
+	return 0;
+
+err:
+	for (i = 0; i < fb->format->num_planes; i++) {
+		if (fb->obj[i])
+			drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
+	}
 	return ret;
 }
 EXPORT_SYMBOL(drm_framebuffer_init);
@@ -960,6 +973,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
 void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = fb->dev;
+	unsigned int i;
+
+	for (i = 0; i < fb->format->num_planes; i++) {
+		if (fb->obj[i])
+			drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
+	}
 
 	mutex_lock(&dev->mode_config.fb_lock);
 	list_del(&fb->head);
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index bc505d938b3e..9d8b9e6b7d25 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -224,23 +224,27 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj)
 }
 
 /**
- * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
+ * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
  * @obj: GEM object
  *
- * Acquires a reference on the GEM buffer object's handle. Required
- * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
- * to release the reference.
+ * Acquires a reference on the GEM buffer object's handle. Required to keep
+ * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
+ * to release the reference. Does nothing if the buffer object has no handle.
  */
-void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
+void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
 {
 	struct drm_device *dev = obj->dev;
 
 	guard(mutex)(&dev->object_name_lock);
 
-	drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
-	drm_gem_object_handle_get(obj);
+	/*
+	 * First ref taken during GEM object creation, if any. Some
+	 * drivers set up internal framebuffers with GEM objects that
+	 * do not have a GEM handle. Hence, this counter can be zero.
+	 */
+	if (obj->handle_count)
+		drm_gem_object_handle_get(obj);
 }
-EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
 
 /**
  * drm_gem_object_handle_free - release resources bound to userspace handles
@@ -272,21 +276,11 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
 	}
 }
 
-/**
- * drm_gem_object_handle_put_unlocked - releases reference on user-space handles
- * @obj: GEM object
- *
- * Releases a reference on the GEM buffer object's handle. Possibly releases
- * the GEM buffer object and associated dma-buf objects.
- */
-void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
+static void drm_gem_object_handle_put_unlocked_tail(struct drm_gem_object *obj)
 {
 	struct drm_device *dev = obj->dev;
 	bool final = false;
 
-	if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
-		return;
-
 	/*
 	* Must bump handle count first as this may be the last
 	* ref, in which case the object would disappear before we
@@ -304,7 +298,32 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
 	if (final)
 		drm_gem_object_put(obj);
 }
-EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
+
+static void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
+{
+	struct drm_device *dev = obj->dev;
+
+	if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
+		return;
+
+	drm_gem_object_handle_put_unlocked_tail(obj);
+}
+
+/**
+ * drm_gem_object_handle_put_if_exists_unlocked - releases reference on user-space handle, if any
+ * @obj: GEM object
+ *
+ * Releases a reference on the GEM buffer object's handle. Possibly releases
+ * the GEM buffer object and associated dma-buf objects. Does nothing if the
+ * buffer object has no handle.
+ */
+void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj)
+{
+	if (!obj->handle_count)
+		return;
+
+	drm_gem_object_handle_put_unlocked_tail(obj);
+}
 
 /*
  * Called at device or object close to release the file's
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index c60d0044d036..618ce725cd75 100644
--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
@@ -100,7 +100,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
 	unsigned int i;
 
 	for (i = 0; i < fb->format->num_planes; i++)
-		drm_gem_object_handle_put_unlocked(fb->obj[i]);
+		drm_gem_object_put(fb->obj[i]);
 
 	drm_framebuffer_cleanup(fb);
 	kfree(fb);
@@ -183,10 +183,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
 		if (!objs[i]) {
 			drm_dbg_kms(dev, "Failed to lookup GEM object\n");
 			ret = -ENOENT;
-			goto err_gem_object_handle_put_unlocked;
+			goto err_gem_object_put;
 		}
-		drm_gem_object_handle_get_unlocked(objs[i]);
-		drm_gem_object_put(objs[i]);
 
 		min_size = (height - 1) * mode_cmd->pitches[i]
 			 + drm_format_info_min_pitch(info, i, width)
@@ -196,22 +194,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
 			drm_dbg_kms(dev,
 				    "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
 				    objs[i]->size, min_size, i);
-			drm_gem_object_handle_put_unlocked(objs[i]);
+			drm_gem_object_put(objs[i]);
 			ret = -EINVAL;
-			goto err_gem_object_handle_put_unlocked;
+			goto err_gem_object_put;
 		}
 	}
 
 	ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
 	if (ret)
-		goto err_gem_object_handle_put_unlocked;
+		goto err_gem_object_put;
 
 	return 0;
 
-err_gem_object_handle_put_unlocked:
+err_gem_object_put:
 	while (i > 0) {
 		--i;
-		drm_gem_object_handle_put_unlocked(objs[i]);
+		drm_gem_object_put(objs[i]);
 	}
 	return ret;
 }
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index f7b414a813ae..9233019f54a8 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -161,8 +161,8 @@ void drm_sysfs_lease_event(struct drm_device *dev);
 
 /* drm_gem.c */
 int drm_gem_init(struct drm_device *dev);
-void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
-void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
+void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
+void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj);
 int drm_gem_handle_create_tail(struct drm_file *file_priv,
 			       struct drm_gem_object *obj,
 			       u32 *handlep);
diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c
index 8edefea2ef59..afd252108cfa 100644
--- a/drivers/gpu/drm/gma500/fbdev.c
+++ b/drivers/gpu/drm/gma500/fbdev.c
@@ -121,7 +121,6 @@ static void psb_fbdev_fb_destroy(struct fb_info *info)
 	drm_fb_helper_fini(fb_helper);
 
 	drm_framebuffer_unregister_private(fb);
-	fb->obj[0] = NULL;
 	drm_framebuffer_cleanup(fb);
 	kfree(fb);
 
@@ -243,7 +242,6 @@ int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
 
 err_drm_framebuffer_unregister_private:
 	drm_framebuffer_unregister_private(fb);
-	fb->obj[0] = NULL;
 	drm_framebuffer_cleanup(fb);
 	kfree(fb);
 err_drm_gem_object_put:
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] drm/framebuffer: Acquire internal references on GEM handles
  2025-07-04  8:53 [PATCH] drm/framebuffer: Acquire internal references on GEM handles Thomas Zimmermann
@ 2025-07-04 12:06 ` Christian König
  2025-07-04 12:31   ` Thomas Zimmermann
  2025-07-06 13:21 ` Mario Limonciello
  1 sibling, 1 reply; 5+ messages in thread
From: Christian König @ 2025-07-04 12:06 UTC (permalink / raw)
  To: Thomas Zimmermann, asrivats, maarten.lankhorst, mripard, airlied,
	simona, patrik.r.jakobsson
  Cc: dri-devel, Bert Karwatzki, Sumit Semwal, linux-media,
	linaro-mm-sig, stable

On 04.07.25 10:53, Thomas Zimmermann wrote:
> Acquire GEM handles in drm_framebuffer_init() and release them in
> the corresponding drm_framebuffer_cleanup(). Ties the handle's
> lifetime to the framebuffer. Not all GEM buffer objects have GEM
> handles. If not set, no refcounting takes place. This is the case
> for some fbdev emulation. This is not a problem as these GEM objects
> do not use dma-bufs and drivers will not release them while fbdev
> emulation is running.
> 
> As all drivers use drm_framebuffer_init(), they will now all hold
> dma-buf references as fixed in commit 5307dce878d4 ("drm/gem: Acquire
> references on GEM handles for framebuffers").
> 
> In the GEM framebuffer helpers, restore the original ref counting
> on buffer objects. As the helpers for handle refcounting are now
> no longer called from outside the DRM core, unexport the symbols.
> 
> Gma500 (unnecessarily) clears the framebuffer's GEM-object pointer
> before calling drm_framebuffer_cleanup(). Remove these lines to
> make it consistent with the rest of the drivers. It's one of the
> fbdev emulations with no GEM handle on their buffers. The change
> to gma500 is therefore rather cosmetic.

Could we separate that change out? I mean we want to backport the patch.

> 
> Tested on i915, amdgpu (by Bert) and gma500. Also tested on i915
> plus udl for the original problem with dma-buf sharing.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Fixes: 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers")
> Reported-by: Bert Karwatzki <spasswolf@web.de>
> Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/
> Tested-by: Bert Karwatzki <spasswolf@web.de>
> Cc: Thomas Zimmermann <tzimmermann@suse.de>
> Cc: Anusha Srivatsa <asrivats@redhat.com>
> Cc: Christian König <christian.koenig@amd.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Maxime Ripard <mripard@kernel.org>
> Cc: Sumit Semwal <sumit.semwal@linaro.org>
> Cc: "Christian König" <christian.koenig@amd.com>
> Cc: linux-media@vger.kernel.org
> Cc: dri-devel@lists.freedesktop.org
> Cc: linaro-mm-sig@lists.linaro.org
> Cc: <stable@vger.kernel.org>
> ---
>  drivers/gpu/drm/drm_framebuffer.c            | 23 +++++++-
>  drivers/gpu/drm/drm_gem.c                    | 59 +++++++++++++-------
>  drivers/gpu/drm/drm_gem_framebuffer_helper.c | 16 +++---
>  drivers/gpu/drm/drm_internal.h               |  4 +-
>  drivers/gpu/drm/gma500/fbdev.c               |  2 -
>  5 files changed, 69 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
> index b781601946db..e4a10dd053fc 100644
> --- a/drivers/gpu/drm/drm_framebuffer.c
> +++ b/drivers/gpu/drm/drm_framebuffer.c
> @@ -862,11 +862,17 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_framebuffer_free);
>  int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>  			 const struct drm_framebuffer_funcs *funcs)
>  {
> +	unsigned int i;
>  	int ret;
>  
>  	if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
>  		return -EINVAL;
>  
> +	for (i = 0; i < fb->format->num_planes; i++) {
> +		if (fb->obj[i])
> +			drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
> +	}
> +
>  	INIT_LIST_HEAD(&fb->filp_head);
>  
>  	fb->funcs = funcs;
> @@ -875,7 +881,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>  	ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
>  				    false, drm_framebuffer_free);
>  	if (ret)
> -		goto out;
> +		goto err;
>  
>  	mutex_lock(&dev->mode_config.fb_lock);
>  	dev->mode_config.num_fb++;
> @@ -883,7 +889,14 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>  	mutex_unlock(&dev->mode_config.fb_lock);
>  
>  	drm_mode_object_register(dev, &fb->base);
> -out:
> +
> +	return 0;
> +
> +err:
> +	for (i = 0; i < fb->format->num_planes; i++) {
> +		if (fb->obj[i])
> +			drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
> +	}
>  	return ret;
>  }
>  EXPORT_SYMBOL(drm_framebuffer_init);
> @@ -960,6 +973,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
>  void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
>  {
>  	struct drm_device *dev = fb->dev;
> +	unsigned int i;
> +
> +	for (i = 0; i < fb->format->num_planes; i++) {
> +		if (fb->obj[i])
> +			drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
> +	}

That goes boom as soon as somebody grabs a GEM handle for the FB used for fbdev emulation (which is perfectly possible with the UAPI but not done currently as far as I know).

It's probably ok for a bug fix we are going to backport, but a more robust long term solution is really desired here I think.

Regards,
Christian.

>  
>  	mutex_lock(&dev->mode_config.fb_lock);
>  	list_del(&fb->head);
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index bc505d938b3e..9d8b9e6b7d25 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -224,23 +224,27 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj)
>  }
>  
>  /**
> - * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
> + * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
>   * @obj: GEM object
>   *
> - * Acquires a reference on the GEM buffer object's handle. Required
> - * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
> - * to release the reference.
> + * Acquires a reference on the GEM buffer object's handle. Required to keep
> + * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
> + * to release the reference. Does nothing if the buffer object has no handle.
>   */
> -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
> +void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
>  {
>  	struct drm_device *dev = obj->dev;
>  
>  	guard(mutex)(&dev->object_name_lock);
>  
> -	drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
> -	drm_gem_object_handle_get(obj);
> +	/*
> +	 * First ref taken during GEM object creation, if any. Some
> +	 * drivers set up internal framebuffers with GEM objects that
> +	 * do not have a GEM handle. Hence, this counter can be zero.
> +	 */
> +	if (obj->handle_count)
> +		drm_gem_object_handle_get(obj);
>  }
> -EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
>  
>  /**
>   * drm_gem_object_handle_free - release resources bound to userspace handles
> @@ -272,21 +276,11 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
>  	}
>  }
>  
> -/**
> - * drm_gem_object_handle_put_unlocked - releases reference on user-space handles
> - * @obj: GEM object
> - *
> - * Releases a reference on the GEM buffer object's handle. Possibly releases
> - * the GEM buffer object and associated dma-buf objects.
> - */
> -void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
> +static void drm_gem_object_handle_put_unlocked_tail(struct drm_gem_object *obj)
>  {
>  	struct drm_device *dev = obj->dev;
>  	bool final = false;
>  
> -	if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
> -		return;
> -
>  	/*
>  	* Must bump handle count first as this may be the last
>  	* ref, in which case the object would disappear before we
> @@ -304,7 +298,32 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
>  	if (final)
>  		drm_gem_object_put(obj);
>  }
> -EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
> +
> +static void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
> +{
> +	struct drm_device *dev = obj->dev;
> +
> +	if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
> +		return;
> +
> +	drm_gem_object_handle_put_unlocked_tail(obj);
> +}
> +
> +/**
> + * drm_gem_object_handle_put_if_exists_unlocked - releases reference on user-space handle, if any
> + * @obj: GEM object
> + *
> + * Releases a reference on the GEM buffer object's handle. Possibly releases
> + * the GEM buffer object and associated dma-buf objects. Does nothing if the
> + * buffer object has no handle.
> + */
> +void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj)
> +{
> +	if (!obj->handle_count)
> +		return;
> +
> +	drm_gem_object_handle_put_unlocked_tail(obj);
> +}
>  
>  /*
>   * Called at device or object close to release the file's
> diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
> index c60d0044d036..618ce725cd75 100644
> --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
> +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
> @@ -100,7 +100,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
>  	unsigned int i;
>  
>  	for (i = 0; i < fb->format->num_planes; i++)
> -		drm_gem_object_handle_put_unlocked(fb->obj[i]);
> +		drm_gem_object_put(fb->obj[i]);
>  
>  	drm_framebuffer_cleanup(fb);
>  	kfree(fb);
> @@ -183,10 +183,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
>  		if (!objs[i]) {
>  			drm_dbg_kms(dev, "Failed to lookup GEM object\n");
>  			ret = -ENOENT;
> -			goto err_gem_object_handle_put_unlocked;
> +			goto err_gem_object_put;
>  		}
> -		drm_gem_object_handle_get_unlocked(objs[i]);
> -		drm_gem_object_put(objs[i]);
>  
>  		min_size = (height - 1) * mode_cmd->pitches[i]
>  			 + drm_format_info_min_pitch(info, i, width)
> @@ -196,22 +194,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
>  			drm_dbg_kms(dev,
>  				    "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
>  				    objs[i]->size, min_size, i);
> -			drm_gem_object_handle_put_unlocked(objs[i]);
> +			drm_gem_object_put(objs[i]);
>  			ret = -EINVAL;
> -			goto err_gem_object_handle_put_unlocked;
> +			goto err_gem_object_put;
>  		}
>  	}
>  
>  	ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
>  	if (ret)
> -		goto err_gem_object_handle_put_unlocked;
> +		goto err_gem_object_put;
>  
>  	return 0;
>  
> -err_gem_object_handle_put_unlocked:
> +err_gem_object_put:
>  	while (i > 0) {
>  		--i;
> -		drm_gem_object_handle_put_unlocked(objs[i]);
> +		drm_gem_object_put(objs[i]);
>  	}
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> index f7b414a813ae..9233019f54a8 100644
> --- a/drivers/gpu/drm/drm_internal.h
> +++ b/drivers/gpu/drm/drm_internal.h
> @@ -161,8 +161,8 @@ void drm_sysfs_lease_event(struct drm_device *dev);
>  
>  /* drm_gem.c */
>  int drm_gem_init(struct drm_device *dev);
> -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
> -void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
> +void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
> +void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj);
>  int drm_gem_handle_create_tail(struct drm_file *file_priv,
>  			       struct drm_gem_object *obj,
>  			       u32 *handlep);
> diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c
> index 8edefea2ef59..afd252108cfa 100644
> --- a/drivers/gpu/drm/gma500/fbdev.c
> +++ b/drivers/gpu/drm/gma500/fbdev.c
> @@ -121,7 +121,6 @@ static void psb_fbdev_fb_destroy(struct fb_info *info)
>  	drm_fb_helper_fini(fb_helper);
>  
>  	drm_framebuffer_unregister_private(fb);
> -	fb->obj[0] = NULL;
>  	drm_framebuffer_cleanup(fb);
>  	kfree(fb);
>  
> @@ -243,7 +242,6 @@ int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
>  
>  err_drm_framebuffer_unregister_private:
>  	drm_framebuffer_unregister_private(fb);
> -	fb->obj[0] = NULL;
>  	drm_framebuffer_cleanup(fb);
>  	kfree(fb);
>  err_drm_gem_object_put:


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] drm/framebuffer: Acquire internal references on GEM handles
  2025-07-04 12:06 ` Christian König
@ 2025-07-04 12:31   ` Thomas Zimmermann
  2025-07-04 14:10     ` Christian König
  0 siblings, 1 reply; 5+ messages in thread
From: Thomas Zimmermann @ 2025-07-04 12:31 UTC (permalink / raw)
  To: Christian König, asrivats, maarten.lankhorst, mripard,
	airlied, simona, patrik.r.jakobsson
  Cc: dri-devel, Bert Karwatzki, Sumit Semwal, linux-media,
	linaro-mm-sig, stable

Hi

Am 04.07.25 um 14:06 schrieb Christian König:
> On 04.07.25 10:53, Thomas Zimmermann wrote:
>> Acquire GEM handles in drm_framebuffer_init() and release them in
>> the corresponding drm_framebuffer_cleanup(). Ties the handle's
>> lifetime to the framebuffer. Not all GEM buffer objects have GEM
>> handles. If not set, no refcounting takes place. This is the case
>> for some fbdev emulation. This is not a problem as these GEM objects
>> do not use dma-bufs and drivers will not release them while fbdev
>> emulation is running.
>>
>> As all drivers use drm_framebuffer_init(), they will now all hold
>> dma-buf references as fixed in commit 5307dce878d4 ("drm/gem: Acquire
>> references on GEM handles for framebuffers").
>>
>> In the GEM framebuffer helpers, restore the original ref counting
>> on buffer objects. As the helpers for handle refcounting are now
>> no longer called from outside the DRM core, unexport the symbols.
>>
>> Gma500 (unnecessarily) clears the framebuffer's GEM-object pointer
>> before calling drm_framebuffer_cleanup(). Remove these lines to
>> make it consistent with the rest of the drivers. It's one of the
>> fbdev emulations with no GEM handle on their buffers. The change
>> to gma500 is therefore rather cosmetic.
> Could we separate that change out? I mean we want to backport the patch.

Sure. gma500 doesn't use handles for its fbdev emulation. So nothing 
changes.

>
>> Tested on i915, amdgpu (by Bert) and gma500. Also tested on i915
>> plus udl for the original problem with dma-buf sharing.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> Fixes: 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers")
>> Reported-by: Bert Karwatzki <spasswolf@web.de>
>> Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/
>> Tested-by: Bert Karwatzki <spasswolf@web.de>
>> Cc: Thomas Zimmermann <tzimmermann@suse.de>
>> Cc: Anusha Srivatsa <asrivats@redhat.com>
>> Cc: Christian König <christian.koenig@amd.com>
>> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>> Cc: Maxime Ripard <mripard@kernel.org>
>> Cc: Sumit Semwal <sumit.semwal@linaro.org>
>> Cc: "Christian König" <christian.koenig@amd.com>
>> Cc: linux-media@vger.kernel.org
>> Cc: dri-devel@lists.freedesktop.org
>> Cc: linaro-mm-sig@lists.linaro.org
>> Cc: <stable@vger.kernel.org>
>> ---
>>   drivers/gpu/drm/drm_framebuffer.c            | 23 +++++++-
>>   drivers/gpu/drm/drm_gem.c                    | 59 +++++++++++++-------
>>   drivers/gpu/drm/drm_gem_framebuffer_helper.c | 16 +++---
>>   drivers/gpu/drm/drm_internal.h               |  4 +-
>>   drivers/gpu/drm/gma500/fbdev.c               |  2 -
>>   5 files changed, 69 insertions(+), 35 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
>> index b781601946db..e4a10dd053fc 100644
>> --- a/drivers/gpu/drm/drm_framebuffer.c
>> +++ b/drivers/gpu/drm/drm_framebuffer.c
>> @@ -862,11 +862,17 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_framebuffer_free);
>>   int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>>   			 const struct drm_framebuffer_funcs *funcs)
>>   {
>> +	unsigned int i;
>>   	int ret;
>>   
>>   	if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
>>   		return -EINVAL;
>>   
>> +	for (i = 0; i < fb->format->num_planes; i++) {
>> +		if (fb->obj[i])
>> +			drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
>> +	}
>> +
>>   	INIT_LIST_HEAD(&fb->filp_head);
>>   
>>   	fb->funcs = funcs;
>> @@ -875,7 +881,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>>   	ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
>>   				    false, drm_framebuffer_free);
>>   	if (ret)
>> -		goto out;
>> +		goto err;
>>   
>>   	mutex_lock(&dev->mode_config.fb_lock);
>>   	dev->mode_config.num_fb++;
>> @@ -883,7 +889,14 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>>   	mutex_unlock(&dev->mode_config.fb_lock);
>>   
>>   	drm_mode_object_register(dev, &fb->base);
>> -out:
>> +
>> +	return 0;
>> +
>> +err:
>> +	for (i = 0; i < fb->format->num_planes; i++) {
>> +		if (fb->obj[i])
>> +			drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
>> +	}
>>   	return ret;
>>   }
>>   EXPORT_SYMBOL(drm_framebuffer_init);
>> @@ -960,6 +973,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
>>   void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
>>   {
>>   	struct drm_device *dev = fb->dev;
>> +	unsigned int i;
>> +
>> +	for (i = 0; i < fb->format->num_planes; i++) {
>> +		if (fb->obj[i])
>> +			drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
>> +	}
> That goes boom as soon as somebody grabs a GEM handle for the FB used for fbdev emulation (which is perfectly possible with the UAPI but not done currently as far as I know).

My uninformed question: how so? I thought userspace gets the handle from 
allocating buffers (e.g., CREATE_DUMB or driver ioctl). That object 
would be distinct from the fbdev object.

>
> It's probably ok for a bug fix we are going to backport, but a more robust long term solution is really desired here I think.

There are only 4 GEM objects per framebuffer at most. So we could flag 
each plane with a bit in struct drm_framebuffer.flags when we acquire 
the handle in drm_framebuffer_init(). _cleanup() would then only unref 
those with the flag set. Does that work?

Best regards
Thomas

>
> Regards,
> Christian.
>
>>   
>>   	mutex_lock(&dev->mode_config.fb_lock);
>>   	list_del(&fb->head);
>> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
>> index bc505d938b3e..9d8b9e6b7d25 100644
>> --- a/drivers/gpu/drm/drm_gem.c
>> +++ b/drivers/gpu/drm/drm_gem.c
>> @@ -224,23 +224,27 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj)
>>   }
>>   
>>   /**
>> - * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
>> + * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
>>    * @obj: GEM object
>>    *
>> - * Acquires a reference on the GEM buffer object's handle. Required
>> - * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
>> - * to release the reference.
>> + * Acquires a reference on the GEM buffer object's handle. Required to keep
>> + * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
>> + * to release the reference. Does nothing if the buffer object has no handle.
>>    */
>> -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
>> +void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
>>   {
>>   	struct drm_device *dev = obj->dev;
>>   
>>   	guard(mutex)(&dev->object_name_lock);
>>   
>> -	drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
>> -	drm_gem_object_handle_get(obj);
>> +	/*
>> +	 * First ref taken during GEM object creation, if any. Some
>> +	 * drivers set up internal framebuffers with GEM objects that
>> +	 * do not have a GEM handle. Hence, this counter can be zero.
>> +	 */
>> +	if (obj->handle_count)
>> +		drm_gem_object_handle_get(obj);
>>   }
>> -EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
>>   
>>   /**
>>    * drm_gem_object_handle_free - release resources bound to userspace handles
>> @@ -272,21 +276,11 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
>>   	}
>>   }
>>   
>> -/**
>> - * drm_gem_object_handle_put_unlocked - releases reference on user-space handles
>> - * @obj: GEM object
>> - *
>> - * Releases a reference on the GEM buffer object's handle. Possibly releases
>> - * the GEM buffer object and associated dma-buf objects.
>> - */
>> -void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
>> +static void drm_gem_object_handle_put_unlocked_tail(struct drm_gem_object *obj)
>>   {
>>   	struct drm_device *dev = obj->dev;
>>   	bool final = false;
>>   
>> -	if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
>> -		return;
>> -
>>   	/*
>>   	* Must bump handle count first as this may be the last
>>   	* ref, in which case the object would disappear before we
>> @@ -304,7 +298,32 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
>>   	if (final)
>>   		drm_gem_object_put(obj);
>>   }
>> -EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
>> +
>> +static void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
>> +{
>> +	struct drm_device *dev = obj->dev;
>> +
>> +	if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
>> +		return;
>> +
>> +	drm_gem_object_handle_put_unlocked_tail(obj);
>> +}
>> +
>> +/**
>> + * drm_gem_object_handle_put_if_exists_unlocked - releases reference on user-space handle, if any
>> + * @obj: GEM object
>> + *
>> + * Releases a reference on the GEM buffer object's handle. Possibly releases
>> + * the GEM buffer object and associated dma-buf objects. Does nothing if the
>> + * buffer object has no handle.
>> + */
>> +void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj)
>> +{
>> +	if (!obj->handle_count)
>> +		return;
>> +
>> +	drm_gem_object_handle_put_unlocked_tail(obj);
>> +}
>>   
>>   /*
>>    * Called at device or object close to release the file's
>> diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
>> index c60d0044d036..618ce725cd75 100644
>> --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
>> +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
>> @@ -100,7 +100,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
>>   	unsigned int i;
>>   
>>   	for (i = 0; i < fb->format->num_planes; i++)
>> -		drm_gem_object_handle_put_unlocked(fb->obj[i]);
>> +		drm_gem_object_put(fb->obj[i]);
>>   
>>   	drm_framebuffer_cleanup(fb);
>>   	kfree(fb);
>> @@ -183,10 +183,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
>>   		if (!objs[i]) {
>>   			drm_dbg_kms(dev, "Failed to lookup GEM object\n");
>>   			ret = -ENOENT;
>> -			goto err_gem_object_handle_put_unlocked;
>> +			goto err_gem_object_put;
>>   		}
>> -		drm_gem_object_handle_get_unlocked(objs[i]);
>> -		drm_gem_object_put(objs[i]);
>>   
>>   		min_size = (height - 1) * mode_cmd->pitches[i]
>>   			 + drm_format_info_min_pitch(info, i, width)
>> @@ -196,22 +194,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
>>   			drm_dbg_kms(dev,
>>   				    "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
>>   				    objs[i]->size, min_size, i);
>> -			drm_gem_object_handle_put_unlocked(objs[i]);
>> +			drm_gem_object_put(objs[i]);
>>   			ret = -EINVAL;
>> -			goto err_gem_object_handle_put_unlocked;
>> +			goto err_gem_object_put;
>>   		}
>>   	}
>>   
>>   	ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
>>   	if (ret)
>> -		goto err_gem_object_handle_put_unlocked;
>> +		goto err_gem_object_put;
>>   
>>   	return 0;
>>   
>> -err_gem_object_handle_put_unlocked:
>> +err_gem_object_put:
>>   	while (i > 0) {
>>   		--i;
>> -		drm_gem_object_handle_put_unlocked(objs[i]);
>> +		drm_gem_object_put(objs[i]);
>>   	}
>>   	return ret;
>>   }
>> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
>> index f7b414a813ae..9233019f54a8 100644
>> --- a/drivers/gpu/drm/drm_internal.h
>> +++ b/drivers/gpu/drm/drm_internal.h
>> @@ -161,8 +161,8 @@ void drm_sysfs_lease_event(struct drm_device *dev);
>>   
>>   /* drm_gem.c */
>>   int drm_gem_init(struct drm_device *dev);
>> -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
>> -void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
>> +void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
>> +void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj);
>>   int drm_gem_handle_create_tail(struct drm_file *file_priv,
>>   			       struct drm_gem_object *obj,
>>   			       u32 *handlep);
>> diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c
>> index 8edefea2ef59..afd252108cfa 100644
>> --- a/drivers/gpu/drm/gma500/fbdev.c
>> +++ b/drivers/gpu/drm/gma500/fbdev.c
>> @@ -121,7 +121,6 @@ static void psb_fbdev_fb_destroy(struct fb_info *info)
>>   	drm_fb_helper_fini(fb_helper);
>>   
>>   	drm_framebuffer_unregister_private(fb);
>> -	fb->obj[0] = NULL;
>>   	drm_framebuffer_cleanup(fb);
>>   	kfree(fb);
>>   
>> @@ -243,7 +242,6 @@ int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
>>   
>>   err_drm_framebuffer_unregister_private:
>>   	drm_framebuffer_unregister_private(fb);
>> -	fb->obj[0] = NULL;
>>   	drm_framebuffer_cleanup(fb);
>>   	kfree(fb);
>>   err_drm_gem_object_put:

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] drm/framebuffer: Acquire internal references on GEM handles
  2025-07-04 12:31   ` Thomas Zimmermann
@ 2025-07-04 14:10     ` Christian König
  0 siblings, 0 replies; 5+ messages in thread
From: Christian König @ 2025-07-04 14:10 UTC (permalink / raw)
  To: Thomas Zimmermann, asrivats, maarten.lankhorst, mripard, airlied,
	simona, patrik.r.jakobsson
  Cc: dri-devel, Bert Karwatzki, Sumit Semwal, linux-media,
	linaro-mm-sig, stable

On 04.07.25 14:31, Thomas Zimmermann wrote:
> Hi
> 
> Am 04.07.25 um 14:06 schrieb Christian König:
>> On 04.07.25 10:53, Thomas Zimmermann wrote:
>>> Acquire GEM handles in drm_framebuffer_init() and release them in
>>> the corresponding drm_framebuffer_cleanup(). Ties the handle's
>>> lifetime to the framebuffer. Not all GEM buffer objects have GEM
>>> handles. If not set, no refcounting takes place. This is the case
>>> for some fbdev emulation. This is not a problem as these GEM objects
>>> do not use dma-bufs and drivers will not release them while fbdev
>>> emulation is running.
>>>
>>> As all drivers use drm_framebuffer_init(), they will now all hold
>>> dma-buf references as fixed in commit 5307dce878d4 ("drm/gem: Acquire
>>> references on GEM handles for framebuffers").
>>>
>>> In the GEM framebuffer helpers, restore the original ref counting
>>> on buffer objects. As the helpers for handle refcounting are now
>>> no longer called from outside the DRM core, unexport the symbols.
>>>
>>> Gma500 (unnecessarily) clears the framebuffer's GEM-object pointer
>>> before calling drm_framebuffer_cleanup(). Remove these lines to
>>> make it consistent with the rest of the drivers. It's one of the
>>> fbdev emulations with no GEM handle on their buffers. The change
>>> to gma500 is therefore rather cosmetic.
>> Could we separate that change out? I mean we want to backport the patch.
> 
> Sure. gma500 doesn't use handles for its fbdev emulation. So nothing changes.
> 
>>
>>> Tested on i915, amdgpu (by Bert) and gma500. Also tested on i915
>>> plus udl for the original problem with dma-buf sharing.
>>>
>>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>>> Fixes: 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers")
>>> Reported-by: Bert Karwatzki <spasswolf@web.de>
>>> Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/
>>> Tested-by: Bert Karwatzki <spasswolf@web.de>
>>> Cc: Thomas Zimmermann <tzimmermann@suse.de>
>>> Cc: Anusha Srivatsa <asrivats@redhat.com>
>>> Cc: Christian König <christian.koenig@amd.com>
>>> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
>>> Cc: Maxime Ripard <mripard@kernel.org>
>>> Cc: Sumit Semwal <sumit.semwal@linaro.org>
>>> Cc: "Christian König" <christian.koenig@amd.com>
>>> Cc: linux-media@vger.kernel.org
>>> Cc: dri-devel@lists.freedesktop.org
>>> Cc: linaro-mm-sig@lists.linaro.org
>>> Cc: <stable@vger.kernel.org>
>>> ---
>>>   drivers/gpu/drm/drm_framebuffer.c            | 23 +++++++-
>>>   drivers/gpu/drm/drm_gem.c                    | 59 +++++++++++++-------
>>>   drivers/gpu/drm/drm_gem_framebuffer_helper.c | 16 +++---
>>>   drivers/gpu/drm/drm_internal.h               |  4 +-
>>>   drivers/gpu/drm/gma500/fbdev.c               |  2 -
>>>   5 files changed, 69 insertions(+), 35 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
>>> index b781601946db..e4a10dd053fc 100644
>>> --- a/drivers/gpu/drm/drm_framebuffer.c
>>> +++ b/drivers/gpu/drm/drm_framebuffer.c
>>> @@ -862,11 +862,17 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_framebuffer_free);
>>>   int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>>>                const struct drm_framebuffer_funcs *funcs)
>>>   {
>>> +    unsigned int i;
>>>       int ret;
>>>         if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
>>>           return -EINVAL;
>>>   +    for (i = 0; i < fb->format->num_planes; i++) {
>>> +        if (fb->obj[i])
>>> +            drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
>>> +    }
>>> +
>>>       INIT_LIST_HEAD(&fb->filp_head);
>>>         fb->funcs = funcs;
>>> @@ -875,7 +881,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>>>       ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
>>>                       false, drm_framebuffer_free);
>>>       if (ret)
>>> -        goto out;
>>> +        goto err;
>>>         mutex_lock(&dev->mode_config.fb_lock);
>>>       dev->mode_config.num_fb++;
>>> @@ -883,7 +889,14 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>>>       mutex_unlock(&dev->mode_config.fb_lock);
>>>         drm_mode_object_register(dev, &fb->base);
>>> -out:
>>> +
>>> +    return 0;
>>> +
>>> +err:
>>> +    for (i = 0; i < fb->format->num_planes; i++) {
>>> +        if (fb->obj[i])
>>> +            drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
>>> +    }
>>>       return ret;
>>>   }
>>>   EXPORT_SYMBOL(drm_framebuffer_init);
>>> @@ -960,6 +973,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
>>>   void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
>>>   {
>>>       struct drm_device *dev = fb->dev;
>>> +    unsigned int i;
>>> +
>>> +    for (i = 0; i < fb->format->num_planes; i++) {
>>> +        if (fb->obj[i])
>>> +            drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
>>> +    }
>> That goes boom as soon as somebody grabs a GEM handle for the FB used for fbdev emulation (which is perfectly possible with the UAPI but not done currently as far as I know).
> 
> My uninformed question: how so? I thought userspace gets the handle from allocating buffers (e.g., CREATE_DUMB or driver ioctl). That object would be distinct from the fbdev object.

The DRM_IOCTL_MODE_GETFB and DRM_IOCTL_MODE_GETFB2 IOCTLs can create handles for the GEM objects in a FB.

So for GEM objects created for fbdev emulation the handle count could go from 0->1 by this.

>>
>> It's probably ok for a bug fix we are going to backport, but a more robust long term solution is really desired here I think.
> 
> There are only 4 GEM objects per framebuffer at most. So we could flag each plane with a bit in struct drm_framebuffer.flags when we acquire the handle in drm_framebuffer_init(). _cleanup() would then only unref those with the flag set. Does that work?

That is what I had in mind as well, yes.

Alternatively we could potentially disallow the transition of the handle count from 0->1 by the DRM_IOCTL_MODE_GETFB and DRM_IOCTL_MODE_GETFB2 IOCTLs.

But my gut feeling is having the flags in the framebuffer object is the more defensive approach. E.g. less potential to backfire.

Regards,
Christian.

> 
> Best regards
> Thomas
> 
>>
>> Regards,
>> Christian.
>>
>>>         mutex_lock(&dev->mode_config.fb_lock);
>>>       list_del(&fb->head);
>>> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
>>> index bc505d938b3e..9d8b9e6b7d25 100644
>>> --- a/drivers/gpu/drm/drm_gem.c
>>> +++ b/drivers/gpu/drm/drm_gem.c
>>> @@ -224,23 +224,27 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj)
>>>   }
>>>     /**
>>> - * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
>>> + * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
>>>    * @obj: GEM object
>>>    *
>>> - * Acquires a reference on the GEM buffer object's handle. Required
>>> - * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
>>> - * to release the reference.
>>> + * Acquires a reference on the GEM buffer object's handle. Required to keep
>>> + * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
>>> + * to release the reference. Does nothing if the buffer object has no handle.
>>>    */
>>> -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
>>> +void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
>>>   {
>>>       struct drm_device *dev = obj->dev;
>>>         guard(mutex)(&dev->object_name_lock);
>>>   -    drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
>>> -    drm_gem_object_handle_get(obj);
>>> +    /*
>>> +     * First ref taken during GEM object creation, if any. Some
>>> +     * drivers set up internal framebuffers with GEM objects that
>>> +     * do not have a GEM handle. Hence, this counter can be zero.
>>> +     */
>>> +    if (obj->handle_count)
>>> +        drm_gem_object_handle_get(obj);
>>>   }
>>> -EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
>>>     /**
>>>    * drm_gem_object_handle_free - release resources bound to userspace handles
>>> @@ -272,21 +276,11 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
>>>       }
>>>   }
>>>   -/**
>>> - * drm_gem_object_handle_put_unlocked - releases reference on user-space handles
>>> - * @obj: GEM object
>>> - *
>>> - * Releases a reference on the GEM buffer object's handle. Possibly releases
>>> - * the GEM buffer object and associated dma-buf objects.
>>> - */
>>> -void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
>>> +static void drm_gem_object_handle_put_unlocked_tail(struct drm_gem_object *obj)
>>>   {
>>>       struct drm_device *dev = obj->dev;
>>>       bool final = false;
>>>   -    if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
>>> -        return;
>>> -
>>>       /*
>>>       * Must bump handle count first as this may be the last
>>>       * ref, in which case the object would disappear before we
>>> @@ -304,7 +298,32 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
>>>       if (final)
>>>           drm_gem_object_put(obj);
>>>   }
>>> -EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
>>> +
>>> +static void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
>>> +{
>>> +    struct drm_device *dev = obj->dev;
>>> +
>>> +    if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
>>> +        return;
>>> +
>>> +    drm_gem_object_handle_put_unlocked_tail(obj);
>>> +}
>>> +
>>> +/**
>>> + * drm_gem_object_handle_put_if_exists_unlocked - releases reference on user-space handle, if any
>>> + * @obj: GEM object
>>> + *
>>> + * Releases a reference on the GEM buffer object's handle. Possibly releases
>>> + * the GEM buffer object and associated dma-buf objects. Does nothing if the
>>> + * buffer object has no handle.
>>> + */
>>> +void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj)
>>> +{
>>> +    if (!obj->handle_count)
>>> +        return;
>>> +
>>> +    drm_gem_object_handle_put_unlocked_tail(obj);
>>> +}
>>>     /*
>>>    * Called at device or object close to release the file's
>>> diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
>>> index c60d0044d036..618ce725cd75 100644
>>> --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
>>> +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
>>> @@ -100,7 +100,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
>>>       unsigned int i;
>>>         for (i = 0; i < fb->format->num_planes; i++)
>>> -        drm_gem_object_handle_put_unlocked(fb->obj[i]);
>>> +        drm_gem_object_put(fb->obj[i]);
>>>         drm_framebuffer_cleanup(fb);
>>>       kfree(fb);
>>> @@ -183,10 +183,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
>>>           if (!objs[i]) {
>>>               drm_dbg_kms(dev, "Failed to lookup GEM object\n");
>>>               ret = -ENOENT;
>>> -            goto err_gem_object_handle_put_unlocked;
>>> +            goto err_gem_object_put;
>>>           }
>>> -        drm_gem_object_handle_get_unlocked(objs[i]);
>>> -        drm_gem_object_put(objs[i]);
>>>             min_size = (height - 1) * mode_cmd->pitches[i]
>>>                + drm_format_info_min_pitch(info, i, width)
>>> @@ -196,22 +194,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
>>>               drm_dbg_kms(dev,
>>>                       "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
>>>                       objs[i]->size, min_size, i);
>>> -            drm_gem_object_handle_put_unlocked(objs[i]);
>>> +            drm_gem_object_put(objs[i]);
>>>               ret = -EINVAL;
>>> -            goto err_gem_object_handle_put_unlocked;
>>> +            goto err_gem_object_put;
>>>           }
>>>       }
>>>         ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
>>>       if (ret)
>>> -        goto err_gem_object_handle_put_unlocked;
>>> +        goto err_gem_object_put;
>>>         return 0;
>>>   -err_gem_object_handle_put_unlocked:
>>> +err_gem_object_put:
>>>       while (i > 0) {
>>>           --i;
>>> -        drm_gem_object_handle_put_unlocked(objs[i]);
>>> +        drm_gem_object_put(objs[i]);
>>>       }
>>>       return ret;
>>>   }
>>> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
>>> index f7b414a813ae..9233019f54a8 100644
>>> --- a/drivers/gpu/drm/drm_internal.h
>>> +++ b/drivers/gpu/drm/drm_internal.h
>>> @@ -161,8 +161,8 @@ void drm_sysfs_lease_event(struct drm_device *dev);
>>>     /* drm_gem.c */
>>>   int drm_gem_init(struct drm_device *dev);
>>> -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
>>> -void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
>>> +void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
>>> +void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj);
>>>   int drm_gem_handle_create_tail(struct drm_file *file_priv,
>>>                      struct drm_gem_object *obj,
>>>                      u32 *handlep);
>>> diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c
>>> index 8edefea2ef59..afd252108cfa 100644
>>> --- a/drivers/gpu/drm/gma500/fbdev.c
>>> +++ b/drivers/gpu/drm/gma500/fbdev.c
>>> @@ -121,7 +121,6 @@ static void psb_fbdev_fb_destroy(struct fb_info *info)
>>>       drm_fb_helper_fini(fb_helper);
>>>         drm_framebuffer_unregister_private(fb);
>>> -    fb->obj[0] = NULL;
>>>       drm_framebuffer_cleanup(fb);
>>>       kfree(fb);
>>>   @@ -243,7 +242,6 @@ int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
>>>     err_drm_framebuffer_unregister_private:
>>>       drm_framebuffer_unregister_private(fb);
>>> -    fb->obj[0] = NULL;
>>>       drm_framebuffer_cleanup(fb);
>>>       kfree(fb);
>>>   err_drm_gem_object_put:
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] drm/framebuffer: Acquire internal references on GEM handles
  2025-07-04  8:53 [PATCH] drm/framebuffer: Acquire internal references on GEM handles Thomas Zimmermann
  2025-07-04 12:06 ` Christian König
@ 2025-07-06 13:21 ` Mario Limonciello
  1 sibling, 0 replies; 5+ messages in thread
From: Mario Limonciello @ 2025-07-06 13:21 UTC (permalink / raw)
  To: Thomas Zimmermann, christian.koenig, asrivats, maarten.lankhorst,
	mripard, airlied, simona, patrik.r.jakobsson
  Cc: dri-devel, Bert Karwatzki, Sumit Semwal, linux-media,
	linaro-mm-sig, stable



On 7/4/25 04:53, Thomas Zimmermann wrote:
> Acquire GEM handles in drm_framebuffer_init() and release them in
> the corresponding drm_framebuffer_cleanup(). Ties the handle's
> lifetime to the framebuffer. Not all GEM buffer objects have GEM
> handles. If not set, no refcounting takes place. This is the case
> for some fbdev emulation. This is not a problem as these GEM objects
> do not use dma-bufs and drivers will not release them while fbdev
> emulation is running.
> 
> As all drivers use drm_framebuffer_init(), they will now all hold
> dma-buf references as fixed in commit 5307dce878d4 ("drm/gem: Acquire
> references on GEM handles for framebuffers").
> 
> In the GEM framebuffer helpers, restore the original ref counting
> on buffer objects. As the helpers for handle refcounting are now
> no longer called from outside the DRM core, unexport the symbols.
> 
> Gma500 (unnecessarily) clears the framebuffer's GEM-object pointer
> before calling drm_framebuffer_cleanup(). Remove these lines to
> make it consistent with the rest of the drivers. It's one of the
> fbdev emulations with no GEM handle on their buffers. The change
> to gma500 is therefore rather cosmetic.
> 
> Tested on i915, amdgpu (by Bert) and gma500. Also tested on i915
> plus udl for the original problem with dma-buf sharing.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> Fixes: 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers")
> Reported-by: Bert Karwatzki <spasswolf@web.de>
> Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/
> Tested-by: Bert Karwatzki <spasswolf@web.de>

(In what's probably no surprise) I reproduced the same issue Bert 
reported and also confirmed this does fix it.

Tested-by: Mario Limonciello <superm1@kernel.org>

This was my HEAD:

commit 1f988d0788f50 ("Merge tag 'hid-for-linus-2025070502' of 
git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid")


> Cc: Thomas Zimmermann <tzimmermann@suse.de>
> Cc: Anusha Srivatsa <asrivats@redhat.com>
> Cc: Christian König <christian.koenig@amd.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Maxime Ripard <mripard@kernel.org>
> Cc: Sumit Semwal <sumit.semwal@linaro.org>
> Cc: "Christian König" <christian.koenig@amd.com>
> Cc: linux-media@vger.kernel.org
> Cc: dri-devel@lists.freedesktop.org
> Cc: linaro-mm-sig@lists.linaro.org
> Cc: <stable@vger.kernel.org>
> ---
>   drivers/gpu/drm/drm_framebuffer.c            | 23 +++++++-
>   drivers/gpu/drm/drm_gem.c                    | 59 +++++++++++++-------
>   drivers/gpu/drm/drm_gem_framebuffer_helper.c | 16 +++---
>   drivers/gpu/drm/drm_internal.h               |  4 +-
>   drivers/gpu/drm/gma500/fbdev.c               |  2 -
>   5 files changed, 69 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
> index b781601946db..e4a10dd053fc 100644
> --- a/drivers/gpu/drm/drm_framebuffer.c
> +++ b/drivers/gpu/drm/drm_framebuffer.c
> @@ -862,11 +862,17 @@ EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_framebuffer_free);
>   int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>   			 const struct drm_framebuffer_funcs *funcs)
>   {
> +	unsigned int i;
>   	int ret;
>   
>   	if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
>   		return -EINVAL;
>   
> +	for (i = 0; i < fb->format->num_planes; i++) {
> +		if (fb->obj[i])
> +			drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
> +	}
> +
>   	INIT_LIST_HEAD(&fb->filp_head);
>   
>   	fb->funcs = funcs;
> @@ -875,7 +881,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>   	ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
>   				    false, drm_framebuffer_free);
>   	if (ret)
> -		goto out;
> +		goto err;
>   
>   	mutex_lock(&dev->mode_config.fb_lock);
>   	dev->mode_config.num_fb++;
> @@ -883,7 +889,14 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
>   	mutex_unlock(&dev->mode_config.fb_lock);
>   
>   	drm_mode_object_register(dev, &fb->base);
> -out:
> +
> +	return 0;
> +
> +err:
> +	for (i = 0; i < fb->format->num_planes; i++) {
> +		if (fb->obj[i])
> +			drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
> +	}
>   	return ret;
>   }
>   EXPORT_SYMBOL(drm_framebuffer_init);
> @@ -960,6 +973,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
>   void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
>   {
>   	struct drm_device *dev = fb->dev;
> +	unsigned int i;
> +
> +	for (i = 0; i < fb->format->num_planes; i++) {
> +		if (fb->obj[i])
> +			drm_gem_object_handle_put_if_exists_unlocked(fb->obj[i]);
> +	}
>   
>   	mutex_lock(&dev->mode_config.fb_lock);
>   	list_del(&fb->head);
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index bc505d938b3e..9d8b9e6b7d25 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -224,23 +224,27 @@ static void drm_gem_object_handle_get(struct drm_gem_object *obj)
>   }
>   
>   /**
> - * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
> + * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
>    * @obj: GEM object
>    *
> - * Acquires a reference on the GEM buffer object's handle. Required
> - * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
> - * to release the reference.
> + * Acquires a reference on the GEM buffer object's handle. Required to keep
> + * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
> + * to release the reference. Does nothing if the buffer object has no handle.
>    */
> -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
> +void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
>   {
>   	struct drm_device *dev = obj->dev;
>   
>   	guard(mutex)(&dev->object_name_lock);
>   
> -	drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
> -	drm_gem_object_handle_get(obj);
> +	/*
> +	 * First ref taken during GEM object creation, if any. Some
> +	 * drivers set up internal framebuffers with GEM objects that
> +	 * do not have a GEM handle. Hence, this counter can be zero.
> +	 */
> +	if (obj->handle_count)
> +		drm_gem_object_handle_get(obj);
>   }
> -EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
>   
>   /**
>    * drm_gem_object_handle_free - release resources bound to userspace handles
> @@ -272,21 +276,11 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
>   	}
>   }
>   
> -/**
> - * drm_gem_object_handle_put_unlocked - releases reference on user-space handles
> - * @obj: GEM object
> - *
> - * Releases a reference on the GEM buffer object's handle. Possibly releases
> - * the GEM buffer object and associated dma-buf objects.
> - */
> -void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
> +static void drm_gem_object_handle_put_unlocked_tail(struct drm_gem_object *obj)
>   {
>   	struct drm_device *dev = obj->dev;
>   	bool final = false;
>   
> -	if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
> -		return;
> -
>   	/*
>   	* Must bump handle count first as this may be the last
>   	* ref, in which case the object would disappear before we
> @@ -304,7 +298,32 @@ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
>   	if (final)
>   		drm_gem_object_put(obj);
>   }
> -EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
> +
> +static void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
> +{
> +	struct drm_device *dev = obj->dev;
> +
> +	if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
> +		return;
> +
> +	drm_gem_object_handle_put_unlocked_tail(obj);
> +}
> +
> +/**
> + * drm_gem_object_handle_put_if_exists_unlocked - releases reference on user-space handle, if any
> + * @obj: GEM object
> + *
> + * Releases a reference on the GEM buffer object's handle. Possibly releases
> + * the GEM buffer object and associated dma-buf objects. Does nothing if the
> + * buffer object has no handle.
> + */
> +void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj)
> +{
> +	if (!obj->handle_count)
> +		return;
> +
> +	drm_gem_object_handle_put_unlocked_tail(obj);
> +}
>   
>   /*
>    * Called at device or object close to release the file's
> diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
> index c60d0044d036..618ce725cd75 100644
> --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
> +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
> @@ -100,7 +100,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
>   	unsigned int i;
>   
>   	for (i = 0; i < fb->format->num_planes; i++)
> -		drm_gem_object_handle_put_unlocked(fb->obj[i]);
> +		drm_gem_object_put(fb->obj[i]);
>   
>   	drm_framebuffer_cleanup(fb);
>   	kfree(fb);
> @@ -183,10 +183,8 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
>   		if (!objs[i]) {
>   			drm_dbg_kms(dev, "Failed to lookup GEM object\n");
>   			ret = -ENOENT;
> -			goto err_gem_object_handle_put_unlocked;
> +			goto err_gem_object_put;
>   		}
> -		drm_gem_object_handle_get_unlocked(objs[i]);
> -		drm_gem_object_put(objs[i]);
>   
>   		min_size = (height - 1) * mode_cmd->pitches[i]
>   			 + drm_format_info_min_pitch(info, i, width)
> @@ -196,22 +194,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
>   			drm_dbg_kms(dev,
>   				    "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
>   				    objs[i]->size, min_size, i);
> -			drm_gem_object_handle_put_unlocked(objs[i]);
> +			drm_gem_object_put(objs[i]);
>   			ret = -EINVAL;
> -			goto err_gem_object_handle_put_unlocked;
> +			goto err_gem_object_put;
>   		}
>   	}
>   
>   	ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
>   	if (ret)
> -		goto err_gem_object_handle_put_unlocked;
> +		goto err_gem_object_put;
>   
>   	return 0;
>   
> -err_gem_object_handle_put_unlocked:
> +err_gem_object_put:
>   	while (i > 0) {
>   		--i;
> -		drm_gem_object_handle_put_unlocked(objs[i]);
> +		drm_gem_object_put(objs[i]);
>   	}
>   	return ret;
>   }
> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> index f7b414a813ae..9233019f54a8 100644
> --- a/drivers/gpu/drm/drm_internal.h
> +++ b/drivers/gpu/drm/drm_internal.h
> @@ -161,8 +161,8 @@ void drm_sysfs_lease_event(struct drm_device *dev);
>   
>   /* drm_gem.c */
>   int drm_gem_init(struct drm_device *dev);
> -void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
> -void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
> +void drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
> +void drm_gem_object_handle_put_if_exists_unlocked(struct drm_gem_object *obj);
>   int drm_gem_handle_create_tail(struct drm_file *file_priv,
>   			       struct drm_gem_object *obj,
>   			       u32 *handlep);
> diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c
> index 8edefea2ef59..afd252108cfa 100644
> --- a/drivers/gpu/drm/gma500/fbdev.c
> +++ b/drivers/gpu/drm/gma500/fbdev.c
> @@ -121,7 +121,6 @@ static void psb_fbdev_fb_destroy(struct fb_info *info)
>   	drm_fb_helper_fini(fb_helper);
>   
>   	drm_framebuffer_unregister_private(fb);
> -	fb->obj[0] = NULL;
>   	drm_framebuffer_cleanup(fb);
>   	kfree(fb);
>   
> @@ -243,7 +242,6 @@ int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
>   
>   err_drm_framebuffer_unregister_private:
>   	drm_framebuffer_unregister_private(fb);
> -	fb->obj[0] = NULL;
>   	drm_framebuffer_cleanup(fb);
>   	kfree(fb);
>   err_drm_gem_object_put:


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-07-06 13:21 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-04  8:53 [PATCH] drm/framebuffer: Acquire internal references on GEM handles Thomas Zimmermann
2025-07-04 12:06 ` Christian König
2025-07-04 12:31   ` Thomas Zimmermann
2025-07-04 14:10     ` Christian König
2025-07-06 13:21 ` Mario Limonciello

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).