|
32 | 32 | #include <linux/debugfs.h> |
33 | 33 | #include <linux/sysctl.h> |
34 | 34 | #include <linux/kdebug.h> |
| 35 | +#include <linux/kthread.h> |
35 | 36 | #include <linux/memory.h> |
36 | 37 | #include <linux/ftrace.h> |
37 | 38 | #include <linux/cpu.h> |
|
40 | 41 | #include <linux/perf_event.h> |
41 | 42 | #include <linux/execmem.h> |
42 | 43 | #include <linux/cleanup.h> |
| 44 | +#include <linux/wait.h> |
43 | 45 |
|
44 | 46 | #include <asm/sections.h> |
45 | 47 | #include <asm/cacheflush.h> |
@@ -514,9 +516,18 @@ static LIST_HEAD(optimizing_list); |
514 | 516 | static LIST_HEAD(unoptimizing_list); |
515 | 517 | static LIST_HEAD(freeing_list); |
516 | 518 |
|
517 | | -static void kprobe_optimizer(struct work_struct *work); |
518 | | -static DECLARE_DELAYED_WORK(optimizing_work, kprobe_optimizer); |
519 | 519 | static void optimize_kprobe(struct kprobe *p); |
| 520 | +static struct task_struct *kprobe_optimizer_task; |
| 521 | +static wait_queue_head_t kprobe_optimizer_wait; |
| 522 | +static atomic_t optimizer_state; |
| 523 | +enum { |
| 524 | + OPTIMIZER_ST_IDLE = 0, |
| 525 | + OPTIMIZER_ST_KICKED = 1, |
| 526 | + OPTIMIZER_ST_FLUSHING = 2, |
| 527 | +}; |
| 528 | + |
| 529 | +static DECLARE_COMPLETION(optimizer_completion); |
| 530 | + |
520 | 531 | #define OPTIMIZE_DELAY 5 |
521 | 532 |
|
522 | 533 | /* |
@@ -609,14 +620,10 @@ static void do_free_cleaned_kprobes(void) |
609 | 620 | } |
610 | 621 | } |
611 | 622 |
|
612 | | -/* Start optimizer after OPTIMIZE_DELAY passed */ |
613 | | -static void kick_kprobe_optimizer(void) |
614 | | -{ |
615 | | - schedule_delayed_work(&optimizing_work, OPTIMIZE_DELAY); |
616 | | -} |
| 623 | +static void kick_kprobe_optimizer(void); |
617 | 624 |
|
618 | 625 | /* Kprobe jump optimizer */ |
619 | | -static void kprobe_optimizer(struct work_struct *work) |
| 626 | +static void kprobe_optimizer(void) |
620 | 627 | { |
621 | 628 | guard(mutex)(&kprobe_mutex); |
622 | 629 |
|
@@ -647,23 +654,71 @@ static void kprobe_optimizer(struct work_struct *work) |
647 | 654 | do_free_cleaned_kprobes(); |
648 | 655 | } |
649 | 656 |
|
650 | | - /* Step 5: Kick optimizer again if needed */ |
| 657 | + /* Step 5: Kick optimizer again if needed. But if there is a flush requested, */ |
| 658 | + if (completion_done(&optimizer_completion)) |
| 659 | + complete(&optimizer_completion); |
| 660 | + |
651 | 661 | if (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list)) |
652 | | - kick_kprobe_optimizer(); |
| 662 | + kick_kprobe_optimizer(); /*normal kick*/ |
| 663 | +} |
| 664 | + |
| 665 | +static int kprobe_optimizer_thread(void *data) |
| 666 | +{ |
| 667 | + while (!kthread_should_stop()) { |
| 668 | + /* To avoid hung_task, wait in interruptible state. */ |
| 669 | + wait_event_interruptible(kprobe_optimizer_wait, |
| 670 | + atomic_read(&optimizer_state) != OPTIMIZER_ST_IDLE || |
| 671 | + kthread_should_stop()); |
| 672 | + |
| 673 | + if (kthread_should_stop()) |
| 674 | + break; |
| 675 | + |
| 676 | + /* |
| 677 | + * If it was a normal kick, wait for OPTIMIZE_DELAY. |
| 678 | + * This wait can be interrupted by a flush request. |
| 679 | + */ |
| 680 | + if (atomic_read(&optimizer_state) == 1) |
| 681 | + wait_event_interruptible_timeout( |
| 682 | + kprobe_optimizer_wait, |
| 683 | + atomic_read(&optimizer_state) == OPTIMIZER_ST_FLUSHING || |
| 684 | + kthread_should_stop(), |
| 685 | + OPTIMIZE_DELAY); |
| 686 | + |
| 687 | + if (kthread_should_stop()) |
| 688 | + break; |
| 689 | + |
| 690 | + atomic_set(&optimizer_state, OPTIMIZER_ST_IDLE); |
| 691 | + |
| 692 | + kprobe_optimizer(); |
| 693 | + } |
| 694 | + return 0; |
| 695 | +} |
| 696 | + |
| 697 | +/* Start optimizer after OPTIMIZE_DELAY passed */ |
| 698 | +static void kick_kprobe_optimizer(void) |
| 699 | +{ |
| 700 | + lockdep_assert_held(&kprobe_mutex); |
| 701 | + if (atomic_cmpxchg(&optimizer_state, |
| 702 | + OPTIMIZER_ST_IDLE, OPTIMIZER_ST_KICKED) == OPTIMIZER_ST_IDLE) |
| 703 | + wake_up(&kprobe_optimizer_wait); |
653 | 704 | } |
654 | 705 |
|
655 | 706 | static void wait_for_kprobe_optimizer_locked(void) |
656 | 707 | { |
657 | 708 | lockdep_assert_held(&kprobe_mutex); |
658 | 709 |
|
659 | 710 | while (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list)) { |
660 | | - mutex_unlock(&kprobe_mutex); |
661 | | - |
662 | | - /* This will also make 'optimizing_work' execute immmediately */ |
663 | | - flush_delayed_work(&optimizing_work); |
664 | | - /* 'optimizing_work' might not have been queued yet, relax */ |
665 | | - cpu_relax(); |
| 711 | + init_completion(&optimizer_completion); |
| 712 | + /* |
| 713 | + * Set state to OPTIMIZER_ST_FLUSHING and wake up the thread if it's |
| 714 | + * idle. If it's already kicked, it will see the state change. |
| 715 | + */ |
| 716 | + if (atomic_xchg_acquire(&optimizer_state, |
| 717 | + OPTIMIZER_ST_FLUSHING) != OPTIMIZER_ST_FLUSHING) |
| 718 | + wake_up(&kprobe_optimizer_wait); |
666 | 719 |
|
| 720 | + mutex_unlock(&kprobe_mutex); |
| 721 | + wait_for_completion(&optimizer_completion); |
667 | 722 | mutex_lock(&kprobe_mutex); |
668 | 723 | } |
669 | 724 | } |
@@ -1016,8 +1071,21 @@ static void __disarm_kprobe(struct kprobe *p, bool reopt) |
1016 | 1071 | } |
1017 | 1072 | } |
1018 | 1073 |
|
| 1074 | +static void __init init_optprobe(void) |
| 1075 | +{ |
| 1076 | +#ifdef __ARCH_WANT_KPROBES_INSN_SLOT |
| 1077 | + /* Init 'kprobe_optinsn_slots' for allocation */ |
| 1078 | + kprobe_optinsn_slots.insn_size = MAX_OPTINSN_SIZE; |
| 1079 | +#endif |
| 1080 | + |
| 1081 | + init_waitqueue_head(&kprobe_optimizer_wait); |
| 1082 | + atomic_set(&optimizer_state, OPTIMIZER_ST_IDLE); |
| 1083 | + kprobe_optimizer_task = kthread_run(kprobe_optimizer_thread, NULL, |
| 1084 | + "kprobe-optimizer"); |
| 1085 | +} |
1019 | 1086 | #else /* !CONFIG_OPTPROBES */ |
1020 | 1087 |
|
| 1088 | +#define init_optprobe() do {} while (0) |
1021 | 1089 | #define optimize_kprobe(p) do {} while (0) |
1022 | 1090 | #define unoptimize_kprobe(p, f) do {} while (0) |
1023 | 1091 | #define kill_optimized_kprobe(p) do {} while (0) |
@@ -2700,10 +2768,8 @@ static int __init init_kprobes(void) |
2700 | 2768 | /* By default, kprobes are armed */ |
2701 | 2769 | kprobes_all_disarmed = false; |
2702 | 2770 |
|
2703 | | -#if defined(CONFIG_OPTPROBES) && defined(__ARCH_WANT_KPROBES_INSN_SLOT) |
2704 | | - /* Init 'kprobe_optinsn_slots' for allocation */ |
2705 | | - kprobe_optinsn_slots.insn_size = MAX_OPTINSN_SIZE; |
2706 | | -#endif |
| 2771 | + /* Initialize the optimization infrastructure */ |
| 2772 | + init_optprobe(); |
2707 | 2773 |
|
2708 | 2774 | err = arch_init_kprobes(); |
2709 | 2775 | if (!err) |
|
0 commit comments