[S390] pgtables: Fix race in enable_sie vs. page table ops
The current enable_sie code sets the mm->context.pgstes bit to tell dup_mm that the new mm should have extended page tables. This bit is also used by the s390 specific page table primitives to decide about the page table layout - which means context.pgstes has two meanings. This can cause any kind of bugs. For example - e.g. shrink_zone can call ptep_clear_flush_young while enable_sie is running. ptep_clear_flush_young will test for context.pgstes. Since enable_sie changed that value of the old struct mm without changing the page table layout ptep_clear_flush_young will do the wrong thing. The solution is to split pgstes into two bits - one for the allocation - one for the current state Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:

committed by
Martin Schwidefsky

parent
2c78091405
commit
250cf776f7
@@ -679,7 +679,7 @@ static inline void pmd_clear(pmd_t *pmd)
|
||||
|
||||
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
|
||||
{
|
||||
if (mm->context.pgstes)
|
||||
if (mm->context.has_pgste)
|
||||
ptep_rcp_copy(ptep);
|
||||
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
|
||||
if (mm->context.noexec)
|
||||
@@ -763,7 +763,7 @@ static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
|
||||
struct page *page;
|
||||
unsigned int skey;
|
||||
|
||||
if (!mm->context.pgstes)
|
||||
if (!mm->context.has_pgste)
|
||||
return -EINVAL;
|
||||
rcp_lock(ptep);
|
||||
pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
|
||||
@@ -794,7 +794,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
|
||||
int young;
|
||||
unsigned long *pgste;
|
||||
|
||||
if (!vma->vm_mm->context.pgstes)
|
||||
if (!vma->vm_mm->context.has_pgste)
|
||||
return 0;
|
||||
physpage = pte_val(*ptep) & PAGE_MASK;
|
||||
pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
|
||||
@@ -844,7 +844,7 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
|
||||
static inline void ptep_invalidate(struct mm_struct *mm,
|
||||
unsigned long address, pte_t *ptep)
|
||||
{
|
||||
if (mm->context.pgstes) {
|
||||
if (mm->context.has_pgste) {
|
||||
rcp_lock(ptep);
|
||||
__ptep_ipte(address, ptep);
|
||||
ptep_rcp_copy(ptep);
|
||||
|
Reference in New Issue
Block a user