drm/i915/userptr: Handle unlocked gup retries
authorChris Wilson <chris@chris-wilson.co.uk>
Mon, 11 Nov 2019 13:32:04 +0000 (13:32 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Mon, 11 Nov 2019 15:46:45 +0000 (15:46 +0000)
Enable gup to retry and fault the pages outside of the mmap_sem lock in
our worker. As we are inside our worker, outside of any critical path,
we can allow the mmap_sem lock to be dropped in order to service a page
fault; this in turn allows the mm to populate the page using a slow
fault handler.

References: 5b56d49fc31d ("mm: add locked parameter to get_user_pages_remote()")
Testcase: igt/gem_userptr/userfault
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191111133205.11590-2-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/gem/i915_gem_userptr.c

index dd104b0..54ebc7a 100644 (file)
@@ -459,26 +459,31 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
        if (pvec != NULL) {
                struct mm_struct *mm = obj->userptr.mm->mm;
                unsigned int flags = 0;
+               int locked = 0;
 
                if (!i915_gem_object_is_readonly(obj))
                        flags |= FOLL_WRITE;
 
                ret = -EFAULT;
                if (mmget_not_zero(mm)) {
-                       down_read(&mm->mmap_sem);
                        while (pinned < npages) {
+                               if (!locked) {
+                                       down_read(&mm->mmap_sem);
+                                       locked = 1;
+                               }
                                ret = get_user_pages_remote
                                        (work->task, mm,
                                         obj->userptr.ptr + pinned * PAGE_SIZE,
                                         npages - pinned,
                                         flags,
-                                        pvec + pinned, NULL, NULL);
+                                        pvec + pinned, NULL, &locked);
                                if (ret < 0)
                                        break;
 
                                pinned += ret;
                        }
-                       up_read(&mm->mmap_sem);
+                       if (locked)
+                               up_read(&mm->mmap_sem);
                        mmput(mm);
                }
        }