From: Jason Gunthorpe <jgg@xxxxxxxxxxxx> This value is being read without any locking, so it is just an unreliable hint, however in many cases we need to have certainty that code is not racing with mmput()/hmm_release(). For the two functions doing find_vma(), document that the caller is expected to hold mmap_sem and thus also have a mmget(). For hmm_range_register acquire a mmget internally as it must not race with hmm_release() when it sets valid. Signed-off-by: Jason Gunthorpe <jgg@xxxxxxxxxxxx> --- mm/hmm.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/mm/hmm.c b/mm/hmm.c index ec54be54d81135..d97ec293336ea5 100644 --- a/mm/hmm.c +++ b/mm/hmm.c @@ -909,8 +909,10 @@ int hmm_range_register(struct hmm_range *range, range->start = start; range->end = end; - /* Check if hmm_mm_destroy() was call. */ - if (mirror->hmm->mm == NULL || mirror->hmm->dead) + /* + * We cannot set range->value to true if hmm_release has already run. + */ + if (!mmget_not_zero(mirror->hmm->mm)) return -EFAULT; range->hmm = mirror->hmm; @@ -928,6 +930,7 @@ int hmm_range_register(struct hmm_range *range, if (!range->hmm->notifiers) range->valid = true; mutex_unlock(&range->hmm->lock); + mmput(mirror->hmm->mm); return 0; } @@ -979,9 +982,13 @@ long hmm_range_snapshot(struct hmm_range *range) struct vm_area_struct *vma; struct mm_walk mm_walk; - /* Check if hmm_mm_destroy() was call. */ - if (hmm->mm == NULL || hmm->dead) - return -EFAULT; + /* + * Caller must hold the mmap_sem, and that requires the caller to have + * a mmget. + */ + lockdep_assert_held(hmm->mm->mmap_sem); + if (WARN_ON(!atomic_read(&hmm->mm->mm_users))) + return -EINVAL; do { /* If range is no longer valid force retry. */ @@ -1077,9 +1084,13 @@ long hmm_range_fault(struct hmm_range *range, bool block) struct mm_walk mm_walk; int ret; - /* Check if hmm_mm_destroy() was call. */ - if (hmm->mm == NULL || hmm->dead) - return -EFAULT; + /* + * Caller must hold the mmap_sem, and that requires the caller to have + * a mmget. + */ + lockdep_assert_held(hmm->mm->mmap_sem); + if (WARN_ON(!atomic_read(&hmm->mm->mm_users))) + return -EINVAL; do { /* If range is no longer valid force retry. */ -- 2.21.0