aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2016-04-05 10:00:00 -0400
committerJani Nikula <jani.nikula@intel.com>2016-04-18 05:35:49 -0400
commitdb9f9203e27495b2d151b695504e286eec026e9b (patch)
tree2c8d22c693031da6bda1ae7976c60f176cea4e7b
parentd43f3ebf12f59c57782ec652da65ef61c2662b40 (diff)
drm/i915/userptr: Hold mmref whilst calling get-user-pages
Holding a reference to the containing task_struct is not sufficient to prevent the mm_struct from being reaped under memory pressure. If this happens whilst we are calling get_user_pages(), explosions erupt - sometimes an immediate GPF, sometimes page flag corruption. To prevent the target mm from being reaped as we are reading from it, acquire a reference before we begin. Testcase: igt/gem_shrink/*userptr Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Michał Winiarski <michal.winiarski@intel.com> Cc: stable@vger.kernel.org Reviewed-by: Michał Winiarski <michal.winiarski@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1459864801-28606-2-git-send-email-chris@chris-wilson.co.uk (cherry picked from commit 40313f0cd0b711a7a5905e5182422799e157d8aa) Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r--drivers/gpu/drm/i915/i915_gem_userptr.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
index 18ba8139e922..4d30b60defda 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -501,19 +501,24 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
501 if (pvec != NULL) { 501 if (pvec != NULL) {
502 struct mm_struct *mm = obj->userptr.mm->mm; 502 struct mm_struct *mm = obj->userptr.mm->mm;
503 503
504 down_read(&mm->mmap_sem); 504 ret = -EFAULT;
505 while (pinned < npages) { 505 if (atomic_inc_not_zero(&mm->mm_users)) {
506 ret = get_user_pages_remote(work->task, mm, 506 down_read(&mm->mmap_sem);
507 obj->userptr.ptr + pinned * PAGE_SIZE, 507 while (pinned < npages) {
508 npages - pinned, 508 ret = get_user_pages_remote
509 !obj->userptr.read_only, 0, 509 (work->task, mm,
510 pvec + pinned, NULL); 510 obj->userptr.ptr + pinned * PAGE_SIZE,
511 if (ret < 0) 511 npages - pinned,
512 break; 512 !obj->userptr.read_only, 0,
513 513 pvec + pinned, NULL);
514 pinned += ret; 514 if (ret < 0)
515 break;
516
517 pinned += ret;
518 }
519 up_read(&mm->mmap_sem);
520 mmput(mm);
515 } 521 }
516 up_read(&mm->mmap_sem);
517 } 522 }
518 523
519 mutex_lock(&dev->struct_mutex); 524 mutex_lock(&dev->struct_mutex);