Register CPU online/offline callbacks via cpuhp_setup_state_nocalls() so stack watches are installed/removed dynamically as CPUs come online or go offline.
Signed-off-by: Jinchao Wang <[email protected]> --- mm/kstackwatch/watch.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/mm/kstackwatch/watch.c b/mm/kstackwatch/watch.c index e02ffc3231ad..d95efefdffe9 100644 --- a/mm/kstackwatch/watch.c +++ b/mm/kstackwatch/watch.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/cpuhotplug.h> #include <linux/hw_breakpoint.h> #include <linux/perf_event.h> #include <linux/preempt.h> @@ -67,6 +68,32 @@ static void ksw_watch_on_local_cpu(void *data) } } +static int ksw_cpu_online(unsigned int cpu) +{ + struct perf_event *bp; + + bp = perf_event_create_kernel_counter(&watch_attr, cpu, NULL, + ksw_watch_handler, NULL); + if (IS_ERR(bp)) { + pr_err("Failed to create watch on CPU %d: %ld\n", cpu, + PTR_ERR(bp)); + return PTR_ERR(bp); + } + + per_cpu(*watch_events, cpu) = bp; + per_cpu(watch_csd, cpu) = CSD_INIT(ksw_watch_on_local_cpu, NULL); + return 0; +} + +static int ksw_cpu_offline(unsigned int cpu) +{ + struct perf_event *bp = per_cpu(*watch_events, cpu); + + if (bp) + unregister_hw_breakpoint(bp); + return 0; +} + int ksw_watch_on(u64 watch_addr, u64 watch_len) { unsigned long flags; @@ -141,6 +168,15 @@ int ksw_watch_init(void) return ret; } + ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "kstackwatch:online", ksw_cpu_online, + ksw_cpu_offline); + if (ret < 0) { + unregister_wide_hw_breakpoint(watch_events); + pr_err("Failed to register CPU hotplug notifier\n"); + return ret; + } + return 0; } -- 2.43.0
