aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/include/asm/pgtable.h
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2008-10-28 06:10:15 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-10-28 06:12:03 -0400
commit250cf776f74b5932a1977d0489cae9206e2351dd (patch)
tree71bb6778e65e8efbdd0cac09a64e4e1194b98c3f /arch/s390/include/asm/pgtable.h
parent2c78091405d6f54748b1fac78c45f2a799e3073a (diff)
[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>
Diffstat (limited to 'arch/s390/include/asm/pgtable.h')
-rw-r--r--arch/s390/include/asm/pgtable.h8
1 files changed, 4 insertions, 4 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 1a928f84afd6..7fc76133b3e4 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -679,7 +679,7 @@ static inline void pmd_clear(pmd_t *pmd)
679 679
680static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) 680static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
681{ 681{
682 if (mm->context.pgstes) 682 if (mm->context.has_pgste)
683 ptep_rcp_copy(ptep); 683 ptep_rcp_copy(ptep);
684 pte_val(*ptep) = _PAGE_TYPE_EMPTY; 684 pte_val(*ptep) = _PAGE_TYPE_EMPTY;
685 if (mm->context.noexec) 685 if (mm->context.noexec)
@@ -763,7 +763,7 @@ static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
763 struct page *page; 763 struct page *page;
764 unsigned int skey; 764 unsigned int skey;
765 765
766 if (!mm->context.pgstes) 766 if (!mm->context.has_pgste)
767 return -EINVAL; 767 return -EINVAL;
768 rcp_lock(ptep); 768 rcp_lock(ptep);
769 pgste = (unsigned long *) (ptep + PTRS_PER_PTE); 769 pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
@@ -794,7 +794,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
794 int young; 794 int young;
795 unsigned long *pgste; 795 unsigned long *pgste;
796 796
797 if (!vma->vm_mm->context.pgstes) 797 if (!vma->vm_mm->context.has_pgste)
798 return 0; 798 return 0;
799 physpage = pte_val(*ptep) & PAGE_MASK; 799 physpage = pte_val(*ptep) & PAGE_MASK;
800 pgste = (unsigned long *) (ptep + PTRS_PER_PTE); 800 pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
@@ -844,7 +844,7 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
844static inline void ptep_invalidate(struct mm_struct *mm, 844static inline void ptep_invalidate(struct mm_struct *mm,
845 unsigned long address, pte_t *ptep) 845 unsigned long address, pte_t *ptep)
846{ 846{
847 if (mm->context.pgstes) { 847 if (mm->context.has_pgste) {
848 rcp_lock(ptep); 848 rcp_lock(ptep);
849 __ptep_ipte(address, ptep); 849 __ptep_ipte(address, ptep);
850 ptep_rcp_copy(ptep); 850 ptep_rcp_copy(ptep);