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

Commit bd1a5c84 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Frederic Weisbecker
Browse files

tracing: Ftrace dynamic ftrace_event_call support



Add dynamic ftrace_event_call support to ftrace. Trace engines can add
new ftrace_event_call to ftrace on the fly. Each operator function of
the call takes an ftrace_event_call data structure as an argument,
because these functions may be shared among several ftrace_event_calls.

Changes from v13:
 - Define remove_subsystem_dir() always (revirt a2ca5e03), because
   trace_remove_event_call() uses it.
 - Modify syscall tracer because of ftrace_event_call change.

[fweisbec@gmail.com: Fixed conflict against latest tracing/core]

Signed-off-by: default avatarMasami Hiramatsu <mhiramat@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Avi Kivity <avi@redhat.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Frank Ch. Eigler <fche@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: K.Prasad <prasad@linux.vnet.ibm.com>
Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Cc: Przemysław Pawełczyk <przemyslaw@pawelczyk.it>
Cc: Roland McGrath <roland@redhat.com>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
Cc: Vegard Nossum <vegard.nossum@gmail.com>
LKML-Reference: <20090813203453.31965.71901.stgit@localhost.localdomain>
Signed-off-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
parent b1cf540f
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -112,12 +112,12 @@ struct ftrace_event_call {
	struct dentry		*dir;
	struct trace_event	*event;
	int			enabled;
	int			(*regfunc)(void *);
	void			(*unregfunc)(void *);
	int			(*regfunc)(struct ftrace_event_call *);
	void			(*unregfunc)(struct ftrace_event_call *);
	int			id;
	int			(*raw_init)(void);
	int			(*show_format)(struct ftrace_event_call *call,
					       struct trace_seq *s);
	int			(*raw_init)(struct ftrace_event_call *);
	int			(*show_format)(struct ftrace_event_call *,
					       struct trace_seq *);
	int			(*define_fields)(struct ftrace_event_call *);
	struct list_head	fields;
	int			filter_active;
@@ -147,11 +147,12 @@ enum {
	FILTER_PTR_STRING,
};

extern int trace_define_field(struct ftrace_event_call *call,
			      const char *type, const char *name,
			      int offset, int size, int is_signed,
			      int filter_type);
extern int trace_define_common_fields(struct ftrace_event_call *call);
extern int trace_define_field(struct ftrace_event_call *call, char *type,
			      char *name, int offset, int size, int is_signed,
			      int filter_type);
extern int trace_add_event_call(struct ftrace_event_call *call);
extern void trace_remove_event_call(struct ftrace_event_call *call);

#define is_signed_type(type)	(((type)(-1)) < 0)

+2 −2
Original line number Diff line number Diff line
@@ -165,7 +165,7 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \
	struct trace_event enter_syscall_print_##sname = {		\
		.trace                  = print_syscall_enter,		\
	};								\
	static int init_enter_##sname(void)				\
	static int init_enter_##sname(struct ftrace_event_call *call)	\
	{								\
		int num, id;						\
		num = syscall_name_to_nr("sys"#sname);			\
@@ -202,7 +202,7 @@ static void prof_sysexit_disable_##sname(struct ftrace_event_call *event_call) \
	struct trace_event exit_syscall_print_##sname = {		\
		.trace                  = print_syscall_exit,		\
	};								\
	static int init_exit_##sname(void)				\
	static int init_exit_##sname(struct ftrace_event_call *call)	\
	{								\
		int num, id;						\
		num = syscall_name_to_nr("sys"#sname);			\
+8 −8
Original line number Diff line number Diff line
@@ -434,7 +434,7 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
 *	event_trace_printk(_RET_IP_, "<call>: " <fmt>);
 * }
 *
 * static int ftrace_reg_event_<call>(void)
 * static int ftrace_reg_event_<call>(struct ftrace_event_call *unused)
 * {
 *	int ret;
 *
@@ -445,7 +445,7 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
 *	return ret;
 * }
 *
 * static void ftrace_unreg_event_<call>(void)
 * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
 * {
 *	unregister_trace_<call>(ftrace_event_<call>);
 * }
@@ -478,7 +478,7 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
 *	trace_current_buffer_unlock_commit(event, irq_flags, pc);
 * }
 *
 * static int ftrace_raw_reg_event_<call>(void)
 * static int ftrace_raw_reg_event_<call>(struct ftrace_event_call *unused)
 * {
 *	int ret;
 *
@@ -489,7 +489,7 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
 *	return ret;
 * }
 *
 * static void ftrace_unreg_event_<call>(void)
 * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
 * {
 *	unregister_trace_<call>(ftrace_raw_event_<call>);
 * }
@@ -498,7 +498,7 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
 *	.trace			= ftrace_raw_output_<call>, <-- stage 2
 * };
 *
 * static int ftrace_raw_init_event_<call>(void)
 * static int ftrace_raw_init_event_<call>(struct ftrace_event_call *unused)
 * {
 *	int id;
 *
@@ -592,7 +592,7 @@ static void ftrace_raw_event_##call(proto) \
		trace_nowake_buffer_unlock_commit(event, irq_flags, pc); \
}									\
									\
static int ftrace_raw_reg_event_##call(void *ptr)			\
static int ftrace_raw_reg_event_##call(struct ftrace_event_call *unused)\
{									\
	int ret;							\
									\
@@ -603,7 +603,7 @@ static int ftrace_raw_reg_event_##call(void *ptr) \
	return ret;							\
}									\
									\
static void ftrace_raw_unreg_event_##call(void *ptr)			\
static void ftrace_raw_unreg_event_##call(struct ftrace_event_call *unused)\
{									\
	unregister_trace_##call(ftrace_raw_event_##call);		\
}									\
@@ -612,7 +612,7 @@ static struct trace_event ftrace_event_type_##call = { \
	.trace			= ftrace_raw_output_##call,		\
};									\
									\
static int ftrace_raw_init_event_##call(void)				\
static int ftrace_raw_init_event_##call(struct ftrace_event_call *unused)\
{									\
	int id;								\
									\
+7 −4
Original line number Diff line number Diff line
@@ -39,16 +39,19 @@ void set_syscall_enter_id(int num, int id);
void set_syscall_exit_id(int num, int id);
extern struct trace_event event_syscall_enter;
extern struct trace_event event_syscall_exit;
extern int reg_event_syscall_enter(void *ptr);
extern void unreg_event_syscall_enter(void *ptr);
extern int reg_event_syscall_exit(void *ptr);
extern void unreg_event_syscall_exit(void *ptr);

extern int syscall_enter_format(struct ftrace_event_call *call,
				struct trace_seq *s);
extern int syscall_exit_format(struct ftrace_event_call *call,
				struct trace_seq *s);
extern int syscall_enter_define_fields(struct ftrace_event_call *call);
extern int syscall_exit_define_fields(struct ftrace_event_call *call);
extern int reg_event_syscall_enter(struct ftrace_event_call *call);
extern void unreg_event_syscall_enter(struct ftrace_event_call *call);
extern int reg_event_syscall_exit(struct ftrace_event_call *call);
extern void unreg_event_syscall_exit(struct ftrace_event_call *call);
extern int
ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s);
enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags);
enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags);
#endif
+84 −37
Original line number Diff line number Diff line
@@ -27,8 +27,8 @@ DEFINE_MUTEX(event_mutex);

LIST_HEAD(ftrace_events);

int trace_define_field(struct ftrace_event_call *call, const char *type,
		       const char *name, int offset, int size, int is_signed,
int trace_define_field(struct ftrace_event_call *call, char *type,
		       char *name, int offset, int size, int is_signed,
		       int filter_type)
{
	struct ftrace_event_field *field;
@@ -92,9 +92,7 @@ int trace_define_common_fields(struct ftrace_event_call *call)
}
EXPORT_SYMBOL_GPL(trace_define_common_fields);

#ifdef CONFIG_MODULES

static void trace_destroy_fields(struct ftrace_event_call *call)
void trace_destroy_fields(struct ftrace_event_call *call)
{
	struct ftrace_event_field *field, *next;

@@ -106,8 +104,6 @@ static void trace_destroy_fields(struct ftrace_event_call *call)
	}
}

#endif /* CONFIG_MODULES */

static void ftrace_event_enable_disable(struct ftrace_event_call *call,
					int enable)
{
@@ -116,14 +112,14 @@ static void ftrace_event_enable_disable(struct ftrace_event_call *call,
		if (call->enabled) {
			call->enabled = 0;
			tracing_stop_cmdline_record();
			call->unregfunc(call->data);
			call->unregfunc(call);
		}
		break;
	case 1:
		if (!call->enabled) {
			call->enabled = 1;
			tracing_start_cmdline_record();
			call->regfunc(call->data);
			call->regfunc(call);
		}
		break;
	}
@@ -991,27 +987,43 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
	return 0;
}

#define for_each_event(event, start, end)			\
	for (event = start;					\
	     (unsigned long)event < (unsigned long)end;		\
	     event++)
static int __trace_add_event_call(struct ftrace_event_call *call)
{
	struct dentry *d_events;
	int ret;

#ifdef CONFIG_MODULES
	if (!call->name)
		return -EINVAL;

static LIST_HEAD(ftrace_module_file_list);
	if (call->raw_init) {
		ret = call->raw_init(call);
		if (ret < 0) {
			if (ret != -ENOSYS)
				pr_warning("Could not initialize trace "
				"events/%s\n", call->name);
			return ret;
		}
	}

/*
 * Modules must own their file_operations to keep up with
 * reference counting.
 */
struct ftrace_module_file_ops {
	struct list_head		list;
	struct module			*mod;
	struct file_operations		id;
	struct file_operations		enable;
	struct file_operations		format;
	struct file_operations		filter;
};
	d_events = event_trace_events_dir();
	if (!d_events)
		return -ENOENT;

	list_add(&call->list, &ftrace_events);
	return event_create_dir(call, d_events, &ftrace_event_id_fops,
				&ftrace_enable_fops, &ftrace_event_filter_fops,
				&ftrace_event_format_fops);
}

/* Add an additional event_call dynamically */
int trace_add_event_call(struct ftrace_event_call *call)
{
	int ret;
	mutex_lock(&event_mutex);
	ret = __trace_add_event_call(call);
	mutex_unlock(&event_mutex);
	return ret;
}

static void remove_subsystem_dir(const char *name)
{
@@ -1039,6 +1051,48 @@ static void remove_subsystem_dir(const char *name)
	}
}

static void __trace_remove_event_call(struct ftrace_event_call *call)
{
	ftrace_event_enable_disable(call, 0);
	if (call->event)
		__unregister_ftrace_event(call->event);
	debugfs_remove_recursive(call->dir);
	list_del(&call->list);
	trace_destroy_fields(call);
	destroy_preds(call);
	remove_subsystem_dir(call->system);
}

/* Remove an event_call */
void trace_remove_event_call(struct ftrace_event_call *call)
{
	mutex_lock(&event_mutex);
	__trace_remove_event_call(call);
	mutex_unlock(&event_mutex);
}

#define for_each_event(event, start, end)			\
	for (event = start;					\
	     (unsigned long)event < (unsigned long)end;		\
	     event++)

#ifdef CONFIG_MODULES

static LIST_HEAD(ftrace_module_file_list);

/*
 * Modules must own their file_operations to keep up with
 * reference counting.
 */
struct ftrace_module_file_ops {
	struct list_head		list;
	struct module			*mod;
	struct file_operations		id;
	struct file_operations		enable;
	struct file_operations		format;
	struct file_operations		filter;
};

static struct ftrace_module_file_ops *
trace_create_file_ops(struct module *mod)
{
@@ -1096,7 +1150,7 @@ static void trace_module_add_events(struct module *mod)
		if (!call->name)
			continue;
		if (call->raw_init) {
			ret = call->raw_init();
			ret = call->raw_init(call);
			if (ret < 0) {
				if (ret != -ENOSYS)
					pr_warning("Could not initialize trace "
@@ -1131,14 +1185,7 @@ static void trace_module_remove_events(struct module *mod)
	list_for_each_entry_safe(call, p, &ftrace_events, list) {
		if (call->mod == mod) {
			found = true;
			ftrace_event_enable_disable(call, 0);
			if (call->event)
				__unregister_ftrace_event(call->event);
			debugfs_remove_recursive(call->dir);
			list_del(&call->list);
			trace_destroy_fields(call);
			destroy_preds(call);
			remove_subsystem_dir(call->system);
			__trace_remove_event_call(call);
		}
	}

@@ -1256,7 +1303,7 @@ static __init int event_trace_init(void)
		if (!call->name)
			continue;
		if (call->raw_init) {
			ret = call->raw_init();
			ret = call->raw_init(call);
			if (ret < 0) {
				if (ret != -ENOSYS)
					pr_warning("Could not initialize trace "
Loading