From: Andrew Morton Date: Thu, 7 Aug 2003 04:13:43 +0000 (-0700) Subject: [PATCH] move_one_page() atomicity fix X-Git-Tag: v2.6.0-test3~12^2~23 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=8a8f9d8ee20f97484e09b27e16f7a876d2de9bc0;p=history.git [PATCH] move_one_page() atomicity fix move_one_page() is awkward. It grabs an atomic_kmap of the source pte (because it needs to know if there's really a page there) and then it needs to allocate a pte for the dest. But it cannot allocate the dest pte while holding the src's atomic kmap. So it performs this little dance peeking at pagetables to predict if alloc_one_pte_map() might need to perform a pte page allocation. When I wrote this code I made it conditional on CONFIG_HIGHPTE. But that was bogus: even in the !CONFIG_HIGHPTE case, get_one_pte_map_nested() will run atomic_kmap() against the pte page, which disables preemption. Net effect: with CONFIG_HIGHMEM && !CONFIG_HIGHPTE we can end up performing a GFP_KERNEL pte page allocation while preemption is disabled. It triggers a might_sleep() warning and indeed is buggy. So the patch removes the conditionality: even in the !CONFIG_HIGHPTE case we still do the pagetable peek and drop the kmap if necessary. (Arguably, we shouldn't be performing the atomic_kmap() at all if !CONFIG_HIGHPTE: all it does is a pointless preemption disable). (Arguably, kmap_atomic() should not be disabling preemption if the target page is not highmem. But we're doing it anyway at present for consistency (ie: debug coverage) and because the filemap.c pagecache copying functions rely on kmap_atomic() disabling do_no_page() for all pages: see do_no_page()'s use of in_atomic()). --- diff --git a/mm/mremap.c b/mm/mremap.c index 088af945ac5e..d9180f18ad6c 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -56,7 +56,6 @@ end: 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; @@ -68,9 +67,6 @@ static inline int page_table_present(struct mm_struct *mm, unsigned long addr) 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) {