mm: hugetlb: add arch hook for clearing page flags before entering pool
authorWill Deacon <will.deacon@arm.com>
Mon, 8 Oct 2012 23:29:32 +0000 (16:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 9 Oct 2012 07:22:24 +0000 (16:22 +0900)
The core page allocator ensures that page flags are zeroed when freeing
pages via free_pages_check.  A number of architectures (ARM, PPC, MIPS)
rely on this property to treat new pages as dirty with respect to the data
cache and perform the appropriate flushing before mapping the pages into
userspace.

This can lead to cache synchronisation problems when using hugepages,
since the allocator keeps its own pool of pages above the usual page
allocator and does not reset the page flags when freeing a page into the
pool.

This patch adds a new architecture hook, arch_clear_hugepage_flags, so
that architectures which rely on the page flags being in a particular
state for fresh allocations can adjust the flags accordingly when a page
is freed into the pool.

Signed-off-by: Will Deacon <will.deacon@arm.com>
Cc: Michal Hocko <mhocko@suse.cz>
Reviewed-by: Michal Hocko <mhocko@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/ia64/include/asm/hugetlb.h
arch/mips/include/asm/hugetlb.h
arch/powerpc/include/asm/hugetlb.h
arch/s390/include/asm/hugetlb.h
arch/sh/include/asm/hugetlb.h
arch/sparc/include/asm/hugetlb.h
arch/tile/include/asm/hugetlb.h
arch/x86/include/asm/hugetlb.h
mm/hugetlb.c

index da55c63728e0e3f5d2b269d8c6bcb1607bddee57..94eaa5bd5d0c4fb33f4240676765d4e5fb92ec58 100644 (file)
@@ -77,4 +77,8 @@ static inline void arch_release_hugepage(struct page *page)
 {
 }
 
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+}
+
 #endif /* _ASM_IA64_HUGETLB_H */
index 58d36889f09b3c7e6af95106d1d6fd22c19f4f0d..bd94946a18f343da04b48aba1a13b83f6e724c18 100644 (file)
@@ -112,4 +112,8 @@ static inline void arch_release_hugepage(struct page *page)
 {
 }
 
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+}
+
 #endif /* __ASM_HUGETLB_H */
index dfdb95bc59a50a9f89267112dfec3c1b0c10abb2..62e11a32c4c2bfcf4bcbff390a29171b68572e99 100644 (file)
@@ -151,6 +151,10 @@ static inline void arch_release_hugepage(struct page *page)
 {
 }
 
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+}
+
 #else /* ! CONFIG_HUGETLB_PAGE */
 static inline void flush_hugetlb_page(struct vm_area_struct *vma,
                                      unsigned long vmaddr)
index 2d6e6e3805641bbc79ce1ee11aa639f48f5e2933..fc322421b1cc127dcb640407454c8e01bbb00df8 100644 (file)
@@ -33,6 +33,7 @@ static inline int prepare_hugepage_range(struct file *file,
 }
 
 #define hugetlb_prefault_arch_hook(mm)         do { } while (0)
+#define arch_clear_hugepage_flags(page)                do { } while (0)
 
 int arch_prepare_hugepage(struct page *page);
 void arch_release_hugepage(struct page *page);
index 967068fb79ac483959ccd13436e1c14601133308..b3808c7d67b23622b6ccaf5729c0d8603b7bd523 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_SH_HUGETLB_H
 #define _ASM_SH_HUGETLB_H
 
+#include <asm/cacheflush.h>
 #include <asm/page.h>
 
 
@@ -89,4 +90,9 @@ static inline void arch_release_hugepage(struct page *page)
 {
 }
 
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+       clear_bit(PG_dcache_clean, &page->flags);
+}
+
 #endif /* _ASM_SH_HUGETLB_H */
index 177061064ee602ed4dc0e8e956a4b682695c79f0..e7927c9758a19eb6bb27fb08944ac92bdf096f2b 100644 (file)
@@ -82,4 +82,8 @@ static inline void arch_release_hugepage(struct page *page)
 {
 }
 
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+}
+
 #endif /* _ASM_SPARC64_HUGETLB_H */
index b2042380a5aab580011e54c436fc24ccc02e9366..0f885af2b62157f12b025f91f694eaa8592c3d49 100644 (file)
@@ -106,6 +106,10 @@ static inline void arch_release_hugepage(struct page *page)
 {
 }
 
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+}
+
 #ifdef CONFIG_HUGETLB_SUPER_PAGES
 static inline pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
                                       struct page *page, int writable)
index 439a9acc132d10f77b469fc24b250f3acc2f51d9..bdd35dbd0605b9c39d20a4111d20cc89f7053a7b 100644 (file)
@@ -90,4 +90,8 @@ static inline void arch_release_hugepage(struct page *page)
 {
 }
 
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+}
+
 #endif /* _ASM_X86_HUGETLB_H */
index bc727122dd44de6c4ae9307c618e58ddf4da3c87..f1bb534254f6977a7685893ee7046774522b93ca 100644 (file)
@@ -637,6 +637,7 @@ static void free_huge_page(struct page *page)
                h->surplus_huge_pages--;
                h->surplus_huge_pages_node[nid]--;
        } else {
+               arch_clear_hugepage_flags(page);
                enqueue_huge_page(h, page);
        }
        spin_unlock(&hugetlb_lock);