From e1c08bdd9fa73e44096e5a82c0d5928b04ab02c8 Mon Sep 17 00:00:00 2001
From: Steven Rostedt <srostedt@redhat.com>
Date: Mon, 12 May 2008 21:20:44 +0200
Subject: ftrace: force recording

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/trace/ftrace.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

(limited to 'kernel/trace')

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 97d5cb7..4facf5c 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -146,6 +146,10 @@ static int notrace __unregister_ftrace_function(struct ftrace_ops *ops)
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
+static struct task_struct *ftraced_task;
+static DECLARE_WAIT_QUEUE_HEAD(ftraced_waiters);
+static unsigned long ftraced_iteration_counter;
+
 enum {
 	FTRACE_ENABLE_CALLS		= (1 << 0),
 	FTRACE_DISABLE_CALLS		= (1 << 1),
@@ -590,9 +594,12 @@ static int notrace ftraced(void *ignore)
 			ftraced_trigger = 0;
 			ftrace_record_suspend--;
 		}
+		ftraced_iteration_counter++;
 		mutex_unlock(&ftraced_lock);
 		mutex_unlock(&ftrace_sysctl_lock);
 
+		wake_up_interruptible(&ftraced_waiters);
+
 		ftrace_shutdown_replenish();
 
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -1050,6 +1057,49 @@ static struct file_operations ftrace_filter_fops = {
 	.release = ftrace_filter_release,
 };
 
+/**
+ * ftrace_force_update - force an update to all recording ftrace functions
+ *
+ * The ftrace dynamic update daemon only wakes up once a second.
+ * There may be cases where an update needs to be done immediately
+ * for tests or internal kernel tracing to begin. This function
+ * wakes the daemon to do an update and will not return until the
+ * update is complete.
+ */
+int ftrace_force_update(void)
+{
+	unsigned long last_counter;
+	DECLARE_WAITQUEUE(wait, current);
+	int ret = 0;
+
+	if (!ftraced_task)
+		return -ENODEV;
+
+	mutex_lock(&ftraced_lock);
+	last_counter = ftraced_iteration_counter;
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&ftraced_waiters, &wait);
+
+	do {
+		mutex_unlock(&ftraced_lock);
+		wake_up_process(ftraced_task);
+		schedule();
+		mutex_lock(&ftraced_lock);
+		if (signal_pending(current)) {
+			ret = -EINTR;
+			break;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+	} while (last_counter == ftraced_iteration_counter);
+
+	mutex_unlock(&ftraced_lock);
+	remove_wait_queue(&ftraced_waiters, &wait);
+	set_current_state(TASK_RUNNING);
+
+	return ret;
+}
+
 static __init int ftrace_init_debugfs(void)
 {
 	struct dentry *d_tracer;
@@ -1095,6 +1145,7 @@ static int __init notrace ftrace_dynamic_init(void)
 		return -1;
 
 	last_ftrace_enabled = ftrace_enabled = 1;
+	ftraced_task = p;
 
 	return 0;
 }
-- 
cgit v1.1