Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de7b2973 authored by Mathieu Desnoyers's avatar Mathieu Desnoyers Committed by Steven Rostedt
Browse files

tracepoint: Use struct pointer instead of name hash for reg/unreg tracepoints

Register/unregister tracepoint probes with struct tracepoint pointer
rather than tracepoint name.

This change, which vastly simplifies tracepoint.c, has been proposed by
Steven Rostedt. It also removes 8.8kB (mostly of text) to the vmlinux
size.

From this point on, the tracers need to pass a struct tracepoint pointer
to probe register/unregister. A probe can now only be connected to a
tracepoint that exists. Moreover, tracers are responsible for
unregistering the probe before the module containing its associated
tracepoint is unloaded.

   text    data     bss     dec     hex filename
10443444        4282528 10391552        25117524        17f4354 vmlinux.orig
10434930        4282848 10391552        25109330        17f2352 vmlinux

Link: http://lkml.kernel.org/r/1396992381-23785-2-git-send-email-mathieu.desnoyers@efficios.com



CC: Ingo Molnar <mingo@kernel.org>
CC: Frederic Weisbecker <fweisbec@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Frank Ch. Eigler <fche@redhat.com>
CC: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarMathieu Desnoyers <mathieu.desnoyers@efficios.com>
[ SDR - fixed return val in void func in tracepoint_module_going() ]
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent 68114e5e
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/percpu.h>
#include <linux/hardirq.h>
#include <linux/perf_event.h>
#include <linux/tracepoint.h>

struct trace_array;
struct trace_buffer;
@@ -232,6 +233,7 @@ enum {
	TRACE_EVENT_FL_IGNORE_ENABLE_BIT,
	TRACE_EVENT_FL_WAS_ENABLED_BIT,
	TRACE_EVENT_FL_USE_CALL_FILTER_BIT,
	TRACE_EVENT_FL_TRACEPOINT_BIT,
};

/*
@@ -244,6 +246,7 @@ enum {
 *                    (used for module unloading, if a module event is enabled,
 *                     it is best to clear the buffers that used it).
 *  USE_CALL_FILTER - For ftrace internal events, don't use file filter
 *  TRACEPOINT    - Event is a tracepoint
 */
enum {
	TRACE_EVENT_FL_FILTERED		= (1 << TRACE_EVENT_FL_FILTERED_BIT),
@@ -252,12 +255,17 @@ enum {
	TRACE_EVENT_FL_IGNORE_ENABLE	= (1 << TRACE_EVENT_FL_IGNORE_ENABLE_BIT),
	TRACE_EVENT_FL_WAS_ENABLED	= (1 << TRACE_EVENT_FL_WAS_ENABLED_BIT),
	TRACE_EVENT_FL_USE_CALL_FILTER	= (1 << TRACE_EVENT_FL_USE_CALL_FILTER_BIT),
	TRACE_EVENT_FL_TRACEPOINT	= (1 << TRACE_EVENT_FL_TRACEPOINT_BIT),
};

struct ftrace_event_call {
	struct list_head	list;
	struct ftrace_event_class *class;
	union {
		char			*name;
		/* Set TRACE_EVENT_FL_TRACEPOINT flag when using "tp" */
		struct tracepoint	*tp;
	};
	struct trace_event	event;
	const char		*print_fmt;
	struct event_filter	*filter;
@@ -271,6 +279,7 @@ struct ftrace_event_call {
	 *   bit 3:		ftrace internal event (do not enable)
	 *   bit 4:		Event was enabled by module
	 *   bit 5:		use call filter rather than file filter
	 *   bit 6:		Event is a tracepoint
	 */
	int			flags; /* static flags of different events */

@@ -283,6 +292,15 @@ struct ftrace_event_call {
#endif
};

static inline const char *
ftrace_event_name(struct ftrace_event_call *call)
{
	if (call->flags & TRACE_EVENT_FL_TRACEPOINT)
		return call->tp ? call->tp->name : NULL;
	else
		return call->name;
}

struct trace_array;
struct ftrace_subsystem_dir;

@@ -353,7 +371,7 @@ struct ftrace_event_file {
#define __TRACE_EVENT_FLAGS(name, value)				\
	static int __init trace_init_flags_##name(void)			\
	{								\
		event_##name.flags = value;				\
		event_##name.flags |= value;				\
		return 0;						\
	}								\
	early_initcall(trace_init_flags_##name);
+25 −16
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@
 *
 * See Documentation/trace/tracepoints.txt.
 *
 * (C) Copyright 2008 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
 * Copyright (C) 2008-2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
 *
 * Heavily inspired from the Linux Kernel Markers.
 *
@@ -21,6 +21,7 @@

struct module;
struct tracepoint;
struct notifier_block;

struct tracepoint_func {
	void *func;
@@ -35,18 +36,13 @@ struct tracepoint {
	struct tracepoint_func __rcu *funcs;
};

/*
 * Connect a probe to a tracepoint.
 * Internal API, should not be used directly.
 */
extern int tracepoint_probe_register(const char *name, void *probe, void *data);

/*
 * Disconnect a probe from a tracepoint.
 * Internal API, should not be used directly.
 */
extern int
tracepoint_probe_unregister(const char *name, void *probe, void *data);
tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);
extern int
tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data);
extern void
for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv),
		void *priv);

#ifdef CONFIG_MODULES
struct tp_module {
@@ -54,12 +50,25 @@ struct tp_module {
	unsigned int num_tracepoints;
	struct tracepoint * const *tracepoints_ptrs;
};

bool trace_module_has_bad_taint(struct module *mod);
extern int register_tracepoint_module_notifier(struct notifier_block *nb);
extern int unregister_tracepoint_module_notifier(struct notifier_block *nb);
#else
static inline bool trace_module_has_bad_taint(struct module *mod)
{
	return false;
}
static inline
int register_tracepoint_module_notifier(struct notifier_block *nb)
{
	return 0;
}
static inline
int unregister_tracepoint_module_notifier(struct notifier_block *nb)
{
	return 0;
}
#endif /* CONFIG_MODULES */

/*
@@ -160,14 +169,14 @@ static inline void tracepoint_synchronize_unregister(void)
	static inline int						\
	register_trace_##name(void (*probe)(data_proto), void *data)	\
	{								\
		return tracepoint_probe_register(#name, (void *)probe,	\
						 data);			\
		return tracepoint_probe_register(&__tracepoint_##name,	\
						(void *)probe, data);	\
	}								\
	static inline int						\
	unregister_trace_##name(void (*probe)(data_proto), void *data)	\
	{								\
		return tracepoint_probe_unregister(#name, (void *)probe, \
						   data);		\
		return tracepoint_probe_unregister(&__tracepoint_##name,\
						(void *)probe, data);	\
	}								\
	static inline void						\
	check_trace_callback_type_##name(void (*cb)(data_proto))	\
+6 −3
Original line number Diff line number Diff line
@@ -470,10 +470,11 @@ static inline notrace int ftrace_get_offsets_##call( \
 * };
 *
 * static struct ftrace_event_call event_<call> = {
 *	.name			= "<call>",
 *	.tp			= &__tracepoint_<call>,
 *	.class			= event_class_<template>,
 *	.event			= &ftrace_event_type_<call>,
 *	.print_fmt		= print_fmt_<call>,
 *	.flags			= TRACE_EVENT_FL_TRACEPOINT,
 * };
 * // its only safe to use pointers when doing linker tricks to
 * // create an array.
@@ -605,10 +606,11 @@ static struct ftrace_event_class __used __refdata event_class_##call = { \
#define DEFINE_EVENT(template, call, proto, args)			\
									\
static struct ftrace_event_call __used event_##call = {			\
	.name			= #call,				\
	.tp			= &__tracepoint_##call,			\
	.class			= &event_class_##template,		\
	.event.funcs		= &ftrace_event_type_funcs_##template,	\
	.print_fmt		= print_fmt_##template,			\
	.flags			= TRACE_EVENT_FL_TRACEPOINT,		\
};									\
static struct ftrace_event_call __used					\
__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
@@ -619,10 +621,11 @@ __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
static const char print_fmt_##call[] = print;				\
									\
static struct ftrace_event_call __used event_##call = {			\
	.name			= #call,				\
	.tp			= &__tracepoint_##call,			\
	.class			= &event_class_##template,		\
	.event.funcs		= &ftrace_event_type_funcs_##call,	\
	.print_fmt		= print_fmt_##call,			\
	.flags			= TRACE_EVENT_FL_TRACEPOINT,		\
};									\
static struct ftrace_event_call __used					\
__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
+32 −23
Original line number Diff line number Diff line
@@ -223,24 +223,25 @@ int ftrace_event_reg(struct ftrace_event_call *call,
{
	struct ftrace_event_file *file = data;

	WARN_ON(!(call->flags & TRACE_EVENT_FL_TRACEPOINT));
	switch (type) {
	case TRACE_REG_REGISTER:
		return tracepoint_probe_register(call->name,
		return tracepoint_probe_register(call->tp,
						 call->class->probe,
						 file);
	case TRACE_REG_UNREGISTER:
		tracepoint_probe_unregister(call->name,
		tracepoint_probe_unregister(call->tp,
					    call->class->probe,
					    file);
		return 0;

#ifdef CONFIG_PERF_EVENTS
	case TRACE_REG_PERF_REGISTER:
		return tracepoint_probe_register(call->name,
		return tracepoint_probe_register(call->tp,
						 call->class->perf_probe,
						 call);
	case TRACE_REG_PERF_UNREGISTER:
		tracepoint_probe_unregister(call->name,
		tracepoint_probe_unregister(call->tp,
					    call->class->perf_probe,
					    call);
		return 0;
@@ -352,7 +353,7 @@ static int __ftrace_event_enable_disable(struct ftrace_event_file *file,
			if (ret) {
				tracing_stop_cmdline_record();
				pr_info("event trace: Could not enable event "
					"%s\n", call->name);
					"%s\n", ftrace_event_name(call));
				break;
			}
			set_bit(FTRACE_EVENT_FL_ENABLED_BIT, &file->flags);
@@ -481,27 +482,29 @@ __ftrace_set_clr_event_nolock(struct trace_array *tr, const char *match,
{
	struct ftrace_event_file *file;
	struct ftrace_event_call *call;
	const char *name;
	int ret = -EINVAL;

	list_for_each_entry(file, &tr->events, list) {

		call = file->event_call;
		name = ftrace_event_name(call);

		if (!call->name || !call->class || !call->class->reg)
		if (!name || !call->class || !call->class->reg)
			continue;

		if (call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
			continue;

		if (match &&
		    strcmp(match, call->name) != 0 &&
		    strcmp(match, name) != 0 &&
		    strcmp(match, call->class->system) != 0)
			continue;

		if (sub && strcmp(sub, call->class->system) != 0)
			continue;

		if (event && strcmp(event, call->name) != 0)
		if (event && strcmp(event, name) != 0)
			continue;

		ftrace_event_enable_disable(file, set);
@@ -699,7 +702,7 @@ static int t_show(struct seq_file *m, void *v)

	if (strcmp(call->class->system, TRACE_SYSTEM) != 0)
		seq_printf(m, "%s:", call->class->system);
	seq_printf(m, "%s\n", call->name);
	seq_printf(m, "%s\n", ftrace_event_name(call));

	return 0;
}
@@ -792,7 +795,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
	mutex_lock(&event_mutex);
	list_for_each_entry(file, &tr->events, list) {
		call = file->event_call;
		if (!call->name || !call->class || !call->class->reg)
		if (!ftrace_event_name(call) || !call->class || !call->class->reg)
			continue;

		if (system && strcmp(call->class->system, system->name) != 0)
@@ -907,7 +910,7 @@ static int f_show(struct seq_file *m, void *v)

	switch ((unsigned long)v) {
	case FORMAT_HEADER:
		seq_printf(m, "name: %s\n", call->name);
		seq_printf(m, "name: %s\n", ftrace_event_name(call));
		seq_printf(m, "ID: %d\n", call->event.type);
		seq_printf(m, "format:\n");
		return 0;
@@ -1527,6 +1530,7 @@ event_create_dir(struct dentry *parent, struct ftrace_event_file *file)
	struct trace_array *tr = file->tr;
	struct list_head *head;
	struct dentry *d_events;
	const char *name;
	int ret;

	/*
@@ -1540,10 +1544,11 @@ event_create_dir(struct dentry *parent, struct ftrace_event_file *file)
	} else
		d_events = parent;

	file->dir = debugfs_create_dir(call->name, d_events);
	name = ftrace_event_name(call);
	file->dir = debugfs_create_dir(name, d_events);
	if (!file->dir) {
		pr_warning("Could not create debugfs '%s' directory\n",
			   call->name);
			   name);
		return -1;
	}

@@ -1567,7 +1572,7 @@ event_create_dir(struct dentry *parent, struct ftrace_event_file *file)
		ret = call->class->define_fields(call);
		if (ret < 0) {
			pr_warning("Could not initialize trace point"
				   " events/%s\n", call->name);
				   " events/%s\n", name);
			return -1;
		}
	}
@@ -1631,15 +1636,17 @@ static void event_remove(struct ftrace_event_call *call)
static int event_init(struct ftrace_event_call *call)
{
	int ret = 0;
	const char *name;

	if (WARN_ON(!call->name))
	name = ftrace_event_name(call);
	if (WARN_ON(!name))
		return -EINVAL;

	if (call->class->raw_init) {
		ret = call->class->raw_init(call);
		if (ret < 0 && ret != -ENOSYS)
			pr_warn("Could not initialize trace events/%s\n",
				call->name);
				name);
	}

	return ret;
@@ -1885,7 +1892,7 @@ __trace_add_event_dirs(struct trace_array *tr)
		ret = __trace_add_new_event(call, tr);
		if (ret < 0)
			pr_warning("Could not create directory for event %s\n",
				   call->name);
				   ftrace_event_name(call));
	}
}

@@ -1894,18 +1901,20 @@ find_event_file(struct trace_array *tr, const char *system, const char *event)
{
	struct ftrace_event_file *file;
	struct ftrace_event_call *call;
	const char *name;

	list_for_each_entry(file, &tr->events, list) {

		call = file->event_call;
		name = ftrace_event_name(call);

		if (!call->name || !call->class || !call->class->reg)
		if (!name || !call->class || !call->class->reg)
			continue;

		if (call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
			continue;

		if (strcmp(event, call->name) == 0 &&
		if (strcmp(event, name) == 0 &&
		    strcmp(system, call->class->system) == 0)
			return file;
	}
@@ -1973,7 +1982,7 @@ event_enable_print(struct seq_file *m, unsigned long ip,
	seq_printf(m, "%s:%s:%s",
		   data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
		   data->file->event_call->class->system,
		   data->file->event_call->name);
		   ftrace_event_name(data->file->event_call));

	if (data->count == -1)
		seq_printf(m, ":unlimited\n");
@@ -2193,7 +2202,7 @@ __trace_early_add_event_dirs(struct trace_array *tr)
		ret = event_create_dir(tr->event_dir, file);
		if (ret < 0)
			pr_warning("Could not create directory for event %s\n",
				   file->event_call->name);
				   ftrace_event_name(file->event_call));
	}
}

@@ -2217,7 +2226,7 @@ __trace_early_add_events(struct trace_array *tr)
		ret = __trace_early_add_new_event(call, tr);
		if (ret < 0)
			pr_warning("Could not create early event %s\n",
				   call->name);
				   ftrace_event_name(call));
	}
}

@@ -2549,7 +2558,7 @@ static __init void event_trace_self_tests(void)
			continue;
#endif

		pr_info("Testing event %s: ", call->name);
		pr_info("Testing event %s: ", ftrace_event_name(call));

		/*
		 * If an event is already enabled, someone is using
+1 −1
Original line number Diff line number Diff line
@@ -1095,7 +1095,7 @@ event_enable_trigger_print(struct seq_file *m, struct event_trigger_ops *ops,
	seq_printf(m, "%s:%s:%s",
		   enable_data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
		   enable_data->file->event_call->class->system,
		   enable_data->file->event_call->name);
		   ftrace_event_name(enable_data->file->event_call));

	if (data->count == -1)
		seq_puts(m, ":unlimited");
Loading