linux-trace-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] tracing/kprobes: Cleanup with guard and __free
@ 2025-01-05 12:47 Masami Hiramatsu (Google)
  2025-01-05 12:47 ` [PATCH v2 1/6] tracing/kprobes: Fix to free objects when failed to copy a symbol Masami Hiramatsu (Google)
                   ` (5 more replies)
  0 siblings, 6 replies; 14+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-05 12:47 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

Hi,

Here is the 2nd version of the series to fix and cleanup probe events in
ftrace with __free().
Fix [2/6] according to Oleg's comment to check the argument and add
cleanup.h, update [3/6] to apply it cleanly on probes/for-next, and fix 
[5/6] to assign NULL to 'tk' instead of using no_free_ptr() after
registering it successfully to avoid __must_check_fn warning.

Thanks,

---

Masami Hiramatsu (Google) (6):
      tracing/kprobes: Fix to free objects when failed to copy a symbol
      Provide __free(argv) for argv_split() users
      tracing: Use __free() for argv in dynevent
      tracing: Use __free() in trace_probe for cleanup
      tracing: Use __free() for kprobe events to cleanup
      tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos


 include/linux/string.h        |    3 +
 kernel/trace/trace_dynevent.c |   23 +++----
 kernel/trace/trace_kprobe.c   |  127 ++++++++++++++++++++---------------------
 kernel/trace/trace_probe.c    |   52 ++++++-----------
 4 files changed, 91 insertions(+), 114 deletions(-)

--
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/6] tracing/kprobes: Fix to free objects when failed to copy a symbol
  2025-01-05 12:47 [PATCH v2 0/6] tracing/kprobes: Cleanup with guard and __free Masami Hiramatsu (Google)
@ 2025-01-05 12:47 ` Masami Hiramatsu (Google)
  2025-01-05 12:47 ` [PATCH v2 2/6] Provide __free(argv) for argv_split() users Masami Hiramatsu (Google)
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-05 12:47 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

In __trace_kprobe_create(), if something fails it must goto error block
to free objects. But when strdup() a symbol, it returns without that.
Fix it to goto the error block to free objects correctly.

Fixes: 6212dd29683e ("tracing/kprobes: Use dyn_event framework for kprobe events")
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index bae26eb14449..4c3e316454a0 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -935,8 +935,10 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		}
 		/* a symbol specified */
 		symbol = kstrdup(argv[1], GFP_KERNEL);
-		if (!symbol)
-			return -ENOMEM;
+		if (!symbol) {
+			ret = -ENOMEM;
+			goto error;
+		}
 
 		tmp = strchr(symbol, '%');
 		if (tmp) {


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/6] Provide __free(argv) for argv_split() users
  2025-01-05 12:47 [PATCH v2 0/6] tracing/kprobes: Cleanup with guard and __free Masami Hiramatsu (Google)
  2025-01-05 12:47 ` [PATCH v2 1/6] tracing/kprobes: Fix to free objects when failed to copy a symbol Masami Hiramatsu (Google)
@ 2025-01-05 12:47 ` Masami Hiramatsu (Google)
  2025-01-05 14:14   ` DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users) Oleg Nesterov
  2025-01-05 12:48 ` [PATCH v2 3/6] tracing: Use __free() for argv in dynevent Masami Hiramatsu (Google)
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 14+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-05 12:47 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Provide __free(argv) macro for argv_split() users so that they can
avoid gotos.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v2:
  - Fix to call argv_free() only if the argument is !IS_ERR_OR_NULL().
  - Add including cleanup.h.
---
 include/linux/string.h |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/string.h b/include/linux/string.h
index 493ac4862c77..07f2a90d5d9c 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -4,6 +4,7 @@
 
 #include <linux/args.h>
 #include <linux/array_size.h>
+#include <linux/cleanup.h>	/* for DEFINE_FREE() */
 #include <linux/compiler.h>	/* for inline */
 #include <linux/types.h>	/* for size_t */
 #include <linux/stddef.h>	/* for NULL */
@@ -312,6 +313,8 @@ extern void *kmemdup_array(const void *src, size_t count, size_t element_size, g
 extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
 
+DEFINE_FREE(argv, char **, if (!IS_ERR_OR_NULL(_T)) argv_free(_T))
+
 /* lib/cmdline.c */
 extern int get_option(char **str, int *pint);
 extern char *get_options(const char *str, int nints, int *ints);


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/6] tracing: Use __free() for argv in dynevent
  2025-01-05 12:47 [PATCH v2 0/6] tracing/kprobes: Cleanup with guard and __free Masami Hiramatsu (Google)
  2025-01-05 12:47 ` [PATCH v2 1/6] tracing/kprobes: Fix to free objects when failed to copy a symbol Masami Hiramatsu (Google)
  2025-01-05 12:47 ` [PATCH v2 2/6] Provide __free(argv) for argv_split() users Masami Hiramatsu (Google)
@ 2025-01-05 12:48 ` Masami Hiramatsu (Google)
  2025-01-05 12:48 ` [PATCH v2 4/6] tracing: Use __free() in trace_probe for cleanup Masami Hiramatsu (Google)
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-05 12:48 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Use __free() for the args allocated by argv_split() in dynevent.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v2:
  - Rebased on probes/for-next, which reverts previous dynevent guard patch.
---
 kernel/trace/trace_dynevent.c |   23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
index 4376887e0d8a..630d9695b2df 100644
--- a/kernel/trace/trace_dynevent.c
+++ b/kernel/trace/trace_dynevent.c
@@ -74,24 +74,20 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
 	struct dyn_event *pos, *n;
 	char *system = NULL, *event, *p;
 	int argc, ret = -ENOENT;
-	char **argv;
+	char **argv __free(argv) = NULL;
 
 	argv = argv_split(GFP_KERNEL, raw_command, &argc);
 	if (!argv)
 		return -ENOMEM;
 
 	if (argv[0][0] == '-') {
-		if (argv[0][1] != ':') {
-			ret = -EINVAL;
-			goto out;
-		}
+		if (argv[0][1] != ':')
+			return -EINVAL;
 		event = &argv[0][2];
 	} else {
 		event = strchr(argv[0], ':');
-		if (!event) {
-			ret = -EINVAL;
-			goto out;
-		}
+		if (!event)
+			return -EINVAL;
 		event++;
 	}
 
@@ -101,10 +97,8 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
 		event = p + 1;
 		*p = '\0';
 	}
-	if (!system && event[0] == '\0') {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (!system && event[0] == '\0')
+		return -EINVAL;
 
 	mutex_lock(&event_mutex);
 	for_each_dyn_event_safe(pos, n) {
@@ -120,8 +114,7 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
 	}
 	tracing_reset_all_online_cpus();
 	mutex_unlock(&event_mutex);
-out:
-	argv_free(argv);
+
 	return ret;
 }
 


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 4/6] tracing: Use __free() in trace_probe for cleanup
  2025-01-05 12:47 [PATCH v2 0/6] tracing/kprobes: Cleanup with guard and __free Masami Hiramatsu (Google)
                   ` (2 preceding siblings ...)
  2025-01-05 12:48 ` [PATCH v2 3/6] tracing: Use __free() for argv in dynevent Masami Hiramatsu (Google)
@ 2025-01-05 12:48 ` Masami Hiramatsu (Google)
  2025-01-05 12:48 ` [PATCH v2 5/6] tracing: Use __free() for kprobe events to cleanup Masami Hiramatsu (Google)
  2025-01-05 12:48 ` [PATCH v2 6/6] tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos Masami Hiramatsu (Google)
  5 siblings, 0 replies; 14+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-05 12:48 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Use __free() in trace_probe to cleanup some gotos.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 kernel/trace/trace_probe.c |   52 +++++++++++++++-----------------------------
 1 file changed, 18 insertions(+), 34 deletions(-)

diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 16a5e368e7b7..bf6a7b81ae95 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -1409,7 +1409,7 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
 					   struct traceprobe_parse_context *ctx)
 {
 	struct fetch_insn *code, *tmp = NULL;
-	char *type, *arg;
+	char *type, *arg __free(kfree) = NULL;
 	int ret, len;
 
 	len = strlen(argv);
@@ -1426,22 +1426,16 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
 		return -ENOMEM;
 
 	parg->comm = kstrdup(arg, GFP_KERNEL);
-	if (!parg->comm) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!parg->comm)
+		return -ENOMEM;
 
 	type = parse_probe_arg_type(arg, parg, ctx);
-	if (IS_ERR(type)) {
-		ret = PTR_ERR(type);
-		goto out;
-	}
+	if (IS_ERR(type))
+		return PTR_ERR(type);
 
 	code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL);
-	if (!code) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!code)
+		return -ENOMEM;
 	code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
 
 	ctx->last_type = NULL;
@@ -1497,8 +1491,6 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
 				kfree(code->data);
 	}
 	kfree(tmp);
-out:
-	kfree(arg);
 
 	return ret;
 }
@@ -1668,7 +1660,7 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
 {
 	const struct btf_param *params = NULL;
 	int i, j, n, used, ret, args_idx = -1;
-	const char **new_argv = NULL;
+	const char **new_argv __free(kfree) = NULL;
 
 	ret = argv_has_var_arg(argc, argv, &args_idx, ctx);
 	if (ret < 0)
@@ -1707,7 +1699,7 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
 				ret = sprint_nth_btf_arg(n, "", buf + used,
 							 bufsize - used, ctx);
 				if (ret < 0)
-					goto error;
+					return ERR_PTR(ret);
 
 				new_argv[j++] = buf + used;
 				used += ret + 1;
@@ -1721,25 +1713,20 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
 			n = simple_strtoul(argv[i] + 4, &type, 10);
 			if (type && !(*type == ':' || *type == '\0')) {
 				trace_probe_log_err(0, BAD_VAR);
-				ret = -ENOENT;
-				goto error;
+				return ERR_PTR(-ENOENT);
 			}
 			/* Note: $argN starts from $arg1 */
 			ret = sprint_nth_btf_arg(n - 1, type, buf + used,
 						 bufsize - used, ctx);
 			if (ret < 0)
-				goto error;
+				return ERR_PTR(ret);
 			new_argv[j++] = buf + used;
 			used += ret + 1;
 		} else
 			new_argv[j++] = argv[i];
 	}
 
-	return new_argv;
-
-error:
-	kfree(new_argv);
-	return ERR_PTR(ret);
+	return_ptr(new_argv);
 }
 
 /* @buf: *buf must be equal to NULL. Caller must to free *buf */
@@ -1747,14 +1734,14 @@ int traceprobe_expand_dentry_args(int argc, const char *argv[], char **buf)
 {
 	int i, used, ret;
 	const int bufsize = MAX_DENTRY_ARGS_LEN;
-	char *tmpbuf = NULL;
+	char *tmpbuf __free(kfree) = NULL;
 
 	if (*buf)
 		return -EINVAL;
 
 	used = 0;
 	for (i = 0; i < argc; i++) {
-		char *tmp;
+		char *tmp __free(kfree) = NULL;
 		char *equal;
 		size_t arg_len;
 
@@ -1769,7 +1756,7 @@ int traceprobe_expand_dentry_args(int argc, const char *argv[], char **buf)
 
 		tmp = kstrdup(argv[i], GFP_KERNEL);
 		if (!tmp)
-			goto nomem;
+			return -ENOMEM;
 
 		equal = strchr(tmp, '=');
 		if (equal)
@@ -1790,18 +1777,15 @@ int traceprobe_expand_dentry_args(int argc, const char *argv[], char **buf)
 				       offsetof(struct file, f_path.dentry),
 				       equal ? equal + 1 : tmp);
 
-		kfree(tmp);
+		kfree(no_free_ptr(tmp));
 		if (ret >= bufsize - used)
-			goto nomem;
+			return -ENOMEM;
 		argv[i] = tmpbuf + used;
 		used += ret + 1;
 	}
 
-	*buf = tmpbuf;
+	*buf = no_free_ptr(tmpbuf);
 	return 0;
-nomem:
-	kfree(tmpbuf);
-	return -ENOMEM;
 }
 
 void traceprobe_finish_parse(struct traceprobe_parse_context *ctx)


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 5/6] tracing: Use __free() for kprobe events to cleanup
  2025-01-05 12:47 [PATCH v2 0/6] tracing/kprobes: Cleanup with guard and __free Masami Hiramatsu (Google)
                   ` (3 preceding siblings ...)
  2025-01-05 12:48 ` [PATCH v2 4/6] tracing: Use __free() in trace_probe for cleanup Masami Hiramatsu (Google)
@ 2025-01-05 12:48 ` Masami Hiramatsu (Google)
  2025-01-06 10:09   ` Masami Hiramatsu
  2025-01-05 12:48 ` [PATCH v2 6/6] tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos Masami Hiramatsu (Google)
  5 siblings, 1 reply; 14+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-05 12:48 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Use __free() in trace_kprobe.c to cleanup code.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v2:
  - Instead of using no_free_ptr(), just assign NULL to the registered pointer.
---
 kernel/trace/trace_kprobe.c |   57 ++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 31 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 4c3e316454a0..e1ae65f57bf9 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -8,6 +8,7 @@
 #define pr_fmt(fmt)	"trace_kprobe: " fmt
 
 #include <linux/bpf-cgroup.h>
+#include <linux/cleanup.h>
 #include <linux/security.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
@@ -257,6 +258,8 @@ static void free_trace_kprobe(struct trace_kprobe *tk)
 	}
 }
 
+DEFINE_FREE(trace_kprobe, struct trace_kprobe *, free_trace_kprobe(_T))
+
 /*
  * Allocate new trace_probe and initialize it (including kprobes).
  */
@@ -268,7 +271,7 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
 					     int maxactive,
 					     int nargs, bool is_return)
 {
-	struct trace_kprobe *tk;
+	struct trace_kprobe *tk __free(trace_kprobe) = NULL;
 	int ret = -ENOMEM;
 
 	tk = kzalloc(struct_size(tk, tp.args, nargs), GFP_KERNEL);
@@ -277,12 +280,12 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
 
 	tk->nhit = alloc_percpu(unsigned long);
 	if (!tk->nhit)
-		goto error;
+		return ERR_PTR(ret);
 
 	if (symbol) {
 		tk->symbol = kstrdup(symbol, GFP_KERNEL);
 		if (!tk->symbol)
-			goto error;
+			return ERR_PTR(ret);
 		tk->rp.kp.symbol_name = tk->symbol;
 		tk->rp.kp.offset = offs;
 	} else
@@ -299,13 +302,10 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
 
 	ret = trace_probe_init(&tk->tp, event, group, false, nargs);
 	if (ret < 0)
-		goto error;
+		return ERR_PTR(ret);
 
 	dyn_event_init(&tk->devent, &trace_kprobe_ops);
-	return tk;
-error:
-	free_trace_kprobe(tk);
-	return ERR_PTR(ret);
+	return_ptr(tk);
 }
 
 static struct trace_kprobe *find_trace_kprobe(const char *event,
@@ -861,11 +861,12 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	 * Type of args:
 	 *  FETCHARG:TYPE : use TYPE instead of unsigned long.
 	 */
-	struct trace_kprobe *tk = NULL;
+	struct trace_kprobe *tk __free(trace_kprobe) = NULL;
 	int i, len, new_argc = 0, ret = 0;
 	bool is_return = false;
-	char *symbol = NULL, *tmp = NULL;
-	const char **new_argv = NULL;
+	char *symbol __free(kfree) = NULL;
+	char *tmp = NULL;
+	const char **new_argv __free(kfree) = NULL;
 	const char *event = NULL, *group = KPROBE_EVENT_SYSTEM;
 	enum probe_print_type ptype;
 	int maxactive = 0;
@@ -874,7 +875,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	char buf[MAX_EVENT_NAME_LEN];
 	char gbuf[MAX_EVENT_NAME_LEN];
 	char abuf[MAX_BTF_ARGS_LEN];
-	char *dbuf = NULL;
+	char *dbuf __free(kfree) = NULL;
 	struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };
 
 	switch (argv[0][0]) {
@@ -931,7 +932,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		/* Check whether uprobe event specified */
 		if (strchr(argv[1], '/') && strchr(argv[1], ':')) {
 			ret = -ECANCELED;
-			goto error;
+			goto out;
 		}
 		/* a symbol specified */
 		symbol = kstrdup(argv[1], GFP_KERNEL);
@@ -1035,7 +1036,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		ctx.offset = 0;
 		ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx);
 		if (ret)
-			goto error;	/* This can be -ENOMEM */
+			goto out;	/* This can be -ENOMEM */
 	}
 	/* entry handler for kretprobe */
 	if (is_return && tk->tp.entry_arg) {
@@ -1046,7 +1047,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	ptype = is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
 	ret = traceprobe_set_print_fmt(&tk->tp, ptype);
 	if (ret < 0)
-		goto error;
+		goto out;
 
 	ret = register_trace_kprobe(tk);
 	if (ret) {
@@ -1057,21 +1058,20 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 			trace_probe_log_err(0, BAD_PROBE_ADDR);
 		else if (ret != -ENOMEM && ret != -EEXIST)
 			trace_probe_log_err(0, FAIL_REG_PROBE);
-		goto error;
-	}
+	} else
+		/*
+		 * Here, 'tk' has been registered to the list successfully,
+		 * so we don't need to free it.
+		 */
+		tk = NULL;
 
 out:
 	traceprobe_finish_parse(&ctx);
 	trace_probe_log_clear();
-	kfree(new_argv);
-	kfree(symbol);
-	kfree(dbuf);
 	return ret;
 
 parse_error:
 	ret = -EINVAL;
-error:
-	free_trace_kprobe(tk);
 	goto out;
 }
 
@@ -1893,7 +1893,7 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 			  bool is_return)
 {
 	enum probe_print_type ptype;
-	struct trace_kprobe *tk;
+	struct trace_kprobe *tk __free(trace_kprobe) = NULL;
 	int ret;
 	char *event;
 
@@ -1924,19 +1924,14 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 
 	ptype = trace_kprobe_is_return(tk) ?
 		PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
-	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0) {
-		ret = -ENOMEM;
-		goto error;
-	}
+	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0)
+		return ERR_PTR(-ENOMEM);
 
 	ret = __register_trace_kprobe(tk);
 	if (ret < 0)
-		goto error;
+		return ERR_PTR(ret);
 
 	return trace_probe_event_call(&tk->tp);
-error:
-	free_trace_kprobe(tk);
-	return ERR_PTR(ret);
 }
 
 void destroy_local_trace_kprobe(struct trace_event_call *event_call)


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 6/6] tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos
  2025-01-05 12:47 [PATCH v2 0/6] tracing/kprobes: Cleanup with guard and __free Masami Hiramatsu (Google)
                   ` (4 preceding siblings ...)
  2025-01-05 12:48 ` [PATCH v2 5/6] tracing: Use __free() for kprobe events to cleanup Masami Hiramatsu (Google)
@ 2025-01-05 12:48 ` Masami Hiramatsu (Google)
  5 siblings, 0 replies; 14+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-05 12:48 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Simplify __trace_kprobe_create() by removing gotos.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   82 ++++++++++++++++++++++---------------------
 1 file changed, 41 insertions(+), 41 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index e1ae65f57bf9..b5c59c0f83cb 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -835,7 +835,8 @@ static int validate_probe_symbol(char *symbol)
 static int trace_kprobe_entry_handler(struct kretprobe_instance *ri,
 				      struct pt_regs *regs);
 
-static int __trace_kprobe_create(int argc, const char *argv[])
+static int ___trace_kprobe_create(int argc, const char *argv[],
+				  struct traceprobe_parse_context *ctx)
 {
 	/*
 	 * Argument syntax:
@@ -876,7 +877,6 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	char gbuf[MAX_EVENT_NAME_LEN];
 	char abuf[MAX_BTF_ARGS_LEN];
 	char *dbuf __free(kfree) = NULL;
-	struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };
 
 	switch (argv[0][0]) {
 	case 'r':
@@ -890,8 +890,6 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	if (argc < 2)
 		return -ECANCELED;
 
-	trace_probe_log_init("trace_kprobe", argc, argv);
-
 	event = strchr(&argv[0][1], ':');
 	if (event)
 		event++;
@@ -899,7 +897,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	if (isdigit(argv[0][1])) {
 		if (!is_return) {
 			trace_probe_log_err(1, BAD_MAXACT_TYPE);
-			goto parse_error;
+			return -EINVAL;
 		}
 		if (event)
 			len = event - &argv[0][1] - 1;
@@ -907,21 +905,21 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 			len = strlen(&argv[0][1]);
 		if (len > MAX_EVENT_NAME_LEN - 1) {
 			trace_probe_log_err(1, BAD_MAXACT);
-			goto parse_error;
+			return -EINVAL;
 		}
 		memcpy(buf, &argv[0][1], len);
 		buf[len] = '\0';
 		ret = kstrtouint(buf, 0, &maxactive);
 		if (ret || !maxactive) {
 			trace_probe_log_err(1, BAD_MAXACT);
-			goto parse_error;
+			return -EINVAL;
 		}
 		/* kretprobes instances are iterated over via a list. The
 		 * maximum should stay reasonable.
 		 */
 		if (maxactive > KRETPROBE_MAXACTIVE_MAX) {
 			trace_probe_log_err(1, MAXACT_TOO_BIG);
-			goto parse_error;
+			return -EINVAL;
 		}
 	}
 
@@ -930,16 +928,13 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) {
 		trace_probe_log_set_index(1);
 		/* Check whether uprobe event specified */
-		if (strchr(argv[1], '/') && strchr(argv[1], ':')) {
-			ret = -ECANCELED;
-			goto out;
-		}
+		if (strchr(argv[1], '/') && strchr(argv[1], ':'))
+			return -ECANCELED;
+
 		/* a symbol specified */
 		symbol = kstrdup(argv[1], GFP_KERNEL);
-		if (!symbol) {
-			ret = -ENOMEM;
-			goto error;
-		}
+		if (!symbol)
+			return -ENOMEM;
 
 		tmp = strchr(symbol, '%');
 		if (tmp) {
@@ -948,7 +943,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 				is_return = true;
 			} else {
 				trace_probe_log_err(tmp - symbol, BAD_ADDR_SUFFIX);
-				goto parse_error;
+				return -EINVAL;
 			}
 		}
 
@@ -956,7 +951,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		ret = traceprobe_split_symbol_offset(symbol, &offset);
 		if (ret || offset < 0 || offset > UINT_MAX) {
 			trace_probe_log_err(0, BAD_PROBE_ADDR);
-			goto parse_error;
+			return -EINVAL;
 		}
 		ret = validate_probe_symbol(symbol);
 		if (ret) {
@@ -964,17 +959,17 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 				trace_probe_log_err(0, NON_UNIQ_SYMBOL);
 			else
 				trace_probe_log_err(0, BAD_PROBE_ADDR);
-			goto parse_error;
+			return -EINVAL;
 		}
 		if (is_return)
-			ctx.flags |= TPARG_FL_RETURN;
+			ctx->flags |= TPARG_FL_RETURN;
 		ret = kprobe_on_func_entry(NULL, symbol, offset);
 		if (ret == 0 && !is_return)
-			ctx.flags |= TPARG_FL_FENTRY;
+			ctx->flags |= TPARG_FL_FENTRY;
 		/* Defer the ENOENT case until register kprobe */
 		if (ret == -EINVAL && is_return) {
 			trace_probe_log_err(0, BAD_RETPROBE);
-			goto parse_error;
+			return -EINVAL;
 		}
 	}
 
@@ -983,7 +978,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		ret = traceprobe_parse_event_name(&event, &group, gbuf,
 						  event - argv[0]);
 		if (ret)
-			goto parse_error;
+			return ret;
 	}
 
 	if (!event) {
@@ -999,26 +994,24 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	}
 
 	argc -= 2; argv += 2;
-	ctx.funcname = symbol;
+	ctx->funcname = symbol;
 	new_argv = traceprobe_expand_meta_args(argc, argv, &new_argc,
-					       abuf, MAX_BTF_ARGS_LEN, &ctx);
+					       abuf, MAX_BTF_ARGS_LEN, ctx);
 	if (IS_ERR(new_argv)) {
 		ret = PTR_ERR(new_argv);
 		new_argv = NULL;
-		goto out;
+		return ret;
 	}
 	if (new_argv) {
 		argc = new_argc;
 		argv = new_argv;
 	}
-	if (argc > MAX_TRACE_ARGS) {
-		ret = -E2BIG;
-		goto out;
-	}
+	if (argc > MAX_TRACE_ARGS)
+		return -E2BIG;
 
 	ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
 	if (ret)
-		goto out;
+		return ret;
 
 	/* setup a probe */
 	tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
@@ -1027,16 +1020,16 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		ret = PTR_ERR(tk);
 		/* This must return -ENOMEM, else there is a bug */
 		WARN_ON_ONCE(ret != -ENOMEM);
-		goto out;	/* We know tk is not allocated */
+		return ret;	/* We know tk is not allocated */
 	}
 
 	/* parse arguments */
 	for (i = 0; i < argc; i++) {
 		trace_probe_log_set_index(i + 2);
-		ctx.offset = 0;
-		ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx);
+		ctx->offset = 0;
+		ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], ctx);
 		if (ret)
-			goto out;	/* This can be -ENOMEM */
+			return ret;	/* This can be -ENOMEM */
 	}
 	/* entry handler for kretprobe */
 	if (is_return && tk->tp.entry_arg) {
@@ -1047,7 +1040,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	ptype = is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
 	ret = traceprobe_set_print_fmt(&tk->tp, ptype);
 	if (ret < 0)
-		goto out;
+		return ret;
 
 	ret = register_trace_kprobe(tk);
 	if (ret) {
@@ -1065,14 +1058,21 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		 */
 		tk = NULL;
 
-out:
+	return ret;
+}
+
+static int __trace_kprobe_create(int argc, const char *argv[])
+{
+	struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };
+	int ret;
+
+	trace_probe_log_init("trace_kprobe", argc, argv);
+
+	ret = ___trace_kprobe_create(argc, argv, &ctx);
+
 	traceprobe_finish_parse(&ctx);
 	trace_probe_log_clear();
 	return ret;
-
-parse_error:
-	ret = -EINVAL;
-	goto out;
 }
 
 static int trace_kprobe_create(const char *raw_command)


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users)
  2025-01-05 12:47 ` [PATCH v2 2/6] Provide __free(argv) for argv_split() users Masami Hiramatsu (Google)
@ 2025-01-05 14:14   ` Oleg Nesterov
  2025-01-06 10:26     ` Peter Zijlstra
  2025-01-06 12:19     ` Masami Hiramatsu
  0 siblings, 2 replies; 14+ messages in thread
From: Oleg Nesterov @ 2025-01-05 14:14 UTC (permalink / raw)
  To: Masami Hiramatsu (Google), Peter Zijlstra
  Cc: Steven Rostedt, Anil S Keshavamurthy, David S . Miller,
	Mathieu Desnoyers, Tzvetomir Stoyanov, Naveen N Rao,
	Josh Poimboeuf, Jason Baron, Ard Biesheuvel, linux-kernel,
	linux-trace-kernel

Masami,

Sorry for abusing this thread. Your patches look fine to me, it is not
that I suggest to change them. I will use your patch as an example for
off-topic discussion.

On 01/05, Masami Hiramatsu (Google) wrote:
>
> +DEFINE_FREE(argv, char **, if (!IS_ERR_OR_NULL(_T)) argv_free(_T))

(IS_ERR looks unneeded but this is cosmetic).

OK, so it can be used as

	void func(void)
	{
		char **argv __free(argv) = argv_split(...);
		do_something(argv);
		return;
	}

And I cry every time when I read the code like this ;)

Because, to understand this code, I need to do the "nontrivial" grep to find
"DEFINE_FREE(argv,".

Perhaps we can establish a simple rule that every DEFINE_FREE() or DEFINE_CLASS()
should add another #define? I mean something like


	DEFINE_FREE(argv, char **, if (!IS_ERR_OR_NULL(_T)) argv_free(_T))
	#define __FREE_ARGV	__free(argv)
	
	void func(void)
	{
		char **argv __FREE_ARGV = argv_split(...);
		do_something(argv);
		return;
	}

This way I can press Ctrl-] and see what the cleanup code actually does.
Can save a second or two. Important when you try to read the code you are
not familiar with.

Same for DEFINE_CLASS. For example,

	int ksys_fchown(unsigned int fd, uid_t user, gid_t group)
	{
		CLASS(fd, f)(fd);

		if (fd_empty(f))
			return -EBADF;

		return vfs_fchown(fd_file(f), user, group);
	}

If you are not familiar with this code, it looks mysterious until you find
DEFINE_CLASS(fd, ...) in include/linux/file.h.

Oleg.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 5/6] tracing: Use __free() for kprobe events to cleanup
  2025-01-05 12:48 ` [PATCH v2 5/6] tracing: Use __free() for kprobe events to cleanup Masami Hiramatsu (Google)
@ 2025-01-06 10:09   ` Masami Hiramatsu
  0 siblings, 0 replies; 14+ messages in thread
From: Masami Hiramatsu @ 2025-01-06 10:09 UTC (permalink / raw)
  To: Masami Hiramatsu (Google)
  Cc: Steven Rostedt, Peter Zijlstra, Anil S Keshavamurthy,
	David S . Miller, Mathieu Desnoyers, Oleg Nesterov,
	Tzvetomir Stoyanov, Naveen N Rao, Josh Poimboeuf, Jason Baron,
	Ard Biesheuvel, linux-kernel, linux-trace-kernel

On Sun,  5 Jan 2025 21:48:29 +0900
"Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:

> From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> 
> Use __free() in trace_kprobe.c to cleanup code.
> 
> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> ---
>  Changes in v2:
>   - Instead of using no_free_ptr(), just assign NULL to the registered pointer.
> ---
>  kernel/trace/trace_kprobe.c |   57 ++++++++++++++++++++-----------------------
>  1 file changed, 26 insertions(+), 31 deletions(-)
> 
> diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
> index 4c3e316454a0..e1ae65f57bf9 100644
> --- a/kernel/trace/trace_kprobe.c
> +++ b/kernel/trace/trace_kprobe.c
> @@ -8,6 +8,7 @@
>  #define pr_fmt(fmt)	"trace_kprobe: " fmt
>  
>  #include <linux/bpf-cgroup.h>
> +#include <linux/cleanup.h>
>  #include <linux/security.h>
>  #include <linux/module.h>
>  #include <linux/uaccess.h>
> @@ -257,6 +258,8 @@ static void free_trace_kprobe(struct trace_kprobe *tk)
>  	}
>  }
>  
> +DEFINE_FREE(trace_kprobe, struct trace_kprobe *, free_trace_kprobe(_T))

Oops, this also need to check !IS_ERR_OR_NULL(_T) since free_trace_kprobe()
only checks the pointer != NULL.

Thanks,

> +
>  /*
>   * Allocate new trace_probe and initialize it (including kprobes).
>   */
> @@ -268,7 +271,7 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
>  					     int maxactive,
>  					     int nargs, bool is_return)
>  {
> -	struct trace_kprobe *tk;
> +	struct trace_kprobe *tk __free(trace_kprobe) = NULL;
>  	int ret = -ENOMEM;
>  
>  	tk = kzalloc(struct_size(tk, tp.args, nargs), GFP_KERNEL);
> @@ -277,12 +280,12 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
>  
>  	tk->nhit = alloc_percpu(unsigned long);
>  	if (!tk->nhit)
> -		goto error;
> +		return ERR_PTR(ret);
>  
>  	if (symbol) {
>  		tk->symbol = kstrdup(symbol, GFP_KERNEL);
>  		if (!tk->symbol)
> -			goto error;
> +			return ERR_PTR(ret);
>  		tk->rp.kp.symbol_name = tk->symbol;
>  		tk->rp.kp.offset = offs;
>  	} else
> @@ -299,13 +302,10 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
>  
>  	ret = trace_probe_init(&tk->tp, event, group, false, nargs);
>  	if (ret < 0)
> -		goto error;
> +		return ERR_PTR(ret);
>  
>  	dyn_event_init(&tk->devent, &trace_kprobe_ops);
> -	return tk;
> -error:
> -	free_trace_kprobe(tk);
> -	return ERR_PTR(ret);
> +	return_ptr(tk);
>  }
>  
>  static struct trace_kprobe *find_trace_kprobe(const char *event,
> @@ -861,11 +861,12 @@ static int __trace_kprobe_create(int argc, const char *argv[])
>  	 * Type of args:
>  	 *  FETCHARG:TYPE : use TYPE instead of unsigned long.
>  	 */
> -	struct trace_kprobe *tk = NULL;
> +	struct trace_kprobe *tk __free(trace_kprobe) = NULL;
>  	int i, len, new_argc = 0, ret = 0;
>  	bool is_return = false;
> -	char *symbol = NULL, *tmp = NULL;
> -	const char **new_argv = NULL;
> +	char *symbol __free(kfree) = NULL;
> +	char *tmp = NULL;
> +	const char **new_argv __free(kfree) = NULL;
>  	const char *event = NULL, *group = KPROBE_EVENT_SYSTEM;
>  	enum probe_print_type ptype;
>  	int maxactive = 0;
> @@ -874,7 +875,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
>  	char buf[MAX_EVENT_NAME_LEN];
>  	char gbuf[MAX_EVENT_NAME_LEN];
>  	char abuf[MAX_BTF_ARGS_LEN];
> -	char *dbuf = NULL;
> +	char *dbuf __free(kfree) = NULL;
>  	struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };
>  
>  	switch (argv[0][0]) {
> @@ -931,7 +932,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
>  		/* Check whether uprobe event specified */
>  		if (strchr(argv[1], '/') && strchr(argv[1], ':')) {
>  			ret = -ECANCELED;
> -			goto error;
> +			goto out;
>  		}
>  		/* a symbol specified */
>  		symbol = kstrdup(argv[1], GFP_KERNEL);
> @@ -1035,7 +1036,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
>  		ctx.offset = 0;
>  		ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx);
>  		if (ret)
> -			goto error;	/* This can be -ENOMEM */
> +			goto out;	/* This can be -ENOMEM */
>  	}
>  	/* entry handler for kretprobe */
>  	if (is_return && tk->tp.entry_arg) {
> @@ -1046,7 +1047,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
>  	ptype = is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
>  	ret = traceprobe_set_print_fmt(&tk->tp, ptype);
>  	if (ret < 0)
> -		goto error;
> +		goto out;
>  
>  	ret = register_trace_kprobe(tk);
>  	if (ret) {
> @@ -1057,21 +1058,20 @@ static int __trace_kprobe_create(int argc, const char *argv[])
>  			trace_probe_log_err(0, BAD_PROBE_ADDR);
>  		else if (ret != -ENOMEM && ret != -EEXIST)
>  			trace_probe_log_err(0, FAIL_REG_PROBE);
> -		goto error;
> -	}
> +	} else
> +		/*
> +		 * Here, 'tk' has been registered to the list successfully,
> +		 * so we don't need to free it.
> +		 */
> +		tk = NULL;
>  
>  out:
>  	traceprobe_finish_parse(&ctx);
>  	trace_probe_log_clear();
> -	kfree(new_argv);
> -	kfree(symbol);
> -	kfree(dbuf);
>  	return ret;
>  
>  parse_error:
>  	ret = -EINVAL;
> -error:
> -	free_trace_kprobe(tk);
>  	goto out;
>  }
>  
> @@ -1893,7 +1893,7 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
>  			  bool is_return)
>  {
>  	enum probe_print_type ptype;
> -	struct trace_kprobe *tk;
> +	struct trace_kprobe *tk __free(trace_kprobe) = NULL;
>  	int ret;
>  	char *event;
>  
> @@ -1924,19 +1924,14 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
>  
>  	ptype = trace_kprobe_is_return(tk) ?
>  		PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
> -	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0) {
> -		ret = -ENOMEM;
> -		goto error;
> -	}
> +	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0)
> +		return ERR_PTR(-ENOMEM);
>  
>  	ret = __register_trace_kprobe(tk);
>  	if (ret < 0)
> -		goto error;
> +		return ERR_PTR(ret);
>  
>  	return trace_probe_event_call(&tk->tp);
> -error:
> -	free_trace_kprobe(tk);
> -	return ERR_PTR(ret);
>  }
>  
>  void destroy_local_trace_kprobe(struct trace_event_call *event_call)
> 


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users)
  2025-01-05 14:14   ` DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users) Oleg Nesterov
@ 2025-01-06 10:26     ` Peter Zijlstra
  2025-01-06 11:18       ` Peter Zijlstra
  2025-01-06 14:44       ` Oleg Nesterov
  2025-01-06 12:19     ` Masami Hiramatsu
  1 sibling, 2 replies; 14+ messages in thread
From: Peter Zijlstra @ 2025-01-06 10:26 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Masami Hiramatsu (Google), Steven Rostedt, Anil S Keshavamurthy,
	David S . Miller, Mathieu Desnoyers, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On Sun, Jan 05, 2025 at 03:14:22PM +0100, Oleg Nesterov wrote:

> OK, so it can be used as
> 
> 	void func(void)
> 	{
> 		char **argv __free(argv) = argv_split(...);
> 		do_something(argv);
> 		return;
> 	}
> 
> And I cry every time when I read the code like this ;)
> 
> Because, to understand this code, I need to do the "nontrivial" grep to find
> "DEFINE_FREE(argv,".
> 
> Perhaps we can establish a simple rule that every DEFINE_FREE() or DEFINE_CLASS()
> should add another #define? I mean something like
> 
> 
> 	DEFINE_FREE(argv, char **, if (!IS_ERR_OR_NULL(_T)) argv_free(_T))
> 	#define __FREE_ARGV	__free(argv)
> 	
> 	void func(void)
> 	{
> 		char **argv __FREE_ARGV = argv_split(...);
> 		do_something(argv);
> 		return;
> 	}
> 
> This way I can press Ctrl-] and see what the cleanup code actually does.
> Can save a second or two. Important when you try to read the code you are
> not familiar with.

Right, so I've been playing with neovim and clangd (lsp), and I'm very
disappointed to have to tell you that that also doesn't get it :-(

One thing we can and should do is something like:

diff --git a/scripts/tags.sh b/scripts/tags.sh
index b21236377998..f01d694abe65 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -212,6 +212,8 @@ regex_c=(
 	'/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_init/'
 	'/^\<DECLARE_IDTENTRY[[:alnum:]_]*([^,)]*,[[:space:]]*\([[:alnum:]_]\+\)/\1/'
 	'/^\<DEFINE_IDTENTRY[[:alnum:]_]*([[:space:]]*\([[:alnum:]_]\+\)/\1/'
+	'/^\<DEFINE_FREE(\([[:alnum:]_]\+\)/cleanup_\1/'
+	'/^\<DEFINE_CLASS(\([[:alnum:]_]\+\)/class_\1/'
 )
 regex_kconfig=(
 	'/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/'

That should be able to let you do: ':ts cleanup_argv'

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users)
  2025-01-06 10:26     ` Peter Zijlstra
@ 2025-01-06 11:18       ` Peter Zijlstra
  2025-01-06 14:44       ` Oleg Nesterov
  1 sibling, 0 replies; 14+ messages in thread
From: Peter Zijlstra @ 2025-01-06 11:18 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Masami Hiramatsu (Google), Steven Rostedt, Anil S Keshavamurthy,
	David S . Miller, Mathieu Desnoyers, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On Mon, Jan 06, 2025 at 11:26:48AM +0100, Peter Zijlstra wrote:
> On Sun, Jan 05, 2025 at 03:14:22PM +0100, Oleg Nesterov wrote:
> 
> > OK, so it can be used as
> > 
> > 	void func(void)
> > 	{
> > 		char **argv __free(argv) = argv_split(...);
> > 		do_something(argv);
> > 		return;
> > 	}
> > 
> > And I cry every time when I read the code like this ;)
> > 
> > Because, to understand this code, I need to do the "nontrivial" grep to find
> > "DEFINE_FREE(argv,".
> > 
> > Perhaps we can establish a simple rule that every DEFINE_FREE() or DEFINE_CLASS()
> > should add another #define? I mean something like
> > 
> > 
> > 	DEFINE_FREE(argv, char **, if (!IS_ERR_OR_NULL(_T)) argv_free(_T))
> > 	#define __FREE_ARGV	__free(argv)
> > 	
> > 	void func(void)
> > 	{
> > 		char **argv __FREE_ARGV = argv_split(...);
> > 		do_something(argv);
> > 		return;
> > 	}
> > 
> > This way I can press Ctrl-] and see what the cleanup code actually does.
> > Can save a second or two. Important when you try to read the code you are
> > not familiar with.
> 
> Right, so I've been playing with neovim and clangd (lsp), and I'm very
> disappointed to have to tell you that that also doesn't get it :-(
> 
> One thing we can and should do is something like:
> 
> diff --git a/scripts/tags.sh b/scripts/tags.sh
> index b21236377998..f01d694abe65 100755
> --- a/scripts/tags.sh
> +++ b/scripts/tags.sh
> @@ -212,6 +212,8 @@ regex_c=(
>  	'/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_init/'
>  	'/^\<DECLARE_IDTENTRY[[:alnum:]_]*([^,)]*,[[:space:]]*\([[:alnum:]_]\+\)/\1/'
>  	'/^\<DEFINE_IDTENTRY[[:alnum:]_]*([[:space:]]*\([[:alnum:]_]\+\)/\1/'
> +	'/^\<DEFINE_FREE(\([[:alnum:]_]\+\)/cleanup_\1/'
> +	'/^\<DEFINE_CLASS(\([[:alnum:]_]\+\)/class_\1/'
	/^\<EXTEND_CLASS(\([[:alnum:]_]\+\),[[:space:]]*\([[:alnum:]]\+\)/class_\1\2/'
	/^\<DEFINE_GUARD(\([[:alnum:]_]\+\)/class_\1/'
	/^\<DEFINE_GUARD_COND(\([[:alnum:]_]\+\),[[:space:]]*\([[:alnum:]]\+\)/class_\1\2/'
	/^\<DEFINE_LOCK_GUARD_[[:digit:]](\([[:alnum:]_]\+\)/class_\1/'
	/^\<DEFINE_LOCK_GUARD_[[:digit:]]_COND(\([[:alnum:]_]\+\),[[:space:]]*\([[:alnum:]]\+\)/class_\1\2/'

I suppose... not tested these

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users)
  2025-01-05 14:14   ` DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users) Oleg Nesterov
  2025-01-06 10:26     ` Peter Zijlstra
@ 2025-01-06 12:19     ` Masami Hiramatsu
  2025-01-06 14:33       ` Oleg Nesterov
  1 sibling, 1 reply; 14+ messages in thread
From: Masami Hiramatsu @ 2025-01-06 12:19 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Peter Zijlstra, Steven Rostedt, Anil S Keshavamurthy,
	David S . Miller, Mathieu Desnoyers, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On Sun, 5 Jan 2025 15:14:22 +0100
Oleg Nesterov <oleg@redhat.com> wrote:

> Masami,
> 
> Sorry for abusing this thread. Your patches look fine to me, it is not
> that I suggest to change them. I will use your patch as an example for
> off-topic discussion.
> 
> On 01/05, Masami Hiramatsu (Google) wrote:
> >
> > +DEFINE_FREE(argv, char **, if (!IS_ERR_OR_NULL(_T)) argv_free(_T))
> 
> (IS_ERR looks unneeded but this is cosmetic).
> 
> OK, so it can be used as
> 
> 	void func(void)
> 	{
> 		char **argv __free(argv) = argv_split(...);
> 		do_something(argv);
> 		return;
> 	}
> 
> And I cry every time when I read the code like this ;)
> 
> Because, to understand this code, I need to do the "nontrivial" grep to find
> "DEFINE_FREE(argv,".
> 
> Perhaps we can establish a simple rule that every DEFINE_FREE() or DEFINE_CLASS()
> should add another #define? I mean something like
> 
> 
> 	DEFINE_FREE(argv, char **, if (!IS_ERR_OR_NULL(_T)) argv_free(_T))
> 	#define __FREE_ARGV	__free(argv)
> 	
> 	void func(void)
> 	{
> 		char **argv __FREE_ARGV = argv_split(...);
> 		do_something(argv);
> 		return;
> 	}
> 
> This way I can press Ctrl-] and see what the cleanup code actually does.
> Can save a second or two. Important when you try to read the code you are
> not familiar with.

That sounds lile a problem of your tool. Do you really need to find the
DEFINE_FREE() or do you think "__free(argv)" is too generic name?
If it is latter, we can make it "__free(argv_free) so that it is more
obvious to call argv_free()?

> 
> Same for DEFINE_CLASS. For example,
> 
> 	int ksys_fchown(unsigned int fd, uid_t user, gid_t group)
> 	{
> 		CLASS(fd, f)(fd);
> 
> 		if (fd_empty(f))
> 			return -EBADF;
> 
> 		return vfs_fchown(fd_file(f), user, group);
> 	}
> 
> If you are not familiar with this code, it looks mysterious until you find
> DEFINE_CLASS(fd, ...) in include/linux/file.h.

DEFINE_CLASS() is somewhat mysterious to me too :) But if I understand
correctly, it is for intermediate macro for implementing guard().

Whether we like it or not, cleanup.h has been introduced, and it will be
more popular. What we need is a document about cleanup.h which includes
better naming conventions for its label.

BTW, I agree that 'argv' was too simple. Basically the label name of
DEFINE_FREE() is better to be a function name for free.
Let me fix that.

Thank you,

-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users)
  2025-01-06 12:19     ` Masami Hiramatsu
@ 2025-01-06 14:33       ` Oleg Nesterov
  0 siblings, 0 replies; 14+ messages in thread
From: Oleg Nesterov @ 2025-01-06 14:33 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Peter Zijlstra, Steven Rostedt, Anil S Keshavamurthy,
	David S . Miller, Mathieu Desnoyers, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On 01/06, Masami Hiramatsu wrote:
>
> On Sun, 5 Jan 2025 15:14:22 +0100
> Oleg Nesterov <oleg@redhat.com> wrote:
>
> > Perhaps we can establish a simple rule that every DEFINE_FREE() or DEFINE_CLASS()
> > should add another #define? I mean something like
> >
> >
> > 	DEFINE_FREE(argv, char **, if (!IS_ERR_OR_NULL(_T)) argv_free(_T))
> > 	#define __FREE_ARGV	__free(argv)
> >
> > 	void func(void)
> > 	{
> > 		char **argv __FREE_ARGV = argv_split(...);
> > 		do_something(argv);
> > 		return;
> > 	}
> >
> > This way I can press Ctrl-] and see what the cleanup code actually does.
> > Can save a second or two. Important when you try to read the code you are
> > not familiar with.
>
> That sounds lile a problem of your tool. Do you really need to find the
> DEFINE_FREE()

Yes, ":tag __free_argv" wont work. it is defined by DEFINE_FREE(argv) above.
I need to find this DEFINE_FREE(argv) to see what __free_argv() actually does.

> > Same for DEFINE_CLASS. For example,
> >
> > 	int ksys_fchown(unsigned int fd, uid_t user, gid_t group)
> > 	{
> > 		CLASS(fd, f)(fd);
> >
> > 		if (fd_empty(f))
> > 			return -EBADF;
> >
> > 		return vfs_fchown(fd_file(f), user, group);
> > 	}
> >
> > If you are not familiar with this code, it looks mysterious until you find
> > DEFINE_CLASS(fd, ...) in include/linux/file.h.
>
> DEFINE_CLASS() is somewhat mysterious to me too :) But if I understand
> correctly, it is for intermediate macro for implementing guard().

Well, in this case you just need to find

	DEFINE_CLASS(fd, struct fd, fdput(_T), fdget(fd), int fd)

in include/linux/file.h, after that the code is clear.

> BTW, I agree that 'argv' was too simple. Basically the label name of
> DEFINE_FREE() is better to be a function name for free.
> Let me fix that.

Up to you, but __free(argv) looks good to me.

Oleg.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users)
  2025-01-06 10:26     ` Peter Zijlstra
  2025-01-06 11:18       ` Peter Zijlstra
@ 2025-01-06 14:44       ` Oleg Nesterov
  1 sibling, 0 replies; 14+ messages in thread
From: Oleg Nesterov @ 2025-01-06 14:44 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Masami Hiramatsu (Google), Steven Rostedt, Anil S Keshavamurthy,
	David S . Miller, Mathieu Desnoyers, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On 01/06, Peter Zijlstra wrote:
>
> On Sun, Jan 05, 2025 at 03:14:22PM +0100, Oleg Nesterov wrote:
>
> > Perhaps we can establish a simple rule that every DEFINE_FREE() or DEFINE_CLASS()
> > should add another #define? I mean something like
> >
> > 	DEFINE_FREE(argv, char **, if (!IS_ERR_OR_NULL(_T)) argv_free(_T))
> > 	#define __FREE_ARGV	__free(argv)
> >
> > 	void func(void)
> > 	{
> > 		char **argv __FREE_ARGV = argv_split(...);
> > 		do_something(argv);
> > 		return;
> > 	}
> >
> > This way I can press Ctrl-] and see what the cleanup code actually does.
> > Can save a second or two. Important when you try to read the code you are
> > not familiar with.
>
> Right, so I've been playing with neovim and clangd (lsp), and I'm very
> disappointed to have to tell you that that also doesn't get it :-(
>
> One thing we can and should do is something like:
>
> diff --git a/scripts/tags.sh b/scripts/tags.sh
> index b21236377998..f01d694abe65 100755
> --- a/scripts/tags.sh
> +++ b/scripts/tags.sh
> @@ -212,6 +212,8 @@ regex_c=(
>  	'/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_init/'
>  	'/^\<DECLARE_IDTENTRY[[:alnum:]_]*([^,)]*,[[:space:]]*\([[:alnum:]_]\+\)/\1/'
>  	'/^\<DEFINE_IDTENTRY[[:alnum:]_]*([[:space:]]*\([[:alnum:]_]\+\)/\1/'
> +	'/^\<DEFINE_FREE(\([[:alnum:]_]\+\)/cleanup_\1/'
> +	'/^\<DEFINE_CLASS(\([[:alnum:]_]\+\)/class_\1/'

Yes, thanks ;)

Ctrl-] still won't work, but at least ":ta cleanup_argv" will do.

Thanks,

Oleg.


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2025-01-06 14:44 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-05 12:47 [PATCH v2 0/6] tracing/kprobes: Cleanup with guard and __free Masami Hiramatsu (Google)
2025-01-05 12:47 ` [PATCH v2 1/6] tracing/kprobes: Fix to free objects when failed to copy a symbol Masami Hiramatsu (Google)
2025-01-05 12:47 ` [PATCH v2 2/6] Provide __free(argv) for argv_split() users Masami Hiramatsu (Google)
2025-01-05 14:14   ` DEFINE_FREE/CLASS && code readability (Was: [PATCH v2 2/6] Provide __free(argv) for argv_split() users) Oleg Nesterov
2025-01-06 10:26     ` Peter Zijlstra
2025-01-06 11:18       ` Peter Zijlstra
2025-01-06 14:44       ` Oleg Nesterov
2025-01-06 12:19     ` Masami Hiramatsu
2025-01-06 14:33       ` Oleg Nesterov
2025-01-05 12:48 ` [PATCH v2 3/6] tracing: Use __free() for argv in dynevent Masami Hiramatsu (Google)
2025-01-05 12:48 ` [PATCH v2 4/6] tracing: Use __free() in trace_probe for cleanup Masami Hiramatsu (Google)
2025-01-05 12:48 ` [PATCH v2 5/6] tracing: Use __free() for kprobe events to cleanup Masami Hiramatsu (Google)
2025-01-06 10:09   ` Masami Hiramatsu
2025-01-05 12:48 ` [PATCH v2 6/6] tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos Masami Hiramatsu (Google)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).