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 | } |
