summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-10-11 23:53:35 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-10-17 16:59:07 +0100
commitc5488307dd679ea3fc23fec77dbf27191c2becda (patch)
tree2a0aa3513a08208c93decc6440322dcd48401ec0 /drivers/gpu/drm
parent0544e38d5ae90676624350468dea88c93eaeacbf (diff)
drm/armada: fix page_flip refcounting leak
A refcounting leak was found of the original frame buffer attached to the CRTC when using the page_flip ioctl, resulting in the frame buffer never being freed. This was not obvious initially, as if the page flip subsequently re-attaches the original frame buffer, the refcounts will be balanced. However, if the original frame buffer is freed, then it will be leaked. Fix this by ensuring that we take a reference on the incoming fb, but rely on the queued work to drop that ref count. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c13
1 files changed, 5 insertions, 8 deletions
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 9a0cc09e665..ef6be294c07 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -945,18 +945,15 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
armada_reg_queue_end(work->regs, i);
/*
- * Hold the old framebuffer for the work - DRM appears to drop our
- * reference to the old framebuffer in drm_mode_page_flip_ioctl().
+ * Ensure that we hold a reference on the new framebuffer.
+ * This has to match the behaviour in mode_set.
*/
- drm_framebuffer_reference(work->old_fb);
+ drm_framebuffer_reference(fb);
ret = armada_drm_crtc_queue_frame_work(dcrtc, work);
if (ret) {
- /*
- * Undo our reference above; DRM does not drop the reference
- * to this object on error, so that's okay.
- */
- drm_framebuffer_unreference(work->old_fb);
+ /* Undo our reference above */
+ drm_framebuffer_unreference(fb);
kfree(work);
return ret;
}