Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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: John David Anglin <dave.anglin@bell.net>
Cc: stable@vger.kernel.org
Signed-off-by: James Bottomley <JBottomley@Parallels.com>

authored by

John David Anglin and committed by
James Bottomley
7139bc15 5da1f88b

+28 -3
+10 -3
arch/parisc/include/asm/pgtable.h
··· 12 12 13 13 #include <linux/bitops.h> 14 14 #include <linux/spinlock.h> 15 + #include <linux/mm_types.h> 15 16 #include <asm/processor.h> 16 17 #include <asm/cache.h> 17 - 18 - struct vm_area_struct; 19 18 20 19 /* 21 20 * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel ··· 39 40 do{ \ 40 41 *(pteptr) = (pteval); \ 41 42 } while(0) 42 - #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) 43 + 44 + extern void purge_tlb_entries(struct mm_struct *, unsigned long); 45 + 46 + #define set_pte_at(mm, addr, ptep, pteval) \ 47 + do { \ 48 + set_pte(ptep, pteval); \ 49 + purge_tlb_entries(mm, addr); \ 50 + } while (0) 43 51 44 52 #endif /* !__ASSEMBLY__ */ 45 53 ··· 472 466 old = pte_val(*ptep); 473 467 new = pte_val(pte_wrprotect(__pte (old))); 474 468 } while (cmpxchg((unsigned long *) ptep, old, new) != old); 469 + purge_tlb_entries(mm, addr); 475 470 #else 476 471 pte_t old_pte = *ptep; 477 472 set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
+18
arch/parisc/kernel/cache.c
··· 419 419 EXPORT_SYMBOL(kunmap_parisc); 420 420 #endif 421 421 422 + void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) 423 + { 424 + unsigned long flags; 425 + 426 + /* Note: purge_tlb_entries can be called at startup with 427 + no context. */ 428 + 429 + /* Disable preemption while we play with %sr1. */ 430 + preempt_disable(); 431 + mtsp(mm->context, 1); 432 + purge_tlb_start(flags); 433 + pdtlb(addr); 434 + pitlb(addr); 435 + purge_tlb_end(flags); 436 + preempt_enable(); 437 + } 438 + EXPORT_SYMBOL(purge_tlb_entries); 439 + 422 440 void __flush_tlb_range(unsigned long sid, unsigned long start, 423 441 unsigned long end) 424 442 {