aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/mm.h2
-rw-r--r--mm/memory.c31
2 files changed, 16 insertions, 17 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 35f811b0cd69..2f6e2f886d4b 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -804,6 +804,8 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
804 struct vm_area_struct *vma); 804 struct vm_area_struct *vma);
805void unmap_mapping_range(struct address_space *mapping, 805void unmap_mapping_range(struct address_space *mapping,
806 loff_t const holebegin, loff_t const holelen, int even_cows); 806 loff_t const holebegin, loff_t const holelen, int even_cows);
807int follow_phys(struct vm_area_struct *vma, unsigned long address,
808 unsigned int flags, unsigned long *prot, resource_size_t *phys);
807int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, 809int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
808 void *buf, int len, int write); 810 void *buf, int len, int write);
809 811
diff --git a/mm/memory.c b/mm/memory.c
index 1e8f0d347c0e..79f28e35d4fc 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2981,9 +2981,9 @@ int in_gate_area_no_task(unsigned long addr)
2981#endif /* __HAVE_ARCH_GATE_AREA */ 2981#endif /* __HAVE_ARCH_GATE_AREA */
2982 2982
2983#ifdef CONFIG_HAVE_IOREMAP_PROT 2983#ifdef CONFIG_HAVE_IOREMAP_PROT
2984static resource_size_t follow_phys(struct vm_area_struct *vma, 2984int follow_phys(struct vm_area_struct *vma,
2985 unsigned long address, unsigned int flags, 2985 unsigned long address, unsigned int flags,
2986 unsigned long *prot) 2986 unsigned long *prot, resource_size_t *phys)
2987{ 2987{
2988 pgd_t *pgd; 2988 pgd_t *pgd;
2989 pud_t *pud; 2989 pud_t *pud;
@@ -2992,24 +2992,26 @@ static resource_size_t follow_phys(struct vm_area_struct *vma,
2992 spinlock_t *ptl; 2992 spinlock_t *ptl;
2993 resource_size_t phys_addr = 0; 2993 resource_size_t phys_addr = 0;
2994 struct mm_struct *mm = vma->vm_mm; 2994 struct mm_struct *mm = vma->vm_mm;
2995 int ret = -EINVAL;
2995 2996
2996 VM_BUG_ON(!(vma->vm_flags & (VM_IO | VM_PFNMAP))); 2997 if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
2998 goto out;
2997 2999
2998 pgd = pgd_offset(mm, address); 3000 pgd = pgd_offset(mm, address);
2999 if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) 3001 if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
3000 goto no_page_table; 3002 goto out;
3001 3003
3002 pud = pud_offset(pgd, address); 3004 pud = pud_offset(pgd, address);
3003 if (pud_none(*pud) || unlikely(pud_bad(*pud))) 3005 if (pud_none(*pud) || unlikely(pud_bad(*pud)))
3004 goto no_page_table; 3006 goto out;
3005 3007
3006 pmd = pmd_offset(pud, address); 3008 pmd = pmd_offset(pud, address);
3007 if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) 3009 if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
3008 goto no_page_table; 3010 goto out;
3009 3011
3010 /* We cannot handle huge page PFN maps. Luckily they don't exist. */ 3012 /* We cannot handle huge page PFN maps. Luckily they don't exist. */
3011 if (pmd_huge(*pmd)) 3013 if (pmd_huge(*pmd))
3012 goto no_page_table; 3014 goto out;
3013 3015
3014 ptep = pte_offset_map_lock(mm, pmd, address, &ptl); 3016 ptep = pte_offset_map_lock(mm, pmd, address, &ptl);
3015 if (!ptep) 3017 if (!ptep)
@@ -3024,13 +3026,13 @@ static resource_size_t follow_phys(struct vm_area_struct *vma,
3024 phys_addr <<= PAGE_SHIFT; /* Shift here to avoid overflow on PAE */ 3026 phys_addr <<= PAGE_SHIFT; /* Shift here to avoid overflow on PAE */
3025 3027
3026 *prot = pgprot_val(pte_pgprot(pte)); 3028 *prot = pgprot_val(pte_pgprot(pte));
3029 *phys = phys_addr;
3030 ret = 0;
3027 3031
3028unlock: 3032unlock:
3029 pte_unmap_unlock(ptep, ptl); 3033 pte_unmap_unlock(ptep, ptl);
3030out: 3034out:
3031 return phys_addr; 3035 return ret;
3032no_page_table:
3033 return 0;
3034} 3036}
3035 3037
3036int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, 3038int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
@@ -3041,12 +3043,7 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
3041 void *maddr; 3043 void *maddr;
3042 int offset = addr & (PAGE_SIZE-1); 3044 int offset = addr & (PAGE_SIZE-1);
3043 3045
3044 if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) 3046 if (follow_phys(vma, addr, write, &prot, &phys_addr))
3045 return -EINVAL;
3046
3047 phys_addr = follow_phys(vma, addr, write, &prot);
3048
3049 if (!phys_addr)
3050 return -EINVAL; 3047 return -EINVAL;
3051 3048
3052 maddr = ioremap_prot(phys_addr, PAGE_SIZE, prot); 3049 maddr = ioremap_prot(phys_addr, PAGE_SIZE, prot);