diff mbox

drm/i915: Avoid undefined behaviour of "u32 >> 32"

Message ID 20170629134901.21909-1-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson June 29, 2017, 1:49 p.m. UTC
When computing a hash for looking up relcoation target handles in an
execbuf, we start with a large size for the hashtable and proceed to
reduce it until the allocation suceeds. The final attempt is with an
order of 0 (i.e. a single element). This means that we then pass bits=0
to hash_32() which then computes "hash >> (32 - 0)" to lookup the single
element. Right shifting by a value the width of the operand is
undefined, so limit the smallest hash table we use to order 1.

Fixes: 4ff4b44cbb70 ("drm/i915: Store a direct lookup from object handle to vma")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_gem_execbuffer.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

Comments

Tvrtko Ursulin June 29, 2017, 2:50 p.m. UTC | #1
On 29/06/2017 14:49, Chris Wilson wrote:
> When computing a hash for looking up relcoation target handles in an
> execbuf, we start with a large size for the hashtable and proceed to
> reduce it until the allocation suceeds. The final attempt is with an
> order of 0 (i.e. a single element). This means that we then pass bits=0
> to hash_32() which then computes "hash >> (32 - 0)" to lookup the single
> element. Right shifting by a value the width of the operand is
> undefined, so limit the smallest hash table we use to order 1.
> 
> Fixes: 4ff4b44cbb70 ("drm/i915: Store a direct lookup from object handle to vma")
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_gem_execbuffer.c | 22 +++++++++++-----------
>   1 file changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> index 718bb75ad387..54791bcb8ccb 100644
> --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> @@ -296,12 +296,8 @@ static int eb_create(struct i915_execbuffer *eb)
>   				break;
>   		} while (--size);
>   
> -		if (unlikely(!eb->buckets)) {
> -			eb->buckets = kzalloc(sizeof(struct hlist_head),
> -					      GFP_TEMPORARY);

Want to maybe drop the NORETRY | NOWARN from the remaining allocation 
now? Wasn't it recently discussed that it is to feeble in it's attempts 
to allocate?

> -			if (unlikely(!eb->buckets))
> -				return -ENOMEM;
> -		}
> +		if (unlikely(!eb->buckets))
> +			return -ENOMEM;
>   
>   		eb->lut_size = size;
>   	} else {
> @@ -453,7 +449,7 @@ eb_add_vma(struct i915_execbuffer *eb,
>   			return err;
>   	}
>   
> -	if (eb->lut_size >= 0) {
> +	if (eb->lut_size > 0) {
>   		vma->exec_handle = entry->handle;
>   		hlist_add_head(&vma->exec_node,
>   			       &eb->buckets[hash_32(entry->handle,
> @@ -897,7 +893,7 @@ static void eb_release_vmas(const struct i915_execbuffer *eb)
>   static void eb_reset_vmas(const struct i915_execbuffer *eb)
>   {
>   	eb_release_vmas(eb);
> -	if (eb->lut_size >= 0)
> +	if (eb->lut_size > 0)
>   		memset(eb->buckets, 0,
>   		       sizeof(struct hlist_head) << eb->lut_size);
>   }
> @@ -906,7 +902,7 @@ static void eb_destroy(const struct i915_execbuffer *eb)
>   {
>   	GEM_BUG_ON(eb->reloc_cache.rq);
>   
> -	if (eb->lut_size >= 0)
> +	if (eb->lut_size > 0)
>   		kfree(eb->buckets);
>   }
>   
> @@ -2185,8 +2181,11 @@ i915_gem_do_execbuffer(struct drm_device *dev,
>   		}
>   	}
>   
> -	if (eb_create(&eb))
> -		return -ENOMEM;
> +	err = eb_create(&eb);
> +	if (err)
> +		goto err_out_fence;
> +
> +	GEM_BUG_ON(!eb.lut_size);
>   
>   	err = eb_select_context(&eb);
>   	if (unlikely(err))
> @@ -2346,6 +2345,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
>   	i915_gem_context_put(eb.ctx);
>   err_destroy:
>   	eb_destroy(&eb);
> +err_out_fence:
>   	if (out_fence_fd != -1)
>   		put_unused_fd(out_fence_fd);
>   err_in_fence:
> 

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

Tvrtko
Chris Wilson June 29, 2017, 3:01 p.m. UTC | #2
Quoting Tvrtko Ursulin (2017-06-29 15:50:17)
> 
> On 29/06/2017 14:49, Chris Wilson wrote:
> > When computing a hash for looking up relcoation target handles in an
> > execbuf, we start with a large size for the hashtable and proceed to
> > reduce it until the allocation suceeds. The final attempt is with an
> > order of 0 (i.e. a single element). This means that we then pass bits=0
> > to hash_32() which then computes "hash >> (32 - 0)" to lookup the single
> > element. Right shifting by a value the width of the operand is
> > undefined, so limit the smallest hash table we use to order 1.
> > 
> > Fixes: 4ff4b44cbb70 ("drm/i915: Store a direct lookup from object handle to vma")
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> > Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> > ---
> >   drivers/gpu/drm/i915/i915_gem_execbuffer.c | 22 +++++++++++-----------
> >   1 file changed, 11 insertions(+), 11 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> > index 718bb75ad387..54791bcb8ccb 100644
> > --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> > +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> > @@ -296,12 +296,8 @@ static int eb_create(struct i915_execbuffer *eb)
> >                               break;
> >               } while (--size);
> >   
> > -             if (unlikely(!eb->buckets)) {
> > -                     eb->buckets = kzalloc(sizeof(struct hlist_head),
> > -                                           GFP_TEMPORARY);
> 
> Want to maybe drop the NORETRY | NOWARN from the remaining allocation 
> now? Wasn't it recently discussed that it is to feeble in it's attempts 
> to allocate?

True that was the point of the allocate afterwards, so that we could do
it with the retry flags. Time for a respin.
-Chris
Chris Wilson June 29, 2017, 3:37 p.m. UTC | #3
Quoting Patchwork (2017-06-29 16:27:13)
> == Series Details ==
> 
> Series: drm/i915: Avoid undefined behaviour of "u32 >> 32" (rev2)
> URL   : https://patchwork.freedesktop.org/series/26556/
> State : success
> 
> == Summary ==
> 
> Series 26556v2 drm/i915: Avoid undefined behaviour of "u32 >> 32"
> https://patchwork.freedesktop.org/api/1.0/series/26556/revisions/2/mbox/
> 
> Test gem_exec_flush:
>         Subgroup basic-batch-kernel-default-uc:
>                 pass       -> FAIL       (fi-snb-2600) fdo#100007
> Test gem_exec_suspend:
>         Subgroup basic-s4-devices:
>                 dmesg-warn -> PASS       (fi-kbl-r) fdo#100125
> Test kms_cursor_legacy:
>         Subgroup basic-busy-flip-before-cursor-atomic:
>                 fail       -> PASS       (fi-snb-2600) fdo#100215
> Test kms_pipe_crc_basic:
>         Subgroup hang-read-crc-pipe-a:
>                 dmesg-warn -> PASS       (fi-pnv-d510) fdo#101597 +1
> 
> fdo#100007 https://bugs.freedesktop.org/show_bug.cgi?id=100007
> fdo#100125 https://bugs.freedesktop.org/show_bug.cgi?id=100125
> fdo#100215 https://bugs.freedesktop.org/show_bug.cgi?id=100215
> fdo#101597 https://bugs.freedesktop.org/show_bug.cgi?id=101597

Hopefully this explains the weird overrun of eb->buckets[] Tomi reported
in eb_add_vma() under tight memory conditions.

Pushed, thanks for the review,
-Chris
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 718bb75ad387..54791bcb8ccb 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -296,12 +296,8 @@  static int eb_create(struct i915_execbuffer *eb)
 				break;
 		} while (--size);
 
-		if (unlikely(!eb->buckets)) {
-			eb->buckets = kzalloc(sizeof(struct hlist_head),
-					      GFP_TEMPORARY);
-			if (unlikely(!eb->buckets))
-				return -ENOMEM;
-		}
+		if (unlikely(!eb->buckets))
+			return -ENOMEM;
 
 		eb->lut_size = size;
 	} else {
@@ -453,7 +449,7 @@  eb_add_vma(struct i915_execbuffer *eb,
 			return err;
 	}
 
-	if (eb->lut_size >= 0) {
+	if (eb->lut_size > 0) {
 		vma->exec_handle = entry->handle;
 		hlist_add_head(&vma->exec_node,
 			       &eb->buckets[hash_32(entry->handle,
@@ -897,7 +893,7 @@  static void eb_release_vmas(const struct i915_execbuffer *eb)
 static void eb_reset_vmas(const struct i915_execbuffer *eb)
 {
 	eb_release_vmas(eb);
-	if (eb->lut_size >= 0)
+	if (eb->lut_size > 0)
 		memset(eb->buckets, 0,
 		       sizeof(struct hlist_head) << eb->lut_size);
 }
@@ -906,7 +902,7 @@  static void eb_destroy(const struct i915_execbuffer *eb)
 {
 	GEM_BUG_ON(eb->reloc_cache.rq);
 
-	if (eb->lut_size >= 0)
+	if (eb->lut_size > 0)
 		kfree(eb->buckets);
 }
 
@@ -2185,8 +2181,11 @@  i915_gem_do_execbuffer(struct drm_device *dev,
 		}
 	}
 
-	if (eb_create(&eb))
-		return -ENOMEM;
+	err = eb_create(&eb);
+	if (err)
+		goto err_out_fence;
+
+	GEM_BUG_ON(!eb.lut_size);
 
 	err = eb_select_context(&eb);
 	if (unlikely(err))
@@ -2346,6 +2345,7 @@  i915_gem_do_execbuffer(struct drm_device *dev,
 	i915_gem_context_put(eb.ctx);
 err_destroy:
 	eb_destroy(&eb);
+err_out_fence:
 	if (out_fence_fd != -1)
 		put_unused_fd(out_fence_fd);
 err_in_fence: