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

Commit ac07bcaa authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'tip/tracing/ftrace' of...

Merge branch 'tip/tracing/ftrace' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into tracing/ftrace
parents 37bd824a 35ebf1ca
Loading
Loading
Loading
Loading
+6 −6
Original line number Original line Diff line number Diff line
@@ -108,7 +108,7 @@ struct ftrace_func_command {


struct seq_file;
struct seq_file;


struct ftrace_hook_ops {
struct ftrace_probe_ops {
	void			(*func)(unsigned long ip,
	void			(*func)(unsigned long ip,
					unsigned long parent_ip,
					unsigned long parent_ip,
					void **data);
					void **data);
@@ -116,19 +116,19 @@ struct ftrace_hook_ops {
	void			(*free)(void **data);
	void			(*free)(void **data);
	int			(*print)(struct seq_file *m,
	int			(*print)(struct seq_file *m,
					 unsigned long ip,
					 unsigned long ip,
					 struct ftrace_hook_ops *ops,
					 struct ftrace_probe_ops *ops,
					 void *data);
					 void *data);
};
};


extern int
extern int
register_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
			      void *data);
			      void *data);
extern void
extern void
unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
				void *data);
				void *data);
extern void
extern void
unregister_ftrace_function_hook_func(char *glob, struct ftrace_hook_ops *ops);
unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops);
extern void unregister_ftrace_function_hook_all(char *glob);
extern void unregister_ftrace_function_probe_all(char *glob);


enum {
enum {
	FTRACE_FL_FREE		= (1 << 0),
	FTRACE_FL_FREE		= (1 << 0),
+52 −50
Original line number Original line Diff line number Diff line
@@ -255,9 +255,9 @@ static struct pid * const ftrace_swapper_pid = &init_struct_pid;


static struct hlist_head ftrace_func_hash[FTRACE_FUNC_HASHSIZE] __read_mostly;
static struct hlist_head ftrace_func_hash[FTRACE_FUNC_HASHSIZE] __read_mostly;


struct ftrace_func_hook {
struct ftrace_func_probe {
	struct hlist_node	node;
	struct hlist_node	node;
	struct ftrace_hook_ops	*ops;
	struct ftrace_probe_ops	*ops;
	unsigned long		flags;
	unsigned long		flags;
	unsigned long		ip;
	unsigned long		ip;
	void			*data;
	void			*data;
@@ -460,8 +460,8 @@ static void ftrace_bug(int failed, unsigned long ip)
static int
static int
__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
{
{
	unsigned long ip, fl;
	unsigned long ftrace_addr;
	unsigned long ftrace_addr;
	unsigned long ip, fl;


	ftrace_addr = (unsigned long)FTRACE_ADDR;
	ftrace_addr = (unsigned long)FTRACE_ADDR;


@@ -530,9 +530,9 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)


static void ftrace_replace_code(int enable)
static void ftrace_replace_code(int enable)
{
{
	int failed;
	struct dyn_ftrace *rec;
	struct dyn_ftrace *rec;
	struct ftrace_page *pg;
	struct ftrace_page *pg;
	int failed;


	do_for_each_ftrace_rec(pg, rec) {
	do_for_each_ftrace_rec(pg, rec) {
		/*
		/*
@@ -830,11 +830,11 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos)


static int t_hash_show(struct seq_file *m, void *v)
static int t_hash_show(struct seq_file *m, void *v)
{
{
	struct ftrace_func_hook *rec;
	struct ftrace_func_probe *rec;
	struct hlist_node *hnd = v;
	struct hlist_node *hnd = v;
	char str[KSYM_SYMBOL_LEN];
	char str[KSYM_SYMBOL_LEN];


	rec = hlist_entry(hnd, struct ftrace_func_hook, node);
	rec = hlist_entry(hnd, struct ftrace_func_probe, node);


	if (rec->ops->print)
	if (rec->ops->print)
		return rec->ops->print(m, rec->ip, rec->ops, rec->data);
		return rec->ops->print(m, rec->ip, rec->ops, rec->data);
@@ -1208,14 +1208,15 @@ ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type)


static void ftrace_match_records(char *buff, int len, int enable)
static void ftrace_match_records(char *buff, int len, int enable)
{
{
	char *search;
	unsigned int search_len;
	struct ftrace_page *pg;
	struct ftrace_page *pg;
	struct dyn_ftrace *rec;
	struct dyn_ftrace *rec;
	unsigned long flag;
	char *search;
	int type;
	int type;
	unsigned long flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
	unsigned search_len;
	int not;
	int not;


	flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
	type = ftrace_setup_glob(buff, len, &search, &not);
	type = ftrace_setup_glob(buff, len, &search, &not);


	search_len = strlen(search);
	search_len = strlen(search);
@@ -1263,14 +1264,16 @@ ftrace_match_module_record(struct dyn_ftrace *rec, char *mod,


static void ftrace_match_module_records(char *buff, char *mod, int enable)
static void ftrace_match_module_records(char *buff, char *mod, int enable)
{
{
	char *search = buff;
	unsigned search_len = 0;
	struct ftrace_page *pg;
	struct ftrace_page *pg;
	struct dyn_ftrace *rec;
	struct dyn_ftrace *rec;
	int type = MATCH_FULL;
	int type = MATCH_FULL;
	unsigned long flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
	char *search = buff;
	unsigned search_len = 0;
	unsigned long flag;
	int not = 0;
	int not = 0;


	flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;

	/* blank or '*' mean the same */
	/* blank or '*' mean the same */
	if (strcmp(buff, "*") == 0)
	if (strcmp(buff, "*") == 0)
		buff[0] = 0;
		buff[0] = 0;
@@ -1348,9 +1351,9 @@ static int __init ftrace_mod_cmd_init(void)
device_initcall(ftrace_mod_cmd_init);
device_initcall(ftrace_mod_cmd_init);


static void
static void
function_trace_hook_call(unsigned long ip, unsigned long parent_ip)
function_trace_probe_call(unsigned long ip, unsigned long parent_ip)
{
{
	struct ftrace_func_hook *entry;
	struct ftrace_func_probe *entry;
	struct hlist_head *hhd;
	struct hlist_head *hhd;
	struct hlist_node *n;
	struct hlist_node *n;
	unsigned long key;
	unsigned long key;
@@ -1376,18 +1379,18 @@ function_trace_hook_call(unsigned long ip, unsigned long parent_ip)
	ftrace_preempt_enable(resched);
	ftrace_preempt_enable(resched);
}
}


static struct ftrace_ops trace_hook_ops __read_mostly =
static struct ftrace_ops trace_probe_ops __read_mostly =
{
{
	.func = function_trace_hook_call,
	.func = function_trace_probe_call,
};
};


static int ftrace_hook_registered;
static int ftrace_probe_registered;


static void __enable_ftrace_function_hook(void)
static void __enable_ftrace_function_probe(void)
{
{
	int i;
	int i;


	if (ftrace_hook_registered)
	if (ftrace_probe_registered)
		return;
		return;


	for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
	for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
@@ -1399,16 +1402,16 @@ static void __enable_ftrace_function_hook(void)
	if (i == FTRACE_FUNC_HASHSIZE)
	if (i == FTRACE_FUNC_HASHSIZE)
		return;
		return;


	__register_ftrace_function(&trace_hook_ops);
	__register_ftrace_function(&trace_probe_ops);
	ftrace_startup(0);
	ftrace_startup(0);
	ftrace_hook_registered = 1;
	ftrace_probe_registered = 1;
}
}


static void __disable_ftrace_function_hook(void)
static void __disable_ftrace_function_probe(void)
{
{
	int i;
	int i;


	if (!ftrace_hook_registered)
	if (!ftrace_probe_registered)
		return;
		return;


	for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
	for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
@@ -1418,16 +1421,16 @@ static void __disable_ftrace_function_hook(void)
	}
	}


	/* no more funcs left */
	/* no more funcs left */
	__unregister_ftrace_function(&trace_hook_ops);
	__unregister_ftrace_function(&trace_probe_ops);
	ftrace_shutdown(0);
	ftrace_shutdown(0);
	ftrace_hook_registered = 0;
	ftrace_probe_registered = 0;
}
}




static void ftrace_free_entry_rcu(struct rcu_head *rhp)
static void ftrace_free_entry_rcu(struct rcu_head *rhp)
{
{
	struct ftrace_func_hook *entry =
	struct ftrace_func_probe *entry =
		container_of(rhp, struct ftrace_func_hook, rcu);
		container_of(rhp, struct ftrace_func_probe, rcu);


	if (entry->ops->free)
	if (entry->ops->free)
		entry->ops->free(&entry->data);
		entry->ops->free(&entry->data);
@@ -1436,21 +1439,21 @@ static void ftrace_free_entry_rcu(struct rcu_head *rhp)




int
int
register_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
			      void *data)
			      void *data)
{
{
	struct ftrace_func_hook *entry;
	struct ftrace_func_probe *entry;
	struct ftrace_page *pg;
	struct ftrace_page *pg;
	struct dyn_ftrace *rec;
	struct dyn_ftrace *rec;
	unsigned long key;
	int type, len, not;
	int type, len, not;
	unsigned long key;
	int count = 0;
	int count = 0;
	char *search;
	char *search;


	type = ftrace_setup_glob(glob, strlen(glob), &search, &not);
	type = ftrace_setup_glob(glob, strlen(glob), &search, &not);
	len = strlen(search);
	len = strlen(search);


	/* we do not support '!' for function hooks */
	/* we do not support '!' for function probes */
	if (WARN_ON(not))
	if (WARN_ON(not))
		return -EINVAL;
		return -EINVAL;


@@ -1465,7 +1468,7 @@ register_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,


		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
		if (!entry) {
		if (!entry) {
			/* If we did not hook to any, then return error */
			/* If we did not process any, then return error */
			if (!count)
			if (!count)
				count = -ENOMEM;
				count = -ENOMEM;
			goto out_unlock;
			goto out_unlock;
@@ -1495,7 +1498,7 @@ register_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
		hlist_add_head_rcu(&entry->node, &ftrace_func_hash[key]);
		hlist_add_head_rcu(&entry->node, &ftrace_func_hash[key]);


	} while_for_each_ftrace_rec();
	} while_for_each_ftrace_rec();
	__enable_ftrace_function_hook();
	__enable_ftrace_function_probe();


 out_unlock:
 out_unlock:
	mutex_unlock(&ftrace_lock);
	mutex_unlock(&ftrace_lock);
@@ -1504,15 +1507,15 @@ register_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
}
}


enum {
enum {
	HOOK_TEST_FUNC		= 1,
	PROBE_TEST_FUNC		= 1,
	HOOK_TEST_DATA		= 2
	PROBE_TEST_DATA		= 2
};
};


static void
static void
__unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
__unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
				  void *data, int flags)
				  void *data, int flags)
{
{
	struct ftrace_func_hook *entry;
	struct ftrace_func_probe *entry;
	struct hlist_node *n, *tmp;
	struct hlist_node *n, *tmp;
	char str[KSYM_SYMBOL_LEN];
	char str[KSYM_SYMBOL_LEN];
	int type = MATCH_FULL;
	int type = MATCH_FULL;
@@ -1527,7 +1530,7 @@ __unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
		type = ftrace_setup_glob(glob, strlen(glob), &search, &not);
		type = ftrace_setup_glob(glob, strlen(glob), &search, &not);
		len = strlen(search);
		len = strlen(search);


		/* we do not support '!' for function hooks */
		/* we do not support '!' for function probes */
		if (WARN_ON(not))
		if (WARN_ON(not))
			return;
			return;
	}
	}
@@ -1539,10 +1542,10 @@ __unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
		hlist_for_each_entry_safe(entry, n, tmp, hhd, node) {
		hlist_for_each_entry_safe(entry, n, tmp, hhd, node) {


			/* break up if statements for readability */
			/* break up if statements for readability */
			if ((flags & HOOK_TEST_FUNC) && entry->ops != ops)
			if ((flags & PROBE_TEST_FUNC) && entry->ops != ops)
				continue;
				continue;


			if ((flags & HOOK_TEST_DATA) && entry->data != data)
			if ((flags & PROBE_TEST_DATA) && entry->data != data)
				continue;
				continue;


			/* do this last, since it is the most expensive */
			/* do this last, since it is the most expensive */
@@ -1557,27 +1560,27 @@ __unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
			call_rcu(&entry->rcu, ftrace_free_entry_rcu);
			call_rcu(&entry->rcu, ftrace_free_entry_rcu);
		}
		}
	}
	}
	__disable_ftrace_function_hook();
	__disable_ftrace_function_probe();
	mutex_unlock(&ftrace_lock);
	mutex_unlock(&ftrace_lock);
}
}


void
void
unregister_ftrace_function_hook(char *glob, struct ftrace_hook_ops *ops,
unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
				void *data)
				void *data)
{
{
	__unregister_ftrace_function_hook(glob, ops, data,
	__unregister_ftrace_function_probe(glob, ops, data,
					  HOOK_TEST_FUNC | HOOK_TEST_DATA);
					  PROBE_TEST_FUNC | PROBE_TEST_DATA);
}
}


void
void
unregister_ftrace_function_hook_func(char *glob, struct ftrace_hook_ops *ops)
unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops)
{
{
	__unregister_ftrace_function_hook(glob, ops, NULL, HOOK_TEST_FUNC);
	__unregister_ftrace_function_probe(glob, ops, NULL, PROBE_TEST_FUNC);
}
}


void unregister_ftrace_function_hook_all(char *glob)
void unregister_ftrace_function_probe_all(char *glob)
{
{
	__unregister_ftrace_function_hook(glob, NULL, NULL, 0);
	__unregister_ftrace_function_probe(glob, NULL, NULL, 0);
}
}


static LIST_HEAD(ftrace_commands);
static LIST_HEAD(ftrace_commands);
@@ -1623,8 +1626,8 @@ int unregister_ftrace_command(struct ftrace_func_command *cmd)


static int ftrace_process_regex(char *buff, int len, int enable)
static int ftrace_process_regex(char *buff, int len, int enable)
{
{
	struct ftrace_func_command *p;
	char *func, *command, *next = buff;
	char *func, *command, *next = buff;
	struct ftrace_func_command *p;
	int ret = -EINVAL;
	int ret = -EINVAL;


	func = strsep(&next, ":");
	func = strsep(&next, ":");
@@ -2392,7 +2395,6 @@ static __init int ftrace_init_debugfs(void)
			   "'set_ftrace_pid' entry\n");
			   "'set_ftrace_pid' entry\n");
	return 0;
	return 0;
}
}

fs_initcall(ftrace_init_debugfs);
fs_initcall(ftrace_init_debugfs);


/**
/**
+1 −1
Original line number Original line Diff line number Diff line
@@ -336,7 +336,7 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
	data->rt_priority = tsk->rt_priority;
	data->rt_priority = tsk->rt_priority;


	/* record this tasks comm */
	/* record this tasks comm */
	tracing_record_cmdline(current);
	tracing_record_cmdline(tsk);
}
}


static void
static void
+16 −15
Original line number Original line Diff line number Diff line
@@ -269,21 +269,21 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)


static int
static int
ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
			 struct ftrace_hook_ops *ops, void *data);
			 struct ftrace_probe_ops *ops, void *data);


static struct ftrace_hook_ops traceon_hook_ops = {
static struct ftrace_probe_ops traceon_probe_ops = {
	.func			= ftrace_traceon,
	.func			= ftrace_traceon,
	.print			= ftrace_trace_onoff_print,
	.print			= ftrace_trace_onoff_print,
};
};


static struct ftrace_hook_ops traceoff_hook_ops = {
static struct ftrace_probe_ops traceoff_probe_ops = {
	.func			= ftrace_traceoff,
	.func			= ftrace_traceoff,
	.print			= ftrace_trace_onoff_print,
	.print			= ftrace_trace_onoff_print,
};
};


static int
static int
ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
			 struct ftrace_hook_ops *ops, void *data)
			 struct ftrace_probe_ops *ops, void *data)
{
{
	char str[KSYM_SYMBOL_LEN];
	char str[KSYM_SYMBOL_LEN];
	long count = (long)data;
	long count = (long)data;
@@ -291,12 +291,14 @@ ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
	kallsyms_lookup(ip, NULL, NULL, NULL, str);
	kallsyms_lookup(ip, NULL, NULL, NULL, str);
	seq_printf(m, "%s:", str);
	seq_printf(m, "%s:", str);


	if (ops == &traceon_hook_ops)
	if (ops == &traceon_probe_ops)
		seq_printf(m, "traceon");
		seq_printf(m, "traceon");
	else
	else
		seq_printf(m, "traceoff");
		seq_printf(m, "traceoff");


	if (count != -1)
	if (count == -1)
		seq_printf(m, ":unlimited\n");
	else
		seq_printf(m, ":count=%ld", count);
		seq_printf(m, ":count=%ld", count);
	seq_putc(m, '\n');
	seq_putc(m, '\n');


@@ -306,15 +308,15 @@ ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
static int
static int
ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param)
ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param)
{
{
	struct ftrace_hook_ops *ops;
	struct ftrace_probe_ops *ops;


	/* we register both traceon and traceoff to this callback */
	/* we register both traceon and traceoff to this callback */
	if (strcmp(cmd, "traceon") == 0)
	if (strcmp(cmd, "traceon") == 0)
		ops = &traceon_hook_ops;
		ops = &traceon_probe_ops;
	else
	else
		ops = &traceoff_hook_ops;
		ops = &traceoff_probe_ops;


	unregister_ftrace_function_hook_func(glob, ops);
	unregister_ftrace_function_probe_func(glob, ops);


	return 0;
	return 0;
}
}
@@ -322,7 +324,7 @@ ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param)
static int
static int
ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable)
ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable)
{
{
	struct ftrace_hook_ops *ops;
	struct ftrace_probe_ops *ops;
	void *count = (void *)-1;
	void *count = (void *)-1;
	char *number;
	char *number;
	int ret;
	int ret;
@@ -336,9 +338,9 @@ ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable)


	/* we register both traceon and traceoff to this callback */
	/* we register both traceon and traceoff to this callback */
	if (strcmp(cmd, "traceon") == 0)
	if (strcmp(cmd, "traceon") == 0)
		ops = &traceon_hook_ops;
		ops = &traceon_probe_ops;
	else
	else
		ops = &traceoff_hook_ops;
		ops = &traceoff_probe_ops;


	if (!param)
	if (!param)
		goto out_reg;
		goto out_reg;
@@ -357,7 +359,7 @@ ftrace_trace_onoff_callback(char *glob, char *cmd, char *param, int enable)
		return ret;
		return ret;


 out_reg:
 out_reg:
	ret = register_ftrace_function_hook(glob, ops, count);
	ret = register_ftrace_function_probe(glob, ops, count);


	return ret;
	return ret;
}
}
@@ -397,6 +399,5 @@ static __init int init_function_trace(void)
	init_func_cmd_traceon();
	init_func_cmd_traceon();
	return register_tracer(&function_trace);
	return register_tracer(&function_trace);
}
}

device_initcall(init_function_trace);
device_initcall(init_function_trace);
+1 −1
Original line number Original line Diff line number Diff line
/*
/*
 * trace irqs off criticall timings
 * trace irqs off critical timings
 *
 *
 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
 * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
 * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
Loading