Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: pass VMA instead of MM to follow_pte()

... and centralize the VM_IO/VM_PFNMAP sanity check in there. We'll
now also perform these sanity checks for direct follow_pte()
invocations.

For generic_access_phys(), we might now check multiple times: nothing to
worry about, really.

Link: https://lkml.kernel.org/r/20240410155527.474777-3-david@redhat.com
Signed-off-by: David Hildenbrand <david@redhat.com>
Acked-by: Sean Christopherson <seanjc@google.com> [KVM]
Cc: Alex Williamson <alex.williamson@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Fei Li <fei1.li@intel.com>
Cc: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Yonghua Huang <yonghua.huang@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

David Hildenbrand and committed by
Andrew Morton
29ae7d96 3d658600

+17 -20
+2 -2
arch/s390/pci/pci_mmio.c
··· 169 169 if (!(vma->vm_flags & VM_WRITE)) 170 170 goto out_unlock_mmap; 171 171 172 - ret = follow_pte(vma->vm_mm, mmio_addr, &ptep, &ptl); 172 + ret = follow_pte(vma, mmio_addr, &ptep, &ptl); 173 173 if (ret) 174 174 goto out_unlock_mmap; 175 175 ··· 308 308 if (!(vma->vm_flags & VM_WRITE)) 309 309 goto out_unlock_mmap; 310 310 311 - ret = follow_pte(vma->vm_mm, mmio_addr, &ptep, &ptl); 311 + ret = follow_pte(vma, mmio_addr, &ptep, &ptl); 312 312 if (ret) 313 313 goto out_unlock_mmap; 314 314
+1 -4
arch/x86/mm/pat/memtype.c
··· 954 954 pte_t *ptep, pte; 955 955 spinlock_t *ptl; 956 956 957 - if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) 958 - return -EINVAL; 959 - 960 - if (follow_pte(vma->vm_mm, vma->vm_start, &ptep, &ptl)) 957 + if (follow_pte(vma, vma->vm_start, &ptep, &ptl)) 961 958 return -EINVAL; 962 959 963 960 pte = ptep_get(ptep);
+2 -2
drivers/vfio/vfio_iommu_type1.c
··· 518 518 spinlock_t *ptl; 519 519 int ret; 520 520 521 - ret = follow_pte(vma->vm_mm, vaddr, &ptep, &ptl); 521 + ret = follow_pte(vma, vaddr, &ptep, &ptl); 522 522 if (ret) { 523 523 bool unlocked = false; 524 524 ··· 532 532 if (ret) 533 533 return ret; 534 534 535 - ret = follow_pte(vma->vm_mm, vaddr, &ptep, &ptl); 535 + ret = follow_pte(vma, vaddr, &ptep, &ptl); 536 536 if (ret) 537 537 return ret; 538 538 }
+1 -2
drivers/virt/acrn/mm.c
··· 187 187 } 188 188 189 189 for (i = 0; i < nr_pages; i++) { 190 - ret = follow_pte(vma->vm_mm, 191 - memmap->vma_base + i * PAGE_SIZE, 190 + ret = follow_pte(vma, memmap->vma_base + i * PAGE_SIZE, 192 191 &ptep, &ptl); 193 192 if (ret) 194 193 break;
+1 -1
include/linux/mm.h
··· 2420 2420 unsigned long end, unsigned long floor, unsigned long ceiling); 2421 2421 int 2422 2422 copy_page_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma); 2423 - int follow_pte(struct mm_struct *mm, unsigned long address, 2423 + int follow_pte(struct vm_area_struct *vma, unsigned long address, 2424 2424 pte_t **ptepp, spinlock_t **ptlp); 2425 2425 int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, 2426 2426 void *buf, int len, int write);
+8 -7
mm/memory.c
··· 5926 5926 5927 5927 /** 5928 5928 * follow_pte - look up PTE at a user virtual address 5929 - * @mm: the mm_struct of the target address space 5929 + * @vma: the memory mapping 5930 5930 * @address: user virtual address 5931 5931 * @ptepp: location to store found PTE 5932 5932 * @ptlp: location to store the lock for the PTE ··· 5945 5945 * 5946 5946 * Return: zero on success, -ve otherwise. 5947 5947 */ 5948 - int follow_pte(struct mm_struct *mm, unsigned long address, 5948 + int follow_pte(struct vm_area_struct *vma, unsigned long address, 5949 5949 pte_t **ptepp, spinlock_t **ptlp) 5950 5950 { 5951 + struct mm_struct *mm = vma->vm_mm; 5951 5952 pgd_t *pgd; 5952 5953 p4d_t *p4d; 5953 5954 pud_t *pud; 5954 5955 pmd_t *pmd; 5955 5956 pte_t *ptep; 5957 + 5958 + if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) 5959 + goto out; 5956 5960 5957 5961 pgd = pgd_offset(mm, address); 5958 5962 if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) ··· 6011 6007 int offset = offset_in_page(addr); 6012 6008 int ret = -EINVAL; 6013 6009 6014 - if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) 6015 - return -EINVAL; 6016 - 6017 6010 retry: 6018 - if (follow_pte(vma->vm_mm, addr, &ptep, &ptl)) 6011 + if (follow_pte(vma, addr, &ptep, &ptl)) 6019 6012 return -EINVAL; 6020 6013 pte = ptep_get(ptep); 6021 6014 pte_unmap_unlock(ptep, ptl); ··· 6027 6026 if (!maddr) 6028 6027 return -ENOMEM; 6029 6028 6030 - if (follow_pte(vma->vm_mm, addr, &ptep, &ptl)) 6029 + if (follow_pte(vma, addr, &ptep, &ptl)) 6031 6030 goto out_unmap; 6032 6031 6033 6032 if (!pte_same(pte, ptep_get(ptep))) {
+2 -2
virt/kvm/kvm_main.c
··· 2902 2902 spinlock_t *ptl; 2903 2903 int r; 2904 2904 2905 - r = follow_pte(vma->vm_mm, addr, &ptep, &ptl); 2905 + r = follow_pte(vma, addr, &ptep, &ptl); 2906 2906 if (r) { 2907 2907 /* 2908 2908 * get_user_pages fails for VM_IO and VM_PFNMAP vmas and does ··· 2917 2917 if (r) 2918 2918 return r; 2919 2919 2920 - r = follow_pte(vma->vm_mm, addr, &ptep, &ptl); 2920 + r = follow_pte(vma, addr, &ptep, &ptl); 2921 2921 if (r) 2922 2922 return r; 2923 2923 }