aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2008-05-06 15:49:23 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-05-06 16:08:58 -0400
commitaeed5fce37196e09b4dac3a1c00d8b7122e040ce (patch)
treed16a8f824ad06ac5dea6052f1986165a0d7fc865
parentbb78be8397d3b0900af3d717672218ee3ea07985 (diff)
x86: fix PAE pmd_bad bootup warning
Fix warning from pmd_bad() at bootup on a HIGHMEM64G HIGHPTE x86_32. That came from 9fc34113f6880b215cbea4e7017fc818700384c2 x86: debug pmd_bad(); but we understand now that the typecasting was wrong for PAE in the previous version: pagetable pages above 4GB looked bad and stopped Arjan from booting. And revert that cded932b75ab0a5f9181ee3da34a0a488d1a14fd x86: fix pmd_bad and pud_bad to support huge pages. It was the wrong way round: we shouldn't weaken every pmd_bad and pud_bad check to let huge pages slip through - in part they check that we _don't_ have a huge page where it's not expected. Put the x86 pmd_bad() and pud_bad() definitions back to what they have long been: they can be improved (x86_32 should use PTE_MASK, to stop PAE thinking junk in the upper word is good; and x86_64 should follow x86_32's stricter comparison, to stop thinking any subset of required bits is good); but that should be a later patch. Fix Hans' good observation that follow_page() will never find pmd_huge() because that would have already failed the pmd_bad test: test pmd_huge in between the pmd_none and pmd_bad tests. Tighten x86's pmd_huge() check? No, once it's a hugepage entry, it can get quite far from a good pmd: for example, PROT_NONE leaves it with only ACCESSED of the KERN_PGTABLE bits. However... though follow_page() contains this and another test for huge pages, so it's nice to keep it working on them, where does it actually get called on a huge page? get_user_pages() checks is_vm_hugetlb_page(vma) to to call alternative hugetlb processing, as does unmap_vmas() and others. Signed-off-by: Hugh Dickins <hugh@veritas.com> Earlier-version-tested-by: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Jeff Chua <jeff.chua.linux@gmail.com> Cc: Hans Rosenfeld <hans.rosenfeld@amd.com> Cc: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/x86/mm/pgtable_32.c7
-rw-r--r--include/asm-x86/pgtable_32.h9
-rw-r--r--include/asm-x86/pgtable_64.h6
-rw-r--r--mm/memory.c5
4 files changed, 7 insertions, 20 deletions
diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c
index 9ee007be9142..369cf065b6a4 100644
--- a/arch/x86/mm/pgtable_32.c
+++ b/arch/x86/mm/pgtable_32.c
@@ -172,10 +172,3 @@ void reserve_top_address(unsigned long reserve)
172 __FIXADDR_TOP = -reserve - PAGE_SIZE; 172 __FIXADDR_TOP = -reserve - PAGE_SIZE;
173 __VMALLOC_RESERVE += reserve; 173 __VMALLOC_RESERVE += reserve;
174} 174}
175
176int pmd_bad(pmd_t pmd)
177{
178 WARN_ON_ONCE(pmd_bad_v1(pmd) != pmd_bad_v2(pmd));
179
180 return pmd_bad_v1(pmd);
181}
diff --git a/include/asm-x86/pgtable_32.h b/include/asm-x86/pgtable_32.h
index 577ab79c4c27..d7f0403bbecb 100644
--- a/include/asm-x86/pgtable_32.h
+++ b/include/asm-x86/pgtable_32.h
@@ -88,14 +88,7 @@ extern unsigned long pg0[];
88/* To avoid harmful races, pmd_none(x) should check only the lower when PAE */ 88/* To avoid harmful races, pmd_none(x) should check only the lower when PAE */
89#define pmd_none(x) (!(unsigned long)pmd_val((x))) 89#define pmd_none(x) (!(unsigned long)pmd_val((x)))
90#define pmd_present(x) (pmd_val((x)) & _PAGE_PRESENT) 90#define pmd_present(x) (pmd_val((x)) & _PAGE_PRESENT)
91 91#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
92extern int pmd_bad(pmd_t pmd);
93
94#define pmd_bad_v1(x) \
95 (_KERNPG_TABLE != (pmd_val((x)) & ~(PAGE_MASK | _PAGE_USER)))
96#define pmd_bad_v2(x) \
97 (_KERNPG_TABLE != (pmd_val((x)) & ~(PAGE_MASK | _PAGE_USER | \
98 _PAGE_PSE | _PAGE_NX)))
99 92
100#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) 93#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
101 94
diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h
index a3bbf8766c1d..efe83dcbd412 100644
--- a/include/asm-x86/pgtable_64.h
+++ b/include/asm-x86/pgtable_64.h
@@ -158,14 +158,12 @@ static inline unsigned long pgd_bad(pgd_t pgd)
158 158
159static inline unsigned long pud_bad(pud_t pud) 159static inline unsigned long pud_bad(pud_t pud)
160{ 160{
161 return pud_val(pud) & 161 return pud_val(pud) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
162 ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER | _PAGE_PSE | _PAGE_NX);
163} 162}
164 163
165static inline unsigned long pmd_bad(pmd_t pmd) 164static inline unsigned long pmd_bad(pmd_t pmd)
166{ 165{
167 return pmd_val(pmd) & 166 return pmd_val(pmd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
168 ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER | _PAGE_PSE | _PAGE_NX);
169} 167}
170 168
171#define pte_none(x) (!pte_val((x))) 169#define pte_none(x) (!pte_val((x)))
diff --git a/mm/memory.c b/mm/memory.c
index bbab1e37055e..48c122d42ed7 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -969,7 +969,7 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
969 goto no_page_table; 969 goto no_page_table;
970 970
971 pmd = pmd_offset(pud, address); 971 pmd = pmd_offset(pud, address);
972 if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) 972 if (pmd_none(*pmd))
973 goto no_page_table; 973 goto no_page_table;
974 974
975 if (pmd_huge(*pmd)) { 975 if (pmd_huge(*pmd)) {
@@ -978,6 +978,9 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
978 goto out; 978 goto out;
979 } 979 }
980 980
981 if (unlikely(pmd_bad(*pmd)))
982 goto no_page_table;
983
981 ptep = pte_offset_map_lock(mm, pmd, address, &ptl); 984 ptep = pte_offset_map_lock(mm, pmd, address, &ptl);
982 if (!ptep) 985 if (!ptep)
983 goto out; 986 goto out;