diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/ftrace.c | 157 |
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 | ||
| 153 | static struct task_struct *ftraced_task; | 153 | static struct task_struct *ftraced_task; |
| 154 | static DECLARE_WAIT_QUEUE_HEAD(ftraced_waiters); | ||
| 155 | static unsigned long ftraced_iteration_counter; | ||
| 156 | 154 | ||
| 157 | enum { | 155 | enum { |
| 158 | FTRACE_ENABLE_CALLS = (1 << 0), | 156 | FTRACE_ENABLE_CALLS = (1 << 0), |
| @@ -189,6 +187,7 @@ static struct ftrace_page *ftrace_pages; | |||
| 189 | 187 | ||
| 190 | static int ftraced_trigger; | 188 | static int ftraced_trigger; |
| 191 | static int ftraced_suspend; | 189 | static int ftraced_suspend; |
| 190 | static int ftraced_stop; | ||
| 192 | 191 | ||
| 193 | static int ftrace_record_suspend; | 192 | static 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 | ||
| 476 | static int __ftrace_update_code(void *ignore); | ||
| 477 | |||
| 477 | static int __ftrace_modify_code(void *data) | 478 | static 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 | ||
| 512 | void 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 | |||
| 522 | void 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 | |||
| 506 | static ftrace_func_t saved_ftrace_func; | 531 | static ftrace_func_t saved_ftrace_func; |
| 507 | 532 | ||
| 508 | static void ftrace_startup(void) | 533 | static 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 | ||
| 637 | static void ftrace_update_code(void) | 665 | static 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 | ||
| 645 | static int ftraced(void *ignore) | 676 | static 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 | ||
| 1247 | static ssize_t | ||
| 1248 | ftraced_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 | |||
| 1258 | static ssize_t | ||
| 1259 | ftraced_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; | ||
