diff options
author | Christian Borntraeger <borntraeger@de.ibm.com> | 2013-05-27 16:19:55 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-06-07 12:53:05 -0700 |
commit | 52f36be0f4e2fafa5dd85fbd6508bbfba314fd58 (patch) | |
tree | 78202186ad4059b15ca00f2f92d8da278db1630e /arch | |
parent | f64747c92f852b35b870408cbc82ffa4f1ce76b8 (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>
Diffstat (limited to 'arch')
-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 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; } |