aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-03-15 17:18:00 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-15 17:18:00 -0400
commitcfb61b5e3e09f8b49bc4d685429df75f45127adc (patch)
tree44556a6711e7cfd44a9e9899eb077c49012872cd
parente2c15aff5f353ba80bd3bb49840837f65fa5cc43 (diff)
sparc64: Fix regression in pmdp_invalidate().
pmdp_invalidate() was changed to update the pmd atomically (to not lose dirty/access bits) and return the original pmd value. However, in doing so, we lost a lot of the essential work that set_pmd_at() does, namely to update hugepage mapping counts and queuing up the batched TLB flush entry. Thus we were not flushing entries out of the TLB when making such PMD changes. Fix this by abstracting the accounting work of set_pmd_at() out into a separate function, and call it from pmdp_establish(). Fixes: a8e654f01cb7 ("sparc64: update pmdp_invalidate() to return old pmd value") Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/mm/tlb.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index 847ddffbf38a..b5cfab711651 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -163,13 +163,10 @@ static void tlb_batch_pmd_scan(struct mm_struct *mm, unsigned long vaddr,
163 pte_unmap(pte); 163 pte_unmap(pte);
164} 164}
165 165
166void set_pmd_at(struct mm_struct *mm, unsigned long addr,
167 pmd_t *pmdp, pmd_t pmd)
168{
169 pmd_t orig = *pmdp;
170
171 *pmdp = pmd;
172 166
167static void __set_pmd_acct(struct mm_struct *mm, unsigned long addr,
168 pmd_t orig, pmd_t pmd)
169{
173 if (mm == &init_mm) 170 if (mm == &init_mm)
174 return; 171 return;
175 172
@@ -219,6 +216,15 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
219 } 216 }
220} 217}
221 218
219void set_pmd_at(struct mm_struct *mm, unsigned long addr,
220 pmd_t *pmdp, pmd_t pmd)
221{
222 pmd_t orig = *pmdp;
223
224 *pmdp = pmd;
225 __set_pmd_acct(mm, addr, orig, pmd);
226}
227
222static inline pmd_t pmdp_establish(struct vm_area_struct *vma, 228static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
223 unsigned long address, pmd_t *pmdp, pmd_t pmd) 229 unsigned long address, pmd_t *pmdp, pmd_t pmd)
224{ 230{
@@ -227,6 +233,7 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
227 do { 233 do {
228 old = *pmdp; 234 old = *pmdp;
229 } while (cmpxchg64(&pmdp->pmd, old.pmd, pmd.pmd) != old.pmd); 235 } while (cmpxchg64(&pmdp->pmd, old.pmd, pmd.pmd) != old.pmd);
236 __set_pmd_acct(vma->vm_mm, address, old, pmd);
230 237
231 return old; 238 return old;
232} 239}