aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/include/asm
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2013-05-27 10:19:55 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-05-28 09:18:05 -0400
commitb56433cb782d1cc7e44fc46d2ce3917fa75d2236 (patch)
tree4ef2bf321a213f0c5ad70c2967a2c5b94a82a8a5 /arch/s390/include/asm
parentd5b4c2f4938aaebc392669111385c3cf50dd309f (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.h15
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}