diff options
author | Johannes Weiner <hannes@cmpxchg.org> | 2009-06-16 18:32:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 22:47:40 -0400 |
commit | 3b6748e2dd69906af3835db4dc9d1c8a3ee4c68c (patch) | |
tree | 5d5476844f8e29e31684ce8ccf7e163ab3182ad6 | |
parent | 03668a4debf4f50de55c34b6e66dae63e1c73716 (diff) |
mm: introduce follow_pfn()
Analoguous to follow_phys(), add a helper that looks up the PFN at a
user virtual address in an IO mapping or a raw PFN mapping.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Christoph Hellwig <hch@infradead.org>
Acked-by: Magnus Damm <magnus.damm@gmail.com>
Cc: Hans Verkuil <hverkuil@xs4all.nl>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/mm.h | 2 | ||||
-rw-r--r-- | mm/memory.c | 29 |
2 files changed, 31 insertions, 0 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h index 7b548e7cfbd9..c80dbd4a62c6 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -792,6 +792,8 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src, | |||
792 | struct vm_area_struct *vma); | 792 | struct vm_area_struct *vma); |
793 | void unmap_mapping_range(struct address_space *mapping, | 793 | void unmap_mapping_range(struct address_space *mapping, |
794 | loff_t const holebegin, loff_t const holelen, int even_cows); | 794 | loff_t const holebegin, loff_t const holelen, int even_cows); |
795 | int follow_pfn(struct vm_area_struct *vma, unsigned long address, | ||
796 | unsigned long *pfn); | ||
795 | int follow_phys(struct vm_area_struct *vma, unsigned long address, | 797 | int follow_phys(struct vm_area_struct *vma, unsigned long address, |
796 | unsigned int flags, unsigned long *prot, resource_size_t *phys); | 798 | unsigned int flags, unsigned long *prot, resource_size_t *phys); |
797 | int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, | 799 | int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, |
diff --git a/mm/memory.c b/mm/memory.c index 24ff20480bb7..d5d1653d60a6 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -3140,6 +3140,35 @@ out: | |||
3140 | return -EINVAL; | 3140 | return -EINVAL; |
3141 | } | 3141 | } |
3142 | 3142 | ||
3143 | /** | ||
3144 | * follow_pfn - look up PFN at a user virtual address | ||
3145 | * @vma: memory mapping | ||
3146 | * @address: user virtual address | ||
3147 | * @pfn: location to store found PFN | ||
3148 | * | ||
3149 | * Only IO mappings and raw PFN mappings are allowed. | ||
3150 | * | ||
3151 | * Returns zero and the pfn at @pfn on success, -ve otherwise. | ||
3152 | */ | ||
3153 | int follow_pfn(struct vm_area_struct *vma, unsigned long address, | ||
3154 | unsigned long *pfn) | ||
3155 | { | ||
3156 | int ret = -EINVAL; | ||
3157 | spinlock_t *ptl; | ||
3158 | pte_t *ptep; | ||
3159 | |||
3160 | if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) | ||
3161 | return ret; | ||
3162 | |||
3163 | ret = follow_pte(vma->vm_mm, address, &ptep, &ptl); | ||
3164 | if (ret) | ||
3165 | return ret; | ||
3166 | *pfn = pte_pfn(*ptep); | ||
3167 | pte_unmap_unlock(ptep, ptl); | ||
3168 | return 0; | ||
3169 | } | ||
3170 | EXPORT_SYMBOL(follow_pfn); | ||
3171 | |||
3143 | #ifdef CONFIG_HAVE_IOREMAP_PROT | 3172 | #ifdef CONFIG_HAVE_IOREMAP_PROT |
3144 | int follow_phys(struct vm_area_struct *vma, | 3173 | int follow_phys(struct vm_area_struct *vma, |
3145 | unsigned long address, unsigned int flags, | 3174 | unsigned long address, unsigned int flags, |