Re: [RFC 1/2] MIPS: tracing/ftrace: Replace in_module() with a generic in_kernel_space()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, Oct 23, 2010 at 5:31 AM, David Daney <ddaney@xxxxxxxxxxxxxxxxxx> wrote:
> On 10/22/2010 01:58 PM, Wu Zhangjin wrote:
>>
>> From: Wu Zhangjin<wuzhangjin@xxxxxxxxx>
>>
>> The module space may be the same as the kernel space sometimes(with
>> related kernel config and gcc options), but the current in_module()
>> assume they are always different, so, it should be fixed.
>>
>> As we know, for the limitation of the fixed 32bit long instruction of
>> MIPS, the "jal target" can only jump to an address whose offset from the
>> jal instruction is smaller than 2^28=256M, which means if the address is
>> in kernel space(the kernel image should be always smaller than 256M), no
>> long call is needed to jump from the address to _mcount, and further, if
>> the module use the same space as kernel space, the situation for module
>> will be the same as the kernel. but currently for MIPS, in most of the
>> situations, module has different space(0xc0000000) from the kernel
>> space(0x80000000) and the offset is bigger than 256M, a register is
>> needed to load the address of _mcount and another instruction "jal
>> <register>" is needed to jump from an address to _mcount.
>>
>> The above can be explained as:
>>
>> if (in_kernel_space(addr)) {
>>        jal _mcount;
>> } else {
>>        load the address of _mcount to a register
>>        jalr<register>
>> }
>>
>
> Why can't we just do code examination to determine which case we are
> patching? There is a very limited and fixed set of instruction sequences
> that GCC will emit for _mcount calls.  We can easily check for all of them.
>
> The mcount call sequence unconditionally emits:
>
>        MOVE $1,$31
>
> In the JALR case (for -mlong-call), the instruction immediately before this
> will have the target register be '$3'.
>

Yes, we can, but we care about the performance here:

The current in_kernel_space() only need to check the address itself
but checking the code at (address-4) need an extra memory access .
Because ftrace_make_{nop,call} may be called to cope with a large
number of _mcount calling sites, considering the low frequency of the
MIPS, using a working and light-weight method here is more important,
so ... why not checking the address directly and the point is it works
well.

> I would rather directly check which case we are patching rather than trying
> to infer it from the address.
>
> Is there any case where a 'stock' kernel currently fails?  If not, this
> patch seems like unneeded code churn.

Hmm, not found such a failure yet, but theoretically the failure may
happen for the old implementation(The in_module() in
arch/mips/kernel/ftrace.c) had the assumption of module would always
be compiled with -mlong-calls, but the method(in_kernel_space) used in
this patch discards the assumption and therefore it is more generic.

Thanks,
Wu Zhangjin

>
>
>
>> As we can see, the above explanation covers all of the situations well
>> and reflect the reality, so, we decide to add a new in_kernel_space()
>> instead of the old in_module().
>>
>> Based on core_kernel_text() from kernel/extable.c, in_kernel_space() is
>> easily to be added. Because all of the functions in the init sections is
>> anotated with notrace, so, differ from core_kernel_text(),
>> in_kernel_space() doesn't care about init section.
>>
>> With this new in_kernel_space(), the ftrace_make_{nop,call} can be
>> explained as following.
>>
>> ftrace_make_call()                                      ftrace_make_nop()
>>
>> if (in_kernel_space(addr)) {
>>        jal _mcount;    (jal ftrace_caller)     <-->    nop
>> } else {
>>        load the address of _mcount to a register<-->   b label
>>        jalr<register>
>>        label:
>> }
>>
>> Signed-off-by: Wu Zhangjin<wuzhangjin@xxxxxxxxx>
>> ---
>>  arch/mips/kernel/ftrace.c |   66
>> ++++++++++++++++++++++++--------------------
>>  1 files changed, 36 insertions(+), 30 deletions(-)
>>
>> diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
>> index 65f1949..6ff5a54 100644
>> --- a/arch/mips/kernel/ftrace.c
>> +++ b/arch/mips/kernel/ftrace.c
>> @@ -17,21 +17,7 @@
>>  #include<asm/cacheflush.h>
>>  #include<asm/uasm.h>
>>
>> -/*
>> - * If the Instruction Pointer is in module space (0xc0000000), return
>> true;
>> - * otherwise, it is in kernel space (0x80000000), return false.
>> - *
>> - * FIXME: This will not work when the kernel space and module space are
>> the
>> - * same. If they are the same, we need to modify scripts/recordmcount.pl,
>> - * ftrace_make_nop/call() and the other related parts to ensure the
>> - * enabling/disabling of the calling site to _mcount is right for both
>> kernel
>> - * and module.
>> - */
>> -
>> -static inline int in_module(unsigned long ip)
>> -{
>> -       return ip&  0x40000000;
>> -}
>> +#include<asm-generic/sections.h>
>>
>>  #ifdef CONFIG_DYNAMIC_FTRACE
>>
>> @@ -69,6 +55,20 @@ static inline void ftrace_dyn_arch_init_insns(void)
>>  #endif
>>  }
>>
>> +/*
>> + * Check if the address is in kernel space
>> + *
>> + * Clone core_kernel_text() from kernel/extable.c, but don't call
>> + * init_kernel_text() for Ftrace don't trace functions in init sections.
>> + */
>> +static inline int in_kernel_space(unsigned long ip)
>> +{
>> +       if (ip>= (unsigned long)_stext&&
>> +           ip<= (unsigned long)_etext)
>> +               return 1;
>> +       return 0;
>> +}
>> +
>>  static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
>>  {
>>        int faulted;
>> @@ -91,10 +91,16 @@ int ftrace_make_nop(struct module *mod,
>>        unsigned long ip = rec->ip;
>>
>>        /*
>> -        * We have compiled module with -mlong-calls, but compiled the
>> kernel
>> -        * without it, we need to cope with them respectively.
>> +        * If ip is in kernel space, long call is not needed, otherwise,
>> it is
>> +        * needed.
>>         */
>> -       if (in_module(ip)) {
>> +       if (in_kernel_space(ip)) {
>> +               /*
>> +                * move at, ra
>> +                * jal _mcount          -->  nop
>> +                */
>> +               new = INSN_NOP;
>> +       } else {
>>  #if defined(KBUILD_MCOUNT_RA_ADDRESS)&&  defined(CONFIG_32BIT)
>>                /*
>>                 * lui v1, hi_16bit_of_mcount        -->  b 1f (0x10000005)
>> @@ -117,12 +123,6 @@ int ftrace_make_nop(struct module *mod,
>>                 */
>>                new = INSN_B_1F_4;
>>  #endif
>> -       } else {
>> -               /*
>> -                * move at, ra
>> -                * jal _mcount          -->  nop
>> -                */
>> -               new = INSN_NOP;
>>        }
>>        return ftrace_modify_code(ip, new);
>>  }
>> @@ -132,8 +132,12 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned
>> long addr)
>>        unsigned int new;
>>        unsigned long ip = rec->ip;
>>
>> -       /* ip, module: 0xc0000000, kernel: 0x80000000 */
>> -       new = in_module(ip) ? insn_lui_v1_hi16_mcount :
>> insn_jal_ftrace_caller;
>> +       /*
>> +        * If ip is in kernel space, long call is not needed, otherwise,
>> it is
>> +        * needed.
>> +        */
>> +       new = in_kernel_space(ip) ? insn_jal_ftrace_caller :
>> +               insn_lui_v1_hi16_mcount;
>>
>>        return ftrace_modify_code(ip, new);
>>  }
>> @@ -200,11 +204,13 @@ unsigned long ftrace_get_parent_addr(unsigned long
>> self_addr,
>>        int faulted;
>>
>>        /*
>> -        * For module, move the ip from calling site of mcount after the
>> -        * instruction "lui v1, hi_16bit_of_mcount"(offset is 24), but for
>> -        * kernel, move after the instruction "move ra, at"(offset is 16)
>> +        * If self_addr is in kernel space, long call is not needed, only
>> need
>> +        * to move ip after the instruction "move ra, at"(offset is 16),
>> +        * otherwise, long call is needed, need to move ip from calling
>> site of
>> +        * mcount after the instruction "lui v1,
>> hi_16bit_of_mcount"(offset is
>> +        * 24).
>>         */
>> -       ip = self_addr - (in_module(self_addr) ? 24 : 16);
>> +       ip = self_addr - (in_kernel_space(self_addr) ? 16 : 24);
>>
>>        /*
>>         * search the text until finding the non-store instruction or
>> "s{d,w}
>
>



[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux