[S390] fix pgste update logic
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 14 Nov 2011 10:19:00 +0000 (11:19 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 14 Nov 2011 10:19:08 +0000 (11:19 +0100)
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>
arch/s390/include/asm/pgtable.h

index 34ede0ea85a9d0ae6d03a8c52b3bb3f43cb4e1ac..524d23b8610ceb65c42661a97e79226125dbadf3 100644 (file)
@@ -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