forked from Minki/linux
[S390] fix pgste update logic
The pgste_update_all / pgste_update_young and pgste_set_pte need to check if the pte entry contains a valid page address before the storage key can be accessed. In addition pgste_set_pte needs to set the access key and fetch protection bit of the new pte entry, not the old entry. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
800252976b
commit
09b538833b
@ -593,6 +593,8 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
|
||||
unsigned long address, bits;
|
||||
unsigned char skey;
|
||||
|
||||
if (!pte_present(*ptep))
|
||||
return pgste;
|
||||
address = pte_val(*ptep) & PAGE_MASK;
|
||||
skey = page_get_storage_key(address);
|
||||
bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
|
||||
@ -625,6 +627,8 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
|
||||
#ifdef CONFIG_PGSTE
|
||||
int young;
|
||||
|
||||
if (!pte_present(*ptep))
|
||||
return pgste;
|
||||
young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
|
||||
/* Transfer page referenced bit to pte software bit (host view) */
|
||||
if (young || (pgste_val(pgste) & RCP_HR_BIT))
|
||||
@ -638,13 +642,15 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
|
||||
|
||||
}
|
||||
|
||||
static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste)
|
||||
static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry)
|
||||
{
|
||||
#ifdef CONFIG_PGSTE
|
||||
unsigned long address;
|
||||
unsigned long okey, nkey;
|
||||
|
||||
address = pte_val(*ptep) & PAGE_MASK;
|
||||
if (!pte_present(entry))
|
||||
return;
|
||||
address = pte_val(entry) & PAGE_MASK;
|
||||
okey = nkey = page_get_storage_key(address);
|
||||
nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT);
|
||||
/* Set page access key and fetch protection bit from pgste */
|
||||
@ -712,7 +718,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
|
||||
|
||||
if (mm_has_pgste(mm)) {
|
||||
pgste = pgste_get_lock(ptep);
|
||||
pgste_set_pte(ptep, pgste);
|
||||
pgste_set_pte(ptep, pgste, entry);
|
||||
*ptep = entry;
|
||||
pgste_set_unlock(ptep, pgste);
|
||||
} else
|
||||
|
Loading…
Reference in New Issue
Block a user