Commit bce7c55d authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] move_one_page kmap atomicity fix

move_one_page() is calling alloc_one_pte_map() while holding an atomic
kmap for the source pte's page.  But alloc_one_pte_map() can sleep in
the page allocator.

So change move_one_page() to take a peek at the destination pagetables
to work out whether the alloc_one_pte_map() will need to perform page
allocation.  If so, drop the atomic kmap and retake it after allocating
the pte.
parent 55ee0843
......@@ -53,6 +53,22 @@ static inline pte_t *get_one_pte_map_nested(struct mm_struct *mm, unsigned long
return pte;
}
#ifdef CONFIG_HIGHPTE /* Save a few cycles on the sane machines */
static inline int page_table_present(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pmd_t *pmd;
pgd = pgd_offset(mm, addr);
if (pgd_none(*pgd))
return 0;
pmd = pmd_offset(pgd, addr);
return pmd_present(*pmd);
}
#else
#define page_table_present(mm, addr) (1)
#endif
static inline pte_t *alloc_one_pte_map(struct mm_struct *mm, unsigned long addr)
{
pmd_t * pmd;
......@@ -98,7 +114,18 @@ static int move_one_page(struct vm_area_struct *vma, unsigned long old_addr, uns
spin_lock(&mm->page_table_lock);
src = get_one_pte_map_nested(mm, old_addr);
if (src) {
/*
* Look to see whether alloc_one_pte_map needs to perform a
* memory allocation. If it does then we need to drop the
* atomic kmap
*/
if (!page_table_present(mm, new_addr)) {
pte_unmap_nested(src);
src = NULL;
}
dst = alloc_one_pte_map(mm, new_addr);
if (src == NULL)
src = get_one_pte_map_nested(mm, old_addr);
error = copy_one_pte(mm, src, dst);
pte_unmap_nested(src);
pte_unmap(dst);
......
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