mm/hmm: do not call hmm_vma_walk_hole() while holding a spinlock
authorJason Gunthorpe <jgg@mellanox.com>
Mon, 2 Mar 2020 19:26:44 +0000 (15:26 -0400)
committerJason Gunthorpe <jgg@mellanox.com>
Thu, 26 Mar 2020 17:33:37 +0000 (14:33 -0300)
This eventually calls into handle_mm_fault() which is a sleeping function.
Release the lock first.

hmm_vma_walk_hole() does not touch the contents of the PUD, so it does not
need the lock.

Fixes: 3afc423632a1 ("mm: pagewalk: add p4d_entry() and pgd_entry()")
Cc: Steven Price <steven.price@arm.com>
Reviewed-by: Ralph Campbell <rcampbell@nvidia.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
mm/hmm.c

index 35f8542..0e7a572 100644 (file)
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -491,8 +491,8 @@ static int hmm_vma_walk_pud(pud_t *pudp, unsigned long start, unsigned long end,
 
        pud = READ_ONCE(*pudp);
        if (pud_none(pud)) {
-               ret = hmm_vma_walk_hole(start, end, -1, walk);
-               goto out_unlock;
+               spin_unlock(ptl);
+               return hmm_vma_walk_hole(start, end, -1, walk);
        }
 
        if (pud_huge(pud) && pud_devmap(pud)) {
@@ -501,8 +501,8 @@ static int hmm_vma_walk_pud(pud_t *pudp, unsigned long start, unsigned long end,
                bool fault, write_fault;
 
                if (!pud_present(pud)) {
-                       ret = hmm_vma_walk_hole(start, end, -1, walk);
-                       goto out_unlock;
+                       spin_unlock(ptl);
+                       return hmm_vma_walk_hole(start, end, -1, walk);
                }
 
                i = (addr - range->start) >> PAGE_SHIFT;
@@ -513,9 +513,9 @@ static int hmm_vma_walk_pud(pud_t *pudp, unsigned long start, unsigned long end,
                hmm_range_need_fault(hmm_vma_walk, pfns, npages,
                                     cpu_flags, &fault, &write_fault);
                if (fault || write_fault) {
-                       ret = hmm_vma_walk_hole_(addr, end, fault,
-                                                write_fault, walk);
-                       goto out_unlock;
+                       spin_unlock(ptl);
+                       return hmm_vma_walk_hole_(addr, end, fault, write_fault,
+                                                 walk);
                }
 
                pfn = pud_pfn(pud) + ((addr & ~PUD_MASK) >> PAGE_SHIFT);