[PATCH v2 1/2] watchdog: pika_wdt: fix timer leak and close race

From: Rosen Penev

Date: Wed Jun 03 2026 - 00:04:14 EST


Two timer lifecycle bugs in the PIKA watchdog driver:

1. pikawdt_exit() unmaps the FPGA IO memory without stopping the ping
timer. A timer tick after iounmap executes pikawdt_ping() on freed
memory. Add timer_delete_sync() before iounmap.

2. pikawdt_release() uses timer_delete() which does not synchronize with
a concurrently executing timer handler. If pikawdt_ping() runs on
another CPU after timer_delete() marks the timer as deleted but before
the open bit is cleared, it can call mod_timer() and re-arm itself.
Once the open bit is subsequently cleared, the condition
(!nowayout && !open) becomes true and the timer keeps patting the
watchdog forever, defeating the intended reset-on-unexpected-close.
Fix by clearing the open bit before calling timer_delete_sync(), which
waits for any in-flight handler to complete.

Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@xxxxxxxxx>
---
drivers/watchdog/pika_wdt.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c
index 87b8988d2520..60a846cb3601 100644
--- a/drivers/watchdog/pika_wdt.c
+++ b/drivers/watchdog/pika_wdt.c
@@ -127,11 +127,12 @@ static int pikawdt_open(struct inode *inode, struct file *file)
*/
static int pikawdt_release(struct inode *inode, struct file *file)
{
+ clear_bit(0, &pikawdt_private.open);
+
/* stop internal ping */
if (!pikawdt_private.expect_close)
- timer_delete(&pikawdt_private.timer);
+ timer_delete_sync(&pikawdt_private.timer);

- clear_bit(0, &pikawdt_private.open);
pikawdt_private.expect_close = 0;
return 0;
}
@@ -291,6 +292,7 @@ static void __exit pikawdt_exit(void)
{
misc_deregister(&pikawdt_miscdev);

+ timer_delete_sync(&pikawdt_private.timer);
iounmap(pikawdt_private.fpga);
}

--
2.54.0