--- x/mm/mremap.c.~1~ 2003-05-14 03:26:14.000000000 +0200 +++ x/mm/mremap.c 2003-05-14 03:50:16.000000000 +0200 @@ -40,9 +40,9 @@ static pte_t *get_one_pte(struct mm_stru goto end; } - pte = pte_offset2_under_lock(pmd, addr, mm); + pte = pte_offset_atomic2(pmd, addr); if (pte_none(*pte)) { - pte_kunmap2(pte); + pte_kunmap_atomic2(pte); pte = NULL; } end: @@ -56,18 +56,40 @@ static inline pte_t *alloc_one_pte(struc pmd = pmd_alloc(mm, pgd_offset(mm, addr), addr); if (pmd) - pte = pte_alloc(mm, pmd, addr); + pte = pte_alloc_atomic(mm, pmd, addr); return pte; } -static inline void copy_one_pte(pte_t * src, pte_t * dst) +#ifdef CONFIG_HIGHMEM +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); +} +#endif + +static int copy_one_pte(pte_t * src, pte_t * dst) +{ + int error = 0; pte_t pte; if (!pte_none(*src)) { pte = ptep_get_and_clear(src); + if (!dst) { + /* No dest? We must put it back. */ + dst = src; + error = 1; + } set_pte(dst, pte); } + + return error; } static int move_one_page(struct mm_struct *mm, unsigned long old_addr, unsigned long new_addr) @@ -78,15 +100,28 @@ static int move_one_page(struct mm_struc spin_lock(&mm->page_table_lock); src = get_one_pte(mm, old_addr); if (src) { +#ifdef CONFIG_HIGHMEM + /* + * Look to see whether alloc_one_pte 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_kunmap_atomic2(src); + src = NULL; + } +#endif dst = alloc_one_pte(mm, new_addr); - if (dst) { - copy_one_pte(src, dst); - pte_kunmap(dst); - } else - error = 1; - pte_kunmap2(src); +#ifdef CONFIG_HIGHMEM + if (src == NULL) + src = get_one_pte(mm, old_addr); +#endif + error = copy_one_pte(src, dst); + pte_kunmap_atomic2(src); + pte_kunmap(dst); } spin_unlock(&mm->page_table_lock); + return error; }