Skip to content

Commit 0dddf20

Browse files
realwujingakpm00
authored andcommitted
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>
1 parent 76149d5 commit 0dddf20

1 file changed

Lines changed: 28 additions & 22 deletions

File tree

kernel/watchdog_perf.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,11 @@ static void watchdog_overflow_callback(struct perf_event *event,
118118
watchdog_hardlockup_check(smp_processor_id(), regs);
119119
}
120120

121-
static int hardlockup_detector_event_create(void)
121+
static struct perf_event *hardlockup_detector_event_create(unsigned int cpu)
122122
{
123-
unsigned int cpu;
124123
struct perf_event_attr *wd_attr;
125124
struct perf_event *evt;
126125

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();
133126
wd_attr = &wd_hw_attr;
134127
wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh);
135128

@@ -143,14 +136,7 @@ static int hardlockup_detector_event_create(void)
143136
watchdog_overflow_callback, NULL);
144137
}
145138

146-
if (IS_ERR(evt)) {
147-
pr_debug("Perf event create on CPU %d failed with %ld\n", cpu,
148-
PTR_ERR(evt));
149-
return PTR_ERR(evt);
150-
}
151-
WARN_ONCE(this_cpu_read(watchdog_ev), "unexpected watchdog_ev leak");
152-
this_cpu_write(watchdog_ev, evt);
153-
return 0;
139+
return evt;
154140
}
155141

156142
/**
@@ -159,17 +145,26 @@ static int hardlockup_detector_event_create(void)
159145
*/
160146
void watchdog_hardlockup_enable(unsigned int cpu)
161147
{
148+
struct perf_event *evt;
149+
162150
WARN_ON_ONCE(cpu != smp_processor_id());
163151

164-
if (hardlockup_detector_event_create())
152+
evt = hardlockup_detector_event_create(cpu);
153+
if (IS_ERR(evt)) {
154+
pr_debug("Perf event create on CPU %d failed with %ld\n", cpu,
155+
PTR_ERR(evt));
165156
return;
157+
}
166158

167159
/* use original value for check */
168160
if (!atomic_fetch_inc(&watchdog_cpus))
169161
pr_info("Enabled. Permanently consumes one hw-PMU counter.\n");
170162

163+
WARN_ONCE(this_cpu_read(watchdog_ev), "unexpected watchdog_ev leak");
164+
this_cpu_write(watchdog_ev, evt);
165+
171166
watchdog_init_timestamp();
172-
perf_event_enable(this_cpu_read(watchdog_ev));
167+
perf_event_enable(evt);
173168
}
174169

175170
/**
@@ -263,19 +258,30 @@ bool __weak __init arch_perf_nmi_is_available(void)
263258
*/
264259
int __init watchdog_hardlockup_probe(void)
265260
{
261+
struct perf_event *evt;
262+
unsigned int cpu;
266263
int ret;
267264

268265
if (!arch_perf_nmi_is_available())
269266
return -ENODEV;
270267

271-
ret = hardlockup_detector_event_create();
268+
if (!hw_nmi_get_sample_period(watchdog_thresh))
269+
return -EINVAL;
272270

273-
if (ret) {
271+
/*
272+
* Test hardware PMU availability by creating a temporary perf event.
273+
* The event is released immediately.
274+
*/
275+
cpu = raw_smp_processor_id();
276+
evt = hardlockup_detector_event_create(cpu);
277+
if (IS_ERR(evt)) {
274278
pr_info("Perf NMI watchdog permanently disabled\n");
279+
ret = PTR_ERR(evt);
275280
} else {
276-
perf_event_release_kernel(this_cpu_read(watchdog_ev));
277-
this_cpu_write(watchdog_ev, NULL);
281+
perf_event_release_kernel(evt);
282+
ret = 0;
278283
}
284+
279285
return ret;
280286
}
281287

0 commit comments

Comments
 (0)