Commit 76fc2aaf authored by David Miller's avatar David Miller Committed by Chris Wright

[PATCH] SPARC64: Fix D-cache corruption in mremap

If we move a mapping from one virtual address to another,
and this changes the virtual color of the mapping to those
pages, we can see corrupt data due to D-cache aliasing.

Check for and deal with this by overriding the move_pte()
macro.  Set things up so that other platforms can cleanly
override the move_pte() macro too.

This long standing bug corrupts user memory, and in particular
has been notorious for corrupting Debian package database
files on sparc64 boxes.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarChris Wright <chrisw@sous-sol.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 0d9a5318
...@@ -159,17 +159,8 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres ...@@ -159,17 +159,8 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres
#define lazy_mmu_prot_update(pte) do { } while (0) #define lazy_mmu_prot_update(pte) do { } while (0)
#endif #endif
#ifndef __HAVE_ARCH_MULTIPLE_ZERO_PAGE #ifndef __HAVE_ARCH_MOVE_PTE
#define move_pte(pte, prot, old_addr, new_addr) (pte) #define move_pte(pte, prot, old_addr, new_addr) (pte)
#else
#define move_pte(pte, prot, old_addr, new_addr) \
({ \
pte_t newpte = (pte); \
if (pte_present(pte) && pfn_valid(pte_pfn(pte)) && \
pte_page(pte) == ZERO_PAGE(old_addr)) \
newpte = mk_pte(ZERO_PAGE(new_addr), (prot)); \
newpte; \
})
#endif #endif
/* /*
......
...@@ -70,7 +70,15 @@ extern unsigned long zero_page_mask; ...@@ -70,7 +70,15 @@ extern unsigned long zero_page_mask;
#define ZERO_PAGE(vaddr) \ #define ZERO_PAGE(vaddr) \
(virt_to_page(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask))) (virt_to_page(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask)))
#define __HAVE_ARCH_MULTIPLE_ZERO_PAGE #define __HAVE_ARCH_MOVE_PTE
#define move_pte(pte, prot, old_addr, new_addr) \
({ \
pte_t newpte = (pte); \
if (pte_present(pte) && pfn_valid(pte_pfn(pte)) && \
pte_page(pte) == ZERO_PAGE(old_addr)) \
newpte = mk_pte(ZERO_PAGE(new_addr), (prot)); \
newpte; \
})
extern void paging_init(void); extern void paging_init(void);
......
...@@ -335,6 +335,23 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *p ...@@ -335,6 +335,23 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *p
#define pte_clear(mm,addr,ptep) \ #define pte_clear(mm,addr,ptep) \
set_pte_at((mm), (addr), (ptep), __pte(0UL)) set_pte_at((mm), (addr), (ptep), __pte(0UL))
#ifdef DCACHE_ALIASING_POSSIBLE
#define __HAVE_ARCH_MOVE_PTE
#define move_pte(pte, prot, old_addr, new_addr) \
({ \
pte_t newpte = (pte); \
if (pte_present(pte)) { \
unsigned long this_pfn = pte_pfn(pte); \
\
if (pfn_valid(this_pfn) && \
(((old_addr) ^ (new_addr)) & (1 << 13))) \
flush_dcache_page_all(current->mm, \
pfn_to_page(this_pfn)); \
} \
newpte; \
})
#endif
extern pgd_t swapper_pg_dir[2048]; extern pgd_t swapper_pg_dir[2048];
extern pmd_t swapper_low_pmd_dir[2048]; extern pmd_t swapper_low_pmd_dir[2048];
......
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