diff mbox series

[RFC,v2,2/5] powerpc/ftrace: Remove pointer to struct module from dyn_arch_ftrace

Message ID 50b038f167f3fb94ed6074e029b6794bbe6e83a2.1718008093.git.naveen@kernel.org (mailing list archive)
State Superseded
Headers show
Series powerpc/ftrace: Move ftrace sequence out of line | expand

Commit Message

Naveen N Rao June 10, 2024, 8:38 a.m. UTC
Pointer to struct module is only relevant for ftrace records belonging
to kernel modules. Having this field in dyn_arch_ftrace wastes memory
for all ftrace records belonging to the kernel. Remove the same in
favour of looking up the module from the ftrace record address, similar
to other architectures.

Signed-off-by: Naveen N Rao <naveen@kernel.org>
---
 arch/powerpc/include/asm/ftrace.h        |  1 -
 arch/powerpc/kernel/trace/ftrace.c       | 47 ++++++++++-----
 arch/powerpc/kernel/trace/ftrace_64_pg.c | 73 +++++++++++-------------
 3 files changed, 64 insertions(+), 57 deletions(-)

Comments

Steven Rostedt June 10, 2024, 8:03 p.m. UTC | #1
On Mon, 10 Jun 2024 14:08:15 +0530
Naveen N Rao <naveen@kernel.org> wrote:

> Pointer to struct module is only relevant for ftrace records belonging
> to kernel modules. Having this field in dyn_arch_ftrace wastes memory
> for all ftrace records belonging to the kernel. Remove the same in
> favour of looking up the module from the ftrace record address, similar
> to other architectures.
> 
> Signed-off-by: Naveen N Rao <naveen@kernel.org>
> ---
>  arch/powerpc/include/asm/ftrace.h        |  1 -
>  arch/powerpc/kernel/trace/ftrace.c       | 47 ++++++++++-----
>  arch/powerpc/kernel/trace/ftrace_64_pg.c | 73 +++++++++++-------------
>  3 files changed, 64 insertions(+), 57 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h
> index 107fc5a48456..201f9d15430a 100644
> --- a/arch/powerpc/include/asm/ftrace.h
> +++ b/arch/powerpc/include/asm/ftrace.h
> @@ -26,7 +26,6 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip,
>  struct module;
>  struct dyn_ftrace;
>  struct dyn_arch_ftrace {
> -	struct module *mod;
>  };

Nice. I always hated that extra field.


>  
>  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
> diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c
> index d8d6b4fd9a14..041be965485e 100644
> --- a/arch/powerpc/kernel/trace/ftrace.c
> +++ b/arch/powerpc/kernel/trace/ftrace.c
> @@ -106,20 +106,36 @@ static unsigned long find_ftrace_tramp(unsigned long ip)
>  	return 0;
>  }
>  
> +static struct module *ftrace_lookup_module(struct dyn_ftrace *rec)
> +{
> +	struct module *mod = NULL;
> +
> +#ifdef CONFIG_MODULES
> +	/*
> +	 * NOTE: __module_text_address() must be called with preemption
> +	 * disabled, but we can rely on ftrace_lock to ensure that 'mod'
> +	 * retains its validity throughout the remainder of this code.
> +	*/
> +	preempt_disable();
> +	mod = __module_text_address(rec->ip);
> +	preempt_enable();
> +
> +	if (!mod)
> +		pr_err("No module loaded at addr=%lx\n", rec->ip);
> +#endif
> +
> +	return mod;
> +}

It may look nicer to have:

#ifdef CONFIG_MODULES
static struct module *ftrace_lookup_module(struct dyn_ftrace *rec)
{
	struct module *mod = NULL;

	/*
	 * NOTE: __module_text_address() must be called with preemption
	 * disabled, but we can rely on ftrace_lock to ensure that 'mod'
	 * retains its validity throughout the remainder of this code.
	*/
	preempt_disable();
	mod = __module_text_address(rec->ip);
	preempt_enable();

	if (!mod)
		pr_err("No module loaded at addr=%lx\n", rec->ip);

	return mod;
}
#else
static inline struct module *ftrace_lookup_module(struct dyn_ftrace *rec)
{
	return NULL;
}
#endif

> +
>  static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_inst_t *call_inst)
>  {
>  	unsigned long ip = rec->ip;
>  	unsigned long stub;
> +	struct module *mod;
>  
>  	if (is_offset_in_branch_range(addr - ip)) {
>  		/* Within range */
>  		stub = addr;
> -#ifdef CONFIG_MODULES
> -	} else if (rec->arch.mod) {
> -		/* Module code would be going to one of the module stubs */
> -		stub = (addr == (unsigned long)ftrace_caller ? rec->arch.mod->arch.tramp :
> -							       rec->arch.mod->arch.tramp_regs);
> -#endif
>  	} else if (core_kernel_text(ip)) {
>  		/* We would be branching to one of our ftrace stubs */
>  		stub = find_ftrace_tramp(ip);
> @@ -128,7 +144,16 @@ static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_
>  			return -EINVAL;
>  		}
>  	} else {
> -		return -EINVAL;
> +		mod = ftrace_lookup_module(rec);
> +		if (mod) {
> +#ifdef CONFIG_MODULES
> +			/* Module code would be going to one of the module stubs */
> +			stub = (addr == (unsigned long)ftrace_caller ? mod->arch.tramp :
> +								       mod->arch.tramp_regs);
> +#endif

You have CONFIG_MODULES here and in ftrace_lookup_module() above, which
would always return NULL. Could you combine the above to be done in
ftrace_lookup_module() so that there's no #ifdef CONFIG_MODULES here?


> +		} else {
> +			return -EINVAL;
> +		}
>  	}
>  
>  	*call_inst = ftrace_create_branch_inst(ip, stub, 1);
> @@ -256,14 +281,6 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
>  	if (ret)
>  		return ret;
>  
> -	if (!core_kernel_text(ip)) {
> -		if (!mod) {
> -			pr_err("0x%lx: No module provided for non-kernel address\n", ip);
> -			return -EFAULT;
> -		}
> -		rec->arch.mod = mod;
> -	}
> -
>  	/* Nop-out the ftrace location */
>  	new = ppc_inst(PPC_RAW_NOP());
>  	addr = MCOUNT_ADDR;

-- Steve
Naveen N Rao June 11, 2024, 2:45 p.m. UTC | #2
On Mon, Jun 10, 2024 at 04:03:56PM GMT, Steven Rostedt wrote:
> On Mon, 10 Jun 2024 14:08:15 +0530
> Naveen N Rao <naveen@kernel.org> wrote:
> 
> > Pointer to struct module is only relevant for ftrace records belonging
> > to kernel modules. Having this field in dyn_arch_ftrace wastes memory
> > for all ftrace records belonging to the kernel. Remove the same in
> > favour of looking up the module from the ftrace record address, similar
> > to other architectures.
> > 
> > Signed-off-by: Naveen N Rao <naveen@kernel.org>
> > ---
> >  arch/powerpc/include/asm/ftrace.h        |  1 -
> >  arch/powerpc/kernel/trace/ftrace.c       | 47 ++++++++++-----
> >  arch/powerpc/kernel/trace/ftrace_64_pg.c | 73 +++++++++++-------------
> >  3 files changed, 64 insertions(+), 57 deletions(-)
> > 
> > diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h
> > index 107fc5a48456..201f9d15430a 100644
> > --- a/arch/powerpc/include/asm/ftrace.h
> > +++ b/arch/powerpc/include/asm/ftrace.h
> > @@ -26,7 +26,6 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip,
> >  struct module;
> >  struct dyn_ftrace;
> >  struct dyn_arch_ftrace {
> > -	struct module *mod;
> >  };
> 
> Nice. I always hated that extra field.

It was your complaint a while back that prompted this change :)

Though I introduce a different pointer here in the next patch. /me 
ducks.

> 
> 
> >  
> >  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
> > diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c
> > index d8d6b4fd9a14..041be965485e 100644
> > --- a/arch/powerpc/kernel/trace/ftrace.c
> > +++ b/arch/powerpc/kernel/trace/ftrace.c
> > @@ -106,20 +106,36 @@ static unsigned long find_ftrace_tramp(unsigned long ip)
> >  	return 0;
> >  }
> >  
> > +static struct module *ftrace_lookup_module(struct dyn_ftrace *rec)
> > +{
> > +	struct module *mod = NULL;
> > +
> > +#ifdef CONFIG_MODULES
> > +	/*
> > +	 * NOTE: __module_text_address() must be called with preemption
> > +	 * disabled, but we can rely on ftrace_lock to ensure that 'mod'
> > +	 * retains its validity throughout the remainder of this code.
> > +	*/
> > +	preempt_disable();
> > +	mod = __module_text_address(rec->ip);
> > +	preempt_enable();
> > +
> > +	if (!mod)
> > +		pr_err("No module loaded at addr=%lx\n", rec->ip);
> > +#endif
> > +
> > +	return mod;
> > +}
> 
> It may look nicer to have:
> 
> #ifdef CONFIG_MODULES
> static struct module *ftrace_lookup_module(struct dyn_ftrace *rec)
> {
> 	struct module *mod = NULL;
> 
> 	/*
> 	 * NOTE: __module_text_address() must be called with preemption
> 	 * disabled, but we can rely on ftrace_lock to ensure that 'mod'
> 	 * retains its validity throughout the remainder of this code.
> 	*/
> 	preempt_disable();
> 	mod = __module_text_address(rec->ip);
> 	preempt_enable();
> 
> 	if (!mod)
> 		pr_err("No module loaded at addr=%lx\n", rec->ip);
> 
> 	return mod;
> }
> #else
> static inline struct module *ftrace_lookup_module(struct dyn_ftrace *rec)
> {
> 	return NULL;
> }
> #endif

I wrote this, and then I thought it will be simpler to do the version I 
posted. I will move back to this since it looks to be the preferred way.

> 
> > +
> >  static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_inst_t *call_inst)
> >  {
> >  	unsigned long ip = rec->ip;
> >  	unsigned long stub;
> > +	struct module *mod;
> >  
> >  	if (is_offset_in_branch_range(addr - ip)) {
> >  		/* Within range */
> >  		stub = addr;
> > -#ifdef CONFIG_MODULES
> > -	} else if (rec->arch.mod) {
> > -		/* Module code would be going to one of the module stubs */
> > -		stub = (addr == (unsigned long)ftrace_caller ? rec->arch.mod->arch.tramp :
> > -							       rec->arch.mod->arch.tramp_regs);
> > -#endif
> >  	} else if (core_kernel_text(ip)) {
> >  		/* We would be branching to one of our ftrace stubs */
> >  		stub = find_ftrace_tramp(ip);
> > @@ -128,7 +144,16 @@ static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_
> >  			return -EINVAL;
> >  		}
> >  	} else {
> > -		return -EINVAL;
> > +		mod = ftrace_lookup_module(rec);
> > +		if (mod) {
> > +#ifdef CONFIG_MODULES
> > +			/* Module code would be going to one of the module stubs */
> > +			stub = (addr == (unsigned long)ftrace_caller ? mod->arch.tramp :
> > +								       mod->arch.tramp_regs);
> > +#endif
> 
> You have CONFIG_MODULES here and in ftrace_lookup_module() above, which
> would always return NULL. Could you combine the above to be done in
> ftrace_lookup_module() so that there's no #ifdef CONFIG_MODULES here?

Yes, indeed. That will look cleaner.


Thanks,
Naveen
diff mbox series

Patch

diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h
index 107fc5a48456..201f9d15430a 100644
--- a/arch/powerpc/include/asm/ftrace.h
+++ b/arch/powerpc/include/asm/ftrace.h
@@ -26,7 +26,6 @@  unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip,
 struct module;
 struct dyn_ftrace;
 struct dyn_arch_ftrace {
-	struct module *mod;
 };
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c
index d8d6b4fd9a14..041be965485e 100644
--- a/arch/powerpc/kernel/trace/ftrace.c
+++ b/arch/powerpc/kernel/trace/ftrace.c
@@ -106,20 +106,36 @@  static unsigned long find_ftrace_tramp(unsigned long ip)
 	return 0;
 }
 
+static struct module *ftrace_lookup_module(struct dyn_ftrace *rec)
+{
+	struct module *mod = NULL;
+
+#ifdef CONFIG_MODULES
+	/*
+	 * NOTE: __module_text_address() must be called with preemption
+	 * disabled, but we can rely on ftrace_lock to ensure that 'mod'
+	 * retains its validity throughout the remainder of this code.
+	*/
+	preempt_disable();
+	mod = __module_text_address(rec->ip);
+	preempt_enable();
+
+	if (!mod)
+		pr_err("No module loaded at addr=%lx\n", rec->ip);
+#endif
+
+	return mod;
+}
+
 static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_inst_t *call_inst)
 {
 	unsigned long ip = rec->ip;
 	unsigned long stub;
+	struct module *mod;
 
 	if (is_offset_in_branch_range(addr - ip)) {
 		/* Within range */
 		stub = addr;
-#ifdef CONFIG_MODULES
-	} else if (rec->arch.mod) {
-		/* Module code would be going to one of the module stubs */
-		stub = (addr == (unsigned long)ftrace_caller ? rec->arch.mod->arch.tramp :
-							       rec->arch.mod->arch.tramp_regs);
-#endif
 	} else if (core_kernel_text(ip)) {
 		/* We would be branching to one of our ftrace stubs */
 		stub = find_ftrace_tramp(ip);
@@ -128,7 +144,16 @@  static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_
 			return -EINVAL;
 		}
 	} else {
-		return -EINVAL;
+		mod = ftrace_lookup_module(rec);
+		if (mod) {
+#ifdef CONFIG_MODULES
+			/* Module code would be going to one of the module stubs */
+			stub = (addr == (unsigned long)ftrace_caller ? mod->arch.tramp :
+								       mod->arch.tramp_regs);
+#endif
+		} else {
+			return -EINVAL;
+		}
 	}
 
 	*call_inst = ftrace_create_branch_inst(ip, stub, 1);
@@ -256,14 +281,6 @@  int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
 	if (ret)
 		return ret;
 
-	if (!core_kernel_text(ip)) {
-		if (!mod) {
-			pr_err("0x%lx: No module provided for non-kernel address\n", ip);
-			return -EFAULT;
-		}
-		rec->arch.mod = mod;
-	}
-
 	/* Nop-out the ftrace location */
 	new = ppc_inst(PPC_RAW_NOP());
 	addr = MCOUNT_ADDR;
diff --git a/arch/powerpc/kernel/trace/ftrace_64_pg.c b/arch/powerpc/kernel/trace/ftrace_64_pg.c
index 12fab1803bcf..45bd8dcf9886 100644
--- a/arch/powerpc/kernel/trace/ftrace_64_pg.c
+++ b/arch/powerpc/kernel/trace/ftrace_64_pg.c
@@ -116,6 +116,24 @@  static unsigned long find_bl_target(unsigned long ip, ppc_inst_t op)
 }
 
 #ifdef CONFIG_MODULES
+static struct module *ftrace_lookup_module(struct dyn_ftrace *rec)
+{
+	struct module *mod;
+	/*
+	 * NOTE: __module_text_address() must be called with preemption
+	 * disabled, but we can rely on ftrace_lock to ensure that 'mod'
+	 * retains its validity throughout the remainder of this code.
+	*/
+	preempt_disable();
+	mod = __module_text_address(rec->ip);
+	preempt_enable();
+
+	if (!mod)
+		pr_err("No module loaded at addr=%lx\n", rec->ip);
+
+	return mod;
+}
+
 static int
 __ftrace_make_nop(struct module *mod,
 		  struct dyn_ftrace *rec, unsigned long addr)
@@ -124,6 +142,12 @@  __ftrace_make_nop(struct module *mod,
 	unsigned long ip = rec->ip;
 	ppc_inst_t op, pop;
 
+	if (!mod) {
+		mod = ftrace_lookup_module(rec);
+		if (!mod)
+			return -EINVAL;
+	}
+
 	/* read where this goes */
 	if (copy_inst_from_kernel_nofault(&op, (void *)ip)) {
 		pr_err("Fetching opcode failed.\n");
@@ -366,27 +390,6 @@  int ftrace_make_nop(struct module *mod,
 		return -EINVAL;
 	}
 
-	/*
-	 * Out of range jumps are called from modules.
-	 * We should either already have a pointer to the module
-	 * or it has been passed in.
-	 */
-	if (!rec->arch.mod) {
-		if (!mod) {
-			pr_err("No module loaded addr=%lx\n", addr);
-			return -EFAULT;
-		}
-		rec->arch.mod = mod;
-	} else if (mod) {
-		if (mod != rec->arch.mod) {
-			pr_err("Record mod %p not equal to passed in mod %p\n",
-			       rec->arch.mod, mod);
-			return -EINVAL;
-		}
-		/* nothing to do if mod == rec->arch.mod */
-	} else
-		mod = rec->arch.mod;
-
 	return __ftrace_make_nop(mod, rec, addr);
 }
 
@@ -411,7 +414,10 @@  __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 	ppc_inst_t op[2];
 	void *ip = (void *)rec->ip;
 	unsigned long entry, ptr, tramp;
-	struct module *mod = rec->arch.mod;
+	struct module *mod = ftrace_lookup_module(rec);
+
+	if (!mod)
+		return -EINVAL;
 
 	/* read where this goes */
 	if (copy_inst_from_kernel_nofault(op, ip))
@@ -533,16 +539,6 @@  int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 		return -EINVAL;
 	}
 
-	/*
-	 * Out of range jumps are called from modules.
-	 * Being that we are converting from nop, it had better
-	 * already have a module defined.
-	 */
-	if (!rec->arch.mod) {
-		pr_err("No module loaded\n");
-		return -EINVAL;
-	}
-
 	return __ftrace_make_call(rec, addr);
 }
 
@@ -555,7 +551,10 @@  __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
 	ppc_inst_t op;
 	unsigned long ip = rec->ip;
 	unsigned long entry, ptr, tramp;
-	struct module *mod = rec->arch.mod;
+	struct module *mod = ftrace_lookup_module(rec);
+
+	if (!mod)
+		return -EINVAL;
 
 	/* If we never set up ftrace trampolines, then bail */
 	if (!mod->arch.tramp || !mod->arch.tramp_regs) {
@@ -668,14 +667,6 @@  int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
 		return -EINVAL;
 	}
 
-	/*
-	 * Out of range jumps are called from modules.
-	 */
-	if (!rec->arch.mod) {
-		pr_err("No module loaded\n");
-		return -EINVAL;
-	}
-
 	return __ftrace_modify_call(rec, old_addr, addr);
 }
 #endif