aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_atomic_helper.c
diff options
context:
space:
mode:
authorLeo (Sunpeng) Li <sunpeng.li@amd.com>2018-01-04 14:47:33 -0500
committerAlex Deucher <alexander.deucher@amd.com>2018-01-09 12:07:00 -0500
commita10195bbe7f4e6ba540083ba13126ef745116cae (patch)
tree4ef9044f02dafe498ddb609cbaac1d6e6dd4a5ca /drivers/gpu/drm/drm_atomic_helper.c
parentdrm/bridge/synopsys: stop clobbering drvdata (diff)
downloadlinux-dev-a10195bbe7f4e6ba540083ba13126ef745116cae.tar.xz
linux-dev-a10195bbe7f4e6ba540083ba13126ef745116cae.zip
drm/atomic: Fix memleak on ERESTARTSYS during non-blocking commits
During a non-blocking commit, it is possible to return before the commit_tail work is queued (-ERESTARTSYS, for example). Since a reference on the crtc commit object is obtained for the pending vblank event when preparing the commit, the above situation will leave us with an extra reference. Therefore, if the commit_tail worker has not consumed the event at the end of a commit, release it's reference. Signed-off-by: Leo (Sunpeng) Li <sunpeng.li@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/1515095253-29817-1-git-send-email-sunpeng.li@amd.com
Diffstat (limited to 'drivers/gpu/drm/drm_atomic_helper.c')
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index ab4032167094..4253f57227e3 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -3421,6 +3421,15 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
{
if (state->commit) {
+ /*
+ * In the event that a non-blocking commit returns
+ * -ERESTARTSYS before the commit_tail work is queued, we will
+ * have an extra reference to the commit object. Release it, if
+ * the event has not been consumed by the worker.
+ */
+ if (state->event)
+ drm_crtc_commit_put(state->commit);
+
kfree(state->commit->event);
state->commit->event = NULL;
drm_crtc_commit_put(state->commit);