Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ec654bf authored by Chris Wilson's avatar Chris Wilson Committed by Jani Nikula
Browse files

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: 4ff4b44c ("drm/i915: Store a direct lookup from object handle to vma")
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170629150425.27508-1-chris@chris-wilson.co.uk


(cherry picked from commit 4d470f73)
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
parent 9c75b185
Loading
Loading
Loading
Loading
+24 −14
Original line number Original line Diff line number Diff line
@@ -288,20 +288,26 @@ static int eb_create(struct i915_execbuffer *eb)
		 * direct lookup.
		 * direct lookup.
		 */
		 */
		do {
		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,
			eb->buckets = kzalloc(sizeof(struct hlist_head) << size,
					      GFP_TEMPORARY |
					      flags);
					      __GFP_NORETRY |
					      __GFP_NOWARN);
			if (eb->buckets)
			if (eb->buckets)
				break;
				break;
		} while (--size);
		} while (--size);


		if (unlikely(!eb->buckets)) {
		if (unlikely(!size))
			eb->buckets = kzalloc(sizeof(struct hlist_head),
					      GFP_TEMPORARY);
			if (unlikely(!eb->buckets))
			return -ENOMEM;
			return -ENOMEM;
		}


		eb->lut_size = size;
		eb->lut_size = size;
	} else {
	} else {
@@ -452,7 +458,7 @@ eb_add_vma(struct i915_execbuffer *eb,
			return err;
			return err;
	}
	}


	if (eb->lut_size >= 0) {
	if (eb->lut_size > 0) {
		vma->exec_handle = entry->handle;
		vma->exec_handle = entry->handle;
		hlist_add_head(&vma->exec_node,
		hlist_add_head(&vma->exec_node,
			       &eb->buckets[hash_32(entry->handle,
			       &eb->buckets[hash_32(entry->handle,
@@ -894,7 +900,7 @@ static void eb_release_vmas(const struct i915_execbuffer *eb)
static void eb_reset_vmas(const struct i915_execbuffer *eb)
static void eb_reset_vmas(const struct i915_execbuffer *eb)
{
{
	eb_release_vmas(eb);
	eb_release_vmas(eb);
	if (eb->lut_size >= 0)
	if (eb->lut_size > 0)
		memset(eb->buckets, 0,
		memset(eb->buckets, 0,
		       sizeof(struct hlist_head) << eb->lut_size);
		       sizeof(struct hlist_head) << eb->lut_size);
}
}
@@ -903,7 +909,7 @@ static void eb_destroy(const struct i915_execbuffer *eb)
{
{
	GEM_BUG_ON(eb->reloc_cache.rq);
	GEM_BUG_ON(eb->reloc_cache.rq);


	if (eb->lut_size >= 0)
	if (eb->lut_size > 0)
		kfree(eb->buckets);
		kfree(eb->buckets);
}
}


@@ -2180,8 +2186,11 @@ i915_gem_do_execbuffer(struct drm_device *dev,
		}
		}
	}
	}


	if (eb_create(&eb))
	err = eb_create(&eb);
		return -ENOMEM;
	if (err)
		goto err_out_fence;

	GEM_BUG_ON(!eb.lut_size);


	/*
	/*
	 * Take a local wakeref for preparing to dispatch the execbuf as
	 * Take a local wakeref for preparing to dispatch the execbuf as
@@ -2340,6 +2349,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
err_rpm:
err_rpm:
	intel_runtime_pm_put(eb.i915);
	intel_runtime_pm_put(eb.i915);
	eb_destroy(&eb);
	eb_destroy(&eb);
err_out_fence:
	if (out_fence_fd != -1)
	if (out_fence_fd != -1)
		put_unused_fd(out_fence_fd);
		put_unused_fd(out_fence_fd);
err_in_fence:
err_in_fence: