ftrace: force recording
authorSteven Rostedt <srostedt@redhat.com>
Mon, 12 May 2008 19:20:44 +0000 (21:20 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Fri, 23 May 2008 18:40:29 +0000 (20:40 +0200)
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
include/linux/ftrace.h
kernel/trace/ftrace.c

index a42390c1d6e1c667ee7ad08f5764fe1b3993b9c3..2c1670c65236043a2245c7ab3684d344cc5a5dc2 100644 (file)
@@ -54,6 +54,8 @@ struct dyn_ftrace {
        unsigned long     flags;
 };
 
+int ftrace_force_update(void);
+
 /* defined in arch */
 extern int ftrace_ip_converted(unsigned long ip);
 extern unsigned char *ftrace_nop_replace(void);
@@ -66,6 +68,8 @@ extern int ftrace_update_ftrace_func(ftrace_func_t func);
 extern void ftrace_caller(void);
 extern void ftrace_call(void);
 extern void mcount_call(void);
+#else
+# define ftrace_force_update() do { } while (0)
 #endif
 
 static inline void tracer_disable(void)
index 97d5cb7b7e757a206fbe497810c5ada742c19870..4facf5ceeb866259f1ffc1daae008ad94edce2a8 100644 (file)
@@ -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;
 }