Commit aeed5fce authored by Hugh Dickins's avatar Hugh Dickins Committed by Linus Torvalds

x86: fix PAE pmd_bad bootup warning

Fix warning from pmd_bad() at bootup on a HIGHMEM64G HIGHPTE x86_32.

That came from 9fc34113 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 cded932b 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: default avatarHugh Dickins <hugh@veritas.com>
Earlier-version-tested-by: default avatarIngo 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: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent bb78be83
...@@ -172,10 +172,3 @@ void reserve_top_address(unsigned long reserve) ...@@ -172,10 +172,3 @@ void reserve_top_address(unsigned long reserve)
__FIXADDR_TOP = -reserve - PAGE_SIZE; __FIXADDR_TOP = -reserve - PAGE_SIZE;
__VMALLOC_RESERVE += reserve; __VMALLOC_RESERVE += reserve;
} }
int pmd_bad(pmd_t pmd)
{
WARN_ON_ONCE(pmd_bad_v1(pmd) != pmd_bad_v2(pmd));
return pmd_bad_v1(pmd);
}
...@@ -88,14 +88,7 @@ extern unsigned long pg0[]; ...@@ -88,14 +88,7 @@ extern unsigned long pg0[];
/* To avoid harmful races, pmd_none(x) should check only the lower when PAE */ /* To avoid harmful races, pmd_none(x) should check only the lower when PAE */
#define pmd_none(x) (!(unsigned long)pmd_val((x))) #define pmd_none(x) (!(unsigned long)pmd_val((x)))
#define pmd_present(x) (pmd_val((x)) & _PAGE_PRESENT) #define pmd_present(x) (pmd_val((x)) & _PAGE_PRESENT)
#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
extern int pmd_bad(pmd_t pmd);
#define pmd_bad_v1(x) \
(_KERNPG_TABLE != (pmd_val((x)) & ~(PAGE_MASK | _PAGE_USER)))
#define pmd_bad_v2(x) \
(_KERNPG_TABLE != (pmd_val((x)) & ~(PAGE_MASK | _PAGE_USER | \
_PAGE_PSE | _PAGE_NX)))
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
......
...@@ -158,14 +158,12 @@ static inline unsigned long pgd_bad(pgd_t pgd) ...@@ -158,14 +158,12 @@ static inline unsigned long pgd_bad(pgd_t pgd)
static inline unsigned long pud_bad(pud_t pud) static inline unsigned long pud_bad(pud_t pud)
{ {
return pud_val(pud) & return pud_val(pud) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER | _PAGE_PSE | _PAGE_NX);
} }
static inline unsigned long pmd_bad(pmd_t pmd) static inline unsigned long pmd_bad(pmd_t pmd)
{ {
return pmd_val(pmd) & return pmd_val(pmd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER | _PAGE_PSE | _PAGE_NX);
} }
#define pte_none(x) (!pte_val((x))) #define pte_none(x) (!pte_val((x)))
......
...@@ -969,7 +969,7 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address, ...@@ -969,7 +969,7 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
goto no_page_table; goto no_page_table;
pmd = pmd_offset(pud, address); pmd = pmd_offset(pud, address);
if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) if (pmd_none(*pmd))
goto no_page_table; goto no_page_table;
if (pmd_huge(*pmd)) { if (pmd_huge(*pmd)) {
...@@ -978,6 +978,9 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address, ...@@ -978,6 +978,9 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
goto out; goto out;
} }
if (unlikely(pmd_bad(*pmd)))
goto no_page_table;
ptep = pte_offset_map_lock(mm, pmd, address, &ptl); ptep = pte_offset_map_lock(mm, pmd, address, &ptl);
if (!ptep) if (!ptep)
goto out; goto out;
......
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