Skip to content

Commit 85e26dd

Browse files
drm/client: fix circular reference counting issue
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 <[email protected]> Fixes: c76f0f7 ("drm: Begin an API for in-kernel clients") Cc: <[email protected]> Reviewed-by: Thomas Zimmermann <[email protected]> Tested-by: Thomas Zimmermann <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 8f20660 commit 85e26dd

File tree

2 files changed

+20
-18
lines changed

2 files changed

+20
-18
lines changed

drivers/gpu/drm/drm_client.c

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -233,21 +233,17 @@ void drm_client_dev_restore(struct drm_device *dev)
233233

234234
static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
235235
{
236-
struct drm_device *dev = buffer->client->dev;
237-
238236
if (buffer->gem) {
239237
drm_gem_vunmap_unlocked(buffer->gem, &buffer->map);
240238
drm_gem_object_put(buffer->gem);
241239
}
242240

243-
if (buffer->handle)
244-
drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file);
245-
246241
kfree(buffer);
247242
}
248243

249244
static struct drm_client_buffer *
250-
drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
245+
drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
246+
u32 format, u32 *handle)
251247
{
252248
const struct drm_format_info *info = drm_format_info(format);
253249
struct drm_mode_create_dumb dumb_args = { };
@@ -269,16 +265,15 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
269265
if (ret)
270266
goto err_delete;
271267

272-
buffer->handle = dumb_args.handle;
273-
buffer->pitch = dumb_args.pitch;
274-
275268
obj = drm_gem_object_lookup(client->file, dumb_args.handle);
276269
if (!obj) {
277270
ret = -ENOENT;
278271
goto err_delete;
279272
}
280273

274+
buffer->pitch = dumb_args.pitch;
281275
buffer->gem = obj;
276+
*handle = dumb_args.handle;
282277

283278
return buffer;
284279

@@ -365,7 +360,8 @@ static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
365360
}
366361

367362
static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
368-
u32 width, u32 height, u32 format)
363+
u32 width, u32 height, u32 format,
364+
u32 handle)
369365
{
370366
struct drm_client_dev *client = buffer->client;
371367
struct drm_mode_fb_cmd fb_req = { };
@@ -377,7 +373,7 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
377373
fb_req.depth = info->depth;
378374
fb_req.width = width;
379375
fb_req.height = height;
380-
fb_req.handle = buffer->handle;
376+
fb_req.handle = handle;
381377
fb_req.pitch = buffer->pitch;
382378

383379
ret = drm_mode_addfb(client->dev, &fb_req, client->file);
@@ -414,13 +410,24 @@ struct drm_client_buffer *
414410
drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
415411
{
416412
struct drm_client_buffer *buffer;
413+
u32 handle;
417414
int ret;
418415

419-
buffer = drm_client_buffer_create(client, width, height, format);
416+
buffer = drm_client_buffer_create(client, width, height, format,
417+
&handle);
420418
if (IS_ERR(buffer))
421419
return buffer;
422420

423-
ret = drm_client_buffer_addfb(buffer, width, height, format);
421+
ret = drm_client_buffer_addfb(buffer, width, height, format, handle);
422+
423+
/*
424+
* The handle is only needed for creating the framebuffer, destroy it
425+
* again to solve a circular dependency should anybody export the GEM
426+
* object as DMA-buf. The framebuffer and our buffer structure are still
427+
* holding references to the GEM object to prevent its destruction.
428+
*/
429+
drm_mode_destroy_dumb(client->dev, handle, client->file);
430+
424431
if (ret) {
425432
drm_client_buffer_delete(buffer);
426433
return ERR_PTR(ret);

include/drm/drm_client.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,6 @@ struct drm_client_buffer {
126126
*/
127127
struct drm_client_dev *client;
128128

129-
/**
130-
* @handle: Buffer handle
131-
*/
132-
u32 handle;
133-
134129
/**
135130
* @pitch: Buffer pitch
136131
*/

0 commit comments

Comments
 (0)