summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2011-05-29 17:48:32 +1000
committerDave Airlie <airlied@redhat.com>2011-06-02 10:46:41 +1000
commit498c555f56a02ec1059bc150cde84411ba0ac010 (patch)
tree645304a165513aeb4b21f3522a2b2c708c277e03 /drivers
parent2f2f96d1ea72e6602ae440ac2867a6004edb37a1 (diff)
downloadlinux-stable-498c555f56a02ec1059bc150cde84411ba0ac010.tar.gz
linux-stable-498c555f56a02ec1059bc150cde84411ba0ac010.tar.bz2
linux-stable-498c555f56a02ec1059bc150cde84411ba0ac010.zip
drm/radeon: fix oops in ttm reserve when pageflipping (v2)
We need to take a reference to this object, pinning doesn't take a reference so if userspace deletes the object it can disappear even if pinned. v2: fix error paths to unreference properly also. should fix: https://bugzilla.kernel.org/show_bug.cgi?id=32402 and https://bugzilla.redhat.com/show_bug.cgi?id=680651 Acked-By: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index ae247eec87c0..292f73f0ddbd 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -264,6 +264,8 @@ static void radeon_unpin_work_func(struct work_struct *__work)
radeon_bo_unreserve(work->old_rbo);
} else
DRM_ERROR("failed to reserve buffer after flip\n");
+
+ drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
kfree(work);
}
@@ -371,6 +373,8 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
new_radeon_fb = to_radeon_framebuffer(fb);
/* schedule unpin of the old buffer */
obj = old_radeon_fb->obj;
+ /* take a reference to the old object */
+ drm_gem_object_reference(obj);
rbo = gem_to_radeon_bo(obj);
work->old_rbo = rbo;
INIT_WORK(&work->work, radeon_unpin_work_func);
@@ -378,12 +382,9 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
/* We borrow the event spin lock for protecting unpin_work */
spin_lock_irqsave(&dev->event_lock, flags);
if (radeon_crtc->unpin_work) {
- spin_unlock_irqrestore(&dev->event_lock, flags);
- kfree(work);
- radeon_fence_unref(&fence);
-
DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
- return -EBUSY;
+ r = -EBUSY;
+ goto unlock_free;
}
radeon_crtc->unpin_work = work;
radeon_crtc->deferred_flip_completion = 0;
@@ -497,6 +498,8 @@ pflip_cleanup1:
pflip_cleanup:
spin_lock_irqsave(&dev->event_lock, flags);
radeon_crtc->unpin_work = NULL;
+unlock_free:
+ drm_gem_object_unreference_unlocked(old_radeon_fb->obj);
spin_unlock_irqrestore(&dev->event_lock, flags);
radeon_fence_unref(&fence);
kfree(work);