Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 637dd3b5 authored by Christian König's avatar Christian König Committed by Alex Deucher
Browse files

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: default avatarChristian König <christian.koenig@amd.com>
Reviewed-by: default avatarFelix Kuehling <Felix.Kuehling@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 211dff55
Loading
Loading
Loading
Loading
+38 −10
Original line number Diff line number Diff line
@@ -494,6 +494,11 @@ static void amdgpu_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_re
/*
 * TTM backend functions.
 */
struct amdgpu_ttm_gup_task_list {
	struct list_head	list;
	struct task_struct	*task;
};

struct amdgpu_ttm_tt {
	struct ttm_dma_tt	ttm;
	struct amdgpu_device	*adev;
@@ -501,6 +506,8 @@ struct amdgpu_ttm_tt {
	uint64_t		userptr;
	struct mm_struct	*usermm;
	uint32_t		userflags;
	spinlock_t              guptasklock;
	struct list_head        guptasks;
};

/* prepare the sg table with the user pages */
@@ -530,9 +537,20 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
		unsigned num_pages = ttm->num_pages - pinned;
		uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
		struct page **pages = ttm->pages + pinned;
		struct amdgpu_ttm_gup_task_list guptask;

		guptask.task = current;
		spin_lock(&gtt->guptasklock);
		list_add(&guptask.list, &gtt->guptasks);
		spin_unlock(&gtt->guptasklock);

		r = get_user_pages(current, current->mm, userptr, num_pages,
				   write, 0, pages, NULL);

		spin_lock(&gtt->guptasklock);
		list_del(&guptask.list);
		spin_unlock(&gtt->guptasklock);

		if (r < 0)
			goto release_pages;

@@ -783,6 +801,9 @@ int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
	gtt->userptr = addr;
	gtt->usermm = current->mm;
	gtt->userflags = flags;
	spin_lock_init(&gtt->guptasklock);
	INIT_LIST_HEAD(&gtt->guptasks);

	return 0;
}

@@ -800,18 +821,25 @@ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
				  unsigned long end)
{
	struct amdgpu_ttm_tt *gtt = (void *)ttm;
	struct amdgpu_ttm_gup_task_list *entry;
	unsigned long size;

	if (gtt == NULL)
		return false;

	if (gtt->ttm.ttm.state != tt_bound || !gtt->userptr)
	if (gtt == NULL || !gtt->userptr)
		return false;

	size = (unsigned long)gtt->ttm.ttm.num_pages * PAGE_SIZE;
	if (gtt->userptr > end || gtt->userptr + size <= start)
		return false;

	spin_lock(&gtt->guptasklock);
	list_for_each_entry(entry, &gtt->guptasks, list) {
		if (entry->task == current) {
			spin_unlock(&gtt->guptasklock);
			return false;
		}
	}
	spin_unlock(&gtt->guptasklock);

	return true;
}