diff options
| -rw-r--r-- | arch/powerpc/mm/hugetlbpage-hash64.c | 31 |
1 files changed, 13 insertions, 18 deletions
diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c index c9acd7910eea..faae9ec4cb04 100644 --- a/arch/powerpc/mm/hugetlbpage-hash64.c +++ b/arch/powerpc/mm/hugetlbpage-hash64.c | |||
| @@ -21,21 +21,13 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, | |||
| 21 | unsigned long old_pte, new_pte; | 21 | unsigned long old_pte, new_pte; |
| 22 | unsigned long va, rflags, pa, sz; | 22 | unsigned long va, rflags, pa, sz; |
| 23 | long slot; | 23 | long slot; |
| 24 | int err = 1; | ||
| 25 | 24 | ||
| 26 | BUG_ON(shift != mmu_psize_defs[mmu_psize].shift); | 25 | BUG_ON(shift != mmu_psize_defs[mmu_psize].shift); |
| 27 | 26 | ||
| 28 | /* Search the Linux page table for a match with va */ | 27 | /* Search the Linux page table for a match with va */ |
| 29 | va = hpt_va(ea, vsid, ssize); | 28 | va = hpt_va(ea, vsid, ssize); |
| 30 | 29 | ||
| 31 | /* | 30 | /* At this point, we have a pte (old_pte) which can be used to build |
| 32 | * Check the user's access rights to the page. If access should be | ||
| 33 | * prevented then send the problem up to do_page_fault. | ||
| 34 | */ | ||
| 35 | if (unlikely(access & ~pte_val(*ptep))) | ||
| 36 | goto out; | ||
| 37 | /* | ||
| 38 | * At this point, we have a pte (old_pte) which can be used to build | ||
| 39 | * or update an HPTE. There are 2 cases: | 31 | * or update an HPTE. There are 2 cases: |
| 40 | * | 32 | * |
| 41 | * 1. There is a valid (present) pte with no associated HPTE (this is | 33 | * 1. There is a valid (present) pte with no associated HPTE (this is |
| @@ -49,9 +41,17 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, | |||
| 49 | 41 | ||
| 50 | do { | 42 | do { |
| 51 | old_pte = pte_val(*ptep); | 43 | old_pte = pte_val(*ptep); |
| 52 | if (old_pte & _PAGE_BUSY) | 44 | /* If PTE busy, retry the access */ |
| 53 | goto out; | 45 | if (unlikely(old_pte & _PAGE_BUSY)) |
| 46 | return 0; | ||
| 47 | /* If PTE permissions don't match, take page fault */ | ||
| 48 | if (unlikely(access & ~old_pte)) | ||
| 49 | return 1; | ||
| 50 | /* Try to lock the PTE, add ACCESSED and DIRTY if it was | ||
| 51 | * a write access */ | ||
| 54 | new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED; | 52 | new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED; |
| 53 | if (access & _PAGE_RW) | ||
| 54 | new_pte |= _PAGE_DIRTY; | ||
| 55 | } while(old_pte != __cmpxchg_u64((unsigned long *)ptep, | 55 | } while(old_pte != __cmpxchg_u64((unsigned long *)ptep, |
| 56 | old_pte, new_pte)); | 56 | old_pte, new_pte)); |
| 57 | 57 | ||
| @@ -127,8 +127,7 @@ repeat: | |||
| 127 | */ | 127 | */ |
| 128 | if (unlikely(slot == -2)) { | 128 | if (unlikely(slot == -2)) { |
| 129 | *ptep = __pte(old_pte); | 129 | *ptep = __pte(old_pte); |
| 130 | err = -1; | 130 | return -1; |
| 131 | goto out; | ||
| 132 | } | 131 | } |
| 133 | 132 | ||
| 134 | new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX); | 133 | new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX); |
| @@ -138,9 +137,5 @@ repeat: | |||
| 138 | * No need to use ldarx/stdcx here | 137 | * No need to use ldarx/stdcx here |
| 139 | */ | 138 | */ |
| 140 | *ptep = __pte(new_pte & ~_PAGE_BUSY); | 139 | *ptep = __pte(new_pte & ~_PAGE_BUSY); |
| 141 | 140 | return 0; | |
| 142 | err = 0; | ||
| 143 | |||
| 144 | out: | ||
| 145 | return err; | ||
| 146 | } | 141 | } |
