Commit 016b33c4 authored by Andy Whitcroft's avatar Andy Whitcroft Committed by Paul Mackerras

powerpc: Add 64 bit version of huge_ptep_set_wrprotect

The implementation of huge_ptep_set_wrprotect() directly calls
ptep_set_wrprotect() to mark a hugepte write protected.  However this
call is not appropriate on ppc64 kernels as this is a small page only
implementation.  This can lead to the hash not being flushed correctly
when a mapping is being converted to COW, allowing processes to continue
using the original copy.

Currently huge_ptep_set_wrprotect() unconditionally calls
ptep_set_wrprotect().  This is fine on ppc32 kernels as this call is
generic.  On 64 bit this is implemented as:

	pte_update(mm, addr, ptep, _PAGE_RW, 0);

On ppc64 this last parameter is the page size and is passed directly on
to hpte_need_flush():

	hpte_need_flush(mm, addr, ptep, old, huge);

And this directly affects the page size we pass to flush_hash_page():

	flush_hash_page(vaddr, rpte, psize, ssize, 0);

As this changes the way the hash is calculated we will flush the wrong
pages, potentially leaving live hashes to the original page.

Move the definition of huge_ptep_set_wrprotect() to the 32/64 bit specific
headers.
Signed-off-by: default avatarAndy Whitcroft <apw@shadowen.org>
Acked-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 03d70617
...@@ -49,12 +49,6 @@ static inline pte_t huge_pte_wrprotect(pte_t pte) ...@@ -49,12 +49,6 @@ static inline pte_t huge_pte_wrprotect(pte_t pte)
return pte_wrprotect(pte); return pte_wrprotect(pte);
} }
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
ptep_set_wrprotect(mm, addr, ptep);
}
static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep, unsigned long addr, pte_t *ptep,
pte_t pte, int dirty) pte_t pte, int dirty)
......
...@@ -652,6 +652,12 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, ...@@ -652,6 +652,12 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
{ {
pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0); pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0);
} }
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
ptep_set_wrprotect(mm, addr, ptep);
}
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty) static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
......
...@@ -312,6 +312,15 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, ...@@ -312,6 +312,15 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
return; return;
old = pte_update(mm, addr, ptep, _PAGE_RW, 0); old = pte_update(mm, addr, ptep, _PAGE_RW, 0);
} }
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
unsigned long old;
if ((pte_val(*ptep) & _PAGE_RW) == 0)
return;
old = pte_update(mm, addr, ptep, _PAGE_RW, 1);
}
/* /*
* We currently remove entries from the hashtable regardless of whether * We currently remove entries from the hashtable regardless of whether
......
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