linux/i386-PAE: avoid temporarily inconsistent pte-s
PATCH 1/1 linux/i386-PAE: avoid temporarily inconsistent pte-s
One more of these issues (which were considered fixed): Other than on x86-64, i386 allows set_fixmap() to replace already present mappings. Consequently, on PAE, care must be taken to not update the high half of a pte while the low half is still holding the old value.
As always, tested on 2.6.22 and made apply on 2.6.18.
Signed-off-by Jan Beulich <[email protected]>
arch/i386/mm/pgtable-xen.c +6 -86
@@ -77,87 +77,6 @@ void show_mem(void) }/* -* Associate a virtual page frame with a given physical page frame -* and protection flags for that frame. -*/ -static void set_pte_pfn (unsigned long vaddr,unsigned long pfn,pgprot_t flags) -{ -pgd_t *pgd; -pud_t *pud; -pmd_t *pmd; -pte_t *pte; - - pgd = swapper_pg_dir +pgd_index (vaddr); -if (pgd_none (*pgd)) { -BUG (); -return ; - } - pud =pud_offset (pgd, vaddr); -if (pud_none (*pud)) { -BUG (); -return ; - } - pmd =pmd_offset (pud, vaddr); -if (pmd_none (*pmd)) { -BUG (); -return ; - } - pte =pte_offset_kernel (pmd, vaddr); -if (pgprot_val (flags)) -/* <pfn,flags> stored as-is, to permit clearing entries */ -set_pte (pte,pfn_pte (pfn, flags)); -else -pte_clear (&init_mm, vaddr, pte); - -/* -* It's enough to flush this one mapping. -* (PGE mappings get flushed as well) -*/ -__flush_tlb_one (vaddr); -} - -/* -* Associate a virtual page frame with a given physical page frame -* and protection flags for that frame. -*/ -static void set_pte_pfn_ma (unsigned long vaddr,unsigned long pfn, -pgprot_t flags) -{ -pgd_t *pgd; -pud_t *pud; -pmd_t *pmd; -pte_t *pte; - - pgd = swapper_pg_dir +pgd_index (vaddr); -if (pgd_none (*pgd)) { -BUG (); -return ; - } - pud =pud_offset (pgd, vaddr); -if (pud_none (*pud)) { -BUG (); -return ; - } - pmd =pmd_offset (pud, vaddr); -if (pmd_none (*pmd)) { -BUG (); -return ; - } - pte =pte_offset_kernel (pmd, vaddr); -if (pgprot_val (flags)) -/* <pfn,flags> stored as-is, to permit clearing entries */ -set_pte (pte,pfn_pte_ma (pfn, flags)); -else -pte_clear (&init_mm, vaddr, pte); - -/* -* It's enough to flush this one mapping. -* (PGE mappings get flushed as well) -*/ -__flush_tlb_one (vaddr); -} - -/* * Associate a large virtual page frame with a given physical page frame * and protection flags for that frame. pfn is for the base of the page, * vaddr is what the page gets mapped to - both must be properly aligned.
@@ -200,6 +119,7 @@ EXPORT_SYMBOL(__FIXADDR_TOP);void __set_fixmap (enum fixed_addresses idx,maddr_t phys,pgprot_t flags) {unsigned long address =__fix_to_virt (idx); +pte_t pte;if (idx >= __end_of_fixed_addresses) {BUG ();
@@ -207,16 +127,16 @@ void __set_fixmap (enum fixed_addresses }switch (idx) {case FIX_WP_TEST : -#ifdef CONFIG_X86_F00F_BUG -case FIX_F00F_IDT : -#endif case FIX_VDSO : -set_pte_pfn (address, phys >>PAGE_SHIFT , flags); + pte =pfn_pte (phys >>PAGE_SHIFT , flags);break ;default : -set_pte_pfn_ma (address, phys >>PAGE_SHIFT , flags); + pte =pfn_pte_ma (phys >>PAGE_SHIFT , flags);break ; } +if (HYPERVISOR_update_va_mapping (address, pte, +UVMF_INVLPG |UVMF_ALL )) +BUG (); nr_fixmaps++; }