| From: Tom Zanussi <tom.zanussi@linux.intel.com> |
| Date: Tue, 5 Sep 2017 16:57:25 -0500 |
| Subject: [PATCH 13/40] tracing: Make traceprobe parsing code reusable |
| |
| traceprobe_probes_write() and traceprobe_command() actually contain |
| nothing that ties them to kprobes - the code is generically useful for |
| similar types of parsing elsewhere, so separate it out and move it to |
| trace.c/trace.h. |
| |
| Other than moving it, the only change is in naming: |
| traceprobe_probes_write() becomes trace_parse_run_command() and |
| traceprobe_command() becomes trace_run_command(). |
| |
| Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| kernel/trace/trace.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ |
| kernel/trace/trace.h | 7 +++ |
| kernel/trace/trace_kprobe.c | 18 ++++----- |
| kernel/trace/trace_probe.c | 86 -------------------------------------------- |
| kernel/trace/trace_probe.h | 7 --- |
| kernel/trace/trace_uprobe.c | 2 - |
| 6 files changed, 103 insertions(+), 103 deletions(-) |
| |
| --- a/kernel/trace/trace.c |
| +++ b/kernel/trace/trace.c |
| @@ -7922,6 +7922,92 @@ void ftrace_dump(enum ftrace_dump_mode o |
| } |
| EXPORT_SYMBOL_GPL(ftrace_dump); |
| |
| +int trace_run_command(const char *buf, int (*createfn)(int, char **)) |
| +{ |
| + char **argv; |
| + int argc, ret; |
| + |
| + argc = 0; |
| + ret = 0; |
| + argv = argv_split(GFP_KERNEL, buf, &argc); |
| + if (!argv) |
| + return -ENOMEM; |
| + |
| + if (argc) |
| + ret = createfn(argc, argv); |
| + |
| + argv_free(argv); |
| + |
| + return ret; |
| +} |
| + |
| +#define WRITE_BUFSIZE 4096 |
| + |
| +ssize_t trace_parse_run_command(struct file *file, const char __user *buffer, |
| + size_t count, loff_t *ppos, |
| + int (*createfn)(int, char **)) |
| +{ |
| + char *kbuf, *buf, *tmp; |
| + int ret = 0; |
| + size_t done = 0; |
| + size_t size; |
| + |
| + kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL); |
| + if (!kbuf) |
| + return -ENOMEM; |
| + |
| + while (done < count) { |
| + size = count - done; |
| + |
| + if (size >= WRITE_BUFSIZE) |
| + size = WRITE_BUFSIZE - 1; |
| + |
| + if (copy_from_user(kbuf, buffer + done, size)) { |
| + ret = -EFAULT; |
| + goto out; |
| + } |
| + kbuf[size] = '\0'; |
| + buf = kbuf; |
| + do { |
| + tmp = strchr(buf, '\n'); |
| + if (tmp) { |
| + *tmp = '\0'; |
| + size = tmp - buf + 1; |
| + } else { |
| + size = strlen(buf); |
| + if (done + size < count) { |
| + if (buf != kbuf) |
| + break; |
| + /* This can accept WRITE_BUFSIZE - 2 ('\n' + '\0') */ |
| + pr_warn("Line length is too long: Should be less than %d\n", |
| + WRITE_BUFSIZE - 2); |
| + ret = -EINVAL; |
| + goto out; |
| + } |
| + } |
| + done += size; |
| + |
| + /* Remove comments */ |
| + tmp = strchr(buf, '#'); |
| + |
| + if (tmp) |
| + *tmp = '\0'; |
| + |
| + ret = trace_run_command(buf, createfn); |
| + if (ret) |
| + goto out; |
| + buf += size; |
| + |
| + } while (done < count); |
| + } |
| + ret = done; |
| + |
| +out: |
| + kfree(kbuf); |
| + |
| + return ret; |
| +} |
| + |
| __init static int tracer_alloc_buffers(void) |
| { |
| int ring_buf_size; |
| --- a/kernel/trace/trace.h |
| +++ b/kernel/trace/trace.h |
| @@ -1651,6 +1651,13 @@ void trace_printk_start_comm(void); |
| int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set); |
| int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled); |
| |
| +#define MAX_EVENT_NAME_LEN 64 |
| + |
| +extern int trace_run_command(const char *buf, int (*createfn)(int, char**)); |
| +extern ssize_t trace_parse_run_command(struct file *file, |
| + const char __user *buffer, size_t count, loff_t *ppos, |
| + int (*createfn)(int, char**)); |
| + |
| /* |
| * Normal trace_printk() and friends allocates special buffers |
| * to do the manipulation, as well as saves the print formats |
| --- a/kernel/trace/trace_kprobe.c |
| +++ b/kernel/trace/trace_kprobe.c |
| @@ -873,8 +873,8 @@ static int probes_open(struct inode *ino |
| static ssize_t probes_write(struct file *file, const char __user *buffer, |
| size_t count, loff_t *ppos) |
| { |
| - return traceprobe_probes_write(file, buffer, count, ppos, |
| - create_trace_kprobe); |
| + return trace_parse_run_command(file, buffer, count, ppos, |
| + create_trace_kprobe); |
| } |
| |
| static const struct file_operations kprobe_events_ops = { |
| @@ -1399,9 +1399,9 @@ static __init int kprobe_trace_self_test |
| |
| pr_info("Testing kprobe tracing: "); |
| |
| - ret = traceprobe_command("p:testprobe kprobe_trace_selftest_target " |
| - "$stack $stack0 +0($stack)", |
| - create_trace_kprobe); |
| + ret = trace_run_command("p:testprobe kprobe_trace_selftest_target " |
| + "$stack $stack0 +0($stack)", |
| + create_trace_kprobe); |
| if (WARN_ON_ONCE(ret)) { |
| pr_warn("error on probing function entry.\n"); |
| warn++; |
| @@ -1421,8 +1421,8 @@ static __init int kprobe_trace_self_test |
| } |
| } |
| |
| - ret = traceprobe_command("r:testprobe2 kprobe_trace_selftest_target " |
| - "$retval", create_trace_kprobe); |
| + ret = trace_run_command("r:testprobe2 kprobe_trace_selftest_target " |
| + "$retval", create_trace_kprobe); |
| if (WARN_ON_ONCE(ret)) { |
| pr_warn("error on probing function return.\n"); |
| warn++; |
| @@ -1492,13 +1492,13 @@ static __init int kprobe_trace_self_test |
| disable_trace_kprobe(tk, file); |
| } |
| |
| - ret = traceprobe_command("-:testprobe", create_trace_kprobe); |
| + ret = trace_run_command("-:testprobe", create_trace_kprobe); |
| if (WARN_ON_ONCE(ret)) { |
| pr_warn("error on deleting a probe.\n"); |
| warn++; |
| } |
| |
| - ret = traceprobe_command("-:testprobe2", create_trace_kprobe); |
| + ret = trace_run_command("-:testprobe2", create_trace_kprobe); |
| if (WARN_ON_ONCE(ret)) { |
| pr_warn("error on deleting a probe.\n"); |
| warn++; |
| --- a/kernel/trace/trace_probe.c |
| +++ b/kernel/trace/trace_probe.c |
| @@ -623,92 +623,6 @@ void traceprobe_free_probe_arg(struct pr |
| kfree(arg->comm); |
| } |
| |
| -int traceprobe_command(const char *buf, int (*createfn)(int, char **)) |
| -{ |
| - char **argv; |
| - int argc, ret; |
| - |
| - argc = 0; |
| - ret = 0; |
| - argv = argv_split(GFP_KERNEL, buf, &argc); |
| - if (!argv) |
| - return -ENOMEM; |
| - |
| - if (argc) |
| - ret = createfn(argc, argv); |
| - |
| - argv_free(argv); |
| - |
| - return ret; |
| -} |
| - |
| -#define WRITE_BUFSIZE 4096 |
| - |
| -ssize_t traceprobe_probes_write(struct file *file, const char __user *buffer, |
| - size_t count, loff_t *ppos, |
| - int (*createfn)(int, char **)) |
| -{ |
| - char *kbuf, *buf, *tmp; |
| - int ret = 0; |
| - size_t done = 0; |
| - size_t size; |
| - |
| - kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL); |
| - if (!kbuf) |
| - return -ENOMEM; |
| - |
| - while (done < count) { |
| - size = count - done; |
| - |
| - if (size >= WRITE_BUFSIZE) |
| - size = WRITE_BUFSIZE - 1; |
| - |
| - if (copy_from_user(kbuf, buffer + done, size)) { |
| - ret = -EFAULT; |
| - goto out; |
| - } |
| - kbuf[size] = '\0'; |
| - buf = kbuf; |
| - do { |
| - tmp = strchr(buf, '\n'); |
| - if (tmp) { |
| - *tmp = '\0'; |
| - size = tmp - buf + 1; |
| - } else { |
| - size = strlen(buf); |
| - if (done + size < count) { |
| - if (buf != kbuf) |
| - break; |
| - /* This can accept WRITE_BUFSIZE - 2 ('\n' + '\0') */ |
| - pr_warn("Line length is too long: Should be less than %d\n", |
| - WRITE_BUFSIZE - 2); |
| - ret = -EINVAL; |
| - goto out; |
| - } |
| - } |
| - done += size; |
| - |
| - /* Remove comments */ |
| - tmp = strchr(buf, '#'); |
| - |
| - if (tmp) |
| - *tmp = '\0'; |
| - |
| - ret = traceprobe_command(buf, createfn); |
| - if (ret) |
| - goto out; |
| - buf += size; |
| - |
| - } while (done < count); |
| - } |
| - ret = done; |
| - |
| -out: |
| - kfree(kbuf); |
| - |
| - return ret; |
| -} |
| - |
| static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, |
| bool is_return) |
| { |
| --- a/kernel/trace/trace_probe.h |
| +++ b/kernel/trace/trace_probe.h |
| @@ -42,7 +42,6 @@ |
| |
| #define MAX_TRACE_ARGS 128 |
| #define MAX_ARGSTR_LEN 63 |
| -#define MAX_EVENT_NAME_LEN 64 |
| #define MAX_STRING_SIZE PATH_MAX |
| |
| /* Reserved field names */ |
| @@ -356,12 +355,6 @@ extern void traceprobe_free_probe_arg(st |
| |
| extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset); |
| |
| -extern ssize_t traceprobe_probes_write(struct file *file, |
| - const char __user *buffer, size_t count, loff_t *ppos, |
| - int (*createfn)(int, char**)); |
| - |
| -extern int traceprobe_command(const char *buf, int (*createfn)(int, char**)); |
| - |
| /* Sum up total data length for dynamic arraies (strings) */ |
| static nokprobe_inline int |
| __get_data_size(struct trace_probe *tp, struct pt_regs *regs) |
| --- a/kernel/trace/trace_uprobe.c |
| +++ b/kernel/trace/trace_uprobe.c |
| @@ -651,7 +651,7 @@ static int probes_open(struct inode *ino |
| static ssize_t probes_write(struct file *file, const char __user *buffer, |
| size_t count, loff_t *ppos) |
| { |
| - return traceprobe_probes_write(file, buffer, count, ppos, create_trace_uprobe); |
| + return trace_parse_run_command(file, buffer, count, ppos, create_trace_uprobe); |
| } |
| |
| static const struct file_operations uprobe_events_ops = { |