diff options
author | Christian Borntraeger <borntraeger@de.ibm.com> | 2013-05-27 10:19:55 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-05-28 09:18:05 -0400 |
commit | b56433cb782d1cc7e44fc46d2ce3917fa75d2236 (patch) | |
tree | 4ef2bf321a213f0c5ad70c2967a2c5b94a82a8a5 /arch/s390/include/asm | |
parent | d5b4c2f4938aaebc392669111385c3cf50dd309f (diff) |
s390/pgtable: Fix check for pgste/storage key handling
pte_present might return true on PAGE_TYPE_NONE, even if
the invalid bit is on. Modify the existing check of the
pgste functions to avoid crashes.
[ Martin Schwidefsky: added ptep_modify_prot_[start|commit] bits ]
Reported-by: Martin Schwidefky <schwidefsky@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
CC: stable@vger.kernel.org
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/include/asm')
-rw-r--r-- | arch/s390/include/asm/pgtable.h | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 0f0de30e3e3f..ac01463038f1 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -646,7 +646,7 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) | |||
646 | unsigned long address, bits; | 646 | unsigned long address, bits; |
647 | unsigned char skey; | 647 | unsigned char skey; |
648 | 648 | ||
649 | if (!pte_present(*ptep)) | 649 | if (pte_val(*ptep) & _PAGE_INVALID) |
650 | return pgste; | 650 | return pgste; |
651 | address = pte_val(*ptep) & PAGE_MASK; | 651 | address = pte_val(*ptep) & PAGE_MASK; |
652 | skey = page_get_storage_key(address); | 652 | skey = page_get_storage_key(address); |
@@ -680,7 +680,7 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste) | |||
680 | #ifdef CONFIG_PGSTE | 680 | #ifdef CONFIG_PGSTE |
681 | int young; | 681 | int young; |
682 | 682 | ||
683 | if (!pte_present(*ptep)) | 683 | if (pte_val(*ptep) & _PAGE_INVALID) |
684 | return pgste; | 684 | return pgste; |
685 | /* Get referenced bit from storage key */ | 685 | /* Get referenced bit from storage key */ |
686 | young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); | 686 | young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); |
@@ -706,7 +706,7 @@ static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry) | |||
706 | unsigned long address; | 706 | unsigned long address; |
707 | unsigned long okey, nkey; | 707 | unsigned long okey, nkey; |
708 | 708 | ||
709 | if (!pte_present(entry)) | 709 | if (pte_val(entry) & _PAGE_INVALID) |
710 | return; | 710 | return; |
711 | address = pte_val(entry) & PAGE_MASK; | 711 | address = pte_val(entry) & PAGE_MASK; |
712 | okey = nkey = page_get_storage_key(address); | 712 | okey = nkey = page_get_storage_key(address); |
@@ -1098,6 +1098,9 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, | |||
1098 | pte = *ptep; | 1098 | pte = *ptep; |
1099 | if (!mm_exclusive(mm)) | 1099 | if (!mm_exclusive(mm)) |
1100 | __ptep_ipte(address, ptep); | 1100 | __ptep_ipte(address, ptep); |
1101 | |||
1102 | if (mm_has_pgste(mm)) | ||
1103 | pgste = pgste_update_all(&pte, pgste); | ||
1101 | return pte; | 1104 | return pte; |
1102 | } | 1105 | } |
1103 | 1106 | ||
@@ -1105,9 +1108,13 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm, | |||
1105 | unsigned long address, | 1108 | unsigned long address, |
1106 | pte_t *ptep, pte_t pte) | 1109 | pte_t *ptep, pte_t pte) |
1107 | { | 1110 | { |
1111 | pgste_t pgste; | ||
1112 | |||
1108 | if (mm_has_pgste(mm)) { | 1113 | if (mm_has_pgste(mm)) { |
1114 | pgste = *(pgste_t *)(ptep + PTRS_PER_PTE); | ||
1115 | pgste_set_key(ptep, pgste, pte); | ||
1109 | pgste_set_pte(ptep, pte); | 1116 | pgste_set_pte(ptep, pte); |
1110 | pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE)); | 1117 | pgste_set_unlock(ptep, pgste); |
1111 | } else | 1118 | } else |
1112 | *ptep = pte; | 1119 | *ptep = pte; |
1113 | } | 1120 | } |