@@ -64,6 +64,7 @@ int trace_get_instance(struct tracefs_instance *instance);
/* Can be overridden */
void tracefs_warning(const char *fmt, ...);
+char *strstrip(char *str);
int str_read_file(const char *file, char **buffer, bool warn);
char *trace_append_file(const char *dir, const char *name);
char *trace_find_tracing_dir(bool debugfs);
@@ -23,6 +23,7 @@ int tracefs_tracing_dir_is_mounted(bool mount, const char **path);
struct tracefs_instance;
void tracefs_instance_free(struct tracefs_instance *instance);
+void tracefs_instance_reset(struct tracefs_instance *instance);
struct tracefs_instance *tracefs_instance_create(const char *name);
struct tracefs_instance *tracefs_instance_alloc(const char *tracing_dir,
const char *name);
@@ -1239,3 +1239,210 @@ char *tracefs_instance_get_affinity(struct tracefs_instance *instance)
return set;
}
+
+static int clear_trigger(const char *file)
+{
+ char trigger[BUFSIZ];
+ char *save = NULL;
+ char *line;
+ char *buf;
+ int size;
+ int len;
+ int ret;
+
+ size = str_read_file(file, &buf, true);
+ if (size < 1)
+ return 0;
+
+ trigger[0] = '!';
+
+ for (line = strtok_r(buf, "\n", &save); line; line = strtok_r(NULL, "\n", &save)) {
+ if (line[0] == '#')
+ continue;
+ len = strlen(line);
+ if (len > BUFSIZ - 2)
+ len = BUFSIZ - 2;
+ strncpy(trigger + 1, line, len);
+ trigger[len + 1] = '\0';
+ /* We don't want any filters or extra on the line */
+ strtok(trigger, " ");
+ write_file(file, trigger, O_WRONLY);
+ }
+
+ free(buf);
+
+ /*
+ * Some triggers have an order in removing them.
+ * They will not be removed if done in the wrong order.
+ */
+ size = str_read_file(file, &buf, true);
+ if (size < 1)
+ return 0;
+
+ ret = 0;
+ for (line = strtok(buf, "\n"); line; line = strtok(NULL, "\n")) {
+ if (line[0] == '#')
+ continue;
+ ret = 1;
+ break;
+ }
+ free(buf);
+ return ret;
+}
+
+static void disable_func_stack_trace_instance(struct tracefs_instance *instance)
+{
+ char *content;
+ char *cond;
+ int size;
+
+ content = tracefs_instance_file_read(instance, "current_tracer", &size);
+ if (!content)
+ return;
+ cond = strstrip(content);
+ if (memcmp(cond, "function", size - (cond - content)) != 0)
+ goto out;
+
+ tracefs_option_disable(instance, TRACEFS_OPTION_FUNC_STACKTRACE);
+ out:
+ free(content);
+}
+
+static void reset_cpu_mask(struct tracefs_instance *instance)
+{
+ int cpus = sysconf(_SC_NPROCESSORS_CONF);
+ int fullwords = (cpus - 1) / 32;
+ int bits = (cpus - 1) % 32 + 1;
+ int len = (fullwords + 1) * 9;
+ char buf[len + 1];
+
+ buf[0] = '\0';
+ sprintf(buf, "%x", (unsigned int)((1ULL << bits) - 1));
+ while (fullwords-- > 0)
+ strcat(buf, ",ffffffff");
+
+ tracefs_instance_file_write(instance, "tracing_cpumask", buf);
+}
+
+static void clear_func_filter(struct tracefs_instance *instance, const char *file)
+{
+ char filter[BUFSIZ];
+ char *line;
+ char *buf;
+ char *p;
+ int len;
+
+ buf = tracefs_instance_file_read(instance, file, NULL);
+ if (!buf)
+ return;
+
+ /* Now remove filters */
+ filter[0] = '!';
+
+ /*
+ * To delete a filter, we need to write a '!filter'
+ * to the file for each filter.
+ */
+ for (line = strtok(buf, "\n"); line; line = strtok(NULL, "\n")) {
+ if (line[0] == '#')
+ continue;
+ len = strlen(line);
+ if (len > BUFSIZ - 2)
+ len = BUFSIZ - 2;
+
+ strncpy(filter + 1, line, len);
+ filter[len + 1] = '\0';
+ /*
+ * To remove "unlimited" filters, we must remove
+ * the ":unlimited" from what we write.
+ */
+ p = strstr(filter, ":unlimited");
+ if (p) {
+ *p = '\0';
+ len = p - filter;
+ }
+ /*
+ * The write to this file expects white space
+ * at the end :-p
+ */
+ filter[len] = '\n';
+ filter[len+1] = '\0';
+ tracefs_instance_file_append(instance, file, filter);
+ }
+}
+
+static void clear_func_filters(struct tracefs_instance *instance)
+{
+ int i;
+ const char * const files[] = { "set_ftrace_filter",
+ "set_ftrace_notrace",
+ "set_graph_function",
+ "set_graph_notrace",
+ "stack_trace_filter",
+ NULL };
+
+ for (i = 0; files[i]; i++)
+ clear_func_filter(instance, files[i]);
+}
+
+/**
+ * tracefs_instance_reset - Reset a ftrace instance to its default state
+ * @instance - a ftrace instance to be reseted
+ *
+ * The main logic and the helper functions are copied from
+ * trace-cmd/tracecmd/trace-record.c, trace_reset()
+ */
+void tracefs_instance_reset(struct tracefs_instance *instance)
+{
+ int has_trigger = -1;
+ char **systems;
+ struct stat st;
+ char **events;
+ char *file;
+ int i, j;
+
+ tracefs_trace_off(instance);
+ disable_func_stack_trace_instance(instance);
+ tracefs_tracer_clear(instance);
+ tracefs_instance_file_write(instance, "events/enable", "0");
+ tracefs_instance_file_write(instance, "set_ftrace_pid", "");
+ tracefs_instance_file_clear(instance, "trace");
+
+ systems = tracefs_event_systems(NULL);
+ if (systems) {
+ for (i = 0; systems[i]; i++) {
+ events = tracefs_system_events(NULL, systems[i]);
+ if (!events)
+ continue;
+ for (j = 0; events[j]; j++) {
+ file = tracefs_event_get_file(instance, systems[i],
+ events[j], "filter");
+ write_file(file, "0", O_WRONLY | O_TRUNC);
+ tracefs_put_tracing_file(file);
+
+ file = tracefs_event_get_file(instance, systems[i],
+ events[j], "trigger");
+ if (has_trigger < 0) {
+ /* Check if the kernel is configured with triggers */
+ if (stat(file, &st) < 0)
+ has_trigger = 0;
+ else
+ has_trigger = 1;
+ }
+ if (has_trigger)
+ clear_trigger(file);
+ tracefs_put_tracing_file(file);
+ }
+ tracefs_list_free(events);
+ }
+ tracefs_list_free(systems);
+ }
+
+ tracefs_instance_file_write(instance, "error_log", " ");
+ tracefs_instance_file_write(instance, "trace_clock", "local");
+ tracefs_instance_file_write(instance, "set_event_pid", "");
+ reset_cpu_mask(instance);
+ clear_func_filters(instance);
+ tracefs_instance_file_write(instance, "tracing_max_latency", "0");
+ tracefs_trace_on(instance);
+}
@@ -319,6 +319,26 @@ void tracefs_put_tracing_file(char *name)
free(name);
}
+/* The function is copied from trace-cmd */
+__hidden char *strstrip(char *str)
+{
+ char *s;
+
+ if (!str)
+ return NULL;
+
+ s = str + strlen(str) - 1;
+ while (s >= str && isspace(*s))
+ s--;
+ s++;
+ *s = '\0';
+
+ for (s = str; *s && isspace(*s); s++)
+ ;
+
+ return s;
+}
+
__hidden int str_read_file(const char *file, char **buffer, bool warn)
{
char stbuf[BUFSIZ];
Resetting a ftrace instance to its default state is not a trivial task. A lot of trace files have to be modified, with different syntaxes and in strict order. Although there is such functionality in "trace-cmd reset" command, it will be good to have it in the tracefs library as well. A new API tracefs_instance_reset() is introduced, which resets given ftrace instance to its default state. The logic and most of the helper functions from "trace-cmd reset" command are copied in the tracefs library. Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> --- include/tracefs-local.h | 1 + include/tracefs.h | 1 + src/tracefs-instance.c | 207 ++++++++++++++++++++++++++++++++++++++++ src/tracefs-utils.c | 20 ++++ 4 files changed, 229 insertions(+)