Commit b8050148 authored by Chris Wilson's avatar Chris Wilson

drm/i915: Handle full s64 precision for wait-ioctl

The wait-ioctl is optionally supplied a timeout with nanosecond
precision in a s64 field. We use nsecs_to_jiffies64() to convert that
into the jiffies consumed by the scheduler, but internally
nsecs_to_jiffies64() does not guard against overflow (as it's purpose is
for use by the scheduler and not drivers!). So we must guard against the
overflow ourselves, and in the process note that we may then return
much earlier than the timeout selected by the user, so don't report
ETIME unless we do hit the timeout. (Woe betold us though if the user
waits for a year (32bit) and the request is still not complete!)

v2: Refine overflow detection (to not include an overffow itself)
Reported-by: default avatarJason Ekstrand <jason.ekstrand@intel.com>
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20170811105731.9482-1-chris@chris-wilson.co.ukReviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
parent b8f55be6
...@@ -4176,6 +4176,11 @@ static inline unsigned long msecs_to_jiffies_timeout(const unsigned int m) ...@@ -4176,6 +4176,11 @@ static inline unsigned long msecs_to_jiffies_timeout(const unsigned int m)
static inline unsigned long nsecs_to_jiffies_timeout(const u64 n) static inline unsigned long nsecs_to_jiffies_timeout(const u64 n)
{ {
/* nsecs_to_jiffies64() does not guard against overflow */
if (NSEC_PER_SEC % HZ &&
div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ)
return MAX_JIFFY_OFFSET;
return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1); return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1);
} }
......
...@@ -3286,7 +3286,7 @@ static unsigned long to_wait_timeout(s64 timeout_ns) ...@@ -3286,7 +3286,7 @@ static unsigned long to_wait_timeout(s64 timeout_ns)
* -ERESTARTSYS: signal interrupted the wait * -ERESTARTSYS: signal interrupted the wait
* -ENONENT: object doesn't exist * -ENONENT: object doesn't exist
* Also possible, but rare: * Also possible, but rare:
* -EAGAIN: GPU wedged * -EAGAIN: incomplete, restart syscall
* -ENOMEM: damn * -ENOMEM: damn
* -ENODEV: Internal IRQ fail * -ENODEV: Internal IRQ fail
* -E?: The add request failed * -E?: The add request failed
...@@ -3334,6 +3334,10 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) ...@@ -3334,6 +3334,10 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
*/ */
if (ret == -ETIME && !nsecs_to_jiffies(args->timeout_ns)) if (ret == -ETIME && !nsecs_to_jiffies(args->timeout_ns))
args->timeout_ns = 0; args->timeout_ns = 0;
/* Asked to wait beyond the jiffie/scheduler precision? */
if (ret == -ETIME && args->timeout_ns)
ret = -EAGAIN;
} }
i915_gem_object_put(obj); i915_gem_object_put(obj);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment