aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ftrace.h3
-rw-r--r--kernel/trace/ftrace.c112
-rw-r--r--kernel/trace/trace_selftest.c4
3 files changed, 110 insertions, 9 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 61e757bd2350..4650a3160b7f 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -58,6 +58,9 @@ struct dyn_ftrace {
58int ftrace_force_update(void); 58int ftrace_force_update(void);
59void ftrace_set_filter(unsigned char *buf, int len, int reset); 59void ftrace_set_filter(unsigned char *buf, int len, int reset);
60 60
61/* totally disable ftrace - can not re-enable after this */
62void ftrace_kill(void);
63
61/* defined in arch */ 64/* defined in arch */
62extern int ftrace_ip_converted(unsigned long ip); 65extern int ftrace_ip_converted(unsigned long ip);
63extern unsigned char *ftrace_nop_replace(void); 66extern unsigned char *ftrace_nop_replace(void);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 8e02aa690b2b..ff42345dd78e 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -29,9 +29,16 @@
29 29
30#include "trace.h" 30#include "trace.h"
31 31
32int ftrace_enabled; 32/* ftrace_enabled is a method to turn ftrace on or off */
33int ftrace_enabled __read_mostly;
33static int last_ftrace_enabled; 34static int last_ftrace_enabled;
34 35
36/*
37 * ftrace_disabled is set when an anomaly is discovered.
38 * ftrace_disabled is much stronger than ftrace_enabled.
39 */
40static int ftrace_disabled __read_mostly;
41
35static DEFINE_SPINLOCK(ftrace_lock); 42static DEFINE_SPINLOCK(ftrace_lock);
36static DEFINE_MUTEX(ftrace_sysctl_lock); 43static DEFINE_MUTEX(ftrace_sysctl_lock);
37 44
@@ -230,10 +237,11 @@ static notrace struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
230 if (ftrace_free_records) { 237 if (ftrace_free_records) {
231 rec = ftrace_free_records; 238 rec = ftrace_free_records;
232 239
233 /* todo, disable tracing altogether on this warning */
234 if (unlikely(!(rec->flags & FTRACE_FL_FREE))) { 240 if (unlikely(!(rec->flags & FTRACE_FL_FREE))) {
235 WARN_ON_ONCE(1); 241 WARN_ON_ONCE(1);
236 ftrace_free_records = NULL; 242 ftrace_free_records = NULL;
243 ftrace_disabled = 1;
244 ftrace_enabled = 0;
237 return NULL; 245 return NULL;
238 } 246 }
239 247
@@ -260,7 +268,7 @@ ftrace_record_ip(unsigned long ip)
260 int resched; 268 int resched;
261 int atomic; 269 int atomic;
262 270
263 if (!ftrace_enabled) 271 if (!ftrace_enabled || ftrace_disabled)
264 return; 272 return;
265 273
266 resched = need_resched(); 274 resched = need_resched();
@@ -485,6 +493,9 @@ static void notrace ftrace_startup(void)
485{ 493{
486 int command = 0; 494 int command = 0;
487 495
496 if (unlikely(ftrace_disabled))
497 return;
498
488 mutex_lock(&ftraced_lock); 499 mutex_lock(&ftraced_lock);
489 ftraced_suspend++; 500 ftraced_suspend++;
490 if (ftraced_suspend == 1) 501 if (ftraced_suspend == 1)
@@ -507,6 +518,9 @@ static void notrace ftrace_shutdown(void)
507{ 518{
508 int command = 0; 519 int command = 0;
509 520
521 if (unlikely(ftrace_disabled))
522 return;
523
510 mutex_lock(&ftraced_lock); 524 mutex_lock(&ftraced_lock);
511 ftraced_suspend--; 525 ftraced_suspend--;
512 if (!ftraced_suspend) 526 if (!ftraced_suspend)
@@ -529,6 +543,9 @@ static void notrace ftrace_startup_sysctl(void)
529{ 543{
530 int command = FTRACE_ENABLE_MCOUNT; 544 int command = FTRACE_ENABLE_MCOUNT;
531 545
546 if (unlikely(ftrace_disabled))
547 return;
548
532 mutex_lock(&ftraced_lock); 549 mutex_lock(&ftraced_lock);
533 /* Force update next time */ 550 /* Force update next time */
534 saved_ftrace_func = NULL; 551 saved_ftrace_func = NULL;
@@ -544,6 +561,9 @@ static void notrace ftrace_shutdown_sysctl(void)
544{ 561{
545 int command = FTRACE_DISABLE_MCOUNT; 562 int command = FTRACE_DISABLE_MCOUNT;
546 563
564 if (unlikely(ftrace_disabled))
565 return;
566
547 mutex_lock(&ftraced_lock); 567 mutex_lock(&ftraced_lock);
548 /* ftraced_suspend is true if ftrace is running */ 568 /* ftraced_suspend is true if ftrace is running */
549 if (ftraced_suspend) 569 if (ftraced_suspend)
@@ -600,6 +620,9 @@ static int notrace __ftrace_update_code(void *ignore)
600 620
601static void notrace ftrace_update_code(void) 621static void notrace ftrace_update_code(void)
602{ 622{
623 if (unlikely(ftrace_disabled))
624 return;
625
603 stop_machine_run(__ftrace_update_code, NULL, NR_CPUS); 626 stop_machine_run(__ftrace_update_code, NULL, NR_CPUS);
604} 627}
605 628
@@ -614,6 +637,9 @@ static int notrace ftraced(void *ignore)
614 /* check once a second */ 637 /* check once a second */
615 schedule_timeout(HZ); 638 schedule_timeout(HZ);
616 639
640 if (unlikely(ftrace_disabled))
641 continue;
642
617 mutex_lock(&ftrace_sysctl_lock); 643 mutex_lock(&ftrace_sysctl_lock);
618 mutex_lock(&ftraced_lock); 644 mutex_lock(&ftraced_lock);
619 if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) { 645 if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) {
@@ -628,6 +654,7 @@ static int notrace ftraced(void *ignore)
628 ftrace_update_cnt != 1 ? "s" : "", 654 ftrace_update_cnt != 1 ? "s" : "",
629 ftrace_update_tot_cnt, 655 ftrace_update_tot_cnt,
630 usecs, usecs != 1 ? "s" : ""); 656 usecs, usecs != 1 ? "s" : "");
657 ftrace_disabled = 1;
631 WARN_ON_ONCE(1); 658 WARN_ON_ONCE(1);
632 } 659 }
633 ftraced_trigger = 0; 660 ftraced_trigger = 0;
@@ -785,6 +812,9 @@ ftrace_avail_open(struct inode *inode, struct file *file)
785 struct ftrace_iterator *iter; 812 struct ftrace_iterator *iter;
786 int ret; 813 int ret;
787 814
815 if (unlikely(ftrace_disabled))
816 return -ENODEV;
817
788 iter = kzalloc(sizeof(*iter), GFP_KERNEL); 818 iter = kzalloc(sizeof(*iter), GFP_KERNEL);
789 if (!iter) 819 if (!iter)
790 return -ENOMEM; 820 return -ENOMEM;
@@ -843,6 +873,9 @@ ftrace_filter_open(struct inode *inode, struct file *file)
843 struct ftrace_iterator *iter; 873 struct ftrace_iterator *iter;
844 int ret = 0; 874 int ret = 0;
845 875
876 if (unlikely(ftrace_disabled))
877 return -ENODEV;
878
846 iter = kzalloc(sizeof(*iter), GFP_KERNEL); 879 iter = kzalloc(sizeof(*iter), GFP_KERNEL);
847 if (!iter) 880 if (!iter)
848 return -ENOMEM; 881 return -ENOMEM;
@@ -1063,6 +1096,9 @@ ftrace_filter_write(struct file *file, const char __user *ubuf,
1063 */ 1096 */
1064notrace void ftrace_set_filter(unsigned char *buf, int len, int reset) 1097notrace void ftrace_set_filter(unsigned char *buf, int len, int reset)
1065{ 1098{
1099 if (unlikely(ftrace_disabled))
1100 return;
1101
1066 mutex_lock(&ftrace_filter_lock); 1102 mutex_lock(&ftrace_filter_lock);
1067 if (reset) 1103 if (reset)
1068 ftrace_filter_reset(); 1104 ftrace_filter_reset();
@@ -1133,7 +1169,7 @@ int ftrace_force_update(void)
1133 DECLARE_WAITQUEUE(wait, current); 1169 DECLARE_WAITQUEUE(wait, current);
1134 int ret = 0; 1170 int ret = 0;
1135 1171
1136 if (!ftraced_task) 1172 if (unlikely(ftrace_disabled))
1137 return -ENODEV; 1173 return -ENODEV;
1138 1174
1139 mutex_lock(&ftraced_lock); 1175 mutex_lock(&ftraced_lock);
@@ -1142,6 +1178,11 @@ int ftrace_force_update(void)
1142 set_current_state(TASK_INTERRUPTIBLE); 1178 set_current_state(TASK_INTERRUPTIBLE);
1143 add_wait_queue(&ftraced_waiters, &wait); 1179 add_wait_queue(&ftraced_waiters, &wait);
1144 1180
1181 if (unlikely(!ftraced_task)) {
1182 ret = -ENODEV;
1183 goto out;
1184 }
1185
1145 do { 1186 do {
1146 mutex_unlock(&ftraced_lock); 1187 mutex_unlock(&ftraced_lock);
1147 wake_up_process(ftraced_task); 1188 wake_up_process(ftraced_task);
@@ -1154,6 +1195,7 @@ int ftrace_force_update(void)
1154 set_current_state(TASK_INTERRUPTIBLE); 1195 set_current_state(TASK_INTERRUPTIBLE);
1155 } while (last_counter == ftraced_iteration_counter); 1196 } while (last_counter == ftraced_iteration_counter);
1156 1197
1198 out:
1157 mutex_unlock(&ftraced_lock); 1199 mutex_unlock(&ftraced_lock);
1158 remove_wait_queue(&ftraced_waiters, &wait); 1200 remove_wait_queue(&ftraced_waiters, &wait);
1159 set_current_state(TASK_RUNNING); 1201 set_current_state(TASK_RUNNING);
@@ -1161,6 +1203,22 @@ int ftrace_force_update(void)
1161 return ret; 1203 return ret;
1162} 1204}
1163 1205
1206static void ftrace_force_shutdown(void)
1207{
1208 struct task_struct *task;
1209 int command = FTRACE_DISABLE_CALLS | FTRACE_UPDATE_TRACE_FUNC;
1210
1211 mutex_lock(&ftraced_lock);
1212 task = ftraced_task;
1213 ftraced_task = NULL;
1214 ftraced_suspend = -1;
1215 ftrace_run_update_code(command);
1216 mutex_unlock(&ftraced_lock);
1217
1218 if (task)
1219 kthread_stop(task);
1220}
1221
1164static __init int ftrace_init_debugfs(void) 1222static __init int ftrace_init_debugfs(void)
1165{ 1223{
1166 struct dentry *d_tracer; 1224 struct dentry *d_tracer;
@@ -1194,21 +1252,29 @@ static int __init notrace ftrace_dynamic_init(void)
1194 stop_machine_run(ftrace_dyn_arch_init, &addr, NR_CPUS); 1252 stop_machine_run(ftrace_dyn_arch_init, &addr, NR_CPUS);
1195 1253
1196 /* ftrace_dyn_arch_init places the return code in addr */ 1254 /* ftrace_dyn_arch_init places the return code in addr */
1197 if (addr) 1255 if (addr) {
1198 return addr; 1256 ret = (int)addr;
1257 goto failed;
1258 }
1199 1259
1200 ret = ftrace_dyn_table_alloc(); 1260 ret = ftrace_dyn_table_alloc();
1201 if (ret) 1261 if (ret)
1202 return ret; 1262 goto failed;
1203 1263
1204 p = kthread_run(ftraced, NULL, "ftraced"); 1264 p = kthread_run(ftraced, NULL, "ftraced");
1205 if (IS_ERR(p)) 1265 if (IS_ERR(p)) {
1206 return -1; 1266 ret = -1;
1267 goto failed;
1268 }
1207 1269
1208 last_ftrace_enabled = ftrace_enabled = 1; 1270 last_ftrace_enabled = ftrace_enabled = 1;
1209 ftraced_task = p; 1271 ftraced_task = p;
1210 1272
1211 return 0; 1273 return 0;
1274
1275 failed:
1276 ftrace_disabled = 1;
1277 return ret;
1212} 1278}
1213 1279
1214core_initcall(ftrace_dynamic_init); 1280core_initcall(ftrace_dynamic_init);
@@ -1217,9 +1283,31 @@ core_initcall(ftrace_dynamic_init);
1217# define ftrace_shutdown() do { } while (0) 1283# define ftrace_shutdown() do { } while (0)
1218# define ftrace_startup_sysctl() do { } while (0) 1284# define ftrace_startup_sysctl() do { } while (0)
1219# define ftrace_shutdown_sysctl() do { } while (0) 1285# define ftrace_shutdown_sysctl() do { } while (0)
1286# define ftrace_force_shutdown() do { } while (0)
1220#endif /* CONFIG_DYNAMIC_FTRACE */ 1287#endif /* CONFIG_DYNAMIC_FTRACE */
1221 1288
1222/** 1289/**
1290 * ftrace_kill - totally shutdown ftrace
1291 *
1292 * This is a safety measure. If something was detected that seems
1293 * wrong, calling this function will keep ftrace from doing
1294 * any more modifications, and updates.
1295 * used when something went wrong.
1296 */
1297void ftrace_kill(void)
1298{
1299 mutex_lock(&ftrace_sysctl_lock);
1300 ftrace_disabled = 1;
1301 ftrace_enabled = 0;
1302
1303 clear_ftrace_function();
1304 mutex_unlock(&ftrace_sysctl_lock);
1305
1306 /* Try to totally disable ftrace */
1307 ftrace_force_shutdown();
1308}
1309
1310/**
1223 * register_ftrace_function - register a function for profiling 1311 * register_ftrace_function - register a function for profiling
1224 * @ops - ops structure that holds the function for profiling. 1312 * @ops - ops structure that holds the function for profiling.
1225 * 1313 *
@@ -1234,6 +1322,9 @@ int register_ftrace_function(struct ftrace_ops *ops)
1234{ 1322{
1235 int ret; 1323 int ret;
1236 1324
1325 if (unlikely(ftrace_disabled))
1326 return -1;
1327
1237 mutex_lock(&ftrace_sysctl_lock); 1328 mutex_lock(&ftrace_sysctl_lock);
1238 ret = __register_ftrace_function(ops); 1329 ret = __register_ftrace_function(ops);
1239 ftrace_startup(); 1330 ftrace_startup();
@@ -1267,6 +1358,9 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
1267{ 1358{
1268 int ret; 1359 int ret;
1269 1360
1361 if (unlikely(ftrace_disabled))
1362 return -ENODEV;
1363
1270 mutex_lock(&ftrace_sysctl_lock); 1364 mutex_lock(&ftrace_sysctl_lock);
1271 1365
1272 ret = proc_dointvec(table, write, file, buffer, lenp, ppos); 1366 ret = proc_dointvec(table, write, file, buffer, lenp, ppos);
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c
index a6f1ed75f836..85715b86a342 100644
--- a/kernel/trace/trace_selftest.c
+++ b/kernel/trace/trace_selftest.c
@@ -248,6 +248,10 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
248 ftrace_enabled = save_ftrace_enabled; 248 ftrace_enabled = save_ftrace_enabled;
249 tracer_enabled = save_tracer_enabled; 249 tracer_enabled = save_tracer_enabled;
250 250
251 /* kill ftrace totally if we failed */
252 if (ret)
253 ftrace_kill();
254
251 return ret; 255 return ret;
252} 256}
253#endif /* CONFIG_FTRACE */ 257#endif /* CONFIG_FTRACE */