Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

watchdog/hardlockup: simplify perf event probe and remove per-cpu dependency

Simplify the hardlockup detector's probe path and remove its implicit
dependency on pinned per-cpu execution.

Refactor hardlockup_detector_event_create() to be stateless. Return the
created perf_event pointer to the caller instead of directly modifying the
per-cpu 'watchdog_ev' variable. This allows the probe path to safely
manage a temporary event without the risk of leaving stale pointers should
task migration occur.

Link: https://lkml.kernel.org/r/20260129022629.2201331-1-realwujing@gmail.com
Signed-off-by: Shouxin Sun <sunshx@chinatelecom.cn>
Signed-off-by: Junnan Zhang <zhangjn11@chinatelecom.cn>
Signed-off-by: Qiliang Yuan <yuanql9@chinatelecom.cn>
Signed-off-by: Qiliang Yuan <realwujing@gmail.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Cc: Jinchao Wang <wangjinchao600@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Li Huafei <lihuafei1@huawei.com>
Cc: Song Liu <song@kernel.org>
Cc: Thorsten Blum <thorsten.blum@linux.dev>
Cc: Wang Jinchao <wangjinchao600@gmail.com>
Cc: Yicong Yang <yangyicong@hisilicon.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Qiliang Yuan and committed by
Andrew Morton
0dddf20b 76149d53

+28 -22
+28 -22
kernel/watchdog_perf.c
··· 118 118 watchdog_hardlockup_check(smp_processor_id(), regs); 119 119 } 120 120 121 - static int hardlockup_detector_event_create(void) 121 + static struct perf_event *hardlockup_detector_event_create(unsigned int cpu) 122 122 { 123 - unsigned int cpu; 124 123 struct perf_event_attr *wd_attr; 125 124 struct perf_event *evt; 126 125 127 - /* 128 - * Preemption is not disabled because memory will be allocated. 129 - * Ensure CPU-locality by calling this in per-CPU kthread. 130 - */ 131 - WARN_ON(!is_percpu_thread()); 132 - cpu = raw_smp_processor_id(); 133 126 wd_attr = &wd_hw_attr; 134 127 wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); 135 128 ··· 136 143 watchdog_overflow_callback, NULL); 137 144 } 138 145 139 - if (IS_ERR(evt)) { 140 - pr_debug("Perf event create on CPU %d failed with %ld\n", cpu, 141 - PTR_ERR(evt)); 142 - return PTR_ERR(evt); 143 - } 144 - WARN_ONCE(this_cpu_read(watchdog_ev), "unexpected watchdog_ev leak"); 145 - this_cpu_write(watchdog_ev, evt); 146 - return 0; 146 + return evt; 147 147 } 148 148 149 149 /** ··· 145 159 */ 146 160 void watchdog_hardlockup_enable(unsigned int cpu) 147 161 { 162 + struct perf_event *evt; 163 + 148 164 WARN_ON_ONCE(cpu != smp_processor_id()); 149 165 150 - if (hardlockup_detector_event_create()) 166 + evt = hardlockup_detector_event_create(cpu); 167 + if (IS_ERR(evt)) { 168 + pr_debug("Perf event create on CPU %d failed with %ld\n", cpu, 169 + PTR_ERR(evt)); 151 170 return; 171 + } 152 172 153 173 /* use original value for check */ 154 174 if (!atomic_fetch_inc(&watchdog_cpus)) 155 175 pr_info("Enabled. Permanently consumes one hw-PMU counter.\n"); 156 176 177 + WARN_ONCE(this_cpu_read(watchdog_ev), "unexpected watchdog_ev leak"); 178 + this_cpu_write(watchdog_ev, evt); 179 + 157 180 watchdog_init_timestamp(); 158 - perf_event_enable(this_cpu_read(watchdog_ev)); 181 + perf_event_enable(evt); 159 182 } 160 183 161 184 /** ··· 258 263 */ 259 264 int __init watchdog_hardlockup_probe(void) 260 265 { 266 + struct perf_event *evt; 267 + unsigned int cpu; 261 268 int ret; 262 269 263 270 if (!arch_perf_nmi_is_available()) 264 271 return -ENODEV; 265 272 266 - ret = hardlockup_detector_event_create(); 273 + if (!hw_nmi_get_sample_period(watchdog_thresh)) 274 + return -EINVAL; 267 275 268 - if (ret) { 276 + /* 277 + * Test hardware PMU availability by creating a temporary perf event. 278 + * The event is released immediately. 279 + */ 280 + cpu = raw_smp_processor_id(); 281 + evt = hardlockup_detector_event_create(cpu); 282 + if (IS_ERR(evt)) { 269 283 pr_info("Perf NMI watchdog permanently disabled\n"); 284 + ret = PTR_ERR(evt); 270 285 } else { 271 - perf_event_release_kernel(this_cpu_read(watchdog_ev)); 272 - this_cpu_write(watchdog_ev, NULL); 286 + perf_event_release_kernel(evt); 287 + ret = 0; 273 288 } 289 + 274 290 return ret; 275 291 } 276 292