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: 4ff4b44cbb
("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
This commit is contained in:
parent
886015a0ad
commit
4d470f7359
|
@ -288,20 +288,26 @@ static int eb_create(struct i915_execbuffer *eb)
|
|||
* direct lookup.
|
||||
*/
|
||||
do {
|
||||
unsigned int flags;
|
||||
|
||||
/* While we can still reduce the allocation size, don't
|
||||
* raise a warning and allow the allocation to fail.
|
||||
* On the last pass though, we want to try as hard
|
||||
* as possible to perform the allocation and warn
|
||||
* if it fails.
|
||||
*/
|
||||
flags = GFP_TEMPORARY;
|
||||
if (size > 1)
|
||||
flags |= __GFP_NORETRY | __GFP_NOWARN;
|
||||
|
||||
eb->buckets = kzalloc(sizeof(struct hlist_head) << size,
|
||||
GFP_TEMPORARY |
|
||||
__GFP_NORETRY |
|
||||
__GFP_NOWARN);
|
||||
flags);
|
||||
if (eb->buckets)
|
||||
break;
|
||||
} while (--size);
|
||||
|
||||
if (unlikely(!eb->buckets)) {
|
||||
eb->buckets = kzalloc(sizeof(struct hlist_head),
|
||||
GFP_TEMPORARY);
|
||||
if (unlikely(!eb->buckets))
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (unlikely(!size))
|
||||
return -ENOMEM;
|
||||
|
||||
eb->lut_size = size;
|
||||
} else {
|
||||
|
@ -452,7 +458,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,
|
||||
|
@ -895,7 +901,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);
|
||||
}
|
||||
|
@ -904,7 +910,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);
|
||||
}
|
||||
|
||||
|
@ -2180,8 +2186,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))
|
||||
|
@ -2341,6 +2350,7 @@ err_rpm:
|
|||
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:
|
||||
|
|
Loading…
Reference in New Issue