diff options
author | Christian Borntraeger <borntraeger@de.ibm.com> | 2008-10-28 06:10:15 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-10-28 06:12:03 -0400 |
commit | 250cf776f74b5932a1977d0489cae9206e2351dd (patch) | |
tree | 71bb6778e65e8efbdd0cac09a64e4e1194b98c3f /arch/s390/include/asm/pgtable.h | |
parent | 2c78091405d6f54748b1fac78c45f2a799e3073a (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.h | 8 |
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 | ||
680 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 680 | static 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) | |||
844 | static inline void ptep_invalidate(struct mm_struct *mm, | 844 | static 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); |