Commit 498c555f authored by Dave Airlie's avatar Dave Airlie

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=680651Acked-By: default avatarAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 2f2f96d1
...@@ -264,6 +264,8 @@ static void radeon_unpin_work_func(struct work_struct *__work) ...@@ -264,6 +264,8 @@ static void radeon_unpin_work_func(struct work_struct *__work)
radeon_bo_unreserve(work->old_rbo); radeon_bo_unreserve(work->old_rbo);
} else } else
DRM_ERROR("failed to reserve buffer after flip\n"); DRM_ERROR("failed to reserve buffer after flip\n");
drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
kfree(work); kfree(work);
} }
...@@ -371,6 +373,8 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, ...@@ -371,6 +373,8 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
new_radeon_fb = to_radeon_framebuffer(fb); new_radeon_fb = to_radeon_framebuffer(fb);
/* schedule unpin of the old buffer */ /* schedule unpin of the old buffer */
obj = old_radeon_fb->obj; obj = old_radeon_fb->obj;
/* take a reference to the old object */
drm_gem_object_reference(obj);
rbo = gem_to_radeon_bo(obj); rbo = gem_to_radeon_bo(obj);
work->old_rbo = rbo; work->old_rbo = rbo;
INIT_WORK(&work->work, radeon_unpin_work_func); INIT_WORK(&work->work, radeon_unpin_work_func);
...@@ -378,12 +382,9 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, ...@@ -378,12 +382,9 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
/* We borrow the event spin lock for protecting unpin_work */ /* We borrow the event spin lock for protecting unpin_work */
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
if (radeon_crtc->unpin_work) { 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"); DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
return -EBUSY; r = -EBUSY;
goto unlock_free;
} }
radeon_crtc->unpin_work = work; radeon_crtc->unpin_work = work;
radeon_crtc->deferred_flip_completion = 0; radeon_crtc->deferred_flip_completion = 0;
...@@ -497,6 +498,8 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, ...@@ -497,6 +498,8 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
pflip_cleanup: pflip_cleanup:
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
radeon_crtc->unpin_work = NULL; radeon_crtc->unpin_work = NULL;
unlock_free:
drm_gem_object_unreference_unlocked(old_radeon_fb->obj);
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
radeon_fence_unref(&fence); radeon_fence_unref(&fence);
kfree(work); kfree(work);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment