From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932247AbdC1MqF (ORCPT ); Tue, 28 Mar 2017 08:46:05 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:34322 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755472AbdC1MqB (ORCPT ); Tue, 28 Mar 2017 08:46:01 -0400 From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Jim Rees , Chris Wilson , Maarten Lankhorst , Jani Nikula , Daniel Vetter , Arnd Bergmann Subject: [PATCH 4.9 86/88] drm: reference count event->completion Date: Tue, 28 Mar 2017 14:31:41 +0200 Message-Id: <20170328122752.208201989@linuxfoundation.org> X-Mailer: git-send-email 2.12.1 In-Reply-To: <20170328122748.656530096@linuxfoundation.org> References: <20170328122748.656530096@linuxfoundation.org> User-Agent: quilt/0.65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Daniel Vetter commit 24835e442f289813aa568d142a755672a740503c upstream. When writing the generic nonblocking commit code I assumed that through clever lifetime management I can assure that the completion (stored in drm_crtc_commit) only gets freed after it is completed. And that worked. I also wanted to make nonblocking helpers resilient against driver bugs, by having timeouts everywhere. And that worked too. Unfortunately taking boths things together results in oopses :( Well, at least sometimes: What seems to happen is that the drm event hangs around forever stuck in limbo land. The nonblocking helpers eventually time out, move on and release it. Now the bug I tested all this against is drivers that just entirely fail to deliver the vblank events like they should, and in those cases the event is simply leaked. But what seems to happen, at least sometimes, on i915 is that the event is set up correctly, but somohow the vblank fails to fire in time. Which means the event isn't leaked, it's still there waiting for eventually a vblank to fire. That tends to happen when re-enabling the pipe, and then the trap springs and the kernel oopses. The correct fix here is simply to refcount the crtc commit to make sure that the event sticks around even for drivers which only sometimes fail to deliver vblanks for some arbitrary reasons. Since crtc commits are already refcounted that's easy to do. References: https://bugs.freedesktop.org/show_bug.cgi?id=96781 Cc: Jim Rees Cc: Chris Wilson Cc: Maarten Lankhorst Cc: Jani Nikula Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161221102331.31033-1-daniel.vetter@ffwll.ch Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_atomic_helper.c | 11 +++++++++++ drivers/gpu/drm/drm_fops.c | 2 +- include/drm/drmP.h | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1382,6 +1382,15 @@ static int stall_checks(struct drm_crtc return ret < 0 ? ret : 0; } +void release_crtc_commit(struct completion *completion) +{ + struct drm_crtc_commit *commit = container_of(completion, + typeof(*commit), + flip_done); + + drm_crtc_commit_put(commit); +} + /** * drm_atomic_helper_setup_commit - setup possibly nonblocking commit * @state: new modeset state to be committed @@ -1474,6 +1483,8 @@ int drm_atomic_helper_setup_commit(struc } crtc_state->event->base.completion = &commit->flip_done; + crtc_state->event->base.completion_release = release_crtc_commit; + drm_crtc_commit_get(commit); } return 0; --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -686,8 +686,8 @@ void drm_send_event_locked(struct drm_de assert_spin_locked(&dev->event_lock); if (e->completion) { - /* ->completion might disappear as soon as it signalled. */ complete_all(e->completion); + e->completion_release(e->completion); e->completion = NULL; } --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -361,6 +361,7 @@ struct drm_ioctl_desc { /* Event queued up for userspace to read */ struct drm_pending_event { struct completion *completion; + void (*completion_release)(struct completion *completion); struct drm_event *event; struct fence *fence; struct list_head link;