Commit 2c79da09 authored by Masami Hiramatsu (Google)'s avatar Masami Hiramatsu (Google) Committed by Steven Rostedt (Google)
Browse files

tracing: Make the backup instance non-reusable

Since there is no reason to reuse the backup instance, make it readonly
(but erasable).  Note that only backup instances are readonly, because
other trace instances will be empty unless it is writable.  Only backup
instances have copy entries from the original.

With this change, most of the trace control files are removed from the
backup instance, including eventfs enable/filter etc.

 # find /sys/kernel/tracing/instances/backup/events/ | wc -l
 4093
 # find /sys/kernel/tracing/instances/boot_map/events/ | wc -l
 9573

Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Link: https://patch.msgid.link/177502546939.1311542.1826814401724828930.stgit@mhiramat.tok.corp.google.com


Signed-off-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent 20ad8b08
Loading
Loading
Loading
Loading
+50 −31
Original line number Diff line number Diff line
@@ -4022,6 +4022,11 @@ int tracing_open_generic_tr(struct inode *inode, struct file *filp)
	if (ret)
		return ret;

	if ((filp->f_mode & FMODE_WRITE) && trace_array_is_readonly(tr)) {
		trace_array_put(tr);
		return -EACCES;
	}

	filp->private_data = inode->i_private;

	return 0;
@@ -7097,6 +7102,11 @@ static int tracing_clock_open(struct inode *inode, struct file *file)
	if (ret)
		return ret;

	if ((file->f_mode & FMODE_WRITE) && trace_array_is_readonly(tr)) {
		trace_array_put(tr);
		return -EACCES;
	}

	ret = single_open(file, tracing_clock_show, inode->i_private);
	if (ret < 0)
		trace_array_put(tr);
@@ -9866,17 +9876,22 @@ static __init void create_trace_instances(struct dentry *d_tracer)
static void
init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
{
	umode_t writable_mode = TRACE_MODE_WRITE;
	int cpu;

	if (trace_array_is_readonly(tr))
		writable_mode = TRACE_MODE_READ;

	trace_create_file("available_tracers", TRACE_MODE_READ, d_tracer,
			  tr, &show_traces_fops);

	trace_create_file("current_tracer", TRACE_MODE_WRITE, d_tracer,
	trace_create_file("current_tracer", writable_mode, d_tracer,
			  tr, &set_tracer_fops);

	trace_create_file("tracing_cpumask", TRACE_MODE_WRITE, d_tracer,
	trace_create_file("tracing_cpumask", writable_mode, d_tracer,
			  tr, &tracing_cpumask_fops);

	/* Options are used for changing print-format even for readonly instance. */
	trace_create_file("trace_options", TRACE_MODE_WRITE, d_tracer,
			  tr, &tracing_iter_fops);

@@ -9886,12 +9901,36 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
	trace_create_file("trace_pipe", TRACE_MODE_READ, d_tracer,
			  tr, &tracing_pipe_fops);

	trace_create_file("buffer_size_kb", TRACE_MODE_WRITE, d_tracer,
	trace_create_file("buffer_size_kb", writable_mode, d_tracer,
			  tr, &tracing_entries_fops);

	trace_create_file("buffer_total_size_kb", TRACE_MODE_READ, d_tracer,
			  tr, &tracing_total_entries_fops);

	trace_create_file("trace_clock", writable_mode, d_tracer, tr,
			  &trace_clock_fops);

	trace_create_file("timestamp_mode", TRACE_MODE_READ, d_tracer, tr,
			  &trace_time_stamp_mode_fops);

	tr->buffer_percent = 50;

	trace_create_file("buffer_subbuf_size_kb", writable_mode, d_tracer,
			  tr, &buffer_subbuf_size_fops);

	create_trace_options_dir(tr);

	if (tr->range_addr_start)
		trace_create_file("last_boot_info", TRACE_MODE_READ, d_tracer,
				  tr, &last_boot_fops);

	for_each_tracing_cpu(cpu)
		tracing_init_tracefs_percpu(tr, cpu);

	/* Read-only instance has above files only. */
	if (trace_array_is_readonly(tr))
		return;

	trace_create_file("free_buffer", 0200, d_tracer,
			  tr, &tracing_free_buffer_fops);

@@ -9903,49 +9942,29 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
	trace_create_file("trace_marker_raw", 0220, d_tracer,
			  tr, &tracing_mark_raw_fops);

	trace_create_file("trace_clock", TRACE_MODE_WRITE, d_tracer, tr,
			  &trace_clock_fops);

	trace_create_file("tracing_on", TRACE_MODE_WRITE, d_tracer,
			  tr, &rb_simple_fops);

	trace_create_file("timestamp_mode", TRACE_MODE_READ, d_tracer, tr,
			  &trace_time_stamp_mode_fops);

	tr->buffer_percent = 50;

	trace_create_file("buffer_percent", TRACE_MODE_WRITE, d_tracer,
			  tr, &buffer_percent_fops);

	trace_create_file("buffer_subbuf_size_kb", TRACE_MODE_WRITE, d_tracer,
			  tr, &buffer_subbuf_size_fops);

	trace_create_file("syscall_user_buf_size", TRACE_MODE_WRITE, d_tracer,
			  tr, &tracing_syscall_buf_fops);

	create_trace_options_dir(tr);
	trace_create_file("tracing_on", TRACE_MODE_WRITE, d_tracer,
			  tr, &rb_simple_fops);

	trace_create_maxlat_file(tr, d_tracer);

	if (ftrace_create_function_files(tr, d_tracer))
		MEM_FAIL(1, "Could not allocate function filter files");

	if (tr->range_addr_start) {
		trace_create_file("last_boot_info", TRACE_MODE_READ, d_tracer,
				  tr, &last_boot_fops);
#ifdef CONFIG_TRACER_SNAPSHOT
	} else {
	if (!tr->range_addr_start)
		trace_create_file("snapshot", TRACE_MODE_WRITE, d_tracer,
				  tr, &snapshot_fops);
#endif
	}

	trace_create_file("error_log", TRACE_MODE_WRITE, d_tracer,
			  tr, &tracing_err_log_fops);

	for_each_tracing_cpu(cpu)
		tracing_init_tracefs_percpu(tr, cpu);

	ftrace_init_tracefs(tr, d_tracer);
}

@@ -10772,7 +10791,7 @@ __init static void enable_instances(void)
		 * Backup buffers can be freed but need vfree().
		 */
		if (backup)
			tr->flags |= TRACE_ARRAY_FL_VMALLOC;
			tr->flags |= TRACE_ARRAY_FL_VMALLOC | TRACE_ARRAY_FL_RDONLY;

		if (start || backup) {
			tr->flags |= TRACE_ARRAY_FL_BOOT | TRACE_ARRAY_FL_LAST_BOOT;
+7 −0
Original line number Diff line number Diff line
@@ -462,6 +462,7 @@ enum {
	TRACE_ARRAY_FL_MOD_INIT		= BIT(3),
	TRACE_ARRAY_FL_MEMMAP		= BIT(4),
	TRACE_ARRAY_FL_VMALLOC		= BIT(5),
	TRACE_ARRAY_FL_RDONLY		= BIT(6),
};

#ifdef CONFIG_MODULES
@@ -491,6 +492,12 @@ extern unsigned long trace_adjust_address(struct trace_array *tr, unsigned long

extern struct trace_array *printk_trace;

static inline bool trace_array_is_readonly(struct trace_array *tr)
{
	/* backup instance is read only. */
	return tr->flags & TRACE_ARRAY_FL_RDONLY;
}

/*
 * The global tracer (top) should be the first trace array added,
 * but we check the flag anyway.
+3 −2
Original line number Diff line number Diff line
@@ -61,7 +61,8 @@ trace_boot_set_instance_options(struct trace_array *tr, struct xbc_node *node)
		v = memparse(p, NULL);
		if (v < PAGE_SIZE)
			pr_err("Buffer size is too small: %s\n", p);
		if (tracing_resize_ring_buffer(tr, v, RING_BUFFER_ALL_CPUS) < 0)
		if (trace_array_is_readonly(tr) ||
		    tracing_resize_ring_buffer(tr, v, RING_BUFFER_ALL_CPUS) < 0)
			pr_err("Failed to resize trace buffer to %s\n", p);
	}

@@ -597,7 +598,7 @@ trace_boot_enable_tracer(struct trace_array *tr, struct xbc_node *node)

	p = xbc_node_find_value(node, "tracer", NULL);
	if (p && *p != '\0') {
		if (tracing_set_tracer(tr, p) < 0)
		if (trace_array_is_readonly(tr) || tracing_set_tracer(tr, p) < 0)
			pr_err("Failed to set given tracer: %s\n", p);
	}

+44 −32
Original line number Diff line number Diff line
@@ -1401,6 +1401,9 @@ static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
{
	int ret;

	if (trace_array_is_readonly(tr))
		return -EACCES;

	mutex_lock(&event_mutex);
	ret = __ftrace_set_clr_event_nolock(tr, match, sub, event, set, mod);
	mutex_unlock(&event_mutex);
@@ -2973,8 +2976,8 @@ event_subsystem_dir(struct trace_array *tr, const char *name,
	} else
		__get_system(system);

	/* ftrace only has directories no files */
	if (strcmp(name, "ftrace") == 0)
	/* ftrace only has directories no files, readonly instance too. */
	if (strcmp(name, "ftrace") == 0 || trace_array_is_readonly(tr))
		nr_entries = 0;
	else
		nr_entries = ARRAY_SIZE(system_entries);
@@ -3139,28 +3142,30 @@ event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file)
	int ret;
	static struct eventfs_entry event_entries[] = {
		{
			.name		= "enable",
			.name		= "format",
			.callback	= event_callback,
			.release	= event_release,
		},
#ifdef CONFIG_PERF_EVENTS
		{
			.name		= "filter",
			.name		= "id",
			.callback	= event_callback,
		},
#endif
#define NR_RO_EVENT_ENTRIES	(1 + IS_ENABLED(CONFIG_PERF_EVENTS))
/* Readonly files must be above this line and counted by NR_RO_EVENT_ENTRIES. */
		{
			.name		= "trigger",
			.name		= "enable",
			.callback	= event_callback,
			.release	= event_release,
		},
		{
			.name		= "format",
			.name		= "filter",
			.callback	= event_callback,
		},
#ifdef CONFIG_PERF_EVENTS
		{
			.name		= "id",
			.name		= "trigger",
			.callback	= event_callback,
		},
#endif
#ifdef CONFIG_HIST_TRIGGERS
		{
			.name		= "hist",
@@ -3193,6 +3198,9 @@ event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file)
	if (!e_events)
		return -ENOMEM;

	if (trace_array_is_readonly(tr))
		nr_entries = NR_RO_EVENT_ENTRIES;
	else
		nr_entries = ARRAY_SIZE(event_entries);

	name = trace_event_name(call);
@@ -4536,31 +4544,44 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
	int nr_entries;
	static struct eventfs_entry events_entries[] = {
		{
			.name		= "enable",
			.name		= "header_page",
			.callback	= events_callback,
		},
		{
			.name		= "header_page",
			.name		= "header_event",
			.callback	= events_callback,
		},
#define NR_RO_TOP_ENTRIES	2
/* Readonly files must be above this line and counted by NR_RO_TOP_ENTRIES. */
		{
			.name		= "header_event",
			.name		= "enable",
			.callback	= events_callback,
		},
	};

	if (!trace_array_is_readonly(tr)) {
		entry = trace_create_file("set_event", TRACE_MODE_WRITE, parent,
					tr, &ftrace_set_event_fops);
		if (!entry)
			return -ENOMEM;

		/* There are not as crucial, just warn if they are not created */
		trace_create_file("show_event_filters", TRACE_MODE_READ, parent, tr,
				&ftrace_show_event_filters_fops);

		trace_create_file("show_event_triggers", TRACE_MODE_READ, parent, tr,
				&ftrace_show_event_triggers_fops);

		trace_create_file("set_event_pid", TRACE_MODE_WRITE, parent,
				tr, &ftrace_set_event_pid_fops);

		trace_create_file("set_event_notrace_pid",
				TRACE_MODE_WRITE, parent, tr,
				&ftrace_set_event_notrace_pid_fops);
		nr_entries = ARRAY_SIZE(events_entries);
	} else {
		nr_entries = NR_RO_TOP_ENTRIES;
	}

	e_events = eventfs_create_events_dir("events", parent, events_entries,
					     nr_entries, tr);
@@ -4569,15 +4590,6 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
		return -ENOMEM;
	}

	/* There are not as crucial, just warn if they are not created */

	trace_create_file("set_event_pid", TRACE_MODE_WRITE, parent,
			  tr, &ftrace_set_event_pid_fops);

	trace_create_file("set_event_notrace_pid",
			  TRACE_MODE_WRITE, parent, tr,
			  &ftrace_set_event_notrace_pid_fops);

	tr->event_dir = e_events;

	return 0;