Inter-revision diff: patch 6

Comparing v8 (message) to v7 (message)

--- v8
+++ v7
@@ -1,207 +1,256 @@
-  * create the appropriate files+functions
-    arch/powerpc/include/asm/livepatch.h
-        klp_check_compiler_support,
-        klp_arch_set_pc
-    arch/powerpc/kernel/livepatch.c with a stub for
-        klp_write_module_reloc
-    This is architecture-independent work in progress.
-  * introduce a fixup in arch/powerpc/kernel/entry_64.S
-    for local calls that are becoming global due to live patching.
-    And of course do the main KLP thing: return to a maybe different
-    address, possibly altered by the live patching ftrace op.
+At least POWER7/8 have MMUs that don't completely autoload;
+a normal, recoverable memory fault might pass through these functions.
+If a dynamic tracer function causes such a fault, any of these functions
+being traced with -mprofile-kernel may cause an endless recursion.
 
 Signed-off-by: Torsten Duwe <duwe@suse.de>
 ---
- arch/powerpc/include/asm/livepatch.h | 45 +++++++++++++++++++++++++++++++
- arch/powerpc/kernel/entry_64.S       | 51 +++++++++++++++++++++++++++++++++---
- arch/powerpc/kernel/livepatch.c      | 38 +++++++++++++++++++++++++++
- 3 files changed, 130 insertions(+), 4 deletions(-)
- create mode 100644 arch/powerpc/include/asm/livepatch.h
- create mode 100644 arch/powerpc/kernel/livepatch.c
+ arch/powerpc/kernel/process.c        |  2 +-
+ arch/powerpc/mm/fault.c              |  2 +-
+ arch/powerpc/mm/hash_utils_64.c      | 18 +++++++++---------
+ arch/powerpc/mm/hugetlbpage-hash64.c |  2 +-
+ arch/powerpc/mm/hugetlbpage.c        |  4 ++--
+ arch/powerpc/mm/mem.c                |  2 +-
+ arch/powerpc/mm/pgtable_64.c         |  2 +-
+ arch/powerpc/mm/slb.c                |  6 +++---
+ arch/powerpc/mm/slice.c              |  8 ++++----
+ 9 files changed, 23 insertions(+), 23 deletions(-)
 
-diff --git a/arch/powerpc/include/asm/livepatch.h b/arch/powerpc/include/asm/livepatch.h
-new file mode 100644
-index 0000000..44e8a2d
---- /dev/null
-+++ b/arch/powerpc/include/asm/livepatch.h
-@@ -0,0 +1,45 @@
-+/*
-+ * livepatch.h - powerpc-specific Kernel Live Patching Core
-+ *
-+ * Copyright (C) 2015 SUSE
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_POWERPC64_LIVEPATCH_H
-+#define _ASM_POWERPC64_LIVEPATCH_H
-+
-+#include <linux/module.h>
-+#include <linux/ftrace.h>
-+
-+#ifdef CONFIG_LIVEPATCH
-+static inline int klp_check_compiler_support(void)
-+{
-+#if !defined(_CALL_ELF) || _CALL_ELF != 2 || !defined(CC_USING_MPROFILE_KERNEL)
-+	return 1;
-+#endif
-+	return 0;
-+}
-+
-+extern int klp_write_module_reloc(struct module *mod, unsigned long type,
-+				   unsigned long loc, unsigned long value);
-+
-+static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
-+{
-+	regs->nip = ip;
-+}
-+#else
-+#error Live patching support is disabled; check CONFIG_LIVEPATCH
-+#endif
-+
-+#endif /* _ASM_POWERPC64_LIVEPATCH_H */
-diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
-index c063564..52c7a15 100644
---- a/arch/powerpc/kernel/entry_64.S
-+++ b/arch/powerpc/kernel/entry_64.S
-@@ -1202,6 +1202,9 @@ _GLOBAL(ftrace_caller)
- 	mflr    r3
- 	std     r3, _NIP(r1)
- 	std	r3, 16(r1)
-+#ifdef CONFIG_LIVEPATCH
-+	mr	r14,r3		/* remember old NIP */
-+#endif
- 	subi    r3, r3, MCOUNT_INSN_SIZE
- 	mfmsr   r4
- 	std     r4, _MSR(r1)
-@@ -1218,7 +1221,10 @@ ftrace_call:
- 	nop
- 
- 	ld	r3, _NIP(r1)
--	mtlr	r3
-+	mtctr	r3		/* prepare to jump there */
-+#ifdef CONFIG_LIVEPATCH
-+	cmpd	r14,r3		/* has NIP been altered? */
-+#endif
- 
- 	REST_8GPRS(0,r1)
- 	REST_8GPRS(8,r1)
-@@ -1231,6 +1237,27 @@ ftrace_call:
- 	mtlr	r12
- 	mr	r2,r0		/* restore callee's TOC */
- 
-+#ifdef CONFIG_LIVEPATCH
-+	beq+	4f		/* likely(old_NIP == new_NIP) */
-+
-+	/* For a local call, restore this TOC after calling the patch function.
-+	 * For a global call, it does not matter what we restore here,
-+	 * since the global caller does its own restore right afterwards,
-+	 * anyway. Just insert a KLP_return_helper frame in any case,
-+	 * so a patch function can always count on the changed stack offsets.
-+	 */
-+	stdu	r1,-32(r1)	/* open new mini stack frame */
-+	std	r0,24(r1)	/* save TOC now, unconditionally. */
-+	bl	5f
-+5:	mflr	r12
-+	addi	r12,r12,(KLP_return_helper+4-.)@l
-+	std	r12,LRSAVE(r1)
-+	mtlr	r12
-+	mfctr	r12		/* allow for TOC calculation in newfunc */
-+	bctr
-+4:
-+#endif
-+
- #ifdef CONFIG_FUNCTION_GRAPH_TRACER
- 	stdu	r1, -112(r1)
- .globl ftrace_graph_call
-@@ -1240,15 +1267,31 @@ _GLOBAL(ftrace_graph_stub)
- 	addi	r1, r1, 112
+diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
+index dccc87e..5e72e8b 100644
+--- a/arch/powerpc/kernel/process.c
++++ b/arch/powerpc/kernel/process.c
+@@ -822,7 +822,7 @@ static inline void __switch_to_tm(struct task_struct *prev)
+  * don't know which of the checkpointed state and the transactional
+  * state to use.
+  */
+-void restore_tm_state(struct pt_regs *regs)
++notrace void restore_tm_state(struct pt_regs *regs)
+ {
+ 	unsigned long msr_diff;
+ 
+diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
+index a67c6d7..125be37 100644
+--- a/arch/powerpc/mm/fault.c
++++ b/arch/powerpc/mm/fault.c
+@@ -205,7 +205,7 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault)
+  * The return value is 0 if the fault was handled, or the signal
+  * number if this is a kernel fault that can't be handled here.
+  */
+-int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
++notrace int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
+ 			    unsigned long error_code)
+ {
+ 	enum ctx_state prev_state = exception_enter();
+diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
+index ba59d59..01d3dee 100644
+--- a/arch/powerpc/mm/hash_utils_64.c
++++ b/arch/powerpc/mm/hash_utils_64.c
+@@ -825,7 +825,7 @@ void early_init_mmu_secondary(void)
+ /*
+  * Called by asm hashtable.S for doing lazy icache flush
+  */
+-unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
++notrace unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
+ {
+ 	struct page *page;
+ 
+@@ -846,7 +846,7 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
+ }
+ 
+ #ifdef CONFIG_PPC_MM_SLICES
+-static unsigned int get_paca_psize(unsigned long addr)
++static notrace unsigned int get_paca_psize(unsigned long addr)
+ {
+ 	u64 lpsizes;
+ 	unsigned char *hpsizes;
+@@ -875,7 +875,7 @@ unsigned int get_paca_psize(unsigned long addr)
+  * For now this makes the whole process use 4k pages.
+  */
+ #ifdef CONFIG_PPC_64K_PAGES
+-void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
++notrace void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
+ {
+ 	if (get_slice_psize(mm, addr) == MMU_PAGE_4K)
+ 		return;
+@@ -897,7 +897,7 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
+  * Result is 0: full permissions, _PAGE_RW: read-only,
+  * _PAGE_USER or _PAGE_USER|_PAGE_RW: no access.
+  */
+-static int subpage_protection(struct mm_struct *mm, unsigned long ea)
++static notrace int subpage_protection(struct mm_struct *mm, unsigned long ea)
+ {
+ 	struct subpage_prot_table *spt = &mm->context.spt;
+ 	u32 spp = 0;
+@@ -945,7 +945,7 @@ void hash_failure_debug(unsigned long ea, unsigned long access,
+ 		trap, vsid, ssize, psize, lpsize, pte);
+ }
+ 
+-static void check_paca_psize(unsigned long ea, struct mm_struct *mm,
++static notrace void check_paca_psize(unsigned long ea, struct mm_struct *mm,
+ 			     int psize, bool user_region)
+ {
+ 	if (user_region) {
+@@ -967,7 +967,7 @@ static void check_paca_psize(unsigned long ea, struct mm_struct *mm,
+  * -1 - critical hash insertion error
+  * -2 - access not permitted by subpage protection mechanism
+  */
+-int hash_page_mm(struct mm_struct *mm, unsigned long ea,
++notrace int hash_page_mm(struct mm_struct *mm, unsigned long ea,
+ 		 unsigned long access, unsigned long trap,
+ 		 unsigned long flags)
+ {
+@@ -1165,7 +1165,7 @@ bail:
+ }
+ EXPORT_SYMBOL_GPL(hash_page_mm);
+ 
+-int hash_page(unsigned long ea, unsigned long access, unsigned long trap,
++notrace int hash_page(unsigned long ea, unsigned long access, unsigned long trap,
+ 	      unsigned long dsisr)
+ {
+ 	unsigned long flags = 0;
+@@ -1296,7 +1296,7 @@ out_exit:
+ /* WARNING: This is called from hash_low_64.S, if you change this prototype,
+  *          do not forget to update the assembly call site !
+  */
+-void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize,
++notrace void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize,
+ 		     unsigned long flags)
+ {
+ 	unsigned long hash, index, shift, hidx, slot;
+@@ -1444,7 +1444,7 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc)
+ 	exception_exit(prev_state);
+ }
+ 
+-long hpte_insert_repeating(unsigned long hash, unsigned long vpn,
++notrace long hpte_insert_repeating(unsigned long hash, unsigned long vpn,
+ 			   unsigned long pa, unsigned long rflags,
+ 			   unsigned long vflags, int psize, int ssize)
+ {
+diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c
+index e2138c7..17fc139 100644
+--- a/arch/powerpc/mm/hugetlbpage-hash64.c
++++ b/arch/powerpc/mm/hugetlbpage-hash64.c
+@@ -18,7 +18,7 @@ extern long hpte_insert_repeating(unsigned long hash, unsigned long vpn,
+ 				  unsigned long pa, unsigned long rlags,
+ 				  unsigned long vflags, int psize, int ssize);
+ 
+-int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
++notrace int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
+ 		     pte_t *ptep, unsigned long trap, unsigned long flags,
+ 		     int ssize, unsigned int shift, unsigned int mmu_psize)
+ {
+diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
+index 744e24b..70dda66 100644
+--- a/arch/powerpc/mm/hugetlbpage.c
++++ b/arch/powerpc/mm/hugetlbpage.c
+@@ -870,7 +870,7 @@ static int __init hugetlbpage_init(void)
  #endif
- 
--	mflr	r0		/* move this LR to CTR */
--	mtctr	r0
--
- 	ld	r0,LRSAVE(r1)	/* restore callee's lr at _mcount site */
- 	mtlr	r0
- 	bctr			/* jump after _mcount site */
- #endif /* CC_USING_MPROFILE_KERNEL */
- _GLOBAL(ftrace_stub)
- 	blr
-+
-+#ifdef CONFIG_LIVEPATCH
-+/* Helper function for local calls that are becoming global
-+   due to live patching.
-+   We can't simply patch the NOP after the original call,
-+   because, depending on the consistency model, some kernel
-+   threads may still have called the original, local function
-+   *without* saving their TOC in the respective stack frame slot,
-+   so the decision is made per-thread during function return by
-+   maybe inserting a KLP_return_helper frame or not.
-+*/
-+KLP_return_helper:
-+	ld	r2,24(r1)	/* restore TOC (saved by ftrace_caller) */
-+	addi r1, r1, 32		/* destroy mini stack frame */
-+	ld	r0,LRSAVE(r1)	/* get the real return address */
-+	mtlr	r0
-+	blr
-+#endif
-+
- #else
- _GLOBAL_TOC(_mcount)
- 	/* Taken from output of objdump from lib64/glibc */
-diff --git a/arch/powerpc/kernel/livepatch.c b/arch/powerpc/kernel/livepatch.c
-new file mode 100644
-index 0000000..cdd15f1
---- /dev/null
-+++ b/arch/powerpc/kernel/livepatch.c
-@@ -0,0 +1,38 @@
-+/*
-+ * livepatch.c - powerpc-specific Kernel Live Patching Core
-+ *
-+ * Copyright (C) 2015 SUSE
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+#include <linux/module.h>
-+#include <asm/livepatch.h>
-+
-+/**
-+ * klp_write_module_reloc() - write a relocation in a module
-+ * @mod:       module in which the section to be modified is found
-+ * @type:      ELF relocation type (see asm/elf.h)
-+ * @loc:       address that the relocation should be written to
-+ * @value:     relocation value (sym address + addend)
-+ *
-+ * This function writes a relocation to the specified location for
-+ * a particular module.
-+ */
-+int klp_write_module_reloc(struct module *mod, unsigned long type,
-+			    unsigned long loc, unsigned long value)
-+{
-+	/* This requires infrastructure changes; we need the loadinfos. */
-+	pr_err("klp_write_module_reloc not yet supported\n");
-+	return -ENOSYS;
-+}
+ arch_initcall(hugetlbpage_init);
+ 
+-void flush_dcache_icache_hugepage(struct page *page)
++notrace void flush_dcache_icache_hugepage(struct page *page)
+ {
+ 	int i;
+ 	void *start;
+@@ -903,7 +903,7 @@ void flush_dcache_icache_hugepage(struct page *page)
+  * when we have MSR[EE] = 0 but the paca->soft_enabled = 1
+  */
+ 
+-pte_t *__find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
++notrace pte_t *__find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
+ 				   bool *is_thp, unsigned *shift)
+ {
+ 	pgd_t pgd, *pgdp;
+diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
+index 22d94c3..f690e8a 100644
+--- a/arch/powerpc/mm/mem.c
++++ b/arch/powerpc/mm/mem.c
+@@ -406,7 +406,7 @@ void flush_dcache_page(struct page *page)
+ }
+ EXPORT_SYMBOL(flush_dcache_page);
+ 
+-void flush_dcache_icache_page(struct page *page)
++notrace void flush_dcache_icache_page(struct page *page)
+ {
+ #ifdef CONFIG_HUGETLB_PAGE
+ 	if (PageCompound(page)) {
+diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
+index 3124a20..bb9041b 100644
+--- a/arch/powerpc/mm/pgtable_64.c
++++ b/arch/powerpc/mm/pgtable_64.c
+@@ -442,7 +442,7 @@ static void page_table_free_rcu(void *table)
+ 	}
+ }
+ 
+-void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
++notrace void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
+ {
+ 	unsigned long pgf = (unsigned long)table;
+ 
+diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
+index 825b687..852bd54 100644
+--- a/arch/powerpc/mm/slb.c
++++ b/arch/powerpc/mm/slb.c
+@@ -96,7 +96,7 @@ static inline void create_shadowed_slbe(unsigned long ea, int ssize,
+ 		     : "memory" );
+ }
+ 
+-static void __slb_flush_and_rebolt(void)
++static notrace void __slb_flush_and_rebolt(void)
+ {
+ 	/* If you change this make sure you change SLB_NUM_BOLTED
+ 	 * and PR KVM appropriately too. */
+@@ -136,7 +136,7 @@ static void __slb_flush_and_rebolt(void)
+ 		     : "memory");
+ }
+ 
+-void slb_flush_and_rebolt(void)
++notrace void slb_flush_and_rebolt(void)
+ {
+ 
+ 	WARN_ON(!irqs_disabled());
+@@ -151,7 +151,7 @@ void slb_flush_and_rebolt(void)
+ 	get_paca()->slb_cache_ptr = 0;
+ }
+ 
+-void slb_vmalloc_update(void)
++notrace void slb_vmalloc_update(void)
+ {
+ 	unsigned long vflags;
+ 
+diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
+index 42954f0..5fb0e5b 100644
+--- a/arch/powerpc/mm/slice.c
++++ b/arch/powerpc/mm/slice.c
+@@ -76,8 +76,8 @@ static void slice_print_mask(const char *label, struct slice_mask mask) {}
+ 
+ #endif
+ 
+-static struct slice_mask slice_range_to_mask(unsigned long start,
+-					     unsigned long len)
++static notrace struct slice_mask slice_range_to_mask(unsigned long start,
++						     unsigned long len)
+ {
+ 	unsigned long end = start + len - 1;
+ 	struct slice_mask ret = { 0, 0 };
+@@ -563,7 +563,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp,
+ 				       current->mm->context.user_psize, 1);
+ }
+ 
+-unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
++notrace unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
+ {
+ 	unsigned char *hpsizes;
+ 	int index, mask_index;
+@@ -644,7 +644,7 @@ void slice_set_user_psize(struct mm_struct *mm, unsigned int psize)
+ 	spin_unlock_irqrestore(&slice_convert_lock, flags);
+ }
+ 
+-void slice_set_range_psize(struct mm_struct *mm, unsigned long start,
++notrace void slice_set_range_psize(struct mm_struct *mm, unsigned long start,
+ 			   unsigned long len, unsigned int psize)
+ {
+ 	struct slice_mask mask = slice_range_to_mask(start, len);
 -- 
 1.8.5.6
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help