[PATCH 1/2] drm/client: fix circular reference counting issue
Thomas Zimmermann
tzimmermann at suse.de
Thu Jan 26 14:30:31 UTC 2023
Hi
Am 26.01.23 um 11:28 schrieb Christian König:
> We reference dump buffers both by their handle as well as their
> object. The problem is now that when anybody iterates over the DRM
> framebuffers and exports the underlying GEM objects through DMA-buf
> we run into a circular reference count situation.
>
> The result is that the fbdev handling holds the GEM handle preventing
> the DMA-buf in the GEM object to be released. This DMA-buf in turn
> holds a reference to the driver module which on unload would release
> the fbdev.
>
> Break that loop by releasing the handle as soon as the DRM
> framebuffer object is created. The DRM framebuffer and the DRM client
> buffer structure still hold a reference to the underlying GEM object
> preventing its destruction.
>
> Signed-off-by: Christian König <christian.koenig at amd.com>
> Fixes: c76f0f7cb546 ("drm: Begin an API for in-kernel clients")
> Cc: <stable at vger.kernel.org>
I tested with Weston and Gnome in X11 and Wayland mode under simpledrm,
which I started stopped from the console. No obvious problems.
I heard that sway/wlroots has issues with drivers that don't support
dma-buf. Maybe(!) that could be affected by this patch.
Anyway, take my r-b, t-b tags.
Reviewed-by: Thomas Zimmermann <tzimmermann at suse.de>
Tested-by: Thomas Zimmermann <tzimmermann at suse.de>
Thank you for fixing this bug.
Best regards
Thomas
> ---
> drivers/gpu/drm/drm_client.c | 33 ++++++++++++++++++++-------------
> include/drm/drm_client.h | 5 -----
> 2 files changed, 20 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
> index 009e7b10455c..f6292ba0e6fc 100644
> --- a/drivers/gpu/drm/drm_client.c
> +++ b/drivers/gpu/drm/drm_client.c
> @@ -243,21 +243,17 @@ void drm_client_dev_restore(struct drm_device *dev)
>
> static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
> {
> - struct drm_device *dev = buffer->client->dev;
> -
> if (buffer->gem) {
> drm_gem_vunmap_unlocked(buffer->gem, &buffer->map);
> drm_gem_object_put(buffer->gem);
> }
>
> - if (buffer->handle)
> - drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file);
> -
> kfree(buffer);
> }
>
> static struct drm_client_buffer *
> -drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
> +drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
> + u32 format, u32 *handle)
> {
> const struct drm_format_info *info = drm_format_info(format);
> struct drm_mode_create_dumb dumb_args = { };
> @@ -279,16 +275,15 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
> if (ret)
> goto err_delete;
>
> - buffer->handle = dumb_args.handle;
> - buffer->pitch = dumb_args.pitch;
> -
> obj = drm_gem_object_lookup(client->file, dumb_args.handle);
> if (!obj) {
> ret = -ENOENT;
> goto err_delete;
> }
>
> + buffer->pitch = dumb_args.pitch;
> buffer->gem = obj;
> + *handle = dumb_args.handle;
>
> return buffer;
>
> @@ -375,7 +370,8 @@ static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
> }
>
> static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
> - u32 width, u32 height, u32 format)
> + u32 width, u32 height, u32 format,
> + u32 handle)
> {
> struct drm_client_dev *client = buffer->client;
> struct drm_mode_fb_cmd fb_req = { };
> @@ -387,7 +383,7 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
> fb_req.depth = info->depth;
> fb_req.width = width;
> fb_req.height = height;
> - fb_req.handle = buffer->handle;
> + fb_req.handle = handle;
> fb_req.pitch = buffer->pitch;
>
> ret = drm_mode_addfb(client->dev, &fb_req, client->file);
> @@ -424,13 +420,24 @@ struct drm_client_buffer *
> drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
> {
> struct drm_client_buffer *buffer;
> + u32 handle;
> int ret;
>
> - buffer = drm_client_buffer_create(client, width, height, format);
> + buffer = drm_client_buffer_create(client, width, height, format,
> + &handle);
> if (IS_ERR(buffer))
> return buffer;
>
> - ret = drm_client_buffer_addfb(buffer, width, height, format);
> + ret = drm_client_buffer_addfb(buffer, width, height, format, handle);
> +
> + /*
> + * The handle is only needed for creating the framebuffer, destroy it
> + * again to solve a circular dependency should anybody export the GEM
> + * object as DMA-buf. The framebuffer and our buffer structure are still
> + * holding references to the GEM object to prevent its destruction.
> + */
> + drm_mode_destroy_dumb(client->dev, handle, client->file);
> +
> if (ret) {
> drm_client_buffer_delete(buffer);
> return ERR_PTR(ret);
> diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
> index 39482527a775..b5acdab73766 100644
> --- a/include/drm/drm_client.h
> +++ b/include/drm/drm_client.h
> @@ -134,11 +134,6 @@ struct drm_client_buffer {
> */
> struct drm_client_dev *client;
>
> - /**
> - * @handle: Buffer handle
> - */
> - u32 handle;
> -
> /**
> * @pitch: Buffer pitch
> */
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20230126/a45a2d43/attachment.sig>
More information about the dri-devel
mailing list