drm/i915: Force the slow path after a user-write error
authorChris Wilson <chris@chris-wilson.co.uk>
Mon, 3 Sep 2018 08:33:35 +0000 (09:33 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Mon, 3 Sep 2018 11:02:03 +0000 (12:02 +0100)
If we fail to write the user relocation back when it is changed, force
ourselves to take the slow relocation path where we can handle faults in
the write path. There is still an element of dubiousness as having
patched up the batch to use the correct offset, it no longer matches the
presumed_offset in the relocation, so a second pass may miss any changes
in layout.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180903083337.13134-3-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/i915_gem_execbuffer.c

index 020a2394fc857d7d4a0bd302d214f46198344601..43706c1db31a20df85870394422bb9a14f78ed94 100644 (file)
@@ -1491,8 +1491,10 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct i915_vma *vma)
                                 * can read from this userspace address.
                                 */
                                offset = gen8_canonical_addr(offset & ~UPDATE);
-                               __put_user(offset,
-                                          &urelocs[r-stack].presumed_offset);
+                               if (unlikely(__put_user(offset, &urelocs[r-stack].presumed_offset))) {
+                                       remain = -EFAULT;
+                                       goto out;
+                               }
                        }
                } while (r++, --count);
                urelocs += ARRAY_SIZE(stack);
@@ -1577,7 +1579,6 @@ static int eb_copy_relocations(const struct i915_execbuffer *eb)
 
                relocs = kvmalloc_array(size, 1, GFP_KERNEL);
                if (!relocs) {
-                       kvfree(relocs);
                        err = -ENOMEM;
                        goto err;
                }
@@ -1591,6 +1592,7 @@ static int eb_copy_relocations(const struct i915_execbuffer *eb)
                        if (__copy_from_user((char *)relocs + copied,
                                             (char __user *)urelocs + copied,
                                             len)) {
+end_user:
                                kvfree(relocs);
                                err = -EFAULT;
                                goto err;
@@ -1614,7 +1616,6 @@ static int eb_copy_relocations(const struct i915_execbuffer *eb)
                        unsafe_put_user(-1,
                                        &urelocs[copied].presumed_offset,
                                        end_user);
-end_user:
                user_access_end();
 
                eb->exec[i].relocs_ptr = (uintptr_t)relocs;