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>
This commit is contained in:
Christian Borntraeger 2013-05-27 16:19:55 +02:00 коммит произвёл Martin Schwidefsky
Родитель d5b4c2f493
Коммит b56433cb78
1 изменённых файлов: 11 добавлений и 4 удалений

Просмотреть файл

@ -646,7 +646,7 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
unsigned long address, bits; unsigned long address, bits;
unsigned char skey; unsigned char skey;
if (!pte_present(*ptep)) if (pte_val(*ptep) & _PAGE_INVALID)
return pgste; return pgste;
address = pte_val(*ptep) & PAGE_MASK; address = pte_val(*ptep) & PAGE_MASK;
skey = page_get_storage_key(address); skey = page_get_storage_key(address);
@ -680,7 +680,7 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
#ifdef CONFIG_PGSTE #ifdef CONFIG_PGSTE
int young; int young;
if (!pte_present(*ptep)) if (pte_val(*ptep) & _PAGE_INVALID)
return pgste; return pgste;
/* Get referenced bit from storage key */ /* Get referenced bit from storage key */
young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); 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)
unsigned long address; unsigned long address;
unsigned long okey, nkey; unsigned long okey, nkey;
if (!pte_present(entry)) if (pte_val(entry) & _PAGE_INVALID)
return; return;
address = pte_val(entry) & PAGE_MASK; address = pte_val(entry) & PAGE_MASK;
okey = nkey = page_get_storage_key(address); okey = nkey = page_get_storage_key(address);
@ -1098,6 +1098,9 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
pte = *ptep; pte = *ptep;
if (!mm_exclusive(mm)) if (!mm_exclusive(mm))
__ptep_ipte(address, ptep); __ptep_ipte(address, ptep);
if (mm_has_pgste(mm))
pgste = pgste_update_all(&pte, pgste);
return pte; return pte;
} }
@ -1105,9 +1108,13 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm,
unsigned long address, unsigned long address,
pte_t *ptep, pte_t pte) pte_t *ptep, pte_t pte)
{ {
pgste_t pgste;
if (mm_has_pgste(mm)) { 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_pte(ptep, pte);
pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE)); pgste_set_unlock(ptep, pgste);
} else } else
*ptep = pte; *ptep = pte;
} }