aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/amdgpu
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2016-03-03 08:24:57 -0500
committerAlex Deucher <alexander.deucher@amd.com>2016-03-08 11:01:46 -0500
commit637dd3b5ca9e0d38b046f04e97a1d2f7523e7e25 (patch)
tree6986a05d8ae674d2b2bcae6fb0ccbf2a198971d8 /drivers/gpu/drm/amd/amdgpu
parent211dff5518d938d0c11205af3113d2c7a292dd98 (diff)
drm/amdgpu: prevent get_user_pages recursion
Remember the tasks which are inside get_user_pages() and ignore MMU callbacks from there. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index e52fc641edfb..53e627970798 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -494,13 +494,20 @@ static void amdgpu_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_re
494/* 494/*
495 * TTM backend functions. 495 * TTM backend functions.
496 */ 496 */
497struct amdgpu_ttm_gup_task_list {
498 struct list_head list;
499 struct task_struct *task;
500};
501
497struct amdgpu_ttm_tt { 502struct amdgpu_ttm_tt {
498 struct ttm_dma_tt ttm; 503 struct ttm_dma_tt ttm;
499 struct amdgpu_device *adev; 504 struct amdgpu_device *adev;
500 u64 offset; 505 u64 offset;
501 uint64_t userptr; 506 uint64_t userptr;
502 struct mm_struct *usermm; 507 struct mm_struct *usermm;
503 uint32_t userflags; 508 uint32_t userflags;
509 spinlock_t guptasklock;
510 struct list_head guptasks;
504}; 511};
505 512
506/* prepare the sg table with the user pages */ 513/* prepare the sg table with the user pages */
@@ -530,9 +537,20 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
530 unsigned num_pages = ttm->num_pages - pinned; 537 unsigned num_pages = ttm->num_pages - pinned;
531 uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE; 538 uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
532 struct page **pages = ttm->pages + pinned; 539 struct page **pages = ttm->pages + pinned;
540 struct amdgpu_ttm_gup_task_list guptask;
541
542 guptask.task = current;
543 spin_lock(&gtt->guptasklock);
544 list_add(&guptask.list, &gtt->guptasks);
545 spin_unlock(&gtt->guptasklock);
533 546
534 r = get_user_pages(current, current->mm, userptr, num_pages, 547 r = get_user_pages(current, current->mm, userptr, num_pages,
535 write, 0, pages, NULL); 548 write, 0, pages, NULL);
549
550 spin_lock(&gtt->guptasklock);
551 list_del(&guptask.list);
552 spin_unlock(&gtt->guptasklock);
553
536 if (r < 0) 554 if (r < 0)
537 goto release_pages; 555 goto release_pages;
538 556
@@ -783,6 +801,9 @@ int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
783 gtt->userptr = addr; 801 gtt->userptr = addr;
784 gtt->usermm = current->mm; 802 gtt->usermm = current->mm;
785 gtt->userflags = flags; 803 gtt->userflags = flags;
804 spin_lock_init(&gtt->guptasklock);
805 INIT_LIST_HEAD(&gtt->guptasks);
806
786 return 0; 807 return 0;
787} 808}
788 809
@@ -800,18 +821,25 @@ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
800 unsigned long end) 821 unsigned long end)
801{ 822{
802 struct amdgpu_ttm_tt *gtt = (void *)ttm; 823 struct amdgpu_ttm_tt *gtt = (void *)ttm;
824 struct amdgpu_ttm_gup_task_list *entry;
803 unsigned long size; 825 unsigned long size;
804 826
805 if (gtt == NULL) 827 if (gtt == NULL || !gtt->userptr)
806 return false;
807
808 if (gtt->ttm.ttm.state != tt_bound || !gtt->userptr)
809 return false; 828 return false;
810 829
811 size = (unsigned long)gtt->ttm.ttm.num_pages * PAGE_SIZE; 830 size = (unsigned long)gtt->ttm.ttm.num_pages * PAGE_SIZE;
812 if (gtt->userptr > end || gtt->userptr + size <= start) 831 if (gtt->userptr > end || gtt->userptr + size <= start)
813 return false; 832 return false;
814 833
834 spin_lock(&gtt->guptasklock);
835 list_for_each_entry(entry, &gtt->guptasks, list) {
836 if (entry->task == current) {
837 spin_unlock(&gtt->guptasklock);
838 return false;
839 }
840 }
841 spin_unlock(&gtt->guptasklock);
842
815 return true; 843 return true;
816} 844}
817 845