Skip to content

Commit c78e710

Browse files
danglin44hdeller
authored andcommitted
parisc: Purge TLB before setting PTE
The attached change interchanges the order of purging the TLB and setting the corresponding page table entry. TLB purges are strongly ordered. It occurred to me one night that setting the PTE first might have subtle ordering issues on SMP machines and cause random memory corruption. A TLB lock guards the insertion of user TLB entries. So after the TLB is purged, a new entry can't be inserted until the lock is released. This ensures that the new PTE value is used when the lock is released. Since making this change, no random segmentation faults have been observed on the Debian hppa buildd servers. Signed-off-by: John David Anglin <dave.anglin@bell.net> Cc: <stable@vger.kernel.org> # v3.16+ Signed-off-by: Helge Deller <deller@gmx.de>
1 parent bc3913a commit c78e710

1 file changed

Lines changed: 4 additions & 4 deletions

File tree

arch/parisc/include/asm/pgtable.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
6565
unsigned long flags; \
6666
spin_lock_irqsave(&pa_tlb_lock, flags); \
6767
old_pte = *ptep; \
68-
set_pte(ptep, pteval); \
6968
if (pte_inserted(old_pte)) \
7069
purge_tlb_entries(mm, addr); \
70+
set_pte(ptep, pteval); \
7171
spin_unlock_irqrestore(&pa_tlb_lock, flags); \
7272
} while (0)
7373

@@ -478,8 +478,8 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
478478
spin_unlock_irqrestore(&pa_tlb_lock, flags);
479479
return 0;
480480
}
481-
set_pte(ptep, pte_mkold(pte));
482481
purge_tlb_entries(vma->vm_mm, addr);
482+
set_pte(ptep, pte_mkold(pte));
483483
spin_unlock_irqrestore(&pa_tlb_lock, flags);
484484
return 1;
485485
}
@@ -492,9 +492,9 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
492492

493493
spin_lock_irqsave(&pa_tlb_lock, flags);
494494
old_pte = *ptep;
495-
set_pte(ptep, __pte(0));
496495
if (pte_inserted(old_pte))
497496
purge_tlb_entries(mm, addr);
497+
set_pte(ptep, __pte(0));
498498
spin_unlock_irqrestore(&pa_tlb_lock, flags);
499499

500500
return old_pte;
@@ -504,8 +504,8 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
504504
{
505505
unsigned long flags;
506506
spin_lock_irqsave(&pa_tlb_lock, flags);
507-
set_pte(ptep, pte_wrprotect(*ptep));
508507
purge_tlb_entries(mm, addr);
508+
set_pte(ptep, pte_wrprotect(*ptep));
509509
spin_unlock_irqrestore(&pa_tlb_lock, flags);
510510
}
511511

0 commit comments

Comments
 (0)