ppc64 ftrace: mark data_access callees "notrace" (pt.1)
PATCH 1/1 ppc64 ftrace: mark data_access callees "notrace" (pt.1)
In order to avoid an endless recursion, functions that may get called from the data access handler must not call into tracing functions, which may cause data access faults ;-)
Advancing from my previous approach that lavishly compiled whole subdirs without the profiling switches, this is more fine-grained (but probably yet incomplete). This patch is necessary albeit not sufficient for FTRACE_WITH_REGS on ppc64.
Patch is against 3.17; fuzz+force should do no harm.
arch/powerpc/kernel/process.c +1 -1
@@ -717,7 +717,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;
arch/powerpc/mm/hash_utils_64.c +8 -8
@@ -846,7 +846,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;
@@ -867,7 +867,7 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) }#ifdef CONFIG_PPC_MM_SLICES -unsigned int get_paca_psize (unsigned long addr) +notrace unsigned int get_paca_psize(unsigned long addr) {u64 lpsizes;unsigned char *hpsizes;
@@ -896,7 +896,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 ;
@@ -919,7 +919,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 ;
@@ -967,7 +967,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) {
@@ -989,7 +989,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 (unsigned long ea,unsigned long access,unsigned long trap) +notrace int hash_page(unsigned long ea, unsigned long access, unsigned long trap) {enum ctx_state prev_state =exception_enter ();pgd_t *pgdir;
@@ -1269,7 +1269,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,int local) {unsigned long hash, index, shift, hidx, slot;
@@ -1343,7 +1343,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) {
arch/powerpc/mm/hugetlbpage-hash64.c +1 -1
@@ -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,int local,int ssize,unsigned int shift,unsigned int mmu_psize) {
arch/powerpc/mm/hugetlbpage.c +2 -2
@@ -905,7 +905,7 @@ static int __init hugetlbpage_init(void)#endif module_init (hugetlbpage_init); -void flush_dcache_icache_hugepage (struct page *page) +notrace void flush_dcache_icache_hugepage(struct page *page) {int i;void *start;
@@ -936,7 +936,7 @@ void flush_dcache_icache_hugepage(struct page *page)* we can follow the address down to the the page and take a ref on it. */ -pte_t *find_linux_pte_or_hugepte (pgd_t *pgdir,unsigned long ea,unsigned *shift) +notrace pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift) {pgd_t pgd, *pgdp;pud_t pud, *pudp;
arch/powerpc/mm/mem.c +1 -1
@@ -400,7 +400,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)) {
arch/powerpc/mm/pgtable_64.c +1 -1
@@ -444,7 +444,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;
arch/powerpc/mm/slb.c +3 -3
@@ -94,7 +94,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. */
@@ -134,7 +134,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 ());
@@ -149,7 +149,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;
arch/powerpc/mm/slice.c +4 -4
@@ -74,8 +74,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 };
@@ -564,7 +564,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;
@@ -676,7 +676,7 @@ void slice_set_psize(struct mm_struct *mm, unsigned long address,#endif } -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);
Michael Ellerman
reviewerQuoted 8 lines · Torsten Duwe
In order to avoid an endless recursion, functions that may get called from the data access handler must not call into tracing functions, which may cause data access faults ;-)
Advancing from my previous approach that lavishly compiled whole subdirs without the profiling switches, this is more fine-grained (but probably yet incomplete). This patch is necessary albeit not sufficient for
FTRACE_WITH_REGSon ppc64.
There's got to be a better solution than this. The chance that you've correctly annotated every function is basically 0, and the chance that we correctly add it to every new or modififed function in the future is also 0.
I don't mean that as a criticism of you, but rather the technique. For starters I don't see any annotations in 32-bit code, or in the BookE code etc.
Can you give us more details on what goes wrong without these annotations?
cheers
Quoted 5 lines · Michael Ellerman
Quoted 4 lines · Torsten Duwe
In order to avoid an endless recursion, functions that may get called from the data access handler must not call into tracing functions, which may cause data access faults ;-)
Quoted 7 lines
Quoted 4 lines
Advancing from my previous approach that lavishly compiled whole subdirs without the profiling switches, this is more fine-grained (but probably yet incomplete). This patch is necessary albeit not sufficient for
FTRACE_WITH_REGSon ppc64.There's got to be a better solution than this. The chance that you've correctly annotated every function is basically 0, and the chance that we correctly add
Well, I used an automated static code analysis to find these, so from that point the chances to find all the relevant funcs is significantly > 0.
Quoted 1 line
it to every new or modififed function in the future is also 0.
Yes, this worries me, too. This may lead to very obscure and confusing breakage :-(
Quoted 1 line
I don't mean that as a criticism of you, but rather the technique. For starters
No problem, I don't take this personally. I'd also prefer a more elegant solution, but the problem seems to stem from this particular hardware.
Quoted 1 line
I don't see any annotations in 32-bit code, or in the BookE code etc.
Exactly, for a start. 32-bit & friends would be another run, for all hardware where the MMU does not fully autoload. What does sparc do, btw?
Quoted 1 line
Can you give us more details on what goes wrong without these annotations?
e.g. ftrace tries to note that a function has been called. The memory location of the tracing framework that is to record this does not yet have an HTAB entry -> data access fault. Should any of the functions involved in the HTAB handling be profiled, ftrace will try to note that function call into some RAM location, which might still not have an entry, etc...
I've seen this lead into an endless recursion, unless, like I wrote and patched before, disabled tracing in all the relevant source dirs. This looked like overkill to me, hence the machine-aided approach to find the exact set of functions affected.
Can you think of a better approach?
Torsten
Quoted 5 lines · Torsten Duwe
Quoted 2 lines · Michael Ellerman
There's got to be a better solution than this.
Can you think of a better approach?
Maybe a per thread variable to lock out a recursion into tracing? Thanks for your doubt.
Torsten
Quoted 6 lines · Torsten Duwe
Quoted 3 lines
Quoted 1 line
There's got to be a better solution than this.
Can you think of a better approach?
Maybe a per thread variable to lock out a recursion into tracing? Thanks for your doubt.
ftrace already handles recursion protection by itself (depending on the per-ftrace-ops FTRACE_OPS_FL_RECURSION_SAFE flag).
It's however not really well-defined what to do when recursion would happen. Therefore __notrace__ annotation, that just completely avoid such situation by making tracing impossible, looks like saner general solution to me.
Signature · 2 lines
Jiri Kosina SUSE Labs
Michael Ellerman
reviewerQuoted 11 lines · Jiri Kosina
Quoted 6 lines · Torsten Duwe
Quoted 3 lines
Quoted 1 line
There's got to be a better solution than this.
Can you think of a better approach?
Maybe a per thread variable to lock out a recursion into tracing? Thanks for your doubt.
ftrace already handles recursion protection by itself (depending on the per-ftrace-ops
FTRACE_OPS_FL_RECURSION_SAFEflag).
OK, so I wonder why that's not working for us?
Quoted 4 lines
It's however not really well-defined what to do when recursion would happen. Therefore
__notrace__annotation, that just completely avoid such situation by making tracing impossible, looks like saner general solution to me.
I disagree. Correctly annotating all functions that might be called ever and for all time is a maintenance nightmare and is never going to work in the long term.
cheers
Quoted 4 lines · Michael Ellerman
Quoted 2 lines
ftrace already handles recursion protection by itself (depending on the per-ftrace-ops
FTRACE_OPS_FL_RECURSION_SAFEflag).OK, so I wonder why that's not working for us?
The situation when traced function recurses to itself is different from the situation when tracing core infrastrcuture would recurse to itself while performing tracing.
Quoted 8 lines
Quoted 4 lines
It's however not really well-defined what to do when recursion would happen. Therefore
__notrace__annotation, that just completely avoid such situation by making tracing impossible, looks like saner general solution to me.I disagree. Correctly annotating all functions that might be called ever and for all time is a maintenance nightmare and is never going to work in the long term.
All the functions called by ftrace must be marked as notrace, there is no way out of it.
Signature · 2 lines
Jiri Kosina SUSE Labs
cover ppc64 ftrace implementation
Quoted 10 lines · Jiri Kosina
Quoted 4 lines · Michael Ellerman
Quoted 2 lines
ftrace already handles recursion protection by itself (depending on the per-ftrace-ops
FTRACE_OPS_FL_RECURSION_SAFEflag).OK, so I wonder why that's not working for us?
The situation when traced function recurses to itself is different from the situation when tracing core infrastrcuture would recurse to itself while performing tracing.
I have used this inspiration to add a catch-all parachute for ftrace_caller, see my last reply. It reappears here as patch 4/4. Expect noticable performance impact compared to the selected "notrace" attributation discussed here. This should still be done in a second step especially for the hardware assistance functions I mentioned.
Torsten
Re: [PATCH 1/4] ppc64 ftrace implementation
Implement ftrace on ppc64
arch/powerpc/include/asm/ftrace.h +5 -0
@@ -46,6 +46,8 @@extern void _mcount (void );#ifdef CONFIG_DYNAMIC_FTRACE +# define FTRACE_ADDR ((unsigned long)ftrace_caller+8) +# define FTRACE_REGS_ADDR FTRACE_ADDRstatic inline unsigned long ftrace_call_adjust (unsigned long addr) {/* reloction of mcount call site is the same as the address */
@@ -58,6 +60,9 @@ struct dyn_arch_ftrace {#endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* __ASSEMBLY__ */ +#ifdef CONFIG_DYNAMIC_FTRACE +#define ARCH_SUPPORTS_FTRACE_OPS 1 +#endif #endif #if defined(CONFIG_FTRACE_SYSCALLS ) && defined(CONFIG_PPC64 ) && !defined(__ASSEMBLY__)
arch/powerpc/kernel/entry_64.S +92 -20
146 lines not on this page · raw message
arch/powerpc/kernel/ftrace.c +59 -8
115 lines not on this page · raw message
arch/powerpc/kernel/module_64.c +30 -3
@@ -138,12 +138,22 @@ static u32 ppc64_stub_insns[] = {0x4e800420 /* bctr */ }; +/* In case of _mcount calls or dynamic ftracing, Do not save the +current callee's TOC (in R2) again into the original caller's stack +frame during this trampoline hop. The stack frame already holds +that of the original caller. _mcount and ftrace_caller will take +care of this TOC value themselves. +*/ +#define SQUASH_TOC_SAVE_INSN (trampoline_addr) \ + ((struct ppc64_stub_entry*)(trampoline_addr))-> \ + jump[2] = PPC_INST_NOP; +#ifdef CONFIG_DYNAMIC_FTRACE static u32 ppc64_stub_mask[] = {0xffff0000 ,0xffff0000 , -0xffffffff , +0x00000000 ,0xffffffff , #if !defined(_CALL_ELF) || _CALL_ELF != 2 0xffffffff,
@@ -170,6 +180,9 @@ bool is_module_trampoline(u32 *p)if ((insna & mask) != (insnb & mask))return false; } +if (insns[2 ] != ppc64_stub_insns[2 ] && + insns[2 ] !=PPC_INST_NOP ) +return false;return true; }
@@ -475,6 +488,14 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,static int restore_r2 (u32 *instruction,struct module *me) {if (*instruction !=PPC_INST_NOP ) { + +/* -mprofile_kernel sequence starting with mflr r0; std r0, LRSAVE(r1) */ +if (instruction[-3 ] ==0x7c0802a6 && instruction[-2 ] ==0xf8010010 ) { +/* Nothing to be done here, it's a _mcount call location +and r2 will have to be restored in the _mcount function */ +return 2 ; + }; +pr_err ("%s: Expect noop after relocate, got %08x\n" , me->name, *instruction);return 0 ;
@@ -490,7 +511,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,unsigned int relsec, struct module *me) { - unsigned int i; + unsigned int i, r2;Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr;Elf64_Sym *sym;unsigned long *location;
@@ -603,8 +624,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, value =stub_for_addr (sechdrs, value, me);if (!value)return -ENOENT ; -if (!restore_r2 ((u32 *)location +1 , me)) +if (!(r2 =restore_r2 ((u32 *)location +1 , me)))return -ENOEXEC ; +/* Squash the TOC saver for profiler calls */ +if (!strcmp ("_mcount" , strtab+sym->st_name)) +SQUASH_TOC_SAVE_INSN (value); }else value +=local_entry_offset (sym);
@@ -665,6 +689,9 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, me->arch.tramp =stub_for_addr (sechdrs, (unsigned long )ftrace_caller, me); +/* ftrace_caller will take care of the TOC; +do not clobber original caller's value. */ +SQUASH_TOC_SAVE_INSN (me->arch.tramp);#endif return 0 ;
Steven Rostedt
maintainerRe: [PATCH 1/4] ppc64 ftrace implementation
Why are your patches all as replies?
Quoted 1 line · On Wed, 3 Jun 2015 15:08:29 +0200 Torsten Duwe <[email protected]> wrote:
Implement ftrace on ppc64
What do you mean "Implement ftrace on ppc64"? It's already implemented.
I'm not even going to bother looking at this patch because I have no idea what its purpose is.
-- Steve
Quoted 3 lines
Signed-off-by Torsten Duwe <[email protected]>
Re: [PATCH 1/4] ppc64 ftrace implementation
Quoted 2 lines · Steven Rostedt
Why are your patches all as replies?
Because I cared too much about the threading and the series that the "Re:" escaped me.
Quoted 3 lines
Quoted 1 line
Implement ftrace on ppc64
What do you mean "Implement ftrace on ppc64"? It's already implemented.
Sorry, too deep in the details. It's DYNAMIC_FTRACE_WITH_REGS, actually. Using gcc's -mprofile-kernel to call into ftrace...
Quoted 2 lines
I'm not even going to bother looking at this patch because I have no idea what its purpose is.
Understandable ;-)
So: Implement DYNAMIC_FTRACE_WITH_REGS, in order to prepare for live patching. Other obvious things I forgot to mention?
Torsten
Re: [PATCH 2/4] ppc64 ftrace configuration
In reply to Torsten DuweAdd Kconfig variables and Makefile magic for ftrace with -mprofile-kernel
Makefile +4 -1
@@ -733,7 +733,10 @@ export CC_FLAGS_FTRACE ifdef CONFIG_HAVE_FENTRY CC_USING_FENTRY := $(call cc-option, -mfentry -DCC_USING_FENTRY) endif -KBUILD_CFLAGS += $(CC_FLAGS_FTRACE) $(CC_USING_FENTRY) +ifdef CONFIG_HAVE_MPROFILE_KERNEL +CC_USING_MPROFILE_KERNEL := $(call cc-option, -mprofile-kernel -DCC_USING_MPROFILE_KERNEL) +endif +KBUILD_CFLAGS += $(CC_FLAGS_FTRACE) $(CC_USING_FENTRY) $(CC_USING_MPROFILE_KERNEL) KBUILD_AFLAGS += $(CC_USING_FENTRY) ifdef CONFIG_DYNAMIC_FTRACE ifdef CONFIG_HAVE_C_RECORDMCOUNT
arch/powerpc/Kconfig +2 -0
@@ -94,8 +94,10 @@ config PPC select OF_RESERVED_MEM select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE + select HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_MPROFILE_KERNEL select SYSCTL_EXCEPTION_TRACE select ARCH_WANT_OPTIONAL_GPIOLIB select VIRT_TO_BUS if !PPC64
kernel/trace/Kconfig +5 -0
@@ -52,6 +52,11 @@ config HAVE_FENTRY help Arch supports the gcc options -pg with -mfentry +config HAVE_MPROFILE_KERNEL + bool + help + Arch supports the gcc options -pg with -mprofile-kernel + config HAVE_C_RECORDMCOUNT bool help
Re: [PATCH 3/4] ppc64 ftrace: spare early boot and low level code
In reply to Torsten DuweUsing -mprofile-kernel on early boot code not only confuses the checker but is also useless, as the infrastructure is not yet in place. Proceed like with -pg, equally with time.o and ftrace itself.
arch/powerpc/kernel/Makefile +6 -6
@@ -17,14 +17,14 @@ endif ifdef CONFIG_FUNCTION_TRACER # Do not trace early boot code -CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog -CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog -CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog -CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog +CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog -mprofile-kernel +CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog -mprofile-kernel +CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog -mprofile-kernel +CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog -mprofile-kernel # do not trace tracer code -CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog +CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog -mprofile-kernel # timers used by tracing -CFLAGS_REMOVE_time.o = -pg -mno-sched-epilog +CFLAGS_REMOVE_time.o = -pg -mno-sched-epilog -mprofile-kernel endif obj-y := cputable.o ptrace.o syscalls.o \
Re: [PATCH 4/4] ppc64 ftrace recursion protection
In reply to Torsten DuweAs suggested by You and Jikos, a flag in task_struct's trace_recursion is used to block a tracer function to recurse into itself, especially on a data access fault. This should catch all functions called by the fault handlers which are not yet attributed notrace.
arch/powerpc/kernel/asm-offsets.c +1 -0
@@ -72,6 +72,7 @@ int main(void)DEFINE (THREAD , offsetof(struct task_struct , thread));DEFINE (MM , offsetof(struct task_struct , mm)); DEFINE(MMCONTEXTID, offsetof(struct mm_struct, context.id)); +DEFINE (TASK_TRACEREC , offsetof(struct task_struct , trace_recursion));#ifdef CONFIG_PPC64 DEFINE (AUDITCONTEXT , offsetof(struct task_struct , audit_context));DEFINE (SIGSEGV ,SIGSEGV );
arch/powerpc/kernel/entry_64.S +13 -2
@@ -1202,7 +1202,13 @@ _GLOBAL(ftrace_caller) SAVE_8GPRS(16,r1) SAVE_8GPRS(24,r1) - + ld r3, PACACURRENT(r13) + ld r4, TASK_TRACEREC(r3) + andi. r5, r4, 0x0010 // ( 1 << TRACE_FTRACE_BIT ) + ori r4, r4, 0x0010 + std r4, TASK_TRACEREC(r3) + bne 3f // ftrace in progress - avoid recursion! + LOAD_REG_IMMEDIATE(r3,function_trace_op) ld r5,0(r3)
@@ -1224,9 +1230,14 @@ ftrace_call: bl ftrace_stub nop + ld r3, PACACURRENT(r13) + ld r4, TASK_TRACEREC(r3) + andi. r4, r4, 0xffef // ~( 1 << TRACE_FTRACE_BIT ) + std r4, TASK_TRACEREC(r3) + ld r3, _NIP(r1) mtlr r3 - +3: REST_8GPRS(0,r1) REST_8GPRS(8,r1) REST_8GPRS(16,r1)
Quoted 6 lines · Michael Ellerman
Quoted 3 lines · Jiri Kosina
ftrace already handles recursion protection by itself (depending on the per-ftrace-ops
FTRACE_OPS_FL_RECURSION_SAFEflag).OK, so I wonder why that's not working for us?
IIRC a data access fault happens just before that flag is looked at ;-)
I'm now thinking about a hybrid solution: mark the most critical functions "notrace", especially those directly involved with MMU loading, and add a per-thread flag to catch the not-so-obvious cases.
Torsten
Quoted 6 lines · Torsten Duwe
Quoted 5 lines · Michael Ellerman
Quoted 3 lines · Jiri Kosina
ftrace already handles recursion protection by itself (depending on the per-ftrace-ops
FTRACE_OPS_FL_RECURSION_SAFEflag).
Quoted 7 lines
Quoted 1 line
OK, so I wonder why that's not working for us?
IIRC a data access fault happens just before that flag is looked at ;-)
I'm now thinking about a hybrid solution: mark the most critical functions "notrace", especially those directly involved with MMU loading, and add a per-thread flag to catch the not-so-obvious cases.
I realised the trace_recursion in the "current" task struct is not so far away, and it should not fault, right? So that part of the solution would look like this on top of my previous ftrace patch set.
It would impact performance further so I'd stick with the "notrace" on certain hot functions, like hash_page. What do you think?
Torsten
arch/powerpc/kernel/asm-offsets.c +1 -0
@@ -72,6 +72,7 @@ int main(void)DEFINE (THREAD , offsetof(struct task_struct , thread));DEFINE (MM , offsetof(struct task_struct , mm)); DEFINE(MMCONTEXTID, offsetof(struct mm_struct, context.id)); +DEFINE (TASK_TRACEREC , offsetof(struct task_struct , trace_recursion));#ifdef CONFIG_PPC64 DEFINE (AUDITCONTEXT , offsetof(struct task_struct , audit_context));DEFINE (SIGSEGV ,SIGSEGV );
arch/powerpc/kernel/entry_64.S +13 -2
@@ -1202,7 +1202,13 @@ _GLOBAL(ftrace_caller) SAVE_8GPRS(16,r1) SAVE_8GPRS(24,r1) - + ld r3, PACACURRENT(r13) + ld r4, TASK_TRACEREC(r3) + andi. r5, r4, 0x0010 // ( 1 << TRACE_FTRACE_BIT ) + ori r4, r4, 0x0010 + std r4, TASK_TRACEREC(r3) + bne 3f // ftrace in progress - avoid recursion! + LOAD_REG_IMMEDIATE(r3,function_trace_op) ld r5,0(r3)
@@ -1224,9 +1230,14 @@ ftrace_call: bl ftrace_stub nop + ld r3, PACACURRENT(r13) + ld r4, TASK_TRACEREC(r3) + andi r4, r4, 0xffef // ~( 1 << TRACE_FTRACE_BIT ) + std r4, TASK_TRACEREC(r3) + ld r3, _NIP(r1) mtlr r3 - +3: REST_8GPRS(0,r1) REST_8GPRS(8,r1) REST_8GPRS(16,r1)