Commit 9a3ed4ef authored by Greg Banks's avatar Greg Banks Committed by Linus Torvalds

[PATCH] oprofile: add check_user_page_readable()

Add check_user_page_readable() for kernel modules which need to follow user
space addresses but can't use get_user().
Signed-off-by: default avatarJohn Levon <levon@movementarian.org>
Signed-off-by: default avatarGreg Banks <gnb@melbourne.sgi.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 066752a3
...@@ -802,6 +802,7 @@ extern struct page * vmalloc_to_page(void *addr); ...@@ -802,6 +802,7 @@ extern struct page * vmalloc_to_page(void *addr);
extern unsigned long vmalloc_to_pfn(void *addr); extern unsigned long vmalloc_to_pfn(void *addr);
extern struct page * follow_page(struct mm_struct *mm, unsigned long address, extern struct page * follow_page(struct mm_struct *mm, unsigned long address,
int write); int write);
extern int check_user_page_readable(struct mm_struct *mm, unsigned long address);
int remap_pfn_range(struct vm_area_struct *, unsigned long, int remap_pfn_range(struct vm_area_struct *, unsigned long,
unsigned long, unsigned long, pgprot_t); unsigned long, unsigned long, pgprot_t);
......
...@@ -747,8 +747,8 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, ...@@ -747,8 +747,8 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address,
* Do a quick page-table lookup for a single page. * Do a quick page-table lookup for a single page.
* mm->page_table_lock must be held. * mm->page_table_lock must be held.
*/ */
struct page * static struct page *
follow_page(struct mm_struct *mm, unsigned long address, int write) __follow_page(struct mm_struct *mm, unsigned long address, int read, int write)
{ {
pgd_t *pgd; pgd_t *pgd;
pud_t *pud; pud_t *pud;
...@@ -784,6 +784,8 @@ follow_page(struct mm_struct *mm, unsigned long address, int write) ...@@ -784,6 +784,8 @@ follow_page(struct mm_struct *mm, unsigned long address, int write)
if (pte_present(pte)) { if (pte_present(pte)) {
if (write && !pte_write(pte)) if (write && !pte_write(pte))
goto out; goto out;
if (read && !pte_read(pte))
goto out;
pfn = pte_pfn(pte); pfn = pte_pfn(pte);
if (pfn_valid(pfn)) { if (pfn_valid(pfn)) {
page = pfn_to_page(pfn); page = pfn_to_page(pfn);
...@@ -798,6 +800,20 @@ follow_page(struct mm_struct *mm, unsigned long address, int write) ...@@ -798,6 +800,20 @@ follow_page(struct mm_struct *mm, unsigned long address, int write)
return NULL; return NULL;
} }
struct page *
follow_page(struct mm_struct *mm, unsigned long address, int write)
{
return __follow_page(mm, address, /*read*/0, write);
}
int
check_user_page_readable(struct mm_struct *mm, unsigned long address)
{
return __follow_page(mm, address, /*read*/1, /*write*/0) != NULL;
}
EXPORT_SYMBOL(check_user_page_readable);
/* /*
* Given a physical address, is there a useful struct page pointing to * Given a physical address, is there a useful struct page pointing to
* it? This may become more complex in the future if we start dealing * it? This may become more complex in the future if we start dealing
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment