[PATCH] mm: kill check_user_page_readable

check_user_page_readable is a problematic variant of follow_page.  It's used
only by oprofile's i386 and arm backtrace code, at interrupt time, to
establish whether a userspace stackframe is currently readable.

This is problematic, because we want to push the page_table_lock down inside
follow_page, and later split it; whereas oprofile is doing a spin_trylock on
it (in the i386 case, forgotten in the arm case), and needs that to pin
perhaps two pages spanned by the stackframe (which might be covered by
different locks when we split).

I think oprofile is going about this in the wrong way: it doesn't need to know
the area is readable (neither i386 nor arm uses read protection of user
pages), it doesn't need to pin the memory, it should simply
__copy_from_user_inatomic, and see if that succeeds or not.  Sorry, but I've
not got around to devising the sparse __user annotations for this.

Then we can eliminate check_user_page_readable, and return to a single
follow_page without the __follow_page variants.

Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Hugh Dickins
2005-10-29 18:16:32 -07:00
committed by Linus Torvalds
parent c0718806cf
commit c34d1b4d16
4 changed files with 26 additions and 88 deletions

View File

@@ -809,8 +809,7 @@ unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
* Do a quick page-table lookup for a single page.
* mm->page_table_lock must be held.
*/
static struct page *__follow_page(struct mm_struct *mm, unsigned long address,
int read, int write, int accessed)
struct page *follow_page(struct mm_struct *mm, unsigned long address, int write)
{
pgd_t *pgd;
pud_t *pud;
@@ -846,16 +845,12 @@ static struct page *__follow_page(struct mm_struct *mm, unsigned long address,
if (pte_present(pte)) {
if (write && !pte_write(pte))
goto out;
if (read && !pte_read(pte))
goto out;
pfn = pte_pfn(pte);
if (pfn_valid(pfn)) {
page = pfn_to_page(pfn);
if (accessed) {
if (write && !pte_dirty(pte) &&!PageDirty(page))
set_page_dirty(page);
mark_page_accessed(page);
}
if (write && !pte_dirty(pte) &&!PageDirty(page))
set_page_dirty(page);
mark_page_accessed(page);
return page;
}
}
@@ -864,22 +859,6 @@ out:
return NULL;
}
inline struct page *
follow_page(struct mm_struct *mm, unsigned long address, int write)
{
return __follow_page(mm, address, 0, write, 1);
}
/*
* check_user_page_readable() can be called frm niterrupt context by oprofile,
* so we need to avoid taking any non-irq-safe locks
*/
int check_user_page_readable(struct mm_struct *mm, unsigned long address)
{
return __follow_page(mm, address, 1, 0, 0) != NULL;
}
EXPORT_SYMBOL(check_user_page_readable);
static inline int
untouched_anonymous_page(struct mm_struct* mm, struct vm_area_struct *vma,
unsigned long address)