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 --- mm/kstackwatch/watch.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/mm/kstackwatch/watch.c b/mm/kstackwatch/watch.c index 14549e02faf1..795e779792da 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 #include #include #include @@ -61,6 +62,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; +} + static void __ksw_watch_target(ulong addr, u16 len) { int cpu; @@ -117,6 +144,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