aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/ftrace.c157
1 files changed, 110 insertions, 47 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 1843edc098a6..f762f5a2d331 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -151,8 +151,6 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
151#ifdef CONFIG_DYNAMIC_FTRACE 151#ifdef CONFIG_DYNAMIC_FTRACE
152 152
153static struct task_struct *ftraced_task; 153static struct task_struct *ftraced_task;
154static DECLARE_WAIT_QUEUE_HEAD(ftraced_waiters);
155static unsigned long ftraced_iteration_counter;
156 154
157enum { 155enum {
158 FTRACE_ENABLE_CALLS = (1 << 0), 156 FTRACE_ENABLE_CALLS = (1 << 0),
@@ -189,6 +187,7 @@ static struct ftrace_page *ftrace_pages;
189 187
190static int ftraced_trigger; 188static int ftraced_trigger;
191static int ftraced_suspend; 189static int ftraced_suspend;
190static int ftraced_stop;
192 191
193static int ftrace_record_suspend; 192static int ftrace_record_suspend;
194 193
@@ -474,14 +473,21 @@ ftrace_code_disable(struct dyn_ftrace *rec)
474 return 1; 473 return 1;
475} 474}
476 475
476static int __ftrace_update_code(void *ignore);
477
477static int __ftrace_modify_code(void *data) 478static int __ftrace_modify_code(void *data)
478{ 479{
479 unsigned long addr; 480 unsigned long addr;
480 int *command = data; 481 int *command = data;
481 482
482 if (*command & FTRACE_ENABLE_CALLS) 483 if (*command & FTRACE_ENABLE_CALLS) {
484 /*
485 * Update any recorded ips now that we have the
486 * machine stopped
487 */
488 __ftrace_update_code(NULL);
483 ftrace_replace_code(1); 489 ftrace_replace_code(1);
484 else if (*command & FTRACE_DISABLE_CALLS) 490 } else if (*command & FTRACE_DISABLE_CALLS)
485 ftrace_replace_code(0); 491 ftrace_replace_code(0);
486 492
487 if (*command & FTRACE_UPDATE_TRACE_FUNC) 493 if (*command & FTRACE_UPDATE_TRACE_FUNC)
@@ -503,6 +509,25 @@ static void ftrace_run_update_code(int command)
503 stop_machine_run(__ftrace_modify_code, &command, NR_CPUS); 509 stop_machine_run(__ftrace_modify_code, &command, NR_CPUS);
504} 510}
505 511
512void ftrace_disable_daemon(void)
513{
514 /* Stop the daemon from calling kstop_machine */
515 mutex_lock(&ftraced_lock);
516 ftraced_stop = 1;
517 mutex_unlock(&ftraced_lock);
518
519 ftrace_force_update();
520}
521
522void ftrace_enable_daemon(void)
523{
524 mutex_lock(&ftraced_lock);
525 ftraced_stop = 0;
526 mutex_unlock(&ftraced_lock);
527
528 ftrace_force_update();
529}
530
506static ftrace_func_t saved_ftrace_func; 531static ftrace_func_t saved_ftrace_func;
507 532
508static void ftrace_startup(void) 533static void ftrace_startup(void)
@@ -603,6 +628,7 @@ static int __ftrace_update_code(void *ignore)
603 int i; 628 int i;
604 629
605 /* Don't be recording funcs now */ 630 /* Don't be recording funcs now */
631 ftrace_record_suspend++;
606 save_ftrace_enabled = ftrace_enabled; 632 save_ftrace_enabled = ftrace_enabled;
607 ftrace_enabled = 0; 633 ftrace_enabled = 0;
608 634
@@ -628,18 +654,23 @@ static int __ftrace_update_code(void *ignore)
628 stop = ftrace_now(raw_smp_processor_id()); 654 stop = ftrace_now(raw_smp_processor_id());
629 ftrace_update_time = stop - start; 655 ftrace_update_time = stop - start;
630 ftrace_update_tot_cnt += ftrace_update_cnt; 656 ftrace_update_tot_cnt += ftrace_update_cnt;
657 ftraced_trigger = 0;
631 658
632 ftrace_enabled = save_ftrace_enabled; 659 ftrace_enabled = save_ftrace_enabled;
660 ftrace_record_suspend--;
633 661
634 return 0; 662 return 0;
635} 663}
636 664
637static void ftrace_update_code(void) 665static int ftrace_update_code(void)
638{ 666{
639 if (unlikely(ftrace_disabled)) 667 if (unlikely(ftrace_disabled) ||
640 return; 668 !ftrace_enabled || !ftraced_trigger)
669 return 0;
641 670
642 stop_machine_run(__ftrace_update_code, NULL, NR_CPUS); 671 stop_machine_run(__ftrace_update_code, NULL, NR_CPUS);
672
673 return 1;
643} 674}
644 675
645static int ftraced(void *ignore) 676static int ftraced(void *ignore)
@@ -658,14 +689,13 @@ static int ftraced(void *ignore)
658 689
659 mutex_lock(&ftrace_sysctl_lock); 690 mutex_lock(&ftrace_sysctl_lock);
660 mutex_lock(&ftraced_lock); 691 mutex_lock(&ftraced_lock);
661 if (ftrace_enabled && ftraced_trigger && !ftraced_suspend) { 692 if (!ftraced_suspend && !ftraced_stop &&
662 ftrace_record_suspend++; 693 ftrace_update_code()) {
663 ftrace_update_code();
664 usecs = nsecs_to_usecs(ftrace_update_time); 694 usecs = nsecs_to_usecs(ftrace_update_time);
665 if (ftrace_update_tot_cnt > 100000) { 695 if (ftrace_update_tot_cnt > 100000) {
666 ftrace_update_tot_cnt = 0; 696 ftrace_update_tot_cnt = 0;
667 pr_info("hm, dftrace overflow: %lu change%s" 697 pr_info("hm, dftrace overflow: %lu change%s"
668 " (%lu total) in %lu usec%s\n", 698 " (%lu total) in %lu usec%s\n",
669 ftrace_update_cnt, 699 ftrace_update_cnt,
670 ftrace_update_cnt != 1 ? "s" : "", 700 ftrace_update_cnt != 1 ? "s" : "",
671 ftrace_update_tot_cnt, 701 ftrace_update_tot_cnt,
@@ -673,15 +703,10 @@ static int ftraced(void *ignore)
673 ftrace_disabled = 1; 703 ftrace_disabled = 1;
674 WARN_ON_ONCE(1); 704 WARN_ON_ONCE(1);
675 } 705 }
676 ftraced_trigger = 0;
677 ftrace_record_suspend--;
678 } 706 }
679 ftraced_iteration_counter++;
680 mutex_unlock(&ftraced_lock); 707 mutex_unlock(&ftraced_lock);
681 mutex_unlock(&ftrace_sysctl_lock); 708 mutex_unlock(&ftrace_sysctl_lock);
682 709
683 wake_up_interruptible(&ftraced_waiters);
684
685 ftrace_shutdown_replenish(); 710 ftrace_shutdown_replenish();
686 } 711 }
687 __set_current_state(TASK_RUNNING); 712 __set_current_state(TASK_RUNNING);
@@ -1219,6 +1244,55 @@ ftrace_notrace_release(struct inode *inode, struct file *file)
1219 return ftrace_regex_release(inode, file, 0); 1244 return ftrace_regex_release(inode, file, 0);
1220} 1245}
1221 1246
1247static ssize_t
1248ftraced_read(struct file *filp, char __user *ubuf,
1249 size_t cnt, loff_t *ppos)
1250{
1251 /* don't worry about races */
1252 char *buf = ftraced_stop ? "disabled\n" : "enabled\n";
1253 int r = strlen(buf);
1254
1255 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
1256}
1257
1258static ssize_t
1259ftraced_write(struct file *filp, const char __user *ubuf,
1260 size_t cnt, loff_t *ppos)
1261{
1262 char buf[64];
1263 long val;
1264 int ret;
1265
1266 if (cnt >= sizeof(buf))
1267 return -EINVAL;
1268
1269 if (copy_from_user(&buf, ubuf, cnt))
1270 return -EFAULT;
1271
1272 if (strncmp(buf, "enable", 6) == 0)
1273 val = 1;
1274 else if (strncmp(buf, "disable", 7) == 0)
1275 val = 0;
1276 else {
1277 buf[cnt] = 0;
1278
1279 ret = strict_strtoul(buf, 10, &val);
1280 if (ret < 0)
1281 return ret;