diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2017-06-29 11:04:25 -0400 |
---|---|---|
committer | Jani Nikula <jani.nikula@intel.com> | 2017-07-03 09:12:48 -0400 |
commit | 4ec654bf3a63d503e3c5336eade5c369ae17db56 (patch) | |
tree | 854ea8aa70115e1d8b0c73f14e9417d1790d4220 | |
parent | 9c75b185274b7766fe69c2e73607c1ed780b284b (diff) |
drm/i915: Avoid undefined behaviour of "u32 >> 32"
When computing a hash for looking up relocation target handles in an
execbuf, we start with a large size for the hashtable and proceed to
halve it until the allocation succeeds. 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 a value by the width of the operand is
undefined, so limit the smallest hash table we use to order 1.
v2: Keep the retry allocation flag for the final pass
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>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170629150425.27508-1-chris@chris-wilson.co.uk
(cherry picked from commit 4d470f7359c4bf22518baa30700ad45649371a22)
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_execbuffer.c | 38 |
1 files changed, 24 insertions, 14 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9337446f1068..054b2e54cdaf 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c | |||
@@ -288,20 +288,26 @@ static int eb_create(struct i915_execbuffer *eb) | |||
288 | * direct lookup. | 288 | * direct lookup. |
289 | */ | 289 | */ |
290 | do { | 290 | do { |
291 | unsigned int flags; | ||
292 | |||
293 | /* While we can still reduce the allocation size, don't | ||
294 | * raise a warning and allow the allocation to fail. | ||
295 | * On the last pass though, we want to try as hard | ||
296 | * as possible to perform the allocation and warn | ||
297 | * if it fails. | ||
298 | */ | ||
299 | flags = GFP_TEMPORARY; | ||
300 | if (size > 1) | ||
301 | flags |= __GFP_NORETRY | __GFP_NOWARN; | ||
302 | |||
291 | eb->buckets = kzalloc(sizeof(struct hlist_head) << size, | 303 | eb->buckets = kzalloc(sizeof(struct hlist_head) << size, |
292 | GFP_TEMPORARY | | 304 | flags); |
293 | __GFP_NORETRY | | ||
294 | __GFP_NOWARN); | ||
295 | if (eb->buckets) | 305 | if (eb->buckets) |
296 | break; | 306 | break; |
297 | } while (--size); | 307 | } while (--size); |
298 | 308 | ||
299 | if (unlikely(!eb->buckets)) { | 309 | if (unlikely(!size)) |
300 | eb->buckets = kzalloc(sizeof(struct hlist_head), | 310 | return -ENOMEM; |
301 | GFP_TEMPORARY); | ||
302 | if (unlikely(!eb->buckets)) | ||
303 | return -ENOMEM; | ||
304 | } | ||
305 | 311 | ||
306 | eb->lut_size = size; | 312 | eb->lut_size = size; |
307 | } else { | 313 | } else { |
@@ -452,7 +458,7 @@ eb_add_vma(struct i915_execbuffer *eb, | |||
452 | return err; | 458 | return err; |
453 | } | 459 | } |
454 | 460 | ||
455 | if (eb->lut_size >= 0) { | 461 | if (eb->lut_size > 0) { |
456 | vma->exec_handle = entry->handle; | 462 | vma->exec_handle = entry->handle; |
457 | hlist_add_head(&vma->exec_node, | 463 | hlist_add_head(&vma->exec_node, |
458 | &eb->buckets[hash_32(entry->handle, | 464 | &eb->buckets[hash_32(entry->handle, |
@@ -894,7 +900,7 @@ static void eb_release_vmas(const struct i915_execbuffer *eb) | |||
894 | static void eb_reset_vmas(const struct i915_execbuffer *eb) | 900 | static void eb_reset_vmas(const struct i915_execbuffer *eb) |
895 | { | 901 | { |
896 | eb_release_vmas(eb); | 902 | eb_release_vmas(eb); |
897 | if (eb->lut_size >= 0) | 903 | if (eb->lut_size > 0) |
898 | memset(eb->buckets, 0, | 904 | memset(eb->buckets, 0, |
899 | sizeof(struct hlist_head) << eb->lut_size); | 905 | sizeof(struct hlist_head) << eb->lut_size); |
900 | } | 906 | } |
@@ -903,7 +909,7 @@ static void eb_destroy(const struct i915_execbuffer *eb) | |||
903 | { | 909 | { |
904 | GEM_BUG_ON(eb->reloc_cache.rq); | 910 | GEM_BUG_ON(eb->reloc_cache.rq); |
905 | 911 | ||
906 | if (eb->lut_size >= 0) | 912 | if (eb->lut_size > 0) |
907 | kfree(eb->buckets); | 913 | kfree(eb->buckets); |
908 | } | 914 | } |
909 | 915 | ||
@@ -2180,8 +2186,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, | |||
2180 | } | 2186 | } |
2181 | } | 2187 | } |
2182 | 2188 | ||
2183 | if (eb_create(&eb)) | 2189 | err = eb_create(&eb); |
2184 | return -ENOMEM; | 2190 | if (err) |
2191 | goto err_out_fence; | ||
2192 | |||
2193 | GEM_BUG_ON(!eb.lut_size); | ||
2185 | 2194 | ||
2186 | /* | 2195 | /* |
2187 | * Take a local wakeref for preparing to dispatch the execbuf as | 2196 | * Take a local wakeref for preparing to dispatch the execbuf as |
@@ -2340,6 +2349,7 @@ err_unlock: | |||
2340 | err_rpm: | 2349 | err_rpm: |
2341 | intel_runtime_pm_put(eb.i915); | 2350 | intel_runtime_pm_put(eb.i915); |
2342 | eb_destroy(&eb); | 2351 | eb_destroy(&eb); |
2352 | err_out_fence: | ||
2343 | if (out_fence_fd != -1) | 2353 | if (out_fence_fd != -1) |
2344 | put_unused_fd(out_fence_fd); | 2354 | put_unused_fd(out_fence_fd); |
2345 | err_in_fence: | 2355 | err_in_fence: |