lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1304088194-6214-2-git-send-email-jolsa@redhat.com>
Date:	Fri, 29 Apr 2011 16:43:12 +0200
From:	Jiri Olsa <jolsa@...hat.com>
To:	rostedt@...dmis.org, fweisbec@...il.com
Cc:	linux-kernel@...r.kernel.org
Subject: [RFC 1/3] tracing: function tracer registration

adding ID and default tracer support for function
tracer registration

---
 arch/x86/include/asm/ftrace.h     |    2 +
 arch/x86/kernel/entry_64.S        |    6 +-
 arch/x86/kernel/ftrace.c          |   13 --
 include/linux/ftrace.h            |    9 +-
 kernel/trace/ftrace.c             |  290 +++++++++++++++----------------------
 kernel/trace/trace_events.c       |    1 +
 kernel/trace/trace_functions.c    |    2 +
 kernel/trace/trace_irqsoff.c      |    1 +
 kernel/trace/trace_sched_wakeup.c |    1 +
 kernel/trace/trace_stack.c        |    1 +
 10 files changed, 136 insertions(+), 190 deletions(-)

diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index db24c22..45ae1fa 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_X86_FTRACE_H
 #define _ASM_X86_FTRACE_H
 
+#define FTRACE_TRACERS_MAX 4
+
 #ifdef __ASSEMBLY__
 
 	.macro MCOUNT_SAVE_FRAME
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 8a445a0..e0ba7d9 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -79,8 +79,10 @@ ENTRY(ftrace_caller)
 	movq 8(%rbp), %rsi
 	subq $MCOUNT_INSN_SIZE, %rdi
 
-GLOBAL(ftrace_call)
-	call ftrace_stub
+	/* by default call all registered handlers */
+	movq $-1, %rdx
+
+	call ftrace_call
 
 	MCOUNT_RESTORE_FRAME
 
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 0ba15a6..dc92378 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -321,19 +321,6 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 	return ftrace_modify_code(rec->ip, old, new);
 }
 
-int ftrace_update_ftrace_func(ftrace_func_t func)
-{
-	unsigned long ip = (unsigned long)(&ftrace_call);
-	unsigned char old[MCOUNT_INSN_SIZE], *new;
-	int ret;
-
-	memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
-	new = ftrace_call_replace(ip, (unsigned long)func);
-	ret = ftrace_modify_code(ip, old, new);
-
-	return ret;
-}
-
 int __init ftrace_dyn_arch_init(void *data)
 {
 	/* The return code is retured via data */
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index ca29e03..b7ab09d 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -30,8 +30,9 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);
 
 struct ftrace_ops {
-	ftrace_func_t	  func;
-	struct ftrace_ops *next;
+	char *name;
+	int   id;
+	ftrace_func_t func;
 };
 
 extern int function_trace_stop;
@@ -175,9 +176,9 @@ int unregister_ftrace_command(struct ftrace_func_command *cmd);
 /* defined in arch */
 extern int ftrace_ip_converted(unsigned long ip);
 extern int ftrace_dyn_arch_init(void *data);
-extern int ftrace_update_ftrace_func(ftrace_func_t func);
 extern void ftrace_caller(void);
-extern void ftrace_call(void);
+extern void ftrace_call(unsigned long ip, unsigned long parent_ip,
+			unsigned long flags);
 extern void mcount_call(void);
 
 #ifndef FTRACE_ADDR
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index ee24fa1..f1eedda 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -76,62 +76,12 @@ static int ftrace_disabled __read_mostly;
 
 static DEFINE_MUTEX(ftrace_lock);
 
-static struct ftrace_ops ftrace_list_end __read_mostly =
-{
-	.func		= ftrace_stub,
-};
-
-static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end;
-ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
-ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub;
-ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
-
-/*
- * Traverse the ftrace_list, invoking all entries.  The reason that we
- * can use rcu_dereference_raw() is that elements removed from this list
- * are simply leaked, so there is no need to interact with a grace-period
- * mechanism.  The rcu_dereference_raw() calls are needed to handle
- * concurrent insertions into the ftrace_list.
- *
- * Silly Alpha and silly pointer-speculation compiler optimizations!
- */
-static void ftrace_list_func(unsigned long ip, unsigned long parent_ip)
-{
-	struct ftrace_ops *op = rcu_dereference_raw(ftrace_list); /*see above*/
-
-	while (op != &ftrace_list_end) {
-		op->func(ip, parent_ip);
-		op = rcu_dereference_raw(op->next); /*see above*/
-	};
-}
-
-static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip)
-{
-	if (!test_tsk_trace_trace(current))
-		return;
-
-	ftrace_pid_function(ip, parent_ip);
-}
+static struct ftrace_ops *ftrace_tracers[FTRACE_TRACERS_MAX];
+static DECLARE_BITMAP(ftrace_tracers_bm, FTRACE_TRACERS_MAX);
+static int ftrace_tracers_cur = -1;
 
-static void set_ftrace_pid_function(ftrace_func_t func)
-{
-	/* do not set ftrace_pid_function to itself! */
-	if (func != ftrace_pid_func)
-		ftrace_pid_function = func;
-}
-
-/**
- * clear_ftrace_function - reset the ftrace function
- *
- * This NULLs the ftrace function and in essence stops
- * tracing.  There may be lag
- */
-void clear_ftrace_function(void)
-{
-	ftrace_trace_function = ftrace_stub;
-	__ftrace_trace_function = ftrace_stub;
-	ftrace_pid_function = ftrace_stub;
-}
+#define for_each_tracer(id, bm) \
+	for_each_set_bit(id, bm, FTRACE_TRACERS_MAX)
 
 #ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
 /*
@@ -147,114 +97,82 @@ static void ftrace_test_stop_func(unsigned long ip, unsigned long parent_ip)
 }
 #endif
 
-static int __register_ftrace_function(struct ftrace_ops *ops)
-{
-	ops->next = ftrace_list;
-	/*
-	 * We are entering ops into the ftrace_list but another
-	 * CPU might be walking that list. We need to make sure
-	 * the ops->next pointer is valid before another CPU sees
-	 * the ops pointer included into the ftrace_list.
-	 */
-	rcu_assign_pointer(ftrace_list, ops);
 
-	if (ftrace_enabled) {
-		ftrace_func_t func;
+void ftrace_call(unsigned long ip, unsigned long parent_ip,
+		 unsigned long flags)
+{
+	int id;
 
-		if (ops->next == &ftrace_list_end)
-			func = ops->func;
-		else
-			func = ftrace_list_func;
+	if (!list_empty(&ftrace_pids) &&
+	    !test_tsk_trace_trace(current))
+		return;
 
-		if (!list_empty(&ftrace_pids)) {
-			set_ftrace_pid_function(func);
-			func = ftrace_pid_func;
-		}
+	rcu_read_lock();
+	for_each_tracer(id, &flags) {
+		struct ftrace_ops *ops = rcu_dereference(ftrace_tracers[id]);
+		if (!ops)
+			continue;
 
-		/*
-		 * For one func, simply call it directly.
-		 * For more than one func, call the chain.
-		 */
-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-		ftrace_trace_function = func;
-#else
-		__ftrace_trace_function = func;
-		ftrace_trace_function = ftrace_test_stop_func;
-#endif
+		ops->func(ip, parent_ip);
 	}
-
-	return 0;
+	rcu_read_unlock();
 }
 
-static int __unregister_ftrace_function(struct ftrace_ops *ops)
+static int __register_ftrace_function(struct ftrace_ops *ops)
 {
-	struct ftrace_ops **p;
+	int id;
 
-	/*
-	 * If we are removing the last function, then simply point
-	 * to the ftrace_stub.
-	 */
-	if (ftrace_list == ops && ops->next == &ftrace_list_end) {
-		ftrace_trace_function = ftrace_stub;
-		ftrace_list = &ftrace_list_end;
-		return 0;
-	}
+	id = find_first_zero_bit(ftrace_tracers_bm, FTRACE_TRACERS_MAX);
+	if (id >= FTRACE_TRACERS_MAX)
+		return -ENOSPC;
 
-	for (p = &ftrace_list; *p != &ftrace_list_end; p = &(*p)->next)
-		if (*p == ops)
-			break;
+	ops->id = id;
+	set_bit(id, ftrace_tracers_bm);
+	ftrace_tracers_cur = id;
+	rcu_assign_pointer(ftrace_tracers[id], ops);
+	return 0;
+}
 
-	if (*p != ops)
-		return -1;
+static int __unregister_ftrace_function(struct ftrace_ops *ops)
+{
+	int id = ops->id;
 
-	*p = (*p)->next;
+	clear_bit(id, ftrace_tracers_bm);
+	BUG_ON(ops != ftrace_tracers[id]);
+	rcu_assign_pointer(ftrace_tracers[id], NULL);
 
-	if (ftrace_enabled) {
-		/* If we only have one func left, then call that directly */
-		if (ftrace_list->next == &ftrace_list_end) {
-			ftrace_func_t func = ftrace_list->func;
+	if (ftrace_tracers_cur != id)
+		return 0;
 
-			if (!list_empty(&ftrace_pids)) {
-				set_ftrace_pid_function(func);
-				func = ftrace_pid_func;
-			}
-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-			ftrace_trace_function = func;
-#else
-			__ftrace_trace_function = func;
-#endif
-		}
-	}
+	/* find another default tracer */
+	ftrace_tracers_cur = find_first_bit(ftrace_tracers_bm,
+					    FTRACE_TRACERS_MAX);
+	if (ftrace_tracers_cur >= FTRACE_TRACERS_MAX)
+		ftrace_tracers_cur = -1;
 
 	return 0;
 }
 
-static void ftrace_update_pid_func(void)
+static int ftrace_tracer_default(char *name)
 {
-	ftrace_func_t func;
+	int id, ret = -EINVAL;
 
-	if (ftrace_trace_function == ftrace_stub)
-		return;
+	mutex_lock(&ftrace_lock);
+	for_each_tracer(id, ftrace_tracers_bm) {
+		struct ftrace_ops *ops = ftrace_tracers[id];
+		BUG_ON(!ops);
 
-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-	func = ftrace_trace_function;
-#else
-	func = __ftrace_trace_function;
-#endif
+		if (!strcmp(name, ops->name))
+			break;
+	}
 
-	if (!list_empty(&ftrace_pids)) {
-		set_ftrace_pid_function(func);
-		func = ftrace_pid_func;
-	} else {
-		if (func == ftrace_pid_func)
-			func = ftrace_pid_function;
+	if (id < FTRACE_TRACERS_MAX) {
+		ftrace_tracers_cur = id;
+		ret = 0;
 	}
 
-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-	ftrace_trace_function = func;
-#else
-	__ftrace_trace_function = func;
-#endif
+	mutex_unlock(&ftrace_lock);
+	return ret;
 }
 
 #ifdef CONFIG_FUNCTION_PROFILER
@@ -717,6 +635,7 @@ static void unregister_ftrace_profiler(void)
 #else
 static struct ftrace_ops ftrace_profile_ops __read_mostly =
 {
+	.name		= "trace_profile",
 	.func		= function_profile_call,
 };
 
@@ -1143,9 +1062,6 @@ static int __ftrace_modify_code(void *data)
 	else if (*command & FTRACE_DISABLE_CALLS)
 		ftrace_replace_code(0);
 
-	if (*command & FTRACE_UPDATE_TRACE_FUNC)
-		ftrace_update_ftrace_func(ftrace_trace_function);
-
 	if (*command & FTRACE_START_FUNC_RET)
 		ftrace_enable_ftrace_graph_caller();
 	else if (*command & FTRACE_STOP_FUNC_RET)
@@ -1174,11 +1090,6 @@ static int ftrace_start_up;
 
 static void ftrace_startup_enable(int command)
 {
-	if (saved_ftrace_func != ftrace_trace_function) {
-		saved_ftrace_func = ftrace_trace_function;
-		command |= FTRACE_UPDATE_TRACE_FUNC;
-	}
-
 	if (!command || !ftrace_enabled)
 		return;
 
@@ -1212,11 +1123,6 @@ static void ftrace_shutdown(int command)
 	if (!ftrace_start_up)
 		command |= FTRACE_DISABLE_CALLS;
 
-	if (saved_ftrace_func != ftrace_trace_function) {
-		saved_ftrace_func = ftrace_trace_function;
-		command |= FTRACE_UPDATE_TRACE_FUNC;
-	}
-
 	if (!command || !ftrace_enabled)
 		return;
 
@@ -1732,6 +1638,53 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin)
 	return ret;
 }
 
+static int ftrace_tracers_show(struct seq_file *seq, void *v)
+{
+	int id;
+
+	mutex_lock(&ftrace_lock);
+	for_each_tracer(id, ftrace_tracers_bm) {
+		struct ftrace_ops *ops = ftrace_tracers[id];
+
+		BUG_ON(!ops);
+		seq_printf(seq, "%s%s\n",
+			ftrace_tracers_cur == id ? "*" : " ",
+			ops->name);
+	}
+
+	mutex_unlock(&ftrace_lock);
+	return 0;
+}
+
+static int
+ftrace_tracers_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ftrace_tracers_show, NULL);
+}
+
+static ssize_t
+ftrace_tracers_write(struct file *filp, const char __user *ubuf, size_t cnt,
+		     loff_t *ppos)
+{
+	char buf[64];
+	int i;
+
+	if (cnt >= sizeof(buf))
+		return -EINVAL;
+
+	if (copy_from_user(&buf, ubuf, cnt))
+		return -EFAULT;
+
+	buf[cnt] = 0;
+	for (i = cnt - 1; i > 0 && isspace(buf[i]); i--)
+		buf[i] = 0;
+
+	if (ftrace_tracer_default(buf))
+		return -EINVAL;
+
+	return cnt;
+}
+
 static int ftrace_match(char *str, char *regex, int len, int type)
 {
 	int matched = 0;
@@ -1952,6 +1905,7 @@ function_trace_probe_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_probe_ops __read_mostly =
 {
+	.name		= "trace_probe",
 	.func		= function_trace_probe_call,
 };
 
@@ -2467,6 +2421,14 @@ static const struct file_operations ftrace_notrace_fops = {
 	.release = ftrace_notrace_release,
 };
 
+static const struct file_operations ftrace_tracers_fops = {
+	.open		= ftrace_tracers_open,
+	.read		= seq_read,
+	.release	= single_release,
+	.llseek		= seq_lseek,
+	.write          = ftrace_tracers_write,
+};
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
 static DEFINE_MUTEX(graph_lock);
@@ -2688,6 +2650,9 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
 	trace_create_file("set_ftrace_notrace", 0644, d_tracer,
 				    NULL, &ftrace_notrace_fops);
 
+	trace_create_file("function_tracers", 0644, d_tracer,
+				    NULL, &ftrace_tracers_fops);
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 	trace_create_file("set_graph_function", 0444, d_tracer,
 				    NULL,
@@ -2950,7 +2915,6 @@ static int ftrace_pid_add(int p)
 
 	set_ftrace_pid_task(pid);
 
-	ftrace_update_pid_func();
 	ftrace_startup_enable(0);
 
 	mutex_unlock(&ftrace_lock);
@@ -2979,7 +2943,6 @@ static void ftrace_pid_reset(void)
 		kfree(fpid);
 	}
 
-	ftrace_update_pid_func();
 	ftrace_startup_enable(0);
 
 	mutex_unlock(&ftrace_lock);
@@ -3127,7 +3090,6 @@ void ftrace_kill(void)
 {
 	ftrace_disabled = 1;
 	ftrace_enabled = 0;
-	clear_ftrace_function();
 }
 
 /**
@@ -3194,24 +3156,10 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 
 	last_ftrace_enabled = !!ftrace_enabled;
 
-	if (ftrace_enabled) {
-
+	if (ftrace_enabled)
 		ftrace_startup_sysctl();
-
-		/* we are starting ftrace again */
-		if (ftrace_list != &ftrace_list_end) {
-			if (ftrace_list->next == &ftrace_list_end)
-				ftrace_trace_function = ftrace_list->func;
-			else
-				ftrace_trace_function = ftrace_list_func;
-		}
-
-	} else {
-		/* stopping ftrace calls (just send to ftrace_stub) */
-		ftrace_trace_function = ftrace_stub;
-
+	else
 		ftrace_shutdown_sysctl();
-	}
 
  out:
 	mutex_unlock(&ftrace_lock);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index e88f74f..43600a1 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1651,6 +1651,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __initdata  =
 {
+	.name = "trace_event",
 	.func = function_test_events_call,
 };
 
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 16aee4d..a991743 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -148,11 +148,13 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __read_mostly =
 {
+	.name = "trace",
 	.func = function_trace_call,
 };
 
 static struct ftrace_ops trace_stack_ops __read_mostly =
 {
+	.name = "trace_stack",
 	.func = function_stack_trace_call,
 };
 
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index a4969b4..6983594 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -152,6 +152,7 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __read_mostly =
 {
+	.name = "trace_irqs",
 	.func = irqsoff_tracer_call,
 };
 #endif /* CONFIG_FUNCTION_TRACER */
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index 7319559..f8b4622 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -128,6 +128,7 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __read_mostly =
 {
+	.name = "trace_wakeup",
 	.func = wakeup_tracer_call,
 };
 #endif /* CONFIG_FUNCTION_TRACER */
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 4c5dead..31f361e 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -132,6 +132,7 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __read_mostly =
 {
+	.name = "trace_stack",
 	.func = stack_trace_call,
 };
 
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ