diff mbox

drm/radeon: fix oops in ttm reserve when pageflipping (v2)

Message ID 1306660580-22359-1-git-send-email-airlied@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dave Airlie May 29, 2011, 9:16 a.m. UTC
From: Dave Airlie <airlied@redhat.com>

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

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/radeon/radeon_display.c |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)

Comments

Alex Deucher May 31, 2011, 9:11 p.m. UTC | #1
On Sun, May 29, 2011 at 5:16 AM, Dave Airlie <airlied@gmail.com> wrote:
> From: Dave Airlie <airlied@redhat.com>
>
> 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
>

Thanks for tracking this down.

Acked-By: Alex Deucher <alexdeucher@gmail.com>

> Signed-off-by: Dave Airlie <airlied@redhat.com>
> ---
>  drivers/gpu/drm/radeon/radeon_display.c |   13 ++++++++-----
>  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 ae247ee..292f73f 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);
> --
> 1.7.4.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index ae247ee..292f73f 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);