From: Naveen N. Rao <hidden> Date: 2019-06-18 14:48:41
Changes since RFC:
- Patches 1 and 2: No changes
- Patch 3: rename function to ftrace_replace_code_rec() to signify that
it acts on a ftrace record.
- Patch 4: numerous small changes, including those suggested by Nick
Piggin.
- Patch 4: additionally handle scenario where __ftrace_make_call() can
be invoked without having called __ftrace_make_call_prep(), when a
kernel module is loaded while function tracing is active.
- Patch 5 to 7: new, to have ftrace claim ownership of two instructions,
and to have kprobes work properly with this.
--
On powerpc64, -mprofile-kernel results in two instructions being
emitted: 'mflr r0' and 'bl _mcount'. So far, we were only nop'ing out
the branch to _mcount(). This series implements an approach to also nop
out the preceding mflr.
- Naveen
Naveen N. Rao (7):
ftrace: Expose flags used for ftrace_replace_code()
x86/ftrace: Fix use of flags in ftrace_replace_code()
ftrace: Expose __ftrace_replace_code()
powerpc/ftrace: Additionally nop out the preceding mflr with
-mprofile-kernel
powerpc/ftrace: Update ftrace_location() for powerpc -mprofile-kernel
kprobes/ftrace: Use ftrace_location() when [dis]arming probes
powerpc/kprobes: Allow probing on any ftrace address
arch/powerpc/kernel/kprobes-ftrace.c | 30 +++
arch/powerpc/kernel/trace/ftrace.c | 272 ++++++++++++++++++++++++---
arch/x86/kernel/ftrace.c | 3 +-
include/linux/ftrace.h | 7 +
kernel/kprobes.c | 10 +-
kernel/trace/ftrace.c | 17 +-
6 files changed, 300 insertions(+), 39 deletions(-)
--
2.22.0
From: Naveen N. Rao <hidden> Date: 2019-06-18 14:47:51
Since ftrace_replace_code() is a __weak function and can be overridden,
we need to expose the flags that can be set. So, move the flags enum to
the header file.
Reviewed-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Naveen N. Rao <redacted>
---
include/linux/ftrace.h | 5 +++++
kernel/trace/ftrace.c | 5 -----
2 files changed, 5 insertions(+), 5 deletions(-)
@@ -162,6 +162,11 @@ enum {FTRACE_OPS_FL_TRACE_ARRAY=1<<15,};+enum{+FTRACE_MODIFY_ENABLE_FL=(1<<0),+FTRACE_MODIFY_MAY_SLEEP_FL=(1<<1),+};+#ifdef CONFIG_DYNAMIC_FTRACE/* The hash used to know what functions callbacks trace */structftrace_ops_hash{
From: Naveen N. Rao <hidden> Date: 2019-06-18 14:47:54
While over-riding ftrace_replace_code(), we still want to reuse the
existing __ftrace_replace_code() function. Rename the function and
make it available for other kernel code.
Signed-off-by: Naveen N. Rao <redacted>
---
include/linux/ftrace.h | 1 +
kernel/trace/ftrace.c | 8 ++++----
2 files changed, 5 insertions(+), 4 deletions(-)
@@ -456,6 +456,7 @@ ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable);/* defined in arch */externintftrace_ip_converted(unsignedlongip);externintftrace_dyn_arch_init(void);+externintftrace_replace_code_rec(structdyn_ftrace*rec,intenable);externvoidftrace_replace_code(intenable);externintftrace_update_ftrace_func(ftrace_func_tfunc);externvoidftrace_caller(void);
From: Naveen N. Rao <hidden> Date: 2019-06-18 14:47:55
In commit a0572f687fb3c ("ftrace: Allow ftrace_replace_code() to be
schedulable), the generic ftrace_replace_code() function was modified to
accept a flags argument in place of a single 'enable' flag. However, the
x86 version of this function was not updated. Fix the same.
Fixes: a0572f687fb3c ("ftrace: Allow ftrace_replace_code() to be schedulable")
Signed-off-by: Naveen N. Rao <redacted>
---
arch/x86/kernel/ftrace.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Naveen N. Rao <hidden> Date: 2019-06-18 14:47:58
With -mprofile-kernel, gcc emits 'mflr r0', followed by 'bl _mcount' to
enable function tracing and profiling. So far, with dynamic ftrace, we
used to only patch out the branch to _mcount(). However, mflr is
executed by the branch unit that can only execute one per cycle on
POWER9 and shared with branches, so it would be nice to avoid it where
possible.
We cannot simply nop out the mflr either. When enabling function
tracing, there can be a race if tracing is enabled when some thread was
interrupted after executing a nop'ed out mflr. In this case, the thread
would execute the now-patched-in branch to _mcount() without having
executed the preceding mflr.
To solve this, we now enable function tracing in 2 steps: patch in the
mflr instruction, use synchronize_rcu_tasks() to ensure all existing
threads make progress, and then patch in the branch to _mcount(). We
override ftrace_replace_code() with a powerpc64 variant for this
purpose.
Suggested-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/trace/ftrace.c | 241 ++++++++++++++++++++++++++---
1 file changed, 219 insertions(+), 22 deletions(-)
@@ -125,7 +125,7 @@ __ftrace_make_nop(struct module *mod,{unsignedlongentry,ptr,tramp;unsignedlongip=rec->ip;-unsignedintop,pop;+unsignedintop;/* read where this goes */if(probe_kernel_read(&op,(void*)ip,sizeof(int))){
@@ -160,8 +160,6 @@ __ftrace_make_nop(struct module *mod,#ifdef CONFIG_MPROFILE_KERNEL/* When using -mkernel_profile there is no load to jump over */-pop=PPC_INST_NOP;-if(probe_kernel_read(&op,(void*)(ip-4),4)){pr_err("Fetching instruction at %lx failed.\n",ip-4);return-EFAULT;
@@ -169,26 +167,23 @@ __ftrace_make_nop(struct module *mod,/* We expect either a mflr r0, or a std r0, LRSAVE(r1) */if(op!=PPC_INST_MFLR&&op!=PPC_INST_STD_LR){-pr_err("Unexpected instruction %08x around bl _mcount\n",op);+pr_err("Unexpected instruction %08x before bl _mcount\n",op);return-EINVAL;}-#else-/*-*Ouroriginalcallsitelookslike:-*-*bl<tramp>-*ldr2,XX(r1)-*-*MiltonMillerpointedoutthatwecannotsimplynopthebranch.-*Ifataskwaspreemptedwhencallingatracefunction,thenops-*willremovethewaytorestoretheTOCinr2andther2TOCwill-*getcorrupted.-*-*Useab+8tojumpovertheload.-*/-pop=PPC_INST_BRANCH|8;/* b +8 */+/* We should patch out the bl to _mcount first */+if(patch_instruction((unsignedint*)ip,PPC_INST_NOP)){+pr_err("Patching NOP failed.\n");+return-EPERM;+}+/* then, nop out the preceding 'mflr r0' as an optimization */+if(op==PPC_INST_MFLR&&+patch_instruction((unsignedint*)(ip-4),PPC_INST_NOP)){+pr_err("Patching NOP failed.\n");+return-EPERM;+}+#else/**Checkwhatisinthenextinstruction.Wecanseeldr2,40(r1),but*onfirstpassafterbootwewillseemflrr0.
@@ -421,6 +429,26 @@ static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)return-EPERM;}+#ifdef CONFIG_MPROFILE_KERNEL+/* Nop out the preceding 'mflr r0' as an optimization */+if(probe_kernel_read(&op,(void*)(ip-4),4)){+pr_err("Fetching instruction at %lx failed.\n",ip-4);+return-EFAULT;+}++/* We expect either a mflr r0, or a std r0, LRSAVE(r1) */+if(op!=PPC_INST_MFLR&&op!=PPC_INST_STD_LR){+pr_err("Unexpected instruction %08x before bl _mcount\n",op);+return-EINVAL;+}++if(op==PPC_INST_MFLR&&+patch_instruction((unsignedint*)(ip-4),PPC_INST_NOP)){+pr_err("Patching NOP failed.\n");+return-EPERM;+}+#endif+return0;}
@@ -429,6 +457,7 @@ int ftrace_make_nop(struct module *mod,{unsignedlongip=rec->ip;unsignedintold,new;+intrc;/**Ifthecallingaddressismorethat24bitsaway,
@@ -439,7 +468,34 @@ int ftrace_make_nop(struct module *mod,/* within range */old=ftrace_call_replace(ip,addr,1);new=PPC_INST_NOP;-returnftrace_modify_code(ip,old,new);+rc=ftrace_modify_code(ip,old,new);+#ifdef CONFIG_MPROFILE_KERNEL+if(rc)+returnrc;++/*+*For-mprofile-kernel,wepatchoutthepreceding'mflrr0'+*instruction,asanoptimization.Itisimportanttonopout+*thebranchto_mcount()first,asalone'mflrr0'is+*harmless.+*/+if(probe_kernel_read(&old,(void*)(ip-4),4)){+pr_err("Fetching instruction at %lx failed.\n",ip-4);+return-EFAULT;+}++/* We expect either a mflr r0, or a std r0, LRSAVE(r1) */+if(old!=PPC_INST_MFLR&&old!=PPC_INST_STD_LR){+pr_err("Unexpected instruction %08x before bl _mcount\n",+old);+return-EINVAL;+}++if(old==PPC_INST_MFLR)+rc=patch_instruction((unsignedint*)(ip-4),+PPC_INST_NOP);+#endif+returnrc;}elseif(core_kernel_text(ip))return__ftrace_make_nop_kernel(rec,addr);
@@ -567,6 +623,37 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)return-EINVAL;}+#ifdef CONFIG_MPROFILE_KERNEL+/*+*Wecouldendupherewithouthavingcalled__ftrace_make_call_prep()+*iffunctiontracingisenabledbeforeamoduleisloaded.+*+*ftrace_module_enable()-->ftrace_replace_code_rec()-->+*ftrace_make_call()-->__ftrace_make_call()+*+*Inthisscenario,thepreviousinstructionwillbeaNOP.Itis+*safetopatchitwitha'mflrr0'sinceweknowforafactthat+*thiscodeisnotyetbeingrun.+*/+ip-=MCOUNT_INSN_SIZE;++/* read where this goes */+if(probe_kernel_read(op,ip,MCOUNT_INSN_SIZE))+return-EFAULT;++/*+*nothingtodoifthisisusingtheolder-mprofile-kernel+*instructionsequence+*/+if(op[0]!=PPC_INST_NOP)+return0;++if(patch_instruction((unsignedint*)ip,PPC_INST_MFLR)){+pr_err("Patching MFLR failed.\n");+return-EPERM;+}+#endif+return0;}
@@ -863,6 +950,116 @@ void arch_ftrace_update_code(int command)ftrace_modify_all_code(command);}+#ifdef CONFIG_MPROFILE_KERNEL+/* Returns 1 if we patched in the mflr */+staticint__ftrace_make_call_prep(structdyn_ftrace*rec)+{+void*ip=(void*)rec->ip-MCOUNT_INSN_SIZE;+unsignedintop[2];++/* read where this goes */+if(probe_kernel_read(op,ip,sizeof(op)))+return-EFAULT;++if(op[1]!=PPC_INST_NOP){+pr_err("Unexpected call sequence at %p: %x %x\n",+ip,op[0],op[1]);+return-EINVAL;+}++/*+*nothingtodoifthisisusingtheolder-mprofile-kernel+*instructionsequence+*/+if(op[0]!=PPC_INST_NOP)+return0;++if(patch_instruction((unsignedint*)ip,PPC_INST_MFLR)){+pr_err("Patching MFLR failed.\n");+return-EPERM;+}++return1;+}++/*+*Whenenablingfunctiontracingfor-mprofile-kernelthatusesa+*2-instructionsequenceof'mflrr0,bl_mcount()',weusea2stepprocess:+*1.Patchinthe'mflrr0'instruction+*1a.synchronize_rcu_tasks()toensurethatanythreadsthathadexecuted+*theearliernoptheremakeprogress(andhencedonotbranchinto+*ftracewithoutexecutingtheprecedingmflr)+*2.Patchinthebranchtoftrace+*/+voidftrace_replace_code(intmod_flags)+{+intenable=mod_flags&FTRACE_MODIFY_ENABLE_FL;+intschedulable=mod_flags&FTRACE_MODIFY_MAY_SLEEP_FL;+intret,failed,make_call=0;+structftrace_rec_iter*iter;+structdyn_ftrace*rec;++if(unlikely(!ftrace_enabled))+return;++for_ftrace_rec_iter(iter){+rec=ftrace_rec_iter_record(iter);++if(rec->flags&FTRACE_FL_DISABLED)+continue;++failed=0;+ret=ftrace_test_record(rec,enable);+if(ret==FTRACE_UPDATE_MAKE_CALL){+failed=__ftrace_make_call_prep(rec);+if(failed<0){+ftrace_bug(failed,rec);+return;+}elseif(failed==1)+make_call++;+}++if(!failed){+/* We can patch the record directly */+failed=ftrace_replace_code_rec(rec,enable);+if(failed){+ftrace_bug(failed,rec);+return;+}+}++if(schedulable)+cond_resched();+}++if(!make_call)+/* No records needed patching a preceding mflr */+return;++synchronize_rcu_tasks();++for_ftrace_rec_iter(iter){+rec=ftrace_rec_iter_record(iter);++if(rec->flags&FTRACE_FL_DISABLED)+continue;++ret=ftrace_test_record(rec,enable);+if(ret==FTRACE_UPDATE_MAKE_CALL)+failed=ftrace_replace_code_rec(rec,enable);++if(failed){+ftrace_bug(failed,rec);+return;+}++if(schedulable)+cond_resched();+}++}+#endif+#ifdef CONFIG_PPC64#define PACATOC offsetof(struct paca_struct, kernel_toc)
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2019-06-19 05:14:47
Hi Naveen,
Sorry I meant to reply to this earlier .. :/
"Naveen N. Rao" [off-list ref] writes:
With -mprofile-kernel, gcc emits 'mflr r0', followed by 'bl _mcount' to
enable function tracing and profiling. So far, with dynamic ftrace, we
used to only patch out the branch to _mcount(). However, mflr is
executed by the branch unit that can only execute one per cycle on
POWER9 and shared with branches, so it would be nice to avoid it where
possible.
We cannot simply nop out the mflr either. When enabling function
tracing, there can be a race if tracing is enabled when some thread was
interrupted after executing a nop'ed out mflr. In this case, the thread
would execute the now-patched-in branch to _mcount() without having
executed the preceding mflr.
To solve this, we now enable function tracing in 2 steps: patch in the
mflr instruction, use synchronize_rcu_tasks() to ensure all existing
threads make progress, and then patch in the branch to _mcount(). We
override ftrace_replace_code() with a powerpc64 variant for this
purpose.
According to the ISA we're not allowed to patch mflr at runtime. See the
section on "CMODX".
I'm also not convinced the ordering between the two patches is
guaranteed by the ISA, given that there's possibly no isync on the other
CPU.
But I haven't had time to dig into it sorry, hopefully later in the
week?
cheers
@@ -125,7 +125,7 @@ __ftrace_make_nop(struct module *mod,{unsignedlongentry,ptr,tramp;unsignedlongip=rec->ip;-unsignedintop,pop;+unsignedintop;/* read where this goes */if(probe_kernel_read(&op,(void*)ip,sizeof(int))){
@@ -160,8 +160,6 @@ __ftrace_make_nop(struct module *mod,#ifdef CONFIG_MPROFILE_KERNEL/* When using -mkernel_profile there is no load to jump over */-pop=PPC_INST_NOP;-if(probe_kernel_read(&op,(void*)(ip-4),4)){pr_err("Fetching instruction at %lx failed.\n",ip-4);return-EFAULT;
@@ -169,26 +167,23 @@ __ftrace_make_nop(struct module *mod,/* We expect either a mflr r0, or a std r0, LRSAVE(r1) */if(op!=PPC_INST_MFLR&&op!=PPC_INST_STD_LR){-pr_err("Unexpected instruction %08x around bl _mcount\n",op);+pr_err("Unexpected instruction %08x before bl _mcount\n",op);return-EINVAL;}-#else-/*-*Ouroriginalcallsitelookslike:-*-*bl<tramp>-*ldr2,XX(r1)-*-*MiltonMillerpointedoutthatwecannotsimplynopthebranch.-*Ifataskwaspreemptedwhencallingatracefunction,thenops-*willremovethewaytorestoretheTOCinr2andther2TOCwill-*getcorrupted.-*-*Useab+8tojumpovertheload.-*/-pop=PPC_INST_BRANCH|8;/* b +8 */+/* We should patch out the bl to _mcount first */+if(patch_instruction((unsignedint*)ip,PPC_INST_NOP)){+pr_err("Patching NOP failed.\n");+return-EPERM;+}+/* then, nop out the preceding 'mflr r0' as an optimization */+if(op==PPC_INST_MFLR&&+patch_instruction((unsignedint*)(ip-4),PPC_INST_NOP)){+pr_err("Patching NOP failed.\n");+return-EPERM;+}+#else/**Checkwhatisinthenextinstruction.Wecanseeldr2,40(r1),but*onfirstpassafterbootwewillseemflrr0.
@@ -421,6 +429,26 @@ static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)return-EPERM;}+#ifdef CONFIG_MPROFILE_KERNEL+/* Nop out the preceding 'mflr r0' as an optimization */+if(probe_kernel_read(&op,(void*)(ip-4),4)){+pr_err("Fetching instruction at %lx failed.\n",ip-4);+return-EFAULT;+}++/* We expect either a mflr r0, or a std r0, LRSAVE(r1) */+if(op!=PPC_INST_MFLR&&op!=PPC_INST_STD_LR){+pr_err("Unexpected instruction %08x before bl _mcount\n",op);+return-EINVAL;+}++if(op==PPC_INST_MFLR&&+patch_instruction((unsignedint*)(ip-4),PPC_INST_NOP)){+pr_err("Patching NOP failed.\n");+return-EPERM;+}+#endif+return0;}
@@ -429,6 +457,7 @@ int ftrace_make_nop(struct module *mod,{unsignedlongip=rec->ip;unsignedintold,new;+intrc;/**Ifthecallingaddressismorethat24bitsaway,
@@ -439,7 +468,34 @@ int ftrace_make_nop(struct module *mod,/* within range */old=ftrace_call_replace(ip,addr,1);new=PPC_INST_NOP;-returnftrace_modify_code(ip,old,new);+rc=ftrace_modify_code(ip,old,new);+#ifdef CONFIG_MPROFILE_KERNEL+if(rc)+returnrc;++/*+*For-mprofile-kernel,wepatchoutthepreceding'mflrr0'+*instruction,asanoptimization.Itisimportanttonopout+*thebranchto_mcount()first,asalone'mflrr0'is+*harmless.+*/+if(probe_kernel_read(&old,(void*)(ip-4),4)){+pr_err("Fetching instruction at %lx failed.\n",ip-4);+return-EFAULT;+}++/* We expect either a mflr r0, or a std r0, LRSAVE(r1) */+if(old!=PPC_INST_MFLR&&old!=PPC_INST_STD_LR){+pr_err("Unexpected instruction %08x before bl _mcount\n",+old);+return-EINVAL;+}++if(old==PPC_INST_MFLR)+rc=patch_instruction((unsignedint*)(ip-4),+PPC_INST_NOP);+#endif+returnrc;}elseif(core_kernel_text(ip))return__ftrace_make_nop_kernel(rec,addr);
@@ -567,6 +623,37 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)return-EINVAL;}+#ifdef CONFIG_MPROFILE_KERNEL+/*+*Wecouldendupherewithouthavingcalled__ftrace_make_call_prep()+*iffunctiontracingisenabledbeforeamoduleisloaded.+*+*ftrace_module_enable()-->ftrace_replace_code_rec()-->+*ftrace_make_call()-->__ftrace_make_call()+*+*Inthisscenario,thepreviousinstructionwillbeaNOP.Itis+*safetopatchitwitha'mflrr0'sinceweknowforafactthat+*thiscodeisnotyetbeingrun.+*/+ip-=MCOUNT_INSN_SIZE;++/* read where this goes */+if(probe_kernel_read(op,ip,MCOUNT_INSN_SIZE))+return-EFAULT;++/*+*nothingtodoifthisisusingtheolder-mprofile-kernel+*instructionsequence+*/+if(op[0]!=PPC_INST_NOP)+return0;++if(patch_instruction((unsignedint*)ip,PPC_INST_MFLR)){+pr_err("Patching MFLR failed.\n");+return-EPERM;+}+#endif+return0;}
@@ -863,6 +950,116 @@ void arch_ftrace_update_code(int command)ftrace_modify_all_code(command);}+#ifdef CONFIG_MPROFILE_KERNEL+/* Returns 1 if we patched in the mflr */+staticint__ftrace_make_call_prep(structdyn_ftrace*rec)+{+void*ip=(void*)rec->ip-MCOUNT_INSN_SIZE;+unsignedintop[2];++/* read where this goes */+if(probe_kernel_read(op,ip,sizeof(op)))+return-EFAULT;++if(op[1]!=PPC_INST_NOP){+pr_err("Unexpected call sequence at %p: %x %x\n",+ip,op[0],op[1]);+return-EINVAL;+}++/*+*nothingtodoifthisisusingtheolder-mprofile-kernel+*instructionsequence+*/+if(op[0]!=PPC_INST_NOP)+return0;++if(patch_instruction((unsignedint*)ip,PPC_INST_MFLR)){+pr_err("Patching MFLR failed.\n");+return-EPERM;+}++return1;+}++/*+*Whenenablingfunctiontracingfor-mprofile-kernelthatusesa+*2-instructionsequenceof'mflrr0,bl_mcount()',weusea2stepprocess:+*1.Patchinthe'mflrr0'instruction+*1a.synchronize_rcu_tasks()toensurethatanythreadsthathadexecuted+*theearliernoptheremakeprogress(andhencedonotbranchinto+*ftracewithoutexecutingtheprecedingmflr)+*2.Patchinthebranchtoftrace+*/+voidftrace_replace_code(intmod_flags)+{+intenable=mod_flags&FTRACE_MODIFY_ENABLE_FL;+intschedulable=mod_flags&FTRACE_MODIFY_MAY_SLEEP_FL;+intret,failed,make_call=0;+structftrace_rec_iter*iter;+structdyn_ftrace*rec;++if(unlikely(!ftrace_enabled))+return;++for_ftrace_rec_iter(iter){+rec=ftrace_rec_iter_record(iter);++if(rec->flags&FTRACE_FL_DISABLED)+continue;++failed=0;+ret=ftrace_test_record(rec,enable);+if(ret==FTRACE_UPDATE_MAKE_CALL){+failed=__ftrace_make_call_prep(rec);+if(failed<0){+ftrace_bug(failed,rec);+return;+}elseif(failed==1)+make_call++;+}++if(!failed){+/* We can patch the record directly */+failed=ftrace_replace_code_rec(rec,enable);+if(failed){+ftrace_bug(failed,rec);+return;+}+}++if(schedulable)+cond_resched();+}++if(!make_call)+/* No records needed patching a preceding mflr */+return;++synchronize_rcu_tasks();++for_ftrace_rec_iter(iter){+rec=ftrace_rec_iter_record(iter);++if(rec->flags&FTRACE_FL_DISABLED)+continue;++ret=ftrace_test_record(rec,enable);+if(ret==FTRACE_UPDATE_MAKE_CALL)+failed=ftrace_replace_code_rec(rec,enable);++if(failed){+ftrace_bug(failed,rec);+return;+}++if(schedulable)+cond_resched();+}++}+#endif+#ifdef CONFIG_PPC64#define PACATOC offsetof(struct paca_struct, kernel_toc)
From: Nicholas Piggin <npiggin@gmail.com> Date: 2019-06-19 07:16:08
Michael Ellerman's on June 19, 2019 3:14 pm:
Hi Naveen,
Sorry I meant to reply to this earlier .. :/
"Naveen N. Rao" [off-list ref] writes:
quoted
With -mprofile-kernel, gcc emits 'mflr r0', followed by 'bl _mcount' to
enable function tracing and profiling. So far, with dynamic ftrace, we
used to only patch out the branch to _mcount(). However, mflr is
executed by the branch unit that can only execute one per cycle on
POWER9 and shared with branches, so it would be nice to avoid it where
possible.
We cannot simply nop out the mflr either. When enabling function
tracing, there can be a race if tracing is enabled when some thread was
interrupted after executing a nop'ed out mflr. In this case, the thread
would execute the now-patched-in branch to _mcount() without having
executed the preceding mflr.
To solve this, we now enable function tracing in 2 steps: patch in the
mflr instruction, use synchronize_rcu_tasks() to ensure all existing
threads make progress, and then patch in the branch to _mcount(). We
override ftrace_replace_code() with a powerpc64 variant for this
purpose.
According to the ISA we're not allowed to patch mflr at runtime. See the
section on "CMODX".
According to "quasi patch class" engineering note, we can patch
anything with a preferred nop. But that's written as an optional
facility, which we don't have a feature to test for.
I'm also not convinced the ordering between the two patches is
guaranteed by the ISA, given that there's possibly no isync on the other
CPU.
Will they go through a context synchronizing event?
synchronize_rcu_tasks() should ensure a thread is scheduled away, but
I'm not actually sure it guarantees CSI if it's kernel->kernel. Could
do a smp_call_function to do the isync on each CPU to be sure.
Thanks,
Nick
From: Naveen N. Rao <hidden> Date: 2019-06-19 09:53:39
Nicholas Piggin wrote:
Michael Ellerman's on June 19, 2019 3:14 pm:
quoted
Hi Naveen,
Sorry I meant to reply to this earlier .. :/
No problem. Thanks for the questions.
quoted
"Naveen N. Rao" [off-list ref] writes:
quoted
With -mprofile-kernel, gcc emits 'mflr r0', followed by 'bl _mcount' to
enable function tracing and profiling. So far, with dynamic ftrace, we
used to only patch out the branch to _mcount(). However, mflr is
executed by the branch unit that can only execute one per cycle on
POWER9 and shared with branches, so it would be nice to avoid it where
possible.
We cannot simply nop out the mflr either. When enabling function
tracing, there can be a race if tracing is enabled when some thread was
interrupted after executing a nop'ed out mflr. In this case, the thread
would execute the now-patched-in branch to _mcount() without having
executed the preceding mflr.
To solve this, we now enable function tracing in 2 steps: patch in the
mflr instruction, use synchronize_rcu_tasks() to ensure all existing
threads make progress, and then patch in the branch to _mcount(). We
override ftrace_replace_code() with a powerpc64 variant for this
purpose.
According to the ISA we're not allowed to patch mflr at runtime. See the
section on "CMODX".
According to "quasi patch class" engineering note, we can patch
anything with a preferred nop. But that's written as an optional
facility, which we don't have a feature to test for.
Hmm... I wonder what the implications are. We've been patching in a
'trap' for kprobes for a long time now, along with having to patch back
the original instruction (which can be anything), when the probe is
removed.
quoted
I'm also not convinced the ordering between the two patches is
guaranteed by the ISA, given that there's possibly no isync on the other
CPU.
Will they go through a context synchronizing event?
synchronize_rcu_tasks() should ensure a thread is scheduled away, but
I'm not actually sure it guarantees CSI if it's kernel->kernel. Could
do a smp_call_function to do the isync on each CPU to be sure.
Good point. Per
Documentation/RCU/Design/Requirements/Requirements.html#Tasks RCU:
"The solution, in the form of Tasks RCU, is to have implicit read-side
critical sections that are delimited by voluntary context switches, that
is, calls to schedule(), cond_resched(), and synchronize_rcu_tasks(). In
addition, transitions to and from userspace execution also delimit
tasks-RCU read-side critical sections."
I suppose transitions to/from userspace, as well as calls to schedule()
result in context synchronizing instruction being executed. But, if some
tasks call cond_resched() and synchronize_rcu_tasks(), we probably won't
have a CSI executed.
Also:
"In CONFIG_PREEMPT=n kernels, trampolines cannot be preempted, so these
APIs map to call_rcu(), synchronize_rcu(), and rcu_barrier(),
respectively."
In this scenario as well, I think we won't have a CSI executed in case
of cond_resched().
Should we enhance patch_instruction() to handle that?
- Naveen
From: Nicholas Piggin <npiggin@gmail.com> Date: 2019-06-19 10:47:03
Naveen N. Rao's on June 19, 2019 7:53 pm:
Nicholas Piggin wrote:
quoted
Michael Ellerman's on June 19, 2019 3:14 pm:
quoted
Hi Naveen,
Sorry I meant to reply to this earlier .. :/
No problem. Thanks for the questions.
quoted
quoted
"Naveen N. Rao" [off-list ref] writes:
quoted
With -mprofile-kernel, gcc emits 'mflr r0', followed by 'bl _mcount' to
enable function tracing and profiling. So far, with dynamic ftrace, we
used to only patch out the branch to _mcount(). However, mflr is
executed by the branch unit that can only execute one per cycle on
POWER9 and shared with branches, so it would be nice to avoid it where
possible.
We cannot simply nop out the mflr either. When enabling function
tracing, there can be a race if tracing is enabled when some thread was
interrupted after executing a nop'ed out mflr. In this case, the thread
would execute the now-patched-in branch to _mcount() without having
executed the preceding mflr.
To solve this, we now enable function tracing in 2 steps: patch in the
mflr instruction, use synchronize_rcu_tasks() to ensure all existing
threads make progress, and then patch in the branch to _mcount(). We
override ftrace_replace_code() with a powerpc64 variant for this
purpose.
According to the ISA we're not allowed to patch mflr at runtime. See the
section on "CMODX".
According to "quasi patch class" engineering note, we can patch
anything with a preferred nop. But that's written as an optional
facility, which we don't have a feature to test for.
Hmm... I wonder what the implications are. We've been patching in a
'trap' for kprobes for a long time now, along with having to patch back
the original instruction (which can be anything), when the probe is
removed.
Will have to check what implementations support "quasi patch class"
instructions. IIRC recent POWER processors are okay. May have to add
a feature test though.
quoted
quoted
I'm also not convinced the ordering between the two patches is
guaranteed by the ISA, given that there's possibly no isync on the other
CPU.
Will they go through a context synchronizing event?
synchronize_rcu_tasks() should ensure a thread is scheduled away, but
I'm not actually sure it guarantees CSI if it's kernel->kernel. Could
do a smp_call_function to do the isync on each CPU to be sure.
Good point. Per
Documentation/RCU/Design/Requirements/Requirements.html#Tasks RCU:
"The solution, in the form of Tasks RCU, is to have implicit read-side
critical sections that are delimited by voluntary context switches, that
is, calls to schedule(), cond_resched(), and synchronize_rcu_tasks(). In
addition, transitions to and from userspace execution also delimit
tasks-RCU read-side critical sections."
I suppose transitions to/from userspace, as well as calls to schedule()
result in context synchronizing instruction being executed. But, if some
tasks call cond_resched() and synchronize_rcu_tasks(), we probably won't
have a CSI executed.
Also:
"In CONFIG_PREEMPT=n kernels, trampolines cannot be preempted, so these
APIs map to call_rcu(), synchronize_rcu(), and rcu_barrier(),
respectively."
In this scenario as well, I think we won't have a CSI executed in case
of cond_resched().
Should we enhance patch_instruction() to handle that?
Well, not sure. Do we have many post-boot callers of it? Should
they take care of their own synchronization requirements?
Thanks,
Nick
From: Naveen N. Rao <hidden> Date: 2019-06-19 17:15:11
Nicholas Piggin wrote:
Naveen N. Rao's on June 19, 2019 7:53 pm:
quoted
Nicholas Piggin wrote:
quoted
Michael Ellerman's on June 19, 2019 3:14 pm:
quoted
I'm also not convinced the ordering between the two patches is
guaranteed by the ISA, given that there's possibly no isync on the other
CPU.
Will they go through a context synchronizing event?
synchronize_rcu_tasks() should ensure a thread is scheduled away, but
I'm not actually sure it guarantees CSI if it's kernel->kernel. Could
do a smp_call_function to do the isync on each CPU to be sure.
Good point. Per
Documentation/RCU/Design/Requirements/Requirements.html#Tasks RCU:
"The solution, in the form of Tasks RCU, is to have implicit read-side
critical sections that are delimited by voluntary context switches, that
is, calls to schedule(), cond_resched(), and synchronize_rcu_tasks(). In
addition, transitions to and from userspace execution also delimit
tasks-RCU read-side critical sections."
I suppose transitions to/from userspace, as well as calls to schedule()
result in context synchronizing instruction being executed. But, if some
tasks call cond_resched() and synchronize_rcu_tasks(), we probably won't
have a CSI executed.
Also:
"In CONFIG_PREEMPT=n kernels, trampolines cannot be preempted, so these
APIs map to call_rcu(), synchronize_rcu(), and rcu_barrier(),
respectively."
In this scenario as well, I think we won't have a CSI executed in case
of cond_resched().
Should we enhance patch_instruction() to handle that?
Well, not sure. Do we have many post-boot callers of it? Should
they take care of their own synchronization requirements?
Kprobes and ftrace are the two users (along with anything else that may
use jump labels).
Looking at this from the CMODX perspective: the main example quoted of
an erratic behavior is when any variant of the patched instruction
causes an exception.
With ftrace, I think we are ok since we only ever patch a 'nop' or a
'bl' (and the 'mflr' now), none of which should cause an exception. As
such, the existing patch_instruction() should suffice.
However, with kprobes, we patch a 'trap' (or a branch in case of
optprobes) on most instructions. I wonder if we should be issuing an
'isync' on all cpus in this case. Or, even if that is sufficient or
necessary.
Thanks,
Naveen
From: Naveen N. Rao <hidden> Date: 2019-06-18 14:48:03
With KPROBES_ON_FTRACE, kprobe is allowed to be inserted on instructions
that branch to _mcount (referred to as ftrace location). With
-mprofile-kernel, we now include the preceding 'mflr r0' as being part
of the ftrace location.
However, by default, probing on an instruction that is not actually the
branch to _mcount() is prohibited, as that is considered to not be at an
instruction boundary. This is not the case on powerpc, so allow the same
by overriding arch_check_ftrace_location()
In addition, we update kprobe_ftrace_handler() to detect this scenarios
and to pass the proper nip to the pre and post probe handlers.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/kprobes-ftrace.c | 30 ++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
@@ -12,14 +12,34 @@#include<linux/preempt.h>#include<linux/ftrace.h>+/*+*With-mprofile-kernel,wepatchtwoinstructions--thebranchto_mcount+*aswellasthepreceding'mflrr0'.Boththeseinstructionsareclaimed+*byftraceandweshouldallowprobingoneitherinstruction.+*/+intarch_check_ftrace_location(structkprobe*p)+{+if(ftrace_location((unsignedlong)p->addr))+p->flags|=KPROBE_FLAG_FTRACE;+return0;+}+/* Ftrace callback handler for kprobes */voidkprobe_ftrace_handler(unsignedlongnip,unsignedlongparent_nip,structftrace_ops*ops,structpt_regs*regs){structkprobe*p;+intmflr_kprobe=0;structkprobe_ctlblk*kcb;p=get_kprobe((kprobe_opcode_t*)nip);+if(unlikely(!p)){+p=get_kprobe((kprobe_opcode_t*)(nip-MCOUNT_INSN_SIZE));+if(!p)+return;+mflr_kprobe=1;+}+if(unlikely(!p)||kprobe_disabled(p))return;
@@ -33,6 +53,9 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip,*/regs->nip-=MCOUNT_INSN_SIZE;+if(mflr_kprobe)+regs->nip-=MCOUNT_INSN_SIZE;+__this_cpu_write(current_kprobe,p);kcb->kprobe_status=KPROBE_HIT_ACTIVE;if(!p->pre_handler||!p->pre_handler(p,regs)){
@@ -45,6 +68,8 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip,kcb->kprobe_status=KPROBE_HIT_SSDONE;p->post_handler(p,regs,0);}+if(mflr_kprobe)+regs->nip+=MCOUNT_INSN_SIZE;}/**Ifpre_handlerreturns!0,itchangesregs->nip.Wehaveto
@@ -57,6 +82,11 @@ NOKPROBE_SYMBOL(kprobe_ftrace_handler);intarch_prepare_kprobe_ftrace(structkprobe*p){+if((unsignedlong)p->addr&0x03){+printk("Attempt to register kprobe at an unaligned address\n");+return-EILSEQ;+}+p->ainsn.insn=NULL;p->ainsn.boostable=-1;return0;
On Tue, 18 Jun 2019 20:17:06 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted hunk
With KPROBES_ON_FTRACE, kprobe is allowed to be inserted on instructions
that branch to _mcount (referred to as ftrace location). With
-mprofile-kernel, we now include the preceding 'mflr r0' as being part
of the ftrace location.
However, by default, probing on an instruction that is not actually the
branch to _mcount() is prohibited, as that is considered to not be at an
instruction boundary. This is not the case on powerpc, so allow the same
by overriding arch_check_ftrace_location()
In addition, we update kprobe_ftrace_handler() to detect this scenarios
and to pass the proper nip to the pre and post probe handlers.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/kprobes-ftrace.c | 30 ++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
@@ -33,6 +53,9 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip, */ regs->nip -= MCOUNT_INSN_SIZE;+ if (mflr_kprobe)+ regs->nip -= MCOUNT_INSN_SIZE;+ __this_cpu_write(current_kprobe, p); kcb->kprobe_status = KPROBE_HIT_ACTIVE; if (!p->pre_handler || !p->pre_handler(p, regs)) {
@@ -45,6 +68,8 @@ void kprobe_ftrace_handler(unsigned long nip, unsigned long parent_nip, kcb->kprobe_status = KPROBE_HIT_SSDONE; p->post_handler(p, regs, 0); }+ if (mflr_kprobe)+ regs->nip += MCOUNT_INSN_SIZE; } /* * If pre_handler returns !0, it changes regs->nip. We have to
@@ -57,6 +82,11 @@ NOKPROBE_SYMBOL(kprobe_ftrace_handler); int arch_prepare_kprobe_ftrace(struct kprobe *p) {+ if ((unsigned long)p->addr & 0x03) {+ printk("Attempt to register kprobe at an unaligned address\n");+ return -EILSEQ;+ }+ p->ainsn.insn = NULL; p->ainsn.boostable = -1; return 0;
@@ -57,6 +82,11 @@ NOKPROBE_SYMBOL(kprobe_ftrace_handler); int arch_prepare_kprobe_ftrace(struct kprobe *p) {+ if ((unsigned long)p->addr & 0x03) {+ printk("Attempt to register kprobe at an unaligned address\n");
Please use the appropriate KERN_<LEVEL> or pr_<level>
From: Naveen N. Rao <hidden> Date: 2019-06-26 09:40:07
Masami Hiramatsu wrote:
On Tue, 18 Jun 2019 20:17:06 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted
With KPROBES_ON_FTRACE, kprobe is allowed to be inserted on instructions
that branch to _mcount (referred to as ftrace location). With
-mprofile-kernel, we now include the preceding 'mflr r0' as being part
of the ftrace location.
However, by default, probing on an instruction that is not actually the
branch to _mcount() is prohibited, as that is considered to not be at an
instruction boundary. This is not the case on powerpc, so allow the same
by overriding arch_check_ftrace_location()
In addition, we update kprobe_ftrace_handler() to detect this scenarios
and to pass the proper nip to the pre and post probe handlers.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/kprobes-ftrace.c | 30 ++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
@@ -57,6 +82,11 @@ NOKPROBE_SYMBOL(kprobe_ftrace_handler); int arch_prepare_kprobe_ftrace(struct kprobe *p) {+ if ((unsigned long)p->addr & 0x03) {+ printk("Attempt to register kprobe at an unaligned address\n");
Please use the appropriate KERN_<LEVEL> or pr_<level>
From: Naveen N. Rao <hidden> Date: 2019-06-18 14:49:15
Ftrace location could include more than a single instruction in case of
some architectures (powerpc64, for now). In this case, kprobe is
permitted on any of those instructions, and uses ftrace infrastructure
for functioning.
However, [dis]arm_kprobe_ftrace() uses the kprobe address when setting
up ftrace filter IP. This won't work if the address points to any
instruction apart from the one that has a branch to _mcount(). To
resolve this, have [dis]arm_kprobe_ftrace() use ftrace_function() to
identify the filter IP.
Signed-off-by: Naveen N. Rao <redacted>
---
kernel/kprobes.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
@@ -978,10 +978,10 @@ static int prepare_kprobe(struct kprobe *p)/* Caller must lock kprobe_mutex */staticintarm_kprobe_ftrace(structkprobe*p){+unsignedlongftrace_ip=ftrace_location((unsignedlong)p->addr);intret=0;-ret=ftrace_set_filter_ip(&kprobe_ftrace_ops,-(unsignedlong)p->addr,0,0);+ret=ftrace_set_filter_ip(&kprobe_ftrace_ops,ftrace_ip,0,0);if(ret){pr_debug("Failed to arm kprobe-ftrace at %pS (%d)\n",p->addr,ret);
@@ -1005,13 +1005,14 @@ static int arm_kprobe_ftrace(struct kprobe *p)*non-emptyfilter_hashforIPMODIFYops,we'resafefromanaccidental*emptyfilter_hashwhichwouldundesirablytraceallfunctions.*/-ftrace_set_filter_ip(&kprobe_ftrace_ops,(unsignedlong)p->addr,1,0);+ftrace_set_filter_ip(&kprobe_ftrace_ops,ftrace_ip,1,0);returnret;}/* Caller must lock kprobe_mutex */staticintdisarm_kprobe_ftrace(structkprobe*p){+unsignedlongftrace_ip=ftrace_location((unsignedlong)p->addr);intret=0;if(kprobe_ftrace_enabled==1){
@@ -1022,8 +1023,7 @@ static int disarm_kprobe_ftrace(struct kprobe *p)kprobe_ftrace_enabled--;-ret=ftrace_set_filter_ip(&kprobe_ftrace_ops,-(unsignedlong)p->addr,1,0);+ret=ftrace_set_filter_ip(&kprobe_ftrace_ops,ftrace_ip,1,0);WARN_ONCE(ret<0,"Failed to disarm kprobe-ftrace at %pS (%d)\n",p->addr,ret);returnret;
On Tue, 18 Jun 2019 20:17:05 +0530
"Naveen N. Rao" [off-list ref] wrote:
Ftrace location could include more than a single instruction in case of
some architectures (powerpc64, for now). In this case, kprobe is
permitted on any of those instructions, and uses ftrace infrastructure
for functioning.
However, [dis]arm_kprobe_ftrace() uses the kprobe address when setting
up ftrace filter IP. This won't work if the address points to any
instruction apart from the one that has a branch to _mcount(). To
resolve this, have [dis]arm_kprobe_ftrace() use ftrace_function() to
identify the filter IP.
This looks good to me.
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Thank you!
@@ -978,10 +978,10 @@ static int prepare_kprobe(struct kprobe *p)/* Caller must lock kprobe_mutex */staticintarm_kprobe_ftrace(structkprobe*p){+unsignedlongftrace_ip=ftrace_location((unsignedlong)p->addr);intret=0;-ret=ftrace_set_filter_ip(&kprobe_ftrace_ops,-(unsignedlong)p->addr,0,0);+ret=ftrace_set_filter_ip(&kprobe_ftrace_ops,ftrace_ip,0,0);if(ret){pr_debug("Failed to arm kprobe-ftrace at %pS (%d)\n",p->addr,ret);
@@ -1005,13 +1005,14 @@ static int arm_kprobe_ftrace(struct kprobe *p)*non-emptyfilter_hashforIPMODIFYops,we'resafefromanaccidental*emptyfilter_hashwhichwouldundesirablytraceallfunctions.*/-ftrace_set_filter_ip(&kprobe_ftrace_ops,(unsignedlong)p->addr,1,0);+ftrace_set_filter_ip(&kprobe_ftrace_ops,ftrace_ip,1,0);returnret;}/* Caller must lock kprobe_mutex */staticintdisarm_kprobe_ftrace(structkprobe*p){+unsignedlongftrace_ip=ftrace_location((unsignedlong)p->addr);intret=0;if(kprobe_ftrace_enabled==1){
@@ -1022,8 +1023,7 @@ static int disarm_kprobe_ftrace(struct kprobe *p)kprobe_ftrace_enabled--;-ret=ftrace_set_filter_ip(&kprobe_ftrace_ops,-(unsignedlong)p->addr,1,0);+ret=ftrace_set_filter_ip(&kprobe_ftrace_ops,ftrace_ip,1,0);WARN_ONCE(ret<0,"Failed to disarm kprobe-ftrace at %pS (%d)\n",p->addr,ret);returnret;
From: Naveen N. Rao <hidden> Date: 2019-06-18 14:50:17
Now that we are patching the preceding 'mflr r0' instruction with
-mprofile-kernel, we need to update ftrace_location[_range]() to
recognise that as being part of ftrace. To do this, we make a small
change to ftrace_location_range() and convert ftrace_cmp_recs() into a
weak function. We implement a custom version of ftrace_cmp_recs() which
looks at the instruction preceding the branch to _mcount() and marks
that instruction as belonging to ftrace if it is a 'nop' or 'mflr r0'.
Signed-off-by: Naveen N. Rao <redacted>
---
arch/powerpc/kernel/trace/ftrace.c | 31 ++++++++++++++++++++++++++++++
include/linux/ftrace.h | 1 +
kernel/trace/ftrace.c | 4 ++--
3 files changed, 34 insertions(+), 2 deletions(-)
@@ -951,6 +951,37 @@ void arch_ftrace_update_code(int command)}#ifdef CONFIG_MPROFILE_KERNEL+/*+*Weneedtocheckifthepreviousinstructionisa'nop'or'mflrr0'.+*Ifso,wewillpatchthosesubsequentlyandthatinstructionmustbe+*consideredaspartofftrace.+*/+intftrace_cmp_recs(constvoid*a,constvoid*b)+{+conststructdyn_ftrace*key=a;+conststructdyn_ftrace*rec=b;+unsignedintop;++if(key->flags<rec->ip-MCOUNT_INSN_SIZE)+return-1;+if(key->ip>=rec->ip+MCOUNT_INSN_SIZE)+return1;++if(key->flags>rec->ip)+return0;++/* check the previous instruction */+if(probe_kernel_read(&op,(void*)rec->ip-MCOUNT_INSN_SIZE,+sizeof(op)))+/* assume we own it */+return0;++if(op!=PPC_INST_NOP&&op!=PPC_INST_MFLR)+return-1;++return0;+}+/* Returns 1 if we patched in the mflr */staticint__ftrace_make_call_prep(structdyn_ftrace*rec){
@@ -1551,7 +1551,7 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end)key.flags=end;/* overload flags, as it is unsigned long */for(pg=ftrace_pages_start;pg;pg=pg->next){-if(end<pg->records[0].ip||+if(end<=pg->records[0].ip||start>=(pg->records[pg->index-1].ip+MCOUNT_INSN_SIZE))continue;rec=bsearch(&key,pg->records,pg->index,
From: Steven Rostedt <rostedt@goodmis.org> Date: 2019-06-18 15:45:14
On Tue, 18 Jun 2019 20:17:04 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted hunk
@@ -1551,7 +1551,7 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end) key.flags = end; /* overload flags, as it is unsigned long */ for (pg = ftrace_pages_start; pg; pg = pg->next) {- if (end < pg->records[0].ip ||+ if (end <= pg->records[0].ip ||
This breaks the algorithm. "end" is inclusive. That is, if you look for
a single byte, where "start" and "end" are the same, and it happens to
be the first ip on the pg page, it will be skipped, and not found.
-- Steve
From: Naveen N. Rao <hidden> Date: 2019-06-18 18:11:47
Steven Rostedt wrote:
On Tue, 18 Jun 2019 20:17:04 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted
@@ -1551,7 +1551,7 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end) key.flags = end; /* overload flags, as it is unsigned long */ for (pg = ftrace_pages_start; pg; pg = pg->next) {- if (end < pg->records[0].ip ||+ if (end <= pg->records[0].ip ||
This breaks the algorithm. "end" is inclusive. That is, if you look for
a single byte, where "start" and "end" are the same, and it happens to
be the first ip on the pg page, it will be skipped, and not found.
Thanks. It looks like I should be over-riding ftrace_location() instead.
I will update this patch.
- Naveen
From: Naveen N. Rao <hidden> Date: 2019-06-18 18:23:23
Naveen N. Rao wrote:
Steven Rostedt wrote:
quoted
On Tue, 18 Jun 2019 20:17:04 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted
@@ -1551,7 +1551,7 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end) key.flags = end; /* overload flags, as it is unsigned long */ for (pg = ftrace_pages_start; pg; pg = pg->next) {- if (end < pg->records[0].ip ||+ if (end <= pg->records[0].ip ||
This breaks the algorithm. "end" is inclusive. That is, if you look for
a single byte, where "start" and "end" are the same, and it happens to
be the first ip on the pg page, it will be skipped, and not found.
Thanks. It looks like I should be over-riding ftrace_location() instead.
I will update this patch.
I think I will have ftrace own the two instruction range, regardless of
whether the preceding instruction is a 'mflr r0' or not. This simplifies
things and I don't see an issue with it as of now. I will do more
testing to confirm.
- Naveen
@@ -951,6 +951,16 @@ void arch_ftrace_update_code(int command)}#ifdef CONFIG_MPROFILE_KERNEL+/*+*Weconsidertwoinstructions--'mflrr0','bl_mcount'--tobepart+*offtrace.Whencheckingforthefirstinstruction,wewanttoinclude+*thenextinstructionintherangecheck.+*/+unsignedlongftrace_location(unsignedlongip)+{+returnftrace_location_range(ip,ip+MCOUNT_INSN_SIZE);+}+/* Returns 1 if we patched in the mflr */staticint__ftrace_make_call_prep(structdyn_ftrace*rec){
@@ -1573,7 +1573,7 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end)*thefunctiontracer.Itcheckstheftraceinternaltablesto*determineiftheaddressbelongsornot.*/-unsignedlongftrace_location(unsignedlongip)+unsignedlong__weakftrace_location(unsignedlongip){returnftrace_location_range(ip,ip);}
From: Steven Rostedt <rostedt@goodmis.org> Date: 2019-06-18 18:32:39
On Tue, 18 Jun 2019 23:53:11 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted hunk
Naveen N. Rao wrote:
quoted
Steven Rostedt wrote:
quoted
On Tue, 18 Jun 2019 20:17:04 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted
@@ -1551,7 +1551,7 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end) key.flags = end; /* overload flags, as it is unsigned long */ for (pg = ftrace_pages_start; pg; pg = pg->next) {- if (end < pg->records[0].ip ||+ if (end <= pg->records[0].ip ||
This breaks the algorithm. "end" is inclusive. That is, if you look for
a single byte, where "start" and "end" are the same, and it happens to
be the first ip on the pg page, it will be skipped, and not found.
Thanks. It looks like I should be over-riding ftrace_location() instead.
I will update this patch.
I think I will have ftrace own the two instruction range, regardless of
whether the preceding instruction is a 'mflr r0' or not. This simplifies
things and I don't see an issue with it as of now. I will do more
testing to confirm.
- Naveen
@@ -951,6 +951,16 @@ void arch_ftrace_update_code(int command)}#ifdef CONFIG_MPROFILE_KERNEL+/*+*Weconsidertwoinstructions--'mflrr0','bl_mcount'--tobepart+*offtrace.Whencheckingforthefirstinstruction,wewanttoinclude+*thenextinstructionintherangecheck.+*/+unsignedlongftrace_location(unsignedlongip)+{+returnftrace_location_range(ip,ip+MCOUNT_INSN_SIZE);+}+/* Returns 1 if we patched in the mflr */staticint__ftrace_make_call_prep(structdyn_ftrace*rec){
@@ -1573,7 +1573,7 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end)*thefunctiontracer.Itcheckstheftraceinternaltablesto*determineiftheaddressbelongsornot.*/-unsignedlongftrace_location(unsignedlongip)+unsignedlong__weakftrace_location(unsignedlongip){returnftrace_location_range(ip,ip);}
Actually, instead of making this a weak function, let's do this:
In include/ftrace.h:
#ifndef FTRACE_IP_EXTENSION
# define FTRACE_IP_EXTENSION 0
#endif
In arch/powerpc/include/asm/ftrace.h
#define FTRACE_IP_EXTENSION MCOUNT_INSN_SIZE
Then we can just have:
unsigned long ftrace_location(unsigned long ip)
{
return ftrace_location_range(ip, ip + FTRACE_IP_EXTENSION);
}
-- Steve
From: Naveen N. Rao <hidden> Date: 2019-06-19 07:56:49
Steven Rostedt wrote:
On Tue, 18 Jun 2019 23:53:11 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted
Naveen N. Rao wrote:
quoted
Steven Rostedt wrote:
quoted
On Tue, 18 Jun 2019 20:17:04 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted
@@ -1551,7 +1551,7 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end) key.flags = end; /* overload flags, as it is unsigned long */ for (pg = ftrace_pages_start; pg; pg = pg->next) {- if (end < pg->records[0].ip ||+ if (end <= pg->records[0].ip ||
This breaks the algorithm. "end" is inclusive. That is, if you look for
a single byte, where "start" and "end" are the same, and it happens to
be the first ip on the pg page, it will be skipped, and not found.
Thanks. It looks like I should be over-riding ftrace_location() instead.
I will update this patch.
I think I will have ftrace own the two instruction range, regardless of
whether the preceding instruction is a 'mflr r0' or not. This simplifies
things and I don't see an issue with it as of now. I will do more
testing to confirm.
- Naveen
@@ -951,6 +951,16 @@ void arch_ftrace_update_code(int command)}#ifdef CONFIG_MPROFILE_KERNEL+/*+*Weconsidertwoinstructions--'mflrr0','bl_mcount'--tobepart+*offtrace.Whencheckingforthefirstinstruction,wewanttoinclude+*thenextinstructionintherangecheck.+*/+unsignedlongftrace_location(unsignedlongip)+{+returnftrace_location_range(ip,ip+MCOUNT_INSN_SIZE);+}+/* Returns 1 if we patched in the mflr */staticint__ftrace_make_call_prep(structdyn_ftrace*rec){
@@ -1573,7 +1573,7 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end)*thefunctiontracer.Itcheckstheftraceinternaltablesto*determineiftheaddressbelongsornot.*/-unsignedlongftrace_location(unsignedlongip)+unsignedlong__weakftrace_location(unsignedlongip){returnftrace_location_range(ip,ip);}
Actually, instead of making this a weak function, let's do this:
In include/ftrace.h:
#ifndef FTRACE_IP_EXTENSION
# define FTRACE_IP_EXTENSION 0
#endif
In arch/powerpc/include/asm/ftrace.h
#define FTRACE_IP_EXTENSION MCOUNT_INSN_SIZE
Then we can just have:
unsigned long ftrace_location(unsigned long ip)
{
return ftrace_location_range(ip, ip + FTRACE_IP_EXTENSION);
}
Thanks, that's indeed nice. I hope you don't mind me adding your SOB for
that.
- Naveen
From: Steven Rostedt <rostedt@goodmis.org> Date: 2019-06-19 09:28:09
On Wed, 19 Jun 2019 13:26:37 +0530
"Naveen N. Rao" [off-list ref] wrote:
quoted
In include/ftrace.h:
#ifndef FTRACE_IP_EXTENSION
# define FTRACE_IP_EXTENSION 0
#endif
In arch/powerpc/include/asm/ftrace.h
#define FTRACE_IP_EXTENSION MCOUNT_INSN_SIZE
Then we can just have:
unsigned long ftrace_location(unsigned long ip)
{
return ftrace_location_range(ip, ip + FTRACE_IP_EXTENSION);
}
Thanks, that's indeed nice. I hope you don't mind me adding your SOB for
that.
Actually, it's best not to put a SOB by anyone other than yourself. It
actually has legal meaning.
In this case, please add:
Suggested-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Thanks!
-- Steve