diff options
-rw-r--r-- | include/linux/ftrace.h | 4 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 51 |
2 files changed, 55 insertions, 0 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index a42390c1d6e1..2c1670c65236 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -54,6 +54,8 @@ struct dyn_ftrace { | |||
54 | unsigned long flags; | 54 | unsigned long flags; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | int ftrace_force_update(void); | ||
58 | |||
57 | /* defined in arch */ | 59 | /* defined in arch */ |
58 | extern int ftrace_ip_converted(unsigned long ip); | 60 | extern int ftrace_ip_converted(unsigned long ip); |
59 | extern unsigned char *ftrace_nop_replace(void); | 61 | extern unsigned char *ftrace_nop_replace(void); |
@@ -66,6 +68,8 @@ extern int ftrace_update_ftrace_func(ftrace_func_t func); | |||
66 | extern void ftrace_caller(void); | 68 | extern void ftrace_caller(void); |
67 | extern void ftrace_call(void); | 69 | extern void ftrace_call(void); |
68 | extern void mcount_call(void); | 70 | extern void mcount_call(void); |
71 | #else | ||
72 | # define ftrace_force_update() do { } while (0) | ||
69 | #endif | 73 | #endif |
70 | 74 | ||
71 | static inline void tracer_disable(void) | 75 | static inline void tracer_disable(void) |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 97d5cb7b7e75..4facf5ceeb86 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) | |||
146 | 146 | ||
147 | #ifdef CONFIG_DYNAMIC_FTRACE | 147 | #ifdef CONFIG_DYNAMIC_FTRACE |
148 | 148 | ||
149 | static struct task_struct *ftraced_task; | ||
150 | static DECLARE_WAIT_QUEUE_HEAD(ftraced_waiters); | ||
151 | static unsigned long ftraced_iteration_counter; | ||
152 | |||
149 | enum { | 153 | enum { |
150 | FTRACE_ENABLE_CALLS = (1 << 0), | 154 | FTRACE_ENABLE_CALLS = (1 << 0), |
151 | FTRACE_DISABLE_CALLS = (1 << 1), | 155 | FTRACE_DISABLE_CALLS = (1 << 1), |
@@ -590,9 +594,12 @@ static int notrace ftraced(void *ignore) | |||
590 | ftraced_trigger = 0; | 594 | ftraced_trigger = 0; |
591 | ftrace_record_suspend--; | 595 | ftrace_record_suspend--; |
592 | } | 596 | } |
597 | ftraced_iteration_counter++; | ||
593 | mutex_unlock(&ftraced_lock); | 598 | mutex_unlock(&ftraced_lock); |
594 | mutex_unlock(&ftrace_sysctl_lock); | 599 | mutex_unlock(&ftrace_sysctl_lock); |
595 | 600 | ||
601 | wake_up_interruptible(&ftraced_waiters); | ||
602 | |||
596 | ftrace_shutdown_replenish(); | 603 | ftrace_shutdown_replenish(); |
597 | 604 | ||
598 | set_current_state(TASK_INTERRUPTIBLE); | 605 | set_current_state(TASK_INTERRUPTIBLE); |
@@ -1050,6 +1057,49 @@ static struct file_operations ftrace_filter_fops = { | |||
1050 | .release = ftrace_filter_release, | 1057 | .release = ftrace_filter_release, |
1051 | }; | 1058 | }; |
1052 | 1059 | ||
1060 | /** | ||
1061 | * ftrace_force_update - force an update to all recording ftrace functions | ||
1062 | * | ||
1063 | * The ftrace dynamic update daemon only wakes up once a second. | ||
1064 | * There may be cases where an update needs to be done immediately | ||
1065 | * for tests or internal kernel tracing to begin. This function | ||
1066 | * wakes the daemon to do an update and will not return until the | ||
1067 | * update is complete. | ||
1068 | */ | ||
1069 | int ftrace_force_update(void) | ||
1070 | { | ||
1071 | unsigned long last_counter; | ||
1072 | DECLARE_WAITQUEUE(wait, current); | ||
1073 | int ret = 0; | ||
1074 | |||
1075 | if (!ftraced_task) | ||
1076 | return -ENODEV; | ||
1077 | |||
1078 | mutex_lock(&ftraced_lock); | ||
1079 | last_counter = ftraced_iteration_counter; | ||
1080 | |||
1081 | set_current_state(TASK_INTERRUPTIBLE); | ||
1082 | add_wait_queue(&ftraced_waiters, &wait); | ||
1083 | |||
1084 | do { | ||
1085 | mutex_unlock(&ftraced_lock); | ||
1086 | wake_up_process(ftraced_task); | ||
1087 | schedule(); | ||
1088 | mutex_lock(&ftraced_lock); | ||
1089 | if (signal_pending(current)) { | ||
1090 | ret = -EINTR; | ||
1091 | break; | ||
1092 | } | ||
1093 | set_current_state(TASK_INTERRUPTIBLE); | ||
1094 | } while (last_counter == ftraced_iteration_counter); | ||
1095 | |||
1096 | mutex_unlock(&ftraced_lock); | ||
1097 | remove_wait_queue(&ftraced_waiters, &wait); | ||
1098 | set_current_state(TASK_RUNNING); | ||
1099 | |||
1100 | return ret; | ||
1101 | } | ||
1102 | |||
1053 | static __init int ftrace_init_debugfs(void) | 1103 | static __init int ftrace_init_debugfs(void) |
1054 | { | 1104 | { |
1055 | struct dentry *d_tracer; | 1105 | struct dentry *d_tracer; |
@@ -1095,6 +1145,7 @@ static int __init notrace ftrace_dynamic_init(void) | |||
1095 | return -1; | 1145 | return -1; |
1096 | 1146 | ||
1097 | last_ftrace_enabled = ftrace_enabled = 1; | 1147 | last_ftrace_enabled = ftrace_enabled = 1; |
1148 | ftraced_task = p; | ||
1098 | 1149 | ||
1099 | return 0; | 1150 | return 0; |
1100 | } | 1151 | } |