drm/amdgpu: Enable amdgpu_ttm_tt_get_user_pages in worker threads
authorFelix Kuehling <Felix.Kuehling@amd.com>
Fri, 23 Mar 2018 19:32:29 +0000 (15:32 -0400)
committerOded Gabbay <oded.gabbay@gmail.com>
Fri, 23 Mar 2018 19:32:29 +0000 (15:32 -0400)
This commit allows amdgpu_ttm_tt_get_user_pages to work in a worker
thread rather than regular process context. This will be used when
KFD userptr BOs are restored after an MMU-notifier eviction.

v2: Manage task reference with get_task_struct/put_task_struct

Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Acked-by: Oded Gabbay <oded.gabbay@gmail.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c

index 205da3f..c713d30 100644 (file)
@@ -695,7 +695,7 @@ struct amdgpu_ttm_tt {
        struct ttm_dma_tt       ttm;
        u64                     offset;
        uint64_t                userptr;
-       struct mm_struct        *usermm;
+       struct task_struct      *usertask;
        uint32_t                userflags;
        spinlock_t              guptasklock;
        struct list_head        guptasks;
@@ -706,14 +706,18 @@ struct amdgpu_ttm_tt {
 int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
 {
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       struct mm_struct *mm = gtt->usertask->mm;
        unsigned int flags = 0;
        unsigned pinned = 0;
        int r;
 
+       if (!mm) /* Happens during process shutdown */
+               return -ESRCH;
+
        if (!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY))
                flags |= FOLL_WRITE;
 
-       down_read(&current->mm->mmap_sem);
+       down_read(&mm->mmap_sem);
 
        if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) {
                /* check that we only use anonymous memory
@@ -721,9 +725,9 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
                unsigned long end = gtt->userptr + ttm->num_pages * PAGE_SIZE;
                struct vm_area_struct *vma;
 
-               vma = find_vma(gtt->usermm, gtt->userptr);
+               vma = find_vma(mm, gtt->userptr);
                if (!vma || vma->vm_file || vma->vm_end < end) {
-                       up_read(&current->mm->mmap_sem);
+                       up_read(&mm->mmap_sem);
                        return -EPERM;
                }
        }
@@ -739,7 +743,12 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
                list_add(&guptask.list, &gtt->guptasks);
                spin_unlock(&gtt->guptasklock);
 
-               r = get_user_pages(userptr, num_pages, flags, p, NULL);
+               if (mm == current->mm)
+                       r = get_user_pages(userptr, num_pages, flags, p, NULL);
+               else
+                       r = get_user_pages_remote(gtt->usertask,
+                                       mm, userptr, num_pages,
+                                       flags, p, NULL, NULL);
 
                spin_lock(&gtt->guptasklock);
                list_del(&guptask.list);
@@ -752,12 +761,12 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
 
        } while (pinned < ttm->num_pages);
 
-       up_read(&current->mm->mmap_sem);
+       up_read(&mm->mmap_sem);
        return 0;
 
 release_pages:
        release_pages(pages, pinned);
-       up_read(&current->mm->mmap_sem);
+       up_read(&mm->mmap_sem);
        return r;
 }
 
@@ -978,6 +987,9 @@ static void amdgpu_ttm_backend_destroy(struct ttm_tt *ttm)
 {
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
 
+       if (gtt->usertask)
+               put_task_struct(gtt->usertask);
+
        ttm_dma_tt_fini(&gtt->ttm);
        kfree(gtt);
 }
@@ -1079,8 +1091,13 @@ int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
                return -EINVAL;
 
        gtt->userptr = addr;
-       gtt->usermm = current->mm;
        gtt->userflags = flags;
+
+       if (gtt->usertask)
+               put_task_struct(gtt->usertask);
+       gtt->usertask = current->group_leader;
+       get_task_struct(gtt->usertask);
+
        spin_lock_init(&gtt->guptasklock);
        INIT_LIST_HEAD(&gtt->guptasks);
        atomic_set(&gtt->mmu_invalidations, 0);
@@ -1096,7 +1113,10 @@ struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm)
        if (gtt == NULL)
                return NULL;
 
-       return gtt->usermm;
+       if (gtt->usertask == NULL)
+               return NULL;
+
+       return gtt->usertask->mm;
 }
 
 bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,