[PATCH 2/2] trace-cmd reset: Add option to preserve specific dynamic events
Metin Kaya <[email protected]>
| Newsgroups | org.kernel.vger.linux-trace-devel |
|---|---|
| Message-ID | <[email protected]> |
One may want to preserve some of the dynamic events (e.g., kprobes)
during a trace-cmd reset. Thus, provide -k command line option for
trace-cmd reset to allow keeping specified events untouched during the
reset operation.
For example, it's possible to prevent kprobes & kretprobes from being
destroyed in trace-cmd reset with this patch:
# Add kprobe and kretprobe for sys_open():
$ echo 'p do_sys_open' > /sys/kernel/tracing/kprobe_events
$ echo 1 > /sys/kernel/tracing/events/kprobes/p_do_sys_open_0/enable
$ echo 'r do_sys_open' >> /sys/kernel/tracing/kprobe_events
$ echo 1 > /sys/kernel/tracing/events/kprobes/r_do_sys_open_0/enable
$ cat /sys/kernel/tracing/kprobe_events
p:kprobes/p_do_sys_open_0 do_sys_open
r128:kprobes/r_do_sys_open_0 do_sys_open
# Issue reset, but keep kprobes and kretprobes ('-k all' would keep
# all existing dynamic events):
$ trace-cmd reset -k kprobe -k kretprobe
$ cat /sys/kernel/tracing/kprobe_events
p:kprobes/p_do_sys_open_0 do_sys_open
r128:kprobes/r_do_sys_open_0 do_sys_open
# Issue reset, but this time only keep kretprobes:
$ trace-cmd reset -k kretprobe
$ cat /sys/kernel/tracing/kprobe_events
r128:kprobes/r_do_sys_open_0 do_sys_open
# Don't preserve any dynamic event:
$ trace-cmd reset
$ cat /sys/kernel/tracing/kprobe_events
$
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=219302
Signed-off-by: Metin Kaya <[email protected]>
---
tracecmd/trace-record.c | 59 ++++++++++++++++++++++++++++++++++++-----
tracecmd/trace-usage.c | 5 +++-
2 files changed, 57 insertions(+), 7 deletions(-)
diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c
index c695cd23..f80b386f 100644
--- a/tracecmd/trace-record.c
+++ b/tracecmd/trace-record.c
@@ -5399,11 +5399,15 @@ static void clear_error_log(void)
clear_instance_error_log(instance);
}
-static void clear_all_dynamic_events(void)
+static void clear_all_dynamic_events(unsigned int exclude_types)
{
- /* Clear event probes first, as they may be attached to other dynamic event */
- tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_EPROBE, true);
- tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_ALL, true);
+ /*
+ * Clear event probes first (if they are not excluded), as they may be
+ * attached to other dynamic event.
+ */
+ if (!(TRACEFS_DYNEVENT_EPROBE & exclude_types))
+ tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_EPROBE, true);
+ tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_ALL & ~exclude_types, true);
}
static void clear_func_filters(void)
@@ -6036,11 +6040,51 @@ void trace_restart(int argc, char **argv)
exit(0);
}
+/**
+ * find_dynevent_type - Find string formatted dynamic event type
+ * in "enum tracefs_dynevent_type".
+ *
+ * @type: Dynamic event type in string format.
+ *
+ * Returns an unsigned int value for the event specified in @type.
+ */
+static unsigned int find_dynevent_type(const char *type)
+{
+ /* WARN: Should be kept in sync with "enum tracefs_dynevent_type". */
+ if (!strcmp(type, "kprobe"))
+ return TRACEFS_DYNEVENT_KPROBE;
+ else if (!strcmp(type, "kretprobe"))
+ return TRACEFS_DYNEVENT_KRETPROBE;
+ else if (!strcmp(type, "uprobe"))
+ return TRACEFS_DYNEVENT_UPROBE;
+ else if (!strcmp(type, "uretprobe"))
+ return TRACEFS_DYNEVENT_URETPROBE;
+ else if (!strcmp(type, "eprobe"))
+ return TRACEFS_DYNEVENT_EPROBE;
+ else if (!strcmp(type, "synth"))
+ return TRACEFS_DYNEVENT_SYNTH;
+ else if (!strcmp(type, "all"))
+ /*
+ * Unfortunately TRACEFS_DYNEVENT_ALL does not work here.
+ * Because tracefs_dynevent_destroy_all() assumes 0 means all
+ * and destroys all dynamic events.
+ */
+ return (TRACEFS_DYNEVENT_KPROBE |
+ TRACEFS_DYNEVENT_KRETPROBE |
+ TRACEFS_DYNEVENT_UPROBE |
+ TRACEFS_DYNEVENT_URETPROBE |
+ TRACEFS_DYNEVENT_EPROBE |
+ TRACEFS_DYNEVENT_SYNTH);
+ else
+ die("Invalid event type '%s'!\n", type);
+}
+
void trace_reset(int argc, char **argv)
{
int c;
int topt = 0;
struct buffer_instance *instance = &top_instance;
+ unsigned int excluded_types = 0;
init_top_instance();
@@ -6048,7 +6092,7 @@ void trace_reset(int argc, char **argv)
int last_specified_all = 0;
struct buffer_instance *inst; /* iterator */
- while ((c = getopt(argc-1, argv+1, "hab:B:td")) >= 0) {
+ while ((c = getopt(argc-1, argv+1, "hab:B:tdk:")) >= 0) {
switch (c) {
case 'h':
@@ -6102,6 +6146,9 @@ void trace_reset(int argc, char **argv)
instance->flags &= ~BUFFER_FL_KEEP;
}
break;
+ case 'k':
+ excluded_types |= find_dynevent_type(optarg);
+ break;
default:
usage(argv);
break;
@@ -6112,7 +6159,7 @@ void trace_reset(int argc, char **argv)
set_buffer_size();
clear_filters();
clear_triggers();
- clear_all_dynamic_events();
+ clear_all_dynamic_events(excluded_types);
clear_error_log();
/* set clock to "local" */
reset_clock();
diff --git a/tracecmd/trace-usage.c b/tracecmd/trace-usage.c
index 8bbf2e3e..f159e5e1 100644
--- a/tracecmd/trace-usage.c
+++ b/tracecmd/trace-usage.c
@@ -193,7 +193,7 @@ static struct usage_help usage_help[] = {
{
"reset",
"disable all kernel tracing and clear the trace buffers",
- " %s reset [-b size][-B buf][-a][-d][-t]\n"
+ " %s reset [-b size][-B buf][-k event][-a][-d][-t]\n"
" Disables the tracer (may reset trace file)\n"
" Used in conjunction with start\n"
" -b change the kernel buffer size (in kilobytes per CPU)\n"
@@ -201,6 +201,9 @@ static struct usage_help usage_help[] = {
" -B reset the given buffer instance (may specify multiple -B)\n"
" -a reset all instances (except top one)\n"
" -t reset the top level instance (useful with -B or -a)\n"
+ " -k keep dynamic event during reset. Valid values are:\n"
+ " 'kprobe', 'kretprobe', 'uprobe', 'uretprobe',\n"
+ " 'eprobe', 'synth' and 'all'.\n"
},
{
"clear",
--
2.34.1