Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7139bc15 authored by John David Anglin's avatar John David Anglin Committed by James Bottomley
Browse files

[PARISC] Purge existing TLB entries in set_pte_at and ptep_set_wrprotect



This patch goes a long way toward fixing the minifail bug, and
it  significantly improves the stability of SMP machines such as
the rp3440.  When write  protecting a page for COW, we need to
purge the existing translation.  Otherwise, the COW break
doesn't occur as expected because the TLB may still have a stale entry
which allows writes.

[jejb: fix up checkpatch errors]
Signed-off-by: default avatarJohn David Anglin <dave.anglin@bell.net>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 5da1f88b
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -12,11 +12,10 @@

#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/mm_types.h>
#include <asm/processor.h>
#include <asm/cache.h>

struct vm_area_struct;

/*
 * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
 * memory.  For the return value to be meaningful, ADDR must be >=
@@ -40,7 +39,14 @@ struct vm_area_struct;
        do{                                                     \
                *(pteptr) = (pteval);                           \
        } while(0)
#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)

extern void purge_tlb_entries(struct mm_struct *, unsigned long);

#define set_pte_at(mm, addr, ptep, pteval)                      \
	do {                                                    \
		set_pte(ptep, pteval);                          \
		purge_tlb_entries(mm, addr);                    \
	} while (0)

#endif /* !__ASSEMBLY__ */

@@ -466,6 +472,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
		old = pte_val(*ptep);
		new = pte_val(pte_wrprotect(__pte (old)));
	} while (cmpxchg((unsigned long *) ptep, old, new) != old);
	purge_tlb_entries(mm, addr);
#else
	pte_t old_pte = *ptep;
	set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
+18 −0
Original line number Diff line number Diff line
@@ -419,6 +419,24 @@ void kunmap_parisc(void *addr)
EXPORT_SYMBOL(kunmap_parisc);
#endif

void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
{
	unsigned long flags;

	/* Note: purge_tlb_entries can be called at startup with
	   no context.  */

	/* Disable preemption while we play with %sr1.  */
	preempt_disable();
	mtsp(mm->context, 1);
	purge_tlb_start(flags);
	pdtlb(addr);
	pitlb(addr);
	purge_tlb_end(flags);
	preempt_enable();
}
EXPORT_SYMBOL(purge_tlb_entries);

void __flush_tlb_range(unsigned long sid, unsigned long start,
		       unsigned long end)
{