From 6ad8d010b2f364b739020e514e61b6a73444464b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 27 May 2007 15:18:22 +1000 Subject: [POWERPC] Fix possible access to free pages I think we have a subtle race on ppc64 with the tlb batching. The common code expects tlb_flush() to actually flush any pending TLB batch. It does that because it delays all page freeing until after tlb_flush() is called, in order to ensure no stale reference to those pages exist in any TLB, thus causing potential access to the freed pages. However, our tlb_flush only triggers the RCU for freeing page table pages, it does not currently trigger a flush of a pending TLB/hash batch, which is, I think, an error. This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- include/asm-powerpc/tlb.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include') diff --git a/include/asm-powerpc/tlb.h b/include/asm-powerpc/tlb.h index 0a17682663d..66714042e43 100644 --- a/include/asm-powerpc/tlb.h +++ b/include/asm-powerpc/tlb.h @@ -38,6 +38,15 @@ extern void pte_free_finish(void); static inline void tlb_flush(struct mmu_gather *tlb) { + struct ppc64_tlb_batch *tlbbatch = &__get_cpu_var(ppc64_tlb_batch); + + /* If there's a TLB batch pending, then we must flush it because the + * pages are going to be freed and we really don't want to have a CPU + * access a freed page because it has a stale TLB + */ + if (tlbbatch->index) + __flush_tlb_pending(tlbbatch); + pte_free_finish(); } -- cgit v1.2.3 From a4c28ab7445f5ca60e56ffd90edb3e9fc1330b71 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Tue, 29 May 2007 20:46:51 +1000 Subject: [POWERPC] Fix return from pte_alloc_one() in out-of-memory case pte_alloc_one() is expected to return NULL if out of memory. But it returns virt_to_page(NULL), which is not NULL. This fixes it. Cc: Paul Mackerras Signed-off-by: Akinobu Mita Signed-off-by: Paul Mackerras --- include/asm-powerpc/pgalloc-64.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-powerpc/pgalloc-64.h b/include/asm-powerpc/pgalloc-64.h index d9a3a8ca58a..94d0294341d 100644 --- a/include/asm-powerpc/pgalloc-64.h +++ b/include/asm-powerpc/pgalloc-64.h @@ -90,7 +90,8 @@ static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) { - return virt_to_page(pte_alloc_one_kernel(mm, address)); + pte_t *pte = pte_alloc_one_kernel(mm, address); + return pte ? virt_to_page(pte) : NULL; } static inline void pte_free_kernel(pte_t *pte) -- cgit v1.2.3