* [PATCH] drm/i915: Fix erroneous dereference of batch_obj inside reset_status
@ 2013-12-04 11:37 Chris Wilson
2013-12-04 12:18 ` Daniel Vetter
2013-12-05 16:07 ` Mika Kuoppala
0 siblings, 2 replies; 6+ messages in thread
From: Chris Wilson @ 2013-12-04 11:37 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson, Mika Kuoppala, stable
As the rings may be processed and their requests deallocated in a
different order to the natural retirement during a reset,
/* Whilst this request exists, batch_obj will be on the
* active_list, and so will hold the active reference. Only when this
* request is retired will the the batch_obj be moved onto the
* inactive_list and lose its active reference. Hence we do not need
* to explicitly hold another reference here.
*/
is violated, and the batch_obj may be dereferenced after it had been
freed on another ring. This can be simply avoided by processing the
status update prior to deallocating any requests.
Fixes regression (a possible OOPS following a GPU hang) from
commit aa60c664e6df502578454621c3a9b1f087ff8d25
Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Date: Wed Jun 12 15:13:20 2013 +0300
drm/i915: find guilty batch buffer on ring resets
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: stable@vger.kernel.org
---
drivers/gpu/drm/i915/i915_gem.c | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index ec4502034203..c1e481d36575 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2442,15 +2442,24 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request)
kfree(request);
}
-static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
- struct intel_ring_buffer *ring)
+static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
+ struct intel_ring_buffer *ring)
{
- u32 completed_seqno;
- u32 acthd;
+ u32 completed_seqno = ring->get_seqno(ring, false);
+ u32 acthd = intel_ring_get_active_head(ring);
+ struct drm_i915_gem_request *request;
+
+ list_for_each_entry(request, &ring->request_list, list) {
+ if (i915_seqno_passed(completed_seqno, request->seqno))
+ continue;
- acthd = intel_ring_get_active_head(ring);
- completed_seqno = ring->get_seqno(ring, false);
+ i915_set_reset_status(ring, request, acthd);
+ }
+}
+static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
+ struct intel_ring_buffer *ring)
+{
while (!list_empty(&ring->request_list)) {
struct drm_i915_gem_request *request;
@@ -2458,9 +2467,6 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
struct drm_i915_gem_request,
list);
- if (request->seqno > completed_seqno)
- i915_set_reset_status(ring, request, acthd);
-
i915_gem_free_request(request);
}
@@ -2503,7 +2509,10 @@ void i915_gem_reset(struct drm_device *dev)
int i;
for_each_ring(ring, dev_priv, i)
- i915_gem_reset_ring_lists(dev_priv, ring);
+ i915_gem_reset_ring_status(dev_priv, ring);
+
+ for_each_ring(ring, dev_priv, i)
+ i915_gem_reset_ring_cleanup(dev_priv, ring);
i915_gem_cleanup_ringbuffer(dev);
--
1.8.5.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH] drm/i915: Fix erroneous dereference of batch_obj inside reset_status
2013-12-04 11:37 [PATCH] drm/i915: Fix erroneous dereference of batch_obj inside reset_status Chris Wilson
@ 2013-12-04 12:18 ` Daniel Vetter
2013-12-04 12:32 ` [Intel-gfx] " Chris Wilson
2013-12-05 16:07 ` Mika Kuoppala
1 sibling, 1 reply; 6+ messages in thread
From: Daniel Vetter @ 2013-12-04 12:18 UTC (permalink / raw)
To: Chris Wilson; +Cc: intel-gfx, stable, Mika Kuoppala
On Wed, Dec 04, 2013 at 11:37:09AM +0000, Chris Wilson wrote:
> As the rings may be processed and their requests deallocated in a
> different order to the natural retirement during a reset,
>
> /* Whilst this request exists, batch_obj will be on the
> * active_list, and so will hold the active reference. Only when this
> * request is retired will the the batch_obj be moved onto the
> * inactive_list and lose its active reference. Hence we do not need
> * to explicitly hold another reference here.
> */
>
> is violated, and the batch_obj may be dereferenced after it had been
> freed on another ring. This can be simply avoided by processing the
> status update prior to deallocating any requests.
>
> Fixes regression (a possible OOPS following a GPU hang) from
> commit aa60c664e6df502578454621c3a9b1f087ff8d25
> Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> Date: Wed Jun 12 15:13:20 2013 +0300
>
> drm/i915: find guilty batch buffer on ring resets
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Mika Kuoppala <mika.kuoppala@intel.com>
> Cc: stable@vger.kernel.org
> ---
> drivers/gpu/drm/i915/i915_gem.c | 29 +++++++++++++++++++----------
> 1 file changed, 19 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index ec4502034203..c1e481d36575 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -2442,15 +2442,24 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request)
> kfree(request);
> }
>
> -static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
> - struct intel_ring_buffer *ring)
> +static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
> + struct intel_ring_buffer *ring)
> {
> - u32 completed_seqno;
> - u32 acthd;
> + u32 completed_seqno = ring->get_seqno(ring, false);
> + u32 acthd = intel_ring_get_active_head(ring);
> + struct drm_i915_gem_request *request;
> +
> + list_for_each_entry(request, &ring->request_list, list) {
> + if (i915_seqno_passed(completed_seqno, request->seqno))
> + continue;
>
> - acthd = intel_ring_get_active_head(ring);
> - completed_seqno = ring->get_seqno(ring, false);
> + i915_set_reset_status(ring, request, acthd);
> + }
> +}
Indeed the fix in the gem reset code is a bit simpler than what I've
feared. We still have fairly tricky code which depends upon that implicit
reference in non-obvious ways. So I still think Mika's refcount patch with
the comments updated is the better approach.
-Daniel
>
> +static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
> + struct intel_ring_buffer *ring)
> +{
> while (!list_empty(&ring->request_list)) {
> struct drm_i915_gem_request *request;
>
> @@ -2458,9 +2467,6 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
> struct drm_i915_gem_request,
> list);
>
> - if (request->seqno > completed_seqno)
> - i915_set_reset_status(ring, request, acthd);
> -
> i915_gem_free_request(request);
> }
>
> @@ -2503,7 +2509,10 @@ void i915_gem_reset(struct drm_device *dev)
> int i;
>
> for_each_ring(ring, dev_priv, i)
> - i915_gem_reset_ring_lists(dev_priv, ring);
> + i915_gem_reset_ring_status(dev_priv, ring);
> +
> + for_each_ring(ring, dev_priv, i)
> + i915_gem_reset_ring_cleanup(dev_priv, ring);
>
> i915_gem_cleanup_ringbuffer(dev);
>
> --
> 1.8.5.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [Intel-gfx] [PATCH] drm/i915: Fix erroneous dereference of batch_obj inside reset_status
2013-12-04 12:18 ` Daniel Vetter
@ 2013-12-04 12:32 ` Chris Wilson
0 siblings, 0 replies; 6+ messages in thread
From: Chris Wilson @ 2013-12-04 12:32 UTC (permalink / raw)
To: Daniel Vetter; +Cc: intel-gfx, Mika Kuoppala, stable
On Wed, Dec 04, 2013 at 01:18:42PM +0100, Daniel Vetter wrote:
> On Wed, Dec 04, 2013 at 11:37:09AM +0000, Chris Wilson wrote:
> > As the rings may be processed and their requests deallocated in a
> > different order to the natural retirement during a reset,
> >
> > /* Whilst this request exists, batch_obj will be on the
> > * active_list, and so will hold the active reference. Only when this
> > * request is retired will the the batch_obj be moved onto the
> > * inactive_list and lose its active reference. Hence we do not need
> > * to explicitly hold another reference here.
> > */
> >
> > is violated, and the batch_obj may be dereferenced after it had been
> > freed on another ring. This can be simply avoided by processing the
> > status update prior to deallocating any requests.
> >
> > Fixes regression (a possible OOPS following a GPU hang) from
> > commit aa60c664e6df502578454621c3a9b1f087ff8d25
> > Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> > Date: Wed Jun 12 15:13:20 2013 +0300
> >
> > drm/i915: find guilty batch buffer on ring resets
> >
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > Cc: Mika Kuoppala <mika.kuoppala@intel.com>
> > Cc: stable@vger.kernel.org
> > ---
> > drivers/gpu/drm/i915/i915_gem.c | 29 +++++++++++++++++++----------
> > 1 file changed, 19 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> > index ec4502034203..c1e481d36575 100644
> > --- a/drivers/gpu/drm/i915/i915_gem.c
> > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > @@ -2442,15 +2442,24 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request)
> > kfree(request);
> > }
> >
> > -static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
> > - struct intel_ring_buffer *ring)
> > +static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
> > + struct intel_ring_buffer *ring)
> > {
> > - u32 completed_seqno;
> > - u32 acthd;
> > + u32 completed_seqno = ring->get_seqno(ring, false);
> > + u32 acthd = intel_ring_get_active_head(ring);
> > + struct drm_i915_gem_request *request;
> > +
> > + list_for_each_entry(request, &ring->request_list, list) {
> > + if (i915_seqno_passed(completed_seqno, request->seqno))
> > + continue;
> >
> > - acthd = intel_ring_get_active_head(ring);
> > - completed_seqno = ring->get_seqno(ring, false);
> > + i915_set_reset_status(ring, request, acthd);
> > + }
> > +}
>
> Indeed the fix in the gem reset code is a bit simpler than what I've
> feared. We still have fairly tricky code which depends upon that implicit
> reference in non-obvious ways. So I still think Mika's refcount patch with
> the comments updated is the better approach.
That batch_obj only exists for GPU hang accounting. It seems pointless
to make everything else more complicated. If you really wanted to
simplify it, you could store the actual batch offset+length rather than
a pointer, which would be even safer.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] drm/i915: Fix erroneous dereference of batch_obj inside reset_status
2013-12-04 11:37 [PATCH] drm/i915: Fix erroneous dereference of batch_obj inside reset_status Chris Wilson
2013-12-04 12:18 ` Daniel Vetter
@ 2013-12-05 16:07 ` Mika Kuoppala
2013-12-05 16:22 ` Chris Wilson
1 sibling, 1 reply; 6+ messages in thread
From: Mika Kuoppala @ 2013-12-05 16:07 UTC (permalink / raw)
To: Chris Wilson, intel-gfx; +Cc: stable
Chris Wilson <chris@chris-wilson.co.uk> writes:
> As the rings may be processed and their requests deallocated in a
> different order to the natural retirement during a reset,
>
> /* Whilst this request exists, batch_obj will be on the
> * active_list, and so will hold the active reference. Only when this
> * request is retired will the the batch_obj be moved onto the
> * inactive_list and lose its active reference. Hence we do not need
> * to explicitly hold another reference here.
> */
>
> is violated, and the batch_obj may be dereferenced after it had been
> freed on another ring. This can be simply avoided by processing the
> status update prior to deallocating any requests.
>
> Fixes regression (a possible OOPS following a GPU hang) from
> commit aa60c664e6df502578454621c3a9b1f087ff8d25
> Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> Date: Wed Jun 12 15:13:20 2013 +0300
>
> drm/i915: find guilty batch buffer on ring resets
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Mika Kuoppala <mika.kuoppala@intel.com>
> Cc: stable@vger.kernel.org
Passes the igt/gem_reset_stats/close-pending-fork and
doesn't affect the fast path.
Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] drm/i915: Fix erroneous dereference of batch_obj inside reset_status
2013-12-05 16:07 ` Mika Kuoppala
@ 2013-12-05 16:22 ` Chris Wilson
2013-12-12 9:54 ` Daniel Vetter
0 siblings, 1 reply; 6+ messages in thread
From: Chris Wilson @ 2013-12-05 16:22 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-gfx, stable
On Thu, Dec 05, 2013 at 06:07:27PM +0200, Mika Kuoppala wrote:
> Chris Wilson <chris@chris-wilson.co.uk> writes:
>
> > As the rings may be processed and their requests deallocated in a
> > different order to the natural retirement during a reset,
> >
> > /* Whilst this request exists, batch_obj will be on the
> > * active_list, and so will hold the active reference. Only when this
> > * request is retired will the the batch_obj be moved onto the
> > * inactive_list and lose its active reference. Hence we do not need
> > * to explicitly hold another reference here.
> > */
> >
> > is violated, and the batch_obj may be dereferenced after it had been
> > freed on another ring. This can be simply avoided by processing the
> > status update prior to deallocating any requests.
> >
> > Fixes regression (a possible OOPS following a GPU hang) from
> > commit aa60c664e6df502578454621c3a9b1f087ff8d25
> > Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> > Date: Wed Jun 12 15:13:20 2013 +0300
> >
> > drm/i915: find guilty batch buffer on ring resets
> >
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > Cc: Mika Kuoppala <mika.kuoppala@intel.com>
> > Cc: stable@vger.kernel.org
>
> Passes the igt/gem_reset_stats/close-pending-fork and
> doesn't affect the fast path.
>
> Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
For reference, this is the comment I added upon request:
@@ -2502,8 +2508,15 @@ void i915_gem_reset(struct drm_device *dev)
struct intel_ring_buffer *ring;
int i;
+ /* Before we free the objects from the requests, we need to inspect
+ * them for finding the guilty party. As the requests only borrow
+ * their reference to the objects, the inspection must be done first.
+ */
+ for_each_ring(ring, dev_priv, i)
+ i915_gem_reset_ring_status(dev_priv, ring);
+
for_each_ring(ring, dev_priv, i)
- i915_gem_reset_ring_lists(dev_priv, ring);
+ i915_gem_reset_ring_cleanup(dev_priv, ring);
i915_gem_cleanup_ringbuffer(dev);
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH] drm/i915: Fix erroneous dereference of batch_obj inside reset_status
2013-12-05 16:22 ` Chris Wilson
@ 2013-12-12 9:54 ` Daniel Vetter
0 siblings, 0 replies; 6+ messages in thread
From: Daniel Vetter @ 2013-12-12 9:54 UTC (permalink / raw)
To: Chris Wilson, Mika Kuoppala, intel-gfx, stable
On Thu, Dec 05, 2013 at 04:22:02PM +0000, Chris Wilson wrote:
> On Thu, Dec 05, 2013 at 06:07:27PM +0200, Mika Kuoppala wrote:
> > Chris Wilson <chris@chris-wilson.co.uk> writes:
> >
> > > As the rings may be processed and their requests deallocated in a
> > > different order to the natural retirement during a reset,
> > >
> > > /* Whilst this request exists, batch_obj will be on the
> > > * active_list, and so will hold the active reference. Only when this
> > > * request is retired will the the batch_obj be moved onto the
> > > * inactive_list and lose its active reference. Hence we do not need
> > > * to explicitly hold another reference here.
> > > */
> > >
> > > is violated, and the batch_obj may be dereferenced after it had been
> > > freed on another ring. This can be simply avoided by processing the
> > > status update prior to deallocating any requests.
> > >
> > > Fixes regression (a possible OOPS following a GPU hang) from
> > > commit aa60c664e6df502578454621c3a9b1f087ff8d25
> > > Author: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> > > Date: Wed Jun 12 15:13:20 2013 +0300
> > >
> > > drm/i915: find guilty batch buffer on ring resets
> > >
> > > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > > Cc: Mika Kuoppala <mika.kuoppala@intel.com>
> > > Cc: stable@vger.kernel.org
> >
> > Passes the igt/gem_reset_stats/close-pending-fork and
> > doesn't affect the fast path.
> >
> > Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
>
> For reference, this is the comment I added upon request:
>
> @@ -2502,8 +2508,15 @@ void i915_gem_reset(struct drm_device *dev)
> struct intel_ring_buffer *ring;
> int i;
>
> + /* Before we free the objects from the requests, we need to inspect
> + * them for finding the guilty party. As the requests only borrow
> + * their reference to the objects, the inspection must be done first.
> + */
> + for_each_ring(ring, dev_priv, i)
> + i915_gem_reset_ring_status(dev_priv, ring);
> +
> for_each_ring(ring, dev_priv, i)
> - i915_gem_reset_ring_lists(dev_priv, ring);
> + i915_gem_reset_ring_cleanup(dev_priv, ring);
>
> i915_gem_cleanup_ringbuffer(dev);
QA didn't hit this bug since the test wasn't added to the right make
target. With that sorted I've now merged this patch (including comment) to
-fixes.
Thanks, Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-12-12 9:53 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-04 11:37 [PATCH] drm/i915: Fix erroneous dereference of batch_obj inside reset_status Chris Wilson
2013-12-04 12:18 ` Daniel Vetter
2013-12-04 12:32 ` [Intel-gfx] " Chris Wilson
2013-12-05 16:07 ` Mika Kuoppala
2013-12-05 16:22 ` Chris Wilson
2013-12-12 9:54 ` Daniel Vetter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox