summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2013-05-27 16:19:55 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-06-07 12:53:05 -0700
commit52f36be0f4e2fafa5dd85fbd6508bbfba314fd58 (patch)
tree78202186ad4059b15ca00f2f92d8da278db1630e
parentf64747c92f852b35b870408cbc82ffa4f1ce76b8 (diff)
s390/pgtable: Fix check for pgste/storage key handling
commit b56433cb782d1cc7e44fc46d2ce3917fa75d2236 upstream. 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> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 3cb47cf02530..fd8001576466 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -637,7 +637,7 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
unsigned long address, bits;
unsigned char skey;
- if (!pte_present(*ptep))
+ if (pte_val(*ptep) & _PAGE_INVALID)
return pgste;
address = pte_val(*ptep) & PAGE_MASK;
skey = page_get_storage_key(address);
@@ -671,7 +671,7 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
#ifdef CONFIG_PGSTE
int young;
- if (!pte_present(*ptep))
+ if (pte_val(*ptep) & _PAGE_INVALID)
return pgste;
/* Get referenced bit from storage key */
young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
@@ -697,7 +697,7 @@ static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry)
unsigned long address;
unsigned long okey, nkey;
- if (!pte_present(entry))
+ if (pte_val(entry) & _PAGE_INVALID)
return;
address = pte_val(entry) & PAGE_MASK;
okey = nkey = page_get_storage_key(address);
@@ -1072,6 +1072,9 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
pte = *ptep;
if (!mm_exclusive(mm))
__ptep_ipte(address, ptep);
+
+ if (mm_has_pgste(mm))
+ pgste = pgste_update_all(&pte, pgste);
return pte;
}
@@ -1079,9 +1082,13 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm,
unsigned long address,
pte_t *ptep, pte_t pte)
{
+ pgste_t pgste;
+
if (mm_has_pgste(mm)) {
+ pgste = *(pgste_t *)(ptep + PTRS_PER_PTE);
+ pgste_set_key(ptep, pgste, pte);
pgste_set_pte(ptep, pte);
- pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE));
+ pgste_set_unlock(ptep, pgste);
} else
*ptep = pte;
}