diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-10-11 18:53:35 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-10-17 11:59:07 -0400 |
commit | c5488307dd679ea3fc23fec77dbf27191c2becda (patch) | |
tree | 2a0aa3513a08208c93decc6440322dcd48401ec0 | |
parent | 0544e38d5ae90676624350468dea88c93eaeacbf (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>
-rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.c | 13 |
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 9a0cc09e6653..ef6be294c07d 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, | |||
945 | armada_reg_queue_end(work->regs, i); | 945 | armada_reg_queue_end(work->regs, i); |
946 | 946 | ||
947 | /* | 947 | /* |
948 | * Hold the old framebuffer for the work - DRM appears to drop our | 948 | * Ensure that we hold a reference on the new framebuffer. |
949 | * reference to the old framebuffer in drm_mode_page_flip_ioctl(). | 949 | * This has to match the behaviour in mode_set. |
950 | */ | 950 | */ |
951 | drm_framebuffer_reference(work->old_fb); | 951 | drm_framebuffer_reference(fb); |
952 | 952 | ||
953 | ret = armada_drm_crtc_queue_frame_work(dcrtc, work); | 953 | ret = armada_drm_crtc_queue_frame_work(dcrtc, work); |
954 | if (ret) { | 954 | if (ret) { |
955 | /* | 955 | /* Undo our reference above */ |
956 | * Undo our reference above; DRM does not drop the reference | 956 | drm_framebuffer_unreference(fb); |
957 | * to this object on error, so that's okay. | ||
958 | */ | ||
959 | drm_framebuffer_unreference(work->old_fb); | ||
960 | kfree(work); | 957 | kfree(work); |
961 | return ret; | 958 | return ret; |
962 | } | 959 | } |