OSDN Git Service

drm/i915/gem: Drop relocation slowpath
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 11 Mar 2020 16:03:10 +0000 (16:03 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Thu, 12 Mar 2020 20:28:57 +0000 (20:28 +0000)
Since the relocations are no longer performed under a global
struct_mutex, or any other lock, that is also held by pagefault handlers,
we can relax and allow our fast path to take a fault. As we no longer
need to abort the fast path for lock avoidance, we no longer need the
slow path handling at all.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200311160310.26711-1-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c

index 0893ce7..d3f4f28 100644 (file)
@@ -1440,9 +1440,7 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
                 * we would try to acquire the struct mutex again. Obviously
                 * this is bad and so lockdep complains vehemently.
                 */
-               pagefault_disable();
-               copied = __copy_from_user_inatomic(r, urelocs, count * sizeof(r[0]));
-               pagefault_enable();
+               copied = __copy_from_user(r, urelocs, count * sizeof(r[0]));
                if (unlikely(copied)) {
                        remain = -EFAULT;
                        goto out;
@@ -1492,236 +1490,6 @@ out:
        return remain;
 }
 
-static int
-eb_relocate_vma_slow(struct i915_execbuffer *eb, struct eb_vma *ev)
-{
-       const struct drm_i915_gem_exec_object2 *entry = ev->exec;
-       struct drm_i915_gem_relocation_entry *relocs =
-               u64_to_ptr(typeof(*relocs), entry->relocs_ptr);
-       unsigned int i;
-       int err;
-
-       for (i = 0; i < entry->relocation_count; i++) {
-               u64 offset = eb_relocate_entry(eb, ev, &relocs[i]);
-
-               if ((s64)offset < 0) {
-                       err = (int)offset;
-                       goto err;
-               }
-       }
-       err = 0;
-err:
-       reloc_cache_reset(&eb->reloc_cache);
-       return err;
-}
-
-static int check_relocations(const struct drm_i915_gem_exec_object2 *entry)
-{
-       const char __user *addr, *end;
-       unsigned long size;
-       char __maybe_unused c;
-
-       size = entry->relocation_count;
-       if (size == 0)
-               return 0;
-
-       if (size > N_RELOC(ULONG_MAX))
-               return -EINVAL;
-
-       addr = u64_to_user_ptr(entry->relocs_ptr);
-       size *= sizeof(struct drm_i915_gem_relocation_entry);
-       if (!access_ok(addr, size))
-               return -EFAULT;
-
-       end = addr + size;
-       for (; addr < end; addr += PAGE_SIZE) {
-               int err = __get_user(c, addr);
-               if (err)
-                       return err;
-       }
-       return __get_user(c, end - 1);
-}
-
-static int eb_copy_relocations(const struct i915_execbuffer *eb)
-{
-       struct drm_i915_gem_relocation_entry *relocs;
-       const unsigned int count = eb->buffer_count;
-       unsigned int i;
-       int err;
-
-       for (i = 0; i < count; i++) {
-               const unsigned int nreloc = eb->exec[i].relocation_count;
-               struct drm_i915_gem_relocation_entry __user *urelocs;
-               unsigned long size;
-               unsigned long copied;
-
-               if (nreloc == 0)
-                       continue;
-
-               err = check_relocations(&eb->exec[i]);
-               if (err)
-                       goto err;
-
-               urelocs = u64_to_user_ptr(eb->exec[i].relocs_ptr);
-               size = nreloc * sizeof(*relocs);
-
-               relocs = kvmalloc_array(size, 1, GFP_KERNEL);
-               if (!relocs) {
-                       err = -ENOMEM;
-                       goto err;
-               }
-
-               /* copy_from_user is limited to < 4GiB */
-               copied = 0;
-               do {
-                       unsigned int len =
-                               min_t(u64, BIT_ULL(31), size - copied);
-
-                       if (__copy_from_user((char *)relocs + copied,
-                                            (char __user *)urelocs + copied,
-                                            len))
-                               goto end;
-
-                       copied += len;
-               } while (copied < size);
-
-               /*
-                * As we do not update the known relocation offsets after
-                * relocating (due to the complexities in lock handling),
-                * we need to mark them as invalid now so that we force the
-                * relocation processing next time. Just in case the target
-                * object is evicted and then rebound into its old
-                * presumed_offset before the next execbuffer - if that
-                * happened we would make the mistake of assuming that the
-                * relocations were valid.
-                */
-               if (!user_access_begin(urelocs, size))
-                       goto end;
-
-               for (copied = 0; copied < nreloc; copied++)
-                       unsafe_put_user(-1,
-                                       &urelocs[copied].presumed_offset,
-                                       end_user);
-               user_access_end();
-
-               eb->exec[i].relocs_ptr = (uintptr_t)relocs;
-       }
-
-       return 0;
-
-end_user:
-       user_access_end();
-end:
-       kvfree(relocs);
-       err = -EFAULT;
-err:
-       while (i--) {
-               relocs = u64_to_ptr(typeof(*relocs), eb->exec[i].relocs_ptr);
-               if (eb->exec[i].relocation_count)
-                       kvfree(relocs);
-       }
-       return err;
-}
-
-static int eb_prefault_relocations(const struct i915_execbuffer *eb)
-{
-       const unsigned int count = eb->buffer_count;
-       unsigned int i;
-
-       for (i = 0; i < count; i++) {
-               int err;
-
-               err = check_relocations(&eb->exec[i]);
-               if (err)
-                       return err;
-       }
-
-       return 0;
-}
-
-static noinline int eb_relocate_slow(struct i915_execbuffer *eb)
-{
-       bool have_copy = false;
-       struct eb_vma *ev;
-       int err = 0;
-
-repeat:
-       if (signal_pending(current)) {
-               err = -ERESTARTSYS;
-               goto out;
-       }
-
-       /*
-        * We take 3 passes through the slowpatch.
-        *
-        * 1 - we try to just prefault all the user relocation entries and
-        * then attempt to reuse the atomic pagefault disabled fast path again.
-        *
-        * 2 - we copy the user entries to a local buffer here outside of the
-        * local and allow ourselves to wait upon any rendering before
-        * relocations
-        *
-        * 3 - we already have a local copy of the relocation entries, but
-        * were interrupted (EAGAIN) whilst waiting for the objects, try again.
-        */
-       if (!err) {
-               err = eb_prefault_relocations(eb);
-       } else if (!have_copy) {
-               err = eb_copy_relocations(eb);
-               have_copy = err == 0;
-       } else {
-               cond_resched();
-               err = 0;
-       }
-       if (err)
-               goto out;
-
-       list_for_each_entry(ev, &eb->relocs, reloc_link) {
-               if (!have_copy) {
-                       pagefault_disable();
-                       err = eb_relocate_vma(eb, ev);
-                       pagefault_enable();
-                       if (err)
-                               goto repeat;
-               } else {
-                       err = eb_relocate_vma_slow(eb, ev);
-                       if (err)
-                               goto err;
-               }
-       }
-
-       /*
-        * Leave the user relocations as are, this is the painfully slow path,
-        * and we want to avoid the complication of dropping the lock whilst
-        * having buffers reserved in the aperture and so causing spurious
-        * ENOSPC for random operations.
-        */
-
-err:
-       if (err == -EAGAIN)
-               goto repeat;
-
-out:
-       if (have_copy) {
-               const unsigned int count = eb->buffer_count;
-               unsigned int i;
-
-               for (i = 0; i < count; i++) {
-                       const struct drm_i915_gem_exec_object2 *entry =
-                               &eb->exec[i];
-                       struct drm_i915_gem_relocation_entry *relocs;
-
-                       if (!entry->relocation_count)
-                               continue;
-
-                       relocs = u64_to_ptr(typeof(*relocs), entry->relocs_ptr);
-                       kvfree(relocs);
-               }
-       }
-
-       return err;
-}
-
 static int eb_relocate(struct i915_execbuffer *eb)
 {
        int err;
@@ -1743,8 +1511,9 @@ static int eb_relocate(struct i915_execbuffer *eb)
                struct eb_vma *ev;
 
                list_for_each_entry(ev, &eb->relocs, reloc_link) {
-                       if (eb_relocate_vma(eb, ev))
-                               return eb_relocate_slow(eb);
+                       err = eb_relocate_vma(eb, ev);
+                       if (err)
+                               return err;
                }
        }