From: Ralph Campbell Subject: [PATCH 1/4] mm/hmm: make full use of walk_page_range() Date: Wed, 11 Sep 2019 15:28:26 -0700 Message-ID: <20190911222829.28874-2-rcampbell@nvidia.com> References: <20190911222829.28874-1-rcampbell@nvidia.com> Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Return-path: In-Reply-To: <20190911222829.28874-1-rcampbell@nvidia.com> Sender: linux-kernel-owner@vger.kernel.org To: linux-mm@kvack.org Cc: linux-kernel@vger.kernel.org, amd-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org, =?UTF-8?q?J=C3=A9r=C3=B4me=20Glisse?= , Jason Gunthorpe , Andrew Morton , Christoph Hellwig , Ralph Campbell List-Id: amd-gfx.lists.freedesktop.org hmm_range_fault() calls find_vma() and walk_page_range() in a loop. This is unnecessary duplication since walk_page_range() calls find_vma() in a loop already. Simplify hmm_range_fault() by defining a walk_test() callback function to filter unhandled vmas. This also fixes a bug where hmm_range_fault() was not checking start >=3D vma->vm_start before checking vma->vm_flags so hmm_range_fault() could return an error based on the wrong vma for the requested range. Signed-off-by: Ralph Campbell Cc: "J=C3=A9r=C3=B4me Glisse" Cc: Jason Gunthorpe Cc: Christoph Hellwig --- mm/hmm.c | 113 ++++++++++++++++++++++++------------------------------- 1 file changed, 50 insertions(+), 63 deletions(-) diff --git a/mm/hmm.c b/mm/hmm.c index 902f5fa6bf93..06041d4399ff 100644 --- a/mm/hmm.c +++ b/mm/hmm.c @@ -252,18 +252,17 @@ static int hmm_vma_do_fault(struct mm_walk *walk, uns= igned long addr, return -EFAULT; } =20 -static int hmm_pfns_bad(unsigned long addr, - unsigned long end, - struct mm_walk *walk) +static int hmm_pfns_fill(unsigned long addr, + unsigned long end, + struct hmm_range *range, + enum hmm_pfn_value_e value) { - struct hmm_vma_walk *hmm_vma_walk =3D walk->private; - struct hmm_range *range =3D hmm_vma_walk->range; uint64_t *pfns =3D range->pfns; unsigned long i; =20 i =3D (addr - range->start) >> PAGE_SHIFT; for (; addr < end; addr +=3D PAGE_SIZE, i++) - pfns[i] =3D range->values[HMM_PFN_ERROR]; + pfns[i] =3D range->values[value]; =20 return 0; } @@ -584,7 +583,7 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp, } return 0; } else if (!pmd_present(pmd)) - return hmm_pfns_bad(start, end, walk); + return hmm_pfns_fill(start, end, range, HMM_PFN_ERROR); =20 if (pmd_devmap(pmd) || pmd_trans_huge(pmd)) { /* @@ -612,7 +611,7 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp, * recover. */ if (pmd_bad(pmd)) - return hmm_pfns_bad(start, end, walk); + return hmm_pfns_fill(start, end, range, HMM_PFN_ERROR); =20 ptep =3D pte_offset_map(pmdp, addr); i =3D (addr - range->start) >> PAGE_SHIFT; @@ -770,13 +769,36 @@ static int hmm_vma_walk_hugetlb_entry(pte_t *pte, uns= igned long hmask, #define hmm_vma_walk_hugetlb_entry NULL #endif /* CONFIG_HUGETLB_PAGE */ =20 -static void hmm_pfns_clear(struct hmm_range *range, - uint64_t *pfns, - unsigned long addr, - unsigned long end) +static int hmm_vma_walk_test(unsigned long start, + unsigned long end, + struct mm_walk *walk) { - for (; addr < end; addr +=3D PAGE_SIZE, pfns++) - *pfns =3D range->values[HMM_PFN_NONE]; + struct hmm_vma_walk *hmm_vma_walk =3D walk->private; + struct hmm_range *range =3D hmm_vma_walk->range; + struct vm_area_struct *vma =3D walk->vma; + + /* If range is no longer valid, force retry. */ + if (!range->valid) + return -EBUSY; + + /* + * Skip vma ranges that don't have struct page backing them or + * map I/O devices directly. + */ + if (vma->vm_flags & (VM_IO | VM_PFNMAP | VM_MIXEDMAP)) + return -EFAULT; + + /* + * If the vma does not allow read access, then assume that it does not + * allow write access either. HMM does not support architectures + * that allow write without read. + */ + if (!(vma->vm_flags & VM_READ)) { + (void) hmm_pfns_fill(start, end, range, HMM_PFN_NONE); + return -EPERM; + } + + return 0; } =20 /* @@ -857,6 +879,7 @@ static const struct mm_walk_ops hmm_walk_ops =3D { .pmd_entry =3D hmm_vma_walk_pmd, .pte_hole =3D hmm_vma_walk_hole, .hugetlb_entry =3D hmm_vma_walk_hugetlb_entry, + .test_walk =3D hmm_vma_walk_test, }; =20 /** @@ -889,63 +912,27 @@ static const struct mm_walk_ops hmm_walk_ops =3D { */ long hmm_range_fault(struct hmm_range *range, unsigned int flags) { - const unsigned long device_vma =3D VM_IO | VM_PFNMAP | VM_MIXEDMAP; - unsigned long start =3D range->start, end; - struct hmm_vma_walk hmm_vma_walk; + unsigned long start =3D range->start; + struct hmm_vma_walk hmm_vma_walk =3D { + .range =3D range, + .last =3D start, + .flags =3D flags, + }; struct hmm *hmm =3D range->hmm; - struct vm_area_struct *vma; int ret; =20 lockdep_assert_held(&hmm->mmu_notifier.mm->mmap_sem); =20 do { - /* If range is no longer valid force retry. */ - if (!range->valid) - return -EBUSY; - - vma =3D find_vma(hmm->mmu_notifier.mm, start); - if (vma =3D=3D NULL || (vma->vm_flags & device_vma)) - return -EFAULT; - - if (!(vma->vm_flags & VM_READ)) { - /* - * If vma do not allow read access, then assume that it - * does not allow write access, either. HMM does not - * support architecture that allow write without read. - */ - hmm_pfns_clear(range, range->pfns, - range->start, range->end); - return -EPERM; - } + ret =3D walk_page_range(hmm->mmu_notifier.mm, start, range->end, + &hmm_walk_ops, &hmm_vma_walk); + start =3D hmm_vma_walk.last; =20 - hmm_vma_walk.pgmap =3D NULL; - hmm_vma_walk.last =3D start; - hmm_vma_walk.flags =3D flags; - hmm_vma_walk.range =3D range; - end =3D min(range->end, vma->vm_end); + /* Keep trying while the range is valid. */ + } while (ret =3D=3D -EBUSY && range->valid); =20 - walk_page_range(vma->vm_mm, start, end, &hmm_walk_ops, - &hmm_vma_walk); - - do { - ret =3D walk_page_range(vma->vm_mm, start, end, - &hmm_walk_ops, &hmm_vma_walk); - start =3D hmm_vma_walk.last; - - /* Keep trying while the range is valid. */ - } while (ret =3D=3D -EBUSY && range->valid); - - if (ret) { - unsigned long i; - - i =3D (hmm_vma_walk.last - range->start) >> PAGE_SHIFT; - hmm_pfns_clear(range, &range->pfns[i], - hmm_vma_walk.last, range->end); - return ret; - } - start =3D end; - - } while (start < range->end); + if (ret) + return ret; =20 return (hmm_vma_walk.last - range->start) >> PAGE_SHIFT; } --=20 2.20.1