[PATCH v3] RISC-V: Don't check text_mutex during stop_machine

Conor Dooley conor at kernel.org
Sat Feb 25 05:45:13 PST 2023



On 25 February 2023 01:50:14 GMT, Changbin Du <changbin.du at huawei.com> wrote:
>On Fri, Feb 24, 2023 at 01:46:38PM +0000, Conor Dooley wrote:
>> On Fri, Feb 24, 2023 at 08:58:57PM +0800, Changbin Du wrote:
>> > On Fri, Feb 24, 2023 at 11:07:42AM +0000, Conor Dooley wrote:
>> > > > > -	lockdep_assert_held(&text_mutex);
>> > > > > +	if (!riscv_ftrace_in_stop_machine)
>> > > > > +		lockdep_assert_held(&text_mutex);
>> > > > >  
>> > > > >  	if (across_pages)
>> > > > >  		patch_map(addr + len, FIX_TEXT_POKE1);
>> > > > This misses this function.
>> > > > 
>> > > > int patch_text(void *addr, u32 insn)
>> > > 
>> > > So, with a corresponding rename to the symbol, does the following look
>> > > okay to you?
>> > > 
>> > > diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c
>> > > index f21592d20306..433b454e693f 100644
>> > > --- a/arch/riscv/kernel/probes/kprobes.c
>> > > +++ b/arch/riscv/kernel/probes/kprobes.c
>> > > @@ -27,9 +27,15 @@ static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
>> > >  
>> > >  	p->ainsn.api.restore = (unsigned long)p->addr + offset;
>> > >  
>> > > +	/*
>> > > +	 * kprobes takes text_mutex, but patch_text() calls stop_machine and
>> > > +	 * lockdep gets confused by the context in which the lock is taken.
>> > > +	 */
>> > > +	riscv_patch_in_stop_machine = true;
>> > >  	patch_text(p->ainsn.api.insn, p->opcode);
>> > >  	patch_text((void *)((unsigned long)(p->ainsn.api.insn) + offset),
>> > >  		   __BUG_INSN_32);
>> > > +	riscv_patch_in_stop_machine = false;
>> > >  }
>> > hmm, why not just put 'riscv_patch_in_stop_machine' into patch_text()? Then you
>> > just need to modify that function.
>> 
>> Right, I intentionally didn't do that as `riscv_patch_in_stop_machine`
>> skips the lockdep check, which we only want to do for codepaths we know
>> the lock will be held for.
>> I didn't want to put it in patch_text() so if users of patch_text() that
>> do not take the lock are added, they will be caught.
>> 
>Understood your concern. Then how abount below instead of discrete changes?

Seems fair enough to me, I'll respin Monday - had some hardware fail so out of action right now.

Thanks,
Conor.

>
>int patch_text(void *addr, u32 insn)
> {
>+       int ret;
>        struct patch_insn patch = {
>                .addr = addr,
>                .insn = insn,
>                .cpu_count = ATOMIC_INIT(0),
>        };
>
>-       return stop_machine_cpuslocked(patch_text_cb,
>+       lockdep_assert_held(&text_mutex);
>+       riscv_patch_in_stop_machine = true
>+       ret = stop_machine_cpuslocked(patch_text_cb,
>                                       &patch, cpu_online_mask);
>+       riscv_patch_in_stop_machine = false;
>+       return ret;
> }
>
>> I'm probably just erring on the paranoid/conservative side of things!



More information about the linux-riscv mailing list