From: Greg Kroah-Hartman Date: Thu, 23 Apr 2026 12:35:05 +0000 (+0200) Subject: 5.10-stable patches X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=2ca3683c5b2eec6c14ba36188e245534d632caa4;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: arm-spear-do-not-use-timer-namespace-for-timer_shutdown-function.patch bluetooth-hci_qca-fix-the-teardown-problem-for-real.patch clocksource-drivers-arm_arch_timer-do-not-use-timer-namespace-for-timer_shutdown-function.patch clocksource-drivers-sp804-do-not-use-timer-namespace-for-timer_shutdown-function.patch documentation-remove-bogus-claim-about-del_timer_sync.patch documentation-replace-del_timer-del_timer_sync.patch drm-amd-display-do-not-add-mhard-float-to-calcs-dsc-and-dcn30-fp-files-for-clang.patch gfs2-validate-i_depth-for-exhash-directories.patch i3c-fix-uninitialized-variable-use-in-i2c-setup.patch scripts-dtc-remove-unused-dts_version-in-dtc-lexer.l.patch timers-add-shutdown-mechanism-to-the-internal-functions.patch timers-fix-null-function-pointer-race-in-timer_shutdown_sync.patch timers-get-rid-of-del_singleshot_timer_sync.patch timers-provide-timer_shutdown.patch timers-rename-del_timer-to-timer_delete.patch timers-replace-bug_on-s.patch timers-silently-ignore-timers-with-a-null-function.patch timers-split-del_timer-to-prepare-for-shutdown-mode.patch timers-update-the-documentation-to-reflect-on-the-new-timer_shutdown-api.patch --- diff --git a/queue-5.10/arm-spear-do-not-use-timer-namespace-for-timer_shutdown-function.patch b/queue-5.10/arm-spear-do-not-use-timer-namespace-for-timer_shutdown-function.patch new file mode 100644 index 0000000000..b5d3312a65 --- /dev/null +++ b/queue-5.10/arm-spear-do-not-use-timer-namespace-for-timer_shutdown-function.patch @@ -0,0 +1,75 @@ +From aha310510@gmail.com Thu Feb 19 18:13:24 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:12:57 +0900 +Subject: ARM: spear: Do not use timer namespace for timer_shutdown() function +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-3-aha310510@gmail.com> + +From: "Steven Rostedt (Google)" + +[ Upstream commit 80b55772d41d8afec68dbc4ff0368a9fe5d1f390 ] + +A new "shutdown" timer state is being added to the generic timer code. One +of the functions to change the timer into the state is called +"timer_shutdown()". This means that there can not be other functions called +"timer_shutdown()" as the timer code owns the "timer_*" name space. + +Rename timer_shutdown() to spear_timer_shutdown() to avoid this conflict. + +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Acked-by: Arnd Bergmann +Acked-by: Viresh Kumar +Link: https://lkml.kernel.org/r/20221106212701.822440504@goodmis.org +Link: https://lore.kernel.org/all/20221105060155.228348078@goodmis.org/ +Link: https://lore.kernel.org/r/20221110064146.810953418@goodmis.org +Link: https://lore.kernel.org/r/20221123201624.513863211@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm/mach-spear/time.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/arm/mach-spear/time.c ++++ b/arch/arm/mach-spear/time.c +@@ -93,7 +93,7 @@ static void __init spear_clocksource_ini + 200, 16, clocksource_mmio_readw_up); + } + +-static inline void timer_shutdown(struct clock_event_device *evt) ++static inline void spear_timer_shutdown(struct clock_event_device *evt) + { + u16 val = readw(gpt_base + CR(CLKEVT)); + +@@ -104,7 +104,7 @@ static inline void timer_shutdown(struct + + static int spear_shutdown(struct clock_event_device *evt) + { +- timer_shutdown(evt); ++ spear_timer_shutdown(evt); + + return 0; + } +@@ -114,7 +114,7 @@ static int spear_set_oneshot(struct cloc + u16 val; + + /* stop the timer */ +- timer_shutdown(evt); ++ spear_timer_shutdown(evt); + + val = readw(gpt_base + CR(CLKEVT)); + val |= CTRL_ONE_SHOT; +@@ -129,7 +129,7 @@ static int spear_set_periodic(struct clo + u16 val; + + /* stop the timer */ +- timer_shutdown(evt); ++ spear_timer_shutdown(evt); + + period = clk_get_rate(gpt_clk) / HZ; + period >>= CTRL_PRESCALER16; diff --git a/queue-5.10/bluetooth-hci_qca-fix-the-teardown-problem-for-real.patch b/queue-5.10/bluetooth-hci_qca-fix-the-teardown-problem-for-real.patch new file mode 100644 index 0000000000..b9ecc46541 --- /dev/null +++ b/queue-5.10/bluetooth-hci_qca-fix-the-teardown-problem-for-real.patch @@ -0,0 +1,78 @@ +From aha310510@gmail.com Thu Feb 19 18:14:15 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:09 +0900 +Subject: Bluetooth: hci_qca: Fix the teardown problem for real +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-15-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit e0d3da982c96aeddc1bbf1cf9469dbb9ebdca657 ] + +While discussing solutions for the teardown problem which results from +circular dependencies between timers and workqueues, where timers schedule +work from their timer callback and workqueues arm the timers from work +items, it was discovered that the recent fix to the QCA code is incorrect. + +That commit fixes the obvious problem of using del_timer() instead of +del_timer_sync() and reorders the teardown calls to + + destroy_workqueue(wq); + del_timer_sync(t); + +This makes it less likely to explode, but it's still broken: + + destroy_workqueue(wq); + /* After this point @wq cannot be touched anymore */ + + ---> timer expires + queue_work(wq) <---- Results in a NULL pointer dereference + deep in the work queue core code. + del_timer_sync(t); + +Use the new timer_shutdown_sync() function to ensure that the timers are +disarmed, no timer callbacks are running and the timers cannot be armed +again. This restores the original teardown sequence: + + timer_shutdown_sync(t); + destroy_workqueue(wq); + +which is now correct because the timer core silently ignores potential +rearming attempts which can happen when destroy_workqueue() drains pending +work before mopping up the workqueue. + +Fixes: 72ef98445aca ("Bluetooth: hci_qca: Use del_timer_sync() before freeing") +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Acked-by: Luiz Augusto von Dentz +Link: https://lore.kernel.org/all/87iljhsftt.ffs@tglx +Link: https://lore.kernel.org/r/20221123201625.435907114@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bluetooth/hci_qca.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -698,9 +698,15 @@ static int qca_close(struct hci_uart *hu + skb_queue_purge(&qca->tx_wait_q); + skb_queue_purge(&qca->txq); + skb_queue_purge(&qca->rx_memdump_q); ++ /* ++ * Shut the timers down so they can't be rearmed when ++ * destroy_workqueue() drains pending work which in turn might try ++ * to arm a timer. After shutdown rearm attempts are silently ++ * ignored by the timer core code. ++ */ ++ timer_shutdown_sync(&qca->tx_idle_timer); ++ timer_shutdown_sync(&qca->wake_retrans_timer); + destroy_workqueue(qca->workqueue); +- del_timer_sync(&qca->tx_idle_timer); +- del_timer_sync(&qca->wake_retrans_timer); + qca->hu = NULL; + + kfree_skb(qca->rx_skb); diff --git a/queue-5.10/clocksource-drivers-arm_arch_timer-do-not-use-timer-namespace-for-timer_shutdown-function.patch b/queue-5.10/clocksource-drivers-arm_arch_timer-do-not-use-timer-namespace-for-timer_shutdown-function.patch new file mode 100644 index 0000000000..c66dc3a6e7 --- /dev/null +++ b/queue-5.10/clocksource-drivers-arm_arch_timer-do-not-use-timer-namespace-for-timer_shutdown-function.patch @@ -0,0 +1,76 @@ +From aha310510@gmail.com Thu Feb 19 18:13:28 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:12:58 +0900 +Subject: clocksource/drivers/arm_arch_timer: Do not use timer namespace for timer_shutdown() function +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-4-aha310510@gmail.com> + +From: "Steven Rostedt (Google)" + +[ Upstream commit 73737a5833ace25a8408b0d3b783637cb6bf29d1 ] + +A new "shutdown" timer state is being added to the generic timer code. One +of the functions to change the timer into the state is called +"timer_shutdown()". This means that there can not be other functions +called "timer_shutdown()" as the timer code owns the "timer_*" name space. + +Rename timer_shutdown() to arch_timer_shutdown() to avoid this conflict. + +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Acked-by: Marc Zyngier +Link: https://lkml.kernel.org/r/20221106212702.002251651@goodmis.org +Link: https://lore.kernel.org/all/20221105060155.409832154@goodmis.org/ +Link: https://lore.kernel.org/r/20221110064146.981725531@goodmis.org +Link: https://lore.kernel.org/r/20221123201624.574672568@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + drivers/clocksource/arm_arch_timer.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/clocksource/arm_arch_timer.c ++++ b/drivers/clocksource/arm_arch_timer.c +@@ -679,8 +679,8 @@ static irqreturn_t arch_timer_handler_vi + return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); + } + +-static __always_inline int timer_shutdown(const int access, +- struct clock_event_device *clk) ++static __always_inline int arch_timer_shutdown(const int access, ++ struct clock_event_device *clk) + { + unsigned long ctrl; + +@@ -693,22 +693,22 @@ static __always_inline int timer_shutdow + + static int arch_timer_shutdown_virt(struct clock_event_device *clk) + { +- return timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk); ++ return arch_timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk); + } + + static int arch_timer_shutdown_phys(struct clock_event_device *clk) + { +- return timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk); ++ return arch_timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk); + } + + static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk) + { +- return timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk); ++ return arch_timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk); + } + + static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk) + { +- return timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk); ++ return arch_timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk); + } + + static __always_inline void set_next_event(const int access, unsigned long evt, diff --git a/queue-5.10/clocksource-drivers-sp804-do-not-use-timer-namespace-for-timer_shutdown-function.patch b/queue-5.10/clocksource-drivers-sp804-do-not-use-timer-namespace-for-timer_shutdown-function.patch new file mode 100644 index 0000000000..b31bfe64dc --- /dev/null +++ b/queue-5.10/clocksource-drivers-sp804-do-not-use-timer-namespace-for-timer_shutdown-function.patch @@ -0,0 +1,63 @@ +From aha310510@gmail.com Thu Feb 19 18:13:32 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:12:59 +0900 +Subject: clocksource/drivers/sp804: Do not use timer namespace for timer_shutdown() function +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-5-aha310510@gmail.com> + +From: "Steven Rostedt (Google)" + +[ Upstream commit 6e1fc2591f116dfb20b65cf27356475461d61bd8 ] + +A new "shutdown" timer state is being added to the generic timer code. One +of the functions to change the timer into the state is called +"timer_shutdown()". This means that there can not be other functions +called "timer_shutdown()" as the timer code owns the "timer_*" name space. + +Rename timer_shutdown() to evt_timer_shutdown() to avoid this conflict. + +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lkml.kernel.org/r/20221106212702.182883323@goodmis.org +Link: https://lore.kernel.org/all/20221105060155.592778858@goodmis.org/ +Link: https://lore.kernel.org/r/20221110064147.158230501@goodmis.org +Link: https://lore.kernel.org/r/20221123201624.634354813@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + drivers/clocksource/timer-sp804.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/clocksource/timer-sp804.c ++++ b/drivers/clocksource/timer-sp804.c +@@ -170,14 +170,14 @@ static irqreturn_t sp804_timer_interrupt + return IRQ_HANDLED; + } + +-static inline void timer_shutdown(struct clock_event_device *evt) ++static inline void evt_timer_shutdown(struct clock_event_device *evt) + { + writel(0, common_clkevt->ctrl); + } + + static int sp804_shutdown(struct clock_event_device *evt) + { +- timer_shutdown(evt); ++ evt_timer_shutdown(evt); + return 0; + } + +@@ -186,7 +186,7 @@ static int sp804_set_periodic(struct clo + unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | + TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + +- timer_shutdown(evt); ++ evt_timer_shutdown(evt); + writel(common_clkevt->reload, common_clkevt->load); + writel(ctrl, common_clkevt->ctrl); + return 0; diff --git a/queue-5.10/documentation-remove-bogus-claim-about-del_timer_sync.patch b/queue-5.10/documentation-remove-bogus-claim-about-del_timer_sync.patch new file mode 100644 index 0000000000..ca66b5bb79 --- /dev/null +++ b/queue-5.10/documentation-remove-bogus-claim-about-del_timer_sync.patch @@ -0,0 +1,57 @@ +From linux-staging+bounces-37306-greg=kroah.com@lists.linux.dev Thu Feb 19 18:13:29 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:12:56 +0900 +Subject: Documentation: Remove bogus claim about del_timer_sync() +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-2-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit b0b0aa5d858d4d2fe39a5e4486e0550e858108f6 ] + +del_timer_sync() does not return the number of times it tried to delete the +timer which rearms itself. It's clearly documented: + + The function returns whether it has deactivated a pending timer or not. + +This part of the documentation is from 2003 where del_timer_sync() really +returned the number of deletion attempts for unknown reasons. The code +was rewritten in 2005, but the documentation was not updated. + +Signed-off-by: Thomas Gleixner +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/r/20221123201624.452282769@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/kernel-hacking/locking.rst | 3 +-- + Documentation/translations/it_IT/kernel-hacking/locking.rst | 4 +--- + 2 files changed, 2 insertions(+), 5 deletions(-) + +--- a/Documentation/kernel-hacking/locking.rst ++++ b/Documentation/kernel-hacking/locking.rst +@@ -1015,8 +1015,7 @@ Another common problem is deleting timer + calling add_timer() at the end of their timer function). + Because this is a fairly common case which is prone to races, you should + use del_timer_sync() (``include/linux/timer.h``) to +-handle this case. It returns the number of times the timer had to be +-deleted before we finally stopped it from adding itself back in. ++handle this case. + + Locking Speed + ============= +--- a/Documentation/translations/it_IT/kernel-hacking/locking.rst ++++ b/Documentation/translations/it_IT/kernel-hacking/locking.rst +@@ -1037,9 +1037,7 @@ Un altro problema è l'eliminazione dei + da soli (chiamando add_timer() alla fine della loro esecuzione). + Dato che questo è un problema abbastanza comune con una propensione + alle corse critiche, dovreste usare del_timer_sync() +-(``include/linux/timer.h``) per gestire questo caso. Questa ritorna il +-numero di volte che il temporizzatore è stato interrotto prima che +-fosse in grado di fermarlo senza che si riavviasse. ++(``include/linux/timer.h``) per gestire questo caso. + + Velocità della sincronizzazione + =============================== diff --git a/queue-5.10/documentation-replace-del_timer-del_timer_sync.patch b/queue-5.10/documentation-replace-del_timer-del_timer_sync.patch new file mode 100644 index 0000000000..94f03d3797 --- /dev/null +++ b/queue-5.10/documentation-replace-del_timer-del_timer_sync.patch @@ -0,0 +1,157 @@ +From linux-staging+bounces-37313-greg=kroah.com@lists.linux.dev Thu Feb 19 18:14:11 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:03 +0900 +Subject: Documentation: Replace del_timer/del_timer_sync() +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-9-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit 87bdd932e85881895d4720255b40ac28749c4e32 ] + +Adjust to the new preferred function names. + +Suggested-by: Steven Rostedt +Signed-off-by: Thomas Gleixner +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/r/20221123201625.075320635@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/RCU/Design/Requirements/Requirements.rst | 2 +- + Documentation/core-api/local_ops.rst | 2 +- + Documentation/kernel-hacking/locking.rst | 11 +++++------ + Documentation/timers/hrtimers.rst | 2 +- + Documentation/translations/it_IT/kernel-hacking/locking.rst | 10 +++++----- + 5 files changed, 13 insertions(+), 14 deletions(-) + +--- a/Documentation/RCU/Design/Requirements/Requirements.rst ++++ b/Documentation/RCU/Design/Requirements/Requirements.rst +@@ -1858,7 +1858,7 @@ unloaded. After a given module has been + one of its functions results in a segmentation fault. The module-unload + functions must therefore cancel any delayed calls to loadable-module + functions, for example, any outstanding ``mod_timer()`` must be dealt +-with via ``del_timer_sync()`` or similar. ++with via ``timer_delete_sync()`` or similar. + + Unfortunately, there is no way to cancel an RCU callback; once you + invoke ``call_rcu()``, the callback function is eventually going to be +--- a/Documentation/core-api/local_ops.rst ++++ b/Documentation/core-api/local_ops.rst +@@ -191,7 +191,7 @@ Here is a sample module which implements + + static void __exit test_exit(void) + { +- del_timer_sync(&test_timer); ++ timer_delete_sync(&test_timer); + } + + module_init(test_init); +--- a/Documentation/kernel-hacking/locking.rst ++++ b/Documentation/kernel-hacking/locking.rst +@@ -976,7 +976,7 @@ you might do the following:: + + while (list) { + struct foo *next = list->next; +- del_timer(&list->timer); ++ timer_delete(&list->timer); + kfree(list); + list = next; + } +@@ -990,7 +990,7 @@ the lock after we spin_unlock_bh(), and + the element (which has already been freed!). + + This can be avoided by checking the result of +-del_timer(): if it returns 1, the timer has been deleted. ++timer_delete(): if it returns 1, the timer has been deleted. + If 0, it means (in this case) that it is currently running, so we can + do:: + +@@ -999,7 +999,7 @@ do:: + + while (list) { + struct foo *next = list->next; +- if (!del_timer(&list->timer)) { ++ if (!timer_delete(&list->timer)) { + /* Give timer a chance to delete this */ + spin_unlock_bh(&list_lock); + goto retry; +@@ -1014,8 +1014,7 @@ do:: + Another common problem is deleting timers which restart themselves (by + calling add_timer() at the end of their timer function). + Because this is a fairly common case which is prone to races, you should +-use del_timer_sync() (``include/linux/timer.h``) to +-handle this case. ++use timer_delete_sync() (``include/linux/timer.h``) to handle this case. + + Locking Speed + ============= +@@ -1343,7 +1342,7 @@ lock. + + - kfree() + +-- add_timer() and del_timer() ++- add_timer() and timer_delete() + + Mutex API reference + =================== +--- a/Documentation/timers/hrtimers.rst ++++ b/Documentation/timers/hrtimers.rst +@@ -118,7 +118,7 @@ existing timer wheel code, as it is matu + was not really a win, due to the different data structures. Also, the + hrtimer functions now have clearer behavior and clearer names - such as + hrtimer_try_to_cancel() and hrtimer_cancel() [which are roughly +-equivalent to del_timer() and del_timer_sync()] - so there's no direct ++equivalent to timer_delete() and timer_delete_sync()] - so there's no direct + 1:1 mapping between them on the algorithmic level, and thus no real + potential for code sharing either. + +--- a/Documentation/translations/it_IT/kernel-hacking/locking.rst ++++ b/Documentation/translations/it_IT/kernel-hacking/locking.rst +@@ -1000,7 +1000,7 @@ potreste fare come segue:: + + while (list) { + struct foo *next = list->next; +- del_timer(&list->timer); ++ timer_delete(&list->timer); + kfree(list); + list = next; + } +@@ -1013,7 +1013,7 @@ e prenderà il *lock* solo dopo spin_unl + di eliminare il suo oggetto (che però è già stato eliminato). + + Questo può essere evitato controllando il valore di ritorno di +-del_timer(): se ritorna 1, il temporizzatore è stato già ++timer_delete(): se ritorna 1, il temporizzatore è stato già + rimosso. Se 0, significa (in questo caso) che il temporizzatore è in + esecuzione, quindi possiamo fare come segue:: + +@@ -1022,7 +1022,7 @@ esecuzione, quindi possiamo fare come se + + while (list) { + struct foo *next = list->next; +- if (!del_timer(&list->timer)) { ++ if (!timer_delete(&list->timer)) { + /* Give timer a chance to delete this */ + spin_unlock_bh(&list_lock); + goto retry; +@@ -1036,7 +1036,7 @@ esecuzione, quindi possiamo fare come se + Un altro problema è l'eliminazione dei temporizzatori che si riavviano + da soli (chiamando add_timer() alla fine della loro esecuzione). + Dato che questo è un problema abbastanza comune con una propensione +-alle corse critiche, dovreste usare del_timer_sync() ++alle corse critiche, dovreste usare timer_delete_sync() + (``include/linux/timer.h``) per gestire questo caso. + + Velocità della sincronizzazione +@@ -1384,7 +1384,7 @@ contesto, o trattenendo un qualsiasi *lo + + - kfree() + +-- add_timer() e del_timer() ++- add_timer() e timer_delete() + + Riferimento per l'API dei Mutex + =============================== diff --git a/queue-5.10/drm-amd-display-do-not-add-mhard-float-to-calcs-dsc-and-dcn30-fp-files-for-clang.patch b/queue-5.10/drm-amd-display-do-not-add-mhard-float-to-calcs-dsc-and-dcn30-fp-files-for-clang.patch new file mode 100644 index 0000000000..8e1e21abb9 --- /dev/null +++ b/queue-5.10/drm-amd-display-do-not-add-mhard-float-to-calcs-dsc-and-dcn30-fp-files-for-clang.patch @@ -0,0 +1,84 @@ +From stable+bounces-233477-greg=kroah.com@vger.kernel.org Tue Apr 7 02:49:29 2026 +From: Nathan Chancellor +Date: Mon, 06 Apr 2026 17:49:08 -0700 +Subject: drm/amd/display: Do not add '-mhard-float' to calcs, dsc, and dcn30 FP files for clang +To: Greg Kroah-Hartman , Sasha Levin +Cc: stable@vger.kernel.org, Nick Desaulniers , amd-gfx@lists.freedesktop.org, llvm@lists.linux.dev, Nathan Chancellor +Message-ID: <20260406-5-10-clang-amdgpu-hard-float-errors-v1-1-09c4c045f848@kernel.org> + +From: Nathan Chancellor + +This patch is for linux-5.10.y only. It is functionally equivalent to +upstream commit 7db038d9790e ("drm/amd/display: Do not add +'-mhard-float' to dml_ccflags for clang"), which was created after all +files that require '-mhard-float' were moved under the dml folder. In +linux-5.10.y, which does not contain upstream commits + + b4bab46400a0 ("drm/amd/display: move calcs folder into DML") + 27e01f10d183 ("drm/amd/display: move FPU associated DSC code to DML folder") + 40b31e5355ba ("drm/amd/display: Remove FPU flags from DCN30 Makefile") + +clang-21 or newer errors with + + clang: error: unsupported option '-mhard-float' for target 'x86_64-pc-linux-gnu' + make[6]: *** [scripts/Makefile.build:286: drivers/gpu/drm/amd/amdgpu/../display/dc/calcs/dcn_calc_math.o] Error 1 + clang: error: unsupported option '-mhard-float' for target 'x86_64-pc-linux-gnu' + make[6]: *** [scripts/Makefile.build:286: drivers/gpu/drm/amd/amdgpu/../display/dc/calcs/dcn_calcs.o] Error 1 + clang: error: unsupported option '-mhard-float' for target 'x86_64-pc-linux-gnu' + make[6]: *** [scripts/Makefile.build:286: drivers/gpu/drm/amd/amdgpu/../display/dc/calcs/dcn_calc_auto.o] Error 1 + clang: error: unsupported option '-mhard-float' for target 'x86_64-pc-linux-gnu' + make[6]: *** [scripts/Makefile.build:286: drivers/gpu/drm/amd/amdgpu/../display/dc/dsc/rc_calc.o] Error 1 + clang: error: unsupported option '-mhard-float' for target 'x86_64-pc-linux-gnu' + make[6]: *** [scripts/Makefile.build:286: drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_optc.o] Error 1 + clang: error: unsupported option '-mhard-float' for target 'x86_64-pc-linux-gnu' + make[6]: *** [scripts/Makefile.build:286: drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_resource.o] Error 1 + +Apply a functionally equivalent change to prevent adding '-mhard-float' +with clang for these files. + +Closes: https://github.com/ClangBuiltLinux/linux/issues/2156 +Signed-off-by: Nathan Chancellor +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/dc/calcs/Makefile | 3 ++- + drivers/gpu/drm/amd/display/dc/dcn30/Makefile | 4 ++-- + drivers/gpu/drm/amd/display/dc/dsc/Makefile | 3 ++- + 3 files changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile +@@ -26,7 +26,8 @@ + # + + ifdef CONFIG_X86 +-calcs_ccflags := -mhard-float -msse ++calcs_ccflags-$(CONFIG_CC_IS_GCC) := -mhard-float ++calcs_ccflags := $(calcs_ccflags-y) -msse + endif + + ifdef CONFIG_PPC64 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/Makefile +@@ -32,8 +32,8 @@ DCN30 = dcn30_init.o dcn30_hubbub.o dcn3 + + + ifdef CONFIG_X86 +-CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := -mhard-float -msse +-CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := -mhard-float -msse ++CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_resource.o := $(if $(CONFIG_CC_IS_GCC),-mhard-float) -msse ++CFLAGS_$(AMDDALPATH)/dc/dcn30/dcn30_optc.o := $(if $(CONFIG_CC_IS_GCC),-mhard-float) -msse + endif + + ifdef CONFIG_PPC64 +--- a/drivers/gpu/drm/amd/display/dc/dsc/Makefile ++++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile +@@ -3,7 +3,8 @@ + # Makefile for the 'dsc' sub-component of DAL. + + ifdef CONFIG_X86 +-dsc_ccflags := -mhard-float -msse ++dsc_ccflags-$(CONFIG_CC_IS_GCC) := -mhard-float ++dsc_ccflags := $(dsc_ccflags-y) -msse + endif + + ifdef CONFIG_PPC64 diff --git a/queue-5.10/gfs2-validate-i_depth-for-exhash-directories.patch b/queue-5.10/gfs2-validate-i_depth-for-exhash-directories.patch new file mode 100644 index 0000000000..516bcd01ad --- /dev/null +++ b/queue-5.10/gfs2-validate-i_depth-for-exhash-directories.patch @@ -0,0 +1,91 @@ +From stable+bounces-240403-greg=kroah.com@vger.kernel.org Thu Apr 23 05:20:44 2026 +From: Ruohan Lan +Date: Thu, 23 Apr 2026 11:20:02 +0800 +Subject: gfs2: Validate i_depth for exhash directories +To: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org +Cc: gfs2@lists.linux.dev, Andrew Price , syzbot+4708579bb230a0582a57@syzkaller.appspotmail.com, Andreas Gruenbacher , Ruohan Lan +Message-ID: <20260423032002.2803528-1-ruohanlan@aliyun.com> + +From: Andrew Price + +[ Upstream commit 557c024ca7250bb65ae60f16c02074106c2f197b ] + +A fuzzer test introduced corruption that ends up with a depth of 0 in +dir_e_read(), causing an undefined shift by 32 at: + + index = hash >> (32 - dip->i_depth); + +As calculated in an open-coded way in dir_make_exhash(), the minimum +depth for an exhash directory is ilog2(sdp->sd_hash_ptrs) and 0 is +invalid as sdp->sd_hash_ptrs is fixed as sdp->bsize / 16 at mount time. + +So we can avoid the undefined behaviour by checking for depth values +lower than the minimum in gfs2_dinode_in(). Values greater than the +maximum are already being checked for there. + +Also switch the calculation in dir_make_exhash() to use ilog2() to +clarify how the depth is calculated. + +Tested with the syzkaller repro.c and xfstests '-g quick'. + +Reported-by: syzbot+4708579bb230a0582a57@syzkaller.appspotmail.com +Signed-off-by: Andrew Price +Signed-off-by: Andreas Gruenbacher +[ To maintain consistency in error handling in gfs2_dinode_in(), +use "goto corrupt" in v5.10. ] +Signed-off-by: Ruohan Lan +Signed-off-by: Greg Kroah-Hartman +--- + fs/gfs2/dir.c | 6 ++---- + fs/gfs2/glops.c | 4 ++++ + 2 files changed, 6 insertions(+), 4 deletions(-) + +--- a/fs/gfs2/dir.c ++++ b/fs/gfs2/dir.c +@@ -60,6 +60,7 @@ + #include + #include + #include ++#include + + #include "gfs2.h" + #include "incore.h" +@@ -910,7 +911,6 @@ static int dir_make_exhash(struct inode + struct qstr args; + struct buffer_head *bh, *dibh; + struct gfs2_leaf *leaf; +- int y; + u32 x; + __be64 *lp; + u64 bn; +@@ -977,9 +977,7 @@ static int dir_make_exhash(struct inode + i_size_write(inode, sdp->sd_sb.sb_bsize / 2); + gfs2_add_inode_blocks(&dip->i_inode, 1); + dip->i_diskflags |= GFS2_DIF_EXHASH; +- +- for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; +- dip->i_depth = y; ++ dip->i_depth = ilog2(sdp->sd_hash_ptrs); + + gfs2_dinode_out(dip, dibh->b_data); + +--- a/fs/gfs2/glops.c ++++ b/fs/gfs2/glops.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "gfs2.h" + #include "incore.h" +@@ -452,6 +453,9 @@ static int gfs2_dinode_in(struct gfs2_in + depth = be16_to_cpu(str->di_depth); + if (unlikely(depth > GFS2_DIR_MAX_DEPTH)) + goto corrupt; ++ if ((ip->i_diskflags & GFS2_DIF_EXHASH) && ++ depth < ilog2(sdp->sd_hash_ptrs)) ++ goto corrupt; + ip->i_depth = (u8)depth; + ip->i_entries = be32_to_cpu(str->di_entries); + diff --git a/queue-5.10/i3c-fix-uninitialized-variable-use-in-i2c-setup.patch b/queue-5.10/i3c-fix-uninitialized-variable-use-in-i2c-setup.patch new file mode 100644 index 0000000000..9f5c6682ce --- /dev/null +++ b/queue-5.10/i3c-fix-uninitialized-variable-use-in-i2c-setup.patch @@ -0,0 +1,45 @@ +From 6cbf8b38dfe3aabe330f2c356949bc4d6a1f034f Mon Sep 17 00:00:00 2001 +From: Jamie Iles +Date: Tue, 8 Mar 2022 13:42:26 +0000 +Subject: i3c: fix uninitialized variable use in i2c setup + +From: Jamie Iles + +commit 6cbf8b38dfe3aabe330f2c356949bc4d6a1f034f upstream. + +Commit 31b9887c7258 ("i3c: remove i2c board info from i2c_dev_desc") +removed the boardinfo from i2c_dev_desc to decouple device enumeration from +setup but did not correctly lookup the i2c_dev_desc to store the new +device, instead dereferencing an uninitialized variable. + +Lookup the device that has already been registered by address to store +the i2c client device. + +Fixes: 31b9887c7258 ("i3c: remove i2c board info from i2c_dev_desc") +Reported-by: kernel test robot +Cc: Alexandre Belloni +Signed-off-by: Jamie Iles +Signed-off-by: Alexandre Belloni +Link: https://lore.kernel.org/r/20220308134226.1042367-1-quic_jiles@quicinc.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/i3c/master.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -2241,8 +2241,13 @@ static int i3c_master_i2c_adapter_init(s + * We silently ignore failures here. The bus should keep working + * correctly even if one or more i2c devices are not registered. + */ +- list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) ++ list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) { ++ i2cdev = i3c_master_find_i2c_dev_by_addr(master, ++ i2cboardinfo->base.addr); ++ if (WARN_ON(!i2cdev)) ++ continue; + i2cdev->dev = i2c_new_client_device(adap, &i2cboardinfo->base); ++ } + + return 0; + } diff --git a/queue-5.10/scripts-dtc-remove-unused-dts_version-in-dtc-lexer.l.patch b/queue-5.10/scripts-dtc-remove-unused-dts_version-in-dtc-lexer.l.patch new file mode 100644 index 0000000000..56a97be723 --- /dev/null +++ b/queue-5.10/scripts-dtc-remove-unused-dts_version-in-dtc-lexer.l.patch @@ -0,0 +1,55 @@ +From stable+bounces-240015-greg=kroah.com@vger.kernel.org Tue Apr 21 02:37:02 2026 +From: Nathan Chancellor +Date: Mon, 20 Apr 2026 17:36:46 -0700 +Subject: scripts/dtc: Remove unused dts_version in dtc-lexer.l +To: Greg Kroah-Hartman , Sasha Levin +Cc: stable@vger.kernel.org, devicetree@vger.kernel.org, Nathan Chancellor +Message-ID: <20260420-stable-dts-unused-but-set-global-v1-1-9bdfba6889bb@kernel.org> + +From: Nathan Chancellor + +This patch is for stable only. Commit 5a09df20872c ("scripts/dtc: Update +to upstream version v1.7.2-69-g53373d135579") upstream applied it as +part of a regular scripts/dtc sync, which may be unsuitable for older +versions of stable where the warning it fixes is present. + +A recent strengthening of -Wunused-but-set-variable (enabled with -Wall) +in clang under a new subwarning, -Wunused-but-set-global, points out an +unused static global variable in dtc-lexer.lex.c (compiled from +dtc-lexer.l): + + scripts/dtc/dtc-lexer.lex.c:641:12: warning: variable 'dts_version' set but not used [-Wunused-but-set-global] + 641 | static int dts_version = 1; + | ^ + +Remove it to clear up the warning, as it is truly unused. + +Fixes: 658f29a51e98 ("of/flattree: Update dtc to current mainline.") +Signed-off-by: Nathan Chancellor +Signed-off-by: Greg Kroah-Hartman +--- +This should apply cleanly to all supported stable branches. +Signed-off-by: Greg Kroah-Hartman +--- + scripts/dtc/dtc-lexer.l | 3 --- + 1 file changed, 3 deletions(-) + +--- a/scripts/dtc/dtc-lexer.l ++++ b/scripts/dtc/dtc-lexer.l +@@ -39,8 +39,6 @@ extern bool treesource_error; + #define DPRINT(fmt, ...) do { } while (0) + #endif + +-static int dts_version = 1; +- + #define BEGIN_DEFAULT() DPRINT("\n"); \ + BEGIN(V1); \ + +@@ -101,7 +99,6 @@ static void PRINTF(1, 2) lexical_error(c + + <*>"/dts-v1/" { + DPRINT("Keyword: /dts-v1/\n"); +- dts_version = 1; + BEGIN_DEFAULT(); + return DT_V1; + } diff --git a/queue-5.10/series b/queue-5.10/series index 0fd2ca779b..cc18e670ad 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -120,3 +120,22 @@ arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-to-0.81v.patch revert-arm64-dts-imx8mq-librem5-set-the-dvs-voltages-lower.patch arm64-dts-imx8mq-librem5-bump-buck1-suspend-voltage-up-to-0.85v.patch +gfs2-validate-i_depth-for-exhash-directories.patch +drm-amd-display-do-not-add-mhard-float-to-calcs-dsc-and-dcn30-fp-files-for-clang.patch +scripts-dtc-remove-unused-dts_version-in-dtc-lexer.l.patch +i3c-fix-uninitialized-variable-use-in-i2c-setup.patch +documentation-remove-bogus-claim-about-del_timer_sync.patch +arm-spear-do-not-use-timer-namespace-for-timer_shutdown-function.patch +clocksource-drivers-arm_arch_timer-do-not-use-timer-namespace-for-timer_shutdown-function.patch +clocksource-drivers-sp804-do-not-use-timer-namespace-for-timer_shutdown-function.patch +timers-get-rid-of-del_singleshot_timer_sync.patch +timers-replace-bug_on-s.patch +timers-rename-del_timer-to-timer_delete.patch +documentation-replace-del_timer-del_timer_sync.patch +timers-silently-ignore-timers-with-a-null-function.patch +timers-split-del_timer-to-prepare-for-shutdown-mode.patch +timers-add-shutdown-mechanism-to-the-internal-functions.patch +timers-provide-timer_shutdown.patch +timers-update-the-documentation-to-reflect-on-the-new-timer_shutdown-api.patch +bluetooth-hci_qca-fix-the-teardown-problem-for-real.patch +timers-fix-null-function-pointer-race-in-timer_shutdown_sync.patch diff --git a/queue-5.10/timers-add-shutdown-mechanism-to-the-internal-functions.patch b/queue-5.10/timers-add-shutdown-mechanism-to-the-internal-functions.patch new file mode 100644 index 0000000000..74fd332dc6 --- /dev/null +++ b/queue-5.10/timers-add-shutdown-mechanism-to-the-internal-functions.patch @@ -0,0 +1,184 @@ +From aha310510@gmail.com Thu Feb 19 18:14:02 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:06 +0900 +Subject: timers: Add shutdown mechanism to the internal functions +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-12-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit 0cc04e80458a822300b93f82ed861a513edde194 ] + +Tearing down timers which have circular dependencies to other +functionality, e.g. workqueues, where the timer can schedule work and work +can arm timers, is not trivial. + +In those cases it is desired to shutdown the timer in a way which prevents +rearming of the timer. The mechanism to do so is to set timer->function to +NULL and use this as an indicator for the timer arming functions to ignore +the (re)arm request. + +Add a shutdown argument to the relevant internal functions which makes the +actual deactivation code set timer->function to NULL which in turn prevents +rearming of the timer. + +Co-developed-by: Steven Rostedt +Signed-off-by: Steven Rostedt +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/all/20220407161745.7d6754b3@gandalf.local.home +Link: https://lore.kernel.org/all/20221110064101.429013735@goodmis.org +Link: https://lore.kernel.org/r/20221123201625.253883224@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + kernel/time/timer.c | 62 +++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 54 insertions(+), 8 deletions(-) + +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1247,12 +1247,19 @@ EXPORT_SYMBOL_GPL(add_timer_on); + /** + * __timer_delete - Internal function: Deactivate a timer + * @timer: The timer to be deactivated ++ * @shutdown: If true, this indicates that the timer is about to be ++ * shutdown permanently. ++ * ++ * If @shutdown is true then @timer->function is set to NULL under the ++ * timer base lock which prevents further rearming of the time. In that ++ * case any attempt to rearm @timer after this function returns will be ++ * silently ignored. + * + * Return: + * * %0 - The timer was not pending + * * %1 - The timer was pending and deactivated + */ +-static int __timer_delete(struct timer_list *timer) ++static int __timer_delete(struct timer_list *timer, bool shutdown) + { + struct timer_base *base; + unsigned long flags; +@@ -1260,9 +1267,22 @@ static int __timer_delete(struct timer_l + + debug_assert_init(timer); + +- if (timer_pending(timer)) { ++ /* ++ * If @shutdown is set then the lock has to be taken whether the ++ * timer is pending or not to protect against a concurrent rearm ++ * which might hit between the lockless pending check and the lock ++ * aquisition. By taking the lock it is ensured that such a newly ++ * enqueued timer is dequeued and cannot end up with ++ * timer->function == NULL in the expiry code. ++ * ++ * If timer->function is currently executed, then this makes sure ++ * that the callback cannot requeue the timer. ++ */ ++ if (timer_pending(timer) || shutdown) { + base = lock_timer_base(timer, &flags); + ret = detach_if_pending(timer, base, true); ++ if (shutdown) ++ timer->function = NULL; + raw_spin_unlock_irqrestore(&base->lock, flags); + } + +@@ -1285,20 +1305,31 @@ static int __timer_delete(struct timer_l + */ + int timer_delete(struct timer_list *timer) + { +- return __timer_delete(timer); ++ return __timer_delete(timer, false); + } + EXPORT_SYMBOL(timer_delete); + + /** + * __try_to_del_timer_sync - Internal function: Try to deactivate a timer + * @timer: Timer to deactivate ++ * @shutdown: If true, this indicates that the timer is about to be ++ * shutdown permanently. ++ * ++ * If @shutdown is true then @timer->function is set to NULL under the ++ * timer base lock which prevents further rearming of the timer. Any ++ * attempt to rearm @timer after this function returns will be silently ++ * ignored. ++ * ++ * This function cannot guarantee that the timer cannot be rearmed ++ * right after dropping the base lock if @shutdown is false. That ++ * needs to be prevented by the calling code if necessary. + * + * Return: + * * %0 - The timer was not pending + * * %1 - The timer was pending and deactivated + * * %-1 - The timer callback function is running on a different CPU + */ +-static int __try_to_del_timer_sync(struct timer_list *timer) ++static int __try_to_del_timer_sync(struct timer_list *timer, bool shutdown) + { + struct timer_base *base; + unsigned long flags; +@@ -1310,6 +1341,8 @@ static int __try_to_del_timer_sync(struc + + if (base->running_timer != timer) + ret = detach_if_pending(timer, base, true); ++ if (shutdown) ++ timer->function = NULL; + + raw_spin_unlock_irqrestore(&base->lock, flags); + +@@ -1334,7 +1367,7 @@ static int __try_to_del_timer_sync(struc + */ + int try_to_del_timer_sync(struct timer_list *timer) + { +- return __try_to_del_timer_sync(timer); ++ return __try_to_del_timer_sync(timer, false); + } + EXPORT_SYMBOL(try_to_del_timer_sync); + +@@ -1415,12 +1448,25 @@ static inline void del_timer_wait_runnin + * __timer_delete_sync - Internal function: Deactivate a timer and wait + * for the handler to finish. + * @timer: The timer to be deactivated ++ * @shutdown: If true, @timer->function will be set to NULL under the ++ * timer base lock which prevents rearming of @timer ++ * ++ * If @shutdown is not set the timer can be rearmed later. If the timer can ++ * be rearmed concurrently, i.e. after dropping the base lock then the ++ * return value is meaningless. ++ * ++ * If @shutdown is set then @timer->function is set to NULL under timer ++ * base lock which prevents rearming of the timer. Any attempt to rearm ++ * a shutdown timer is silently ignored. ++ * ++ * If the timer should be reused after shutdown it has to be initialized ++ * again. + * + * Return: + * * %0 - The timer was not pending + * * %1 - The timer was pending and deactivated + */ +-static int __timer_delete_sync(struct timer_list *timer) ++static int __timer_delete_sync(struct timer_list *timer, bool shutdown) + { + int ret; + +@@ -1443,7 +1489,7 @@ static int __timer_delete_sync(struct ti + WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE)); + + do { +- ret = __try_to_del_timer_sync(timer); ++ ret = __try_to_del_timer_sync(timer, shutdown); + + if (unlikely(ret < 0)) { + del_timer_wait_running(timer); +@@ -1495,7 +1541,7 @@ static int __timer_delete_sync(struct ti + */ + int timer_delete_sync(struct timer_list *timer) + { +- return __timer_delete_sync(timer); ++ return __timer_delete_sync(timer, false); + } + EXPORT_SYMBOL(timer_delete_sync); + diff --git a/queue-5.10/timers-fix-null-function-pointer-race-in-timer_shutdown_sync.patch b/queue-5.10/timers-fix-null-function-pointer-race-in-timer_shutdown_sync.patch new file mode 100644 index 0000000000..30d5b1a2a7 --- /dev/null +++ b/queue-5.10/timers-fix-null-function-pointer-race-in-timer_shutdown_sync.patch @@ -0,0 +1,92 @@ +From aha310510@gmail.com Thu Feb 19 18:14:19 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:10 +0900 +Subject: timers: Fix NULL function pointer race in timer_shutdown_sync() +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev +Message-ID: <20260219171310.118170-16-aha310510@gmail.com> + +From: Yipeng Zou + +[ Upstream commit 20739af07383e6eb1ec59dcd70b72ebfa9ac362c ] + +There is a race condition between timer_shutdown_sync() and timer +expiration that can lead to hitting a WARN_ON in expire_timers(). + +The issue occurs when timer_shutdown_sync() clears the timer function +to NULL while the timer is still running on another CPU. The race +scenario looks like this: + +CPU0 CPU1 + + lock_timer_base() + expire_timers() + base->running_timer = timer; + unlock_timer_base() + [call_timer_fn enter] + mod_timer() + ... +timer_shutdown_sync() +lock_timer_base() +// For now, will not detach the timer but only clear its function to NULL +if (base->running_timer != timer) + ret = detach_if_pending(timer, base, true); +if (shutdown) + timer->function = NULL; +unlock_timer_base() + [call_timer_fn exit] + lock_timer_base() + base->running_timer = NULL; + unlock_timer_base() + ... + // Now timer is pending while its function set to NULL. + // next timer trigger + + expire_timers() + WARN_ON_ONCE(!fn) // hit + ... +lock_timer_base() +// Now timer will detach +if (base->running_timer != timer) + ret = detach_if_pending(timer, base, true); +if (shutdown) + timer->function = NULL; +unlock_timer_base() + +The problem is that timer_shutdown_sync() clears the timer function +regardless of whether the timer is currently running. This can leave a +pending timer with a NULL function pointer, which triggers the +WARN_ON_ONCE(!fn) check in expire_timers(). + +Fix this by only clearing the timer function when actually detaching the +timer. If the timer is running, leave the function pointer intact, which is +safe because the timer will be properly detached when it finishes running. + +Fixes: 0cc04e80458a ("timers: Add shutdown mechanism to the internal functions") +Signed-off-by: Yipeng Zou +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20251122093942.301559-1-zouyipeng@huawei.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + kernel/time/timer.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1360,10 +1360,11 @@ static int __try_to_del_timer_sync(struc + + base = lock_timer_base(timer, &flags); + +- if (base->running_timer != timer) ++ if (base->running_timer != timer) { + ret = detach_if_pending(timer, base, true); +- if (shutdown) +- timer->function = NULL; ++ if (shutdown) ++ timer->function = NULL; ++ } + + raw_spin_unlock_irqrestore(&base->lock, flags); + diff --git a/queue-5.10/timers-get-rid-of-del_singleshot_timer_sync.patch b/queue-5.10/timers-get-rid-of-del_singleshot_timer_sync.patch new file mode 100644 index 0000000000..df0a1e0421 --- /dev/null +++ b/queue-5.10/timers-get-rid-of-del_singleshot_timer_sync.patch @@ -0,0 +1,119 @@ +From aha310510@gmail.com Thu Feb 19 18:13:37 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:00 +0900 +Subject: timers: Get rid of del_singleshot_timer_sync() +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-6-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit 9a5a305686971f4be10c6d7251c8348d74b3e014 ] + +del_singleshot_timer_sync() used to be an optimization for deleting timers +which are not rearmed from the timer callback function. + +This optimization turned out to be broken and got mapped to +del_timer_sync() about 17 years ago. + +Get rid of the undocumented indirection and use del_timer_sync() directly. + +No functional change. + +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/r/20221123201624.706987932@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + drivers/char/tpm/tpm-dev-common.c | 4 ++-- + drivers/staging/wlan-ng/hfa384x_usb.c | 4 ++-- + drivers/staging/wlan-ng/prism2usb.c | 6 +++--- + include/linux/timer.h | 2 -- + kernel/time/timer.c | 2 +- + net/sunrpc/xprt.c | 2 +- + 6 files changed, 9 insertions(+), 11 deletions(-) + +--- a/drivers/char/tpm/tpm-dev-common.c ++++ b/drivers/char/tpm/tpm-dev-common.c +@@ -158,7 +158,7 @@ ssize_t tpm_common_read(struct file *fil + out: + if (!priv->response_length) { + *off = 0; +- del_singleshot_timer_sync(&priv->user_read_timer); ++ del_timer_sync(&priv->user_read_timer); + flush_work(&priv->timeout_work); + } + mutex_unlock(&priv->buffer_mutex); +@@ -265,7 +265,7 @@ __poll_t tpm_common_poll(struct file *fi + void tpm_common_release(struct file *file, struct file_priv *priv) + { + flush_work(&priv->async_work); +- del_singleshot_timer_sync(&priv->user_read_timer); ++ del_timer_sync(&priv->user_read_timer); + flush_work(&priv->timeout_work); + file->private_data = NULL; + priv->response_length = 0; +--- a/drivers/staging/wlan-ng/hfa384x_usb.c ++++ b/drivers/staging/wlan-ng/hfa384x_usb.c +@@ -1116,8 +1116,8 @@ cleanup: + if (ctlx == get_active_ctlx(hw)) { + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + +- del_singleshot_timer_sync(&hw->reqtimer); +- del_singleshot_timer_sync(&hw->resptimer); ++ del_timer_sync(&hw->reqtimer); ++ del_timer_sync(&hw->resptimer); + hw->req_timer_done = 1; + hw->resp_timer_done = 1; + usb_kill_urb(&hw->ctlx_urb); +--- a/drivers/staging/wlan-ng/prism2usb.c ++++ b/drivers/staging/wlan-ng/prism2usb.c +@@ -171,9 +171,9 @@ static void prism2sta_disconnect_usb(str + */ + prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); + +- del_singleshot_timer_sync(&hw->throttle); +- del_singleshot_timer_sync(&hw->reqtimer); +- del_singleshot_timer_sync(&hw->resptimer); ++ del_timer_sync(&hw->throttle); ++ del_timer_sync(&hw->reqtimer); ++ del_timer_sync(&hw->resptimer); + + /* Unlink all the URBs. This "removes the wheels" + * from the entire CTLX handling mechanism. +--- a/include/linux/timer.h ++++ b/include/linux/timer.h +@@ -198,8 +198,6 @@ static inline int del_timer_sync(struct + return timer_delete_sync(timer); + } + +-#define del_singleshot_timer_sync(t) del_timer_sync(t) +- + extern void init_timers(void); + extern void run_local_timers(void); + struct hrtimer; +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1905,7 +1905,7 @@ signed long __sched schedule_timeout(sig + timer_setup_on_stack(&timer.timer, process_timeout, 0); + __mod_timer(&timer.timer, expire, MOD_TIMER_NOTPENDING); + schedule(); +- del_singleshot_timer_sync(&timer.timer); ++ del_timer_sync(&timer.timer); + + /* Remove the timer from the object tracker */ + destroy_timer_on_stack(&timer.timer); +--- a/net/sunrpc/xprt.c ++++ b/net/sunrpc/xprt.c +@@ -1117,7 +1117,7 @@ xprt_request_enqueue_receive(struct rpc_ + spin_unlock(&xprt->queue_lock); + + /* Turn off autodisconnect */ +- del_singleshot_timer_sync(&xprt->timer); ++ del_timer_sync(&xprt->timer); + } + + /** diff --git a/queue-5.10/timers-provide-timer_shutdown.patch b/queue-5.10/timers-provide-timer_shutdown.patch new file mode 100644 index 0000000000..90641ccd8f --- /dev/null +++ b/queue-5.10/timers-provide-timer_shutdown.patch @@ -0,0 +1,148 @@ +From aha310510@gmail.com Thu Feb 19 18:14:07 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:07 +0900 +Subject: timers: Provide timer_shutdown[_sync]() +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-13-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit f571faf6e443b6011ccb585d57866177af1f643c ] + +Tearing down timers which have circular dependencies to other +functionality, e.g. workqueues, where the timer can schedule work and work +can arm timers, is not trivial. + +In those cases it is desired to shutdown the timer in a way which prevents +rearming of the timer. The mechanism to do so is to set timer->function to +NULL and use this as an indicator for the timer arming functions to ignore +the (re)arm request. + +Expose new interfaces for this: timer_shutdown_sync() and timer_shutdown(). + +timer_shutdown_sync() has the same functionality as timer_delete_sync() +plus the NULL-ification of the timer function. + +timer_shutdown() has the same functionality as timer_delete() plus the +NULL-ification of the timer function. + +In both cases the rearming of the timer is prevented by silently discarding +rearm attempts due to timer->function being NULL. + +Co-developed-by: Steven Rostedt +Signed-off-by: Steven Rostedt +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/all/20220407161745.7d6754b3@gandalf.local.home +Link: https://lore.kernel.org/all/20221110064101.429013735@goodmis.org +Link: https://lore.kernel.org/r/20221123201625.314230270@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/timer.h | 2 + + kernel/time/timer.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 68 insertions(+) + +--- a/include/linux/timer.h ++++ b/include/linux/timer.h +@@ -184,6 +184,8 @@ extern void add_timer(struct timer_list + extern int try_to_del_timer_sync(struct timer_list *timer); + extern int timer_delete_sync(struct timer_list *timer); + extern int timer_delete(struct timer_list *timer); ++extern int timer_shutdown_sync(struct timer_list *timer); ++extern int timer_shutdown(struct timer_list *timer); + + /** + * del_timer_sync - Delete a pending timer and wait for a running callback +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1310,6 +1310,27 @@ int timer_delete(struct timer_list *time + EXPORT_SYMBOL(timer_delete); + + /** ++ * timer_shutdown - Deactivate a timer and prevent rearming ++ * @timer: The timer to be deactivated ++ * ++ * The function does not wait for an eventually running timer callback on a ++ * different CPU but it prevents rearming of the timer. Any attempt to arm ++ * @timer after this function returns will be silently ignored. ++ * ++ * This function is useful for teardown code and should only be used when ++ * timer_shutdown_sync() cannot be invoked due to locking or context constraints. ++ * ++ * Return: ++ * * %0 - The timer was not pending ++ * * %1 - The timer was pending ++ */ ++int timer_shutdown(struct timer_list *timer) ++{ ++ return __timer_delete(timer, true); ++} ++EXPORT_SYMBOL_GPL(timer_shutdown); ++ ++/** + * __try_to_del_timer_sync - Internal function: Try to deactivate a timer + * @timer: Timer to deactivate + * @shutdown: If true, this indicates that the timer is about to be +@@ -1535,6 +1556,9 @@ static int __timer_delete_sync(struct ti + * lock. If there is the possibility of a concurrent rearm then the return + * value of the function is meaningless. + * ++ * If such a guarantee is needed, e.g. for teardown situations then use ++ * timer_shutdown_sync() instead. ++ * + * Return: + * * %0 - The timer was not pending + * * %1 - The timer was pending and deactivated +@@ -1545,6 +1569,48 @@ int timer_delete_sync(struct timer_list + } + EXPORT_SYMBOL(timer_delete_sync); + ++/** ++ * timer_shutdown_sync - Shutdown a timer and prevent rearming ++ * @timer: The timer to be shutdown ++ * ++ * When the function returns it is guaranteed that: ++ * - @timer is not queued ++ * - The callback function of @timer is not running ++ * - @timer cannot be enqueued again. Any attempt to rearm ++ * @timer is silently ignored. ++ * ++ * See timer_delete_sync() for synchronization rules. ++ * ++ * This function is useful for final teardown of an infrastructure where ++ * the timer is subject to a circular dependency problem. ++ * ++ * A common pattern for this is a timer and a workqueue where the timer can ++ * schedule work and work can arm the timer. On shutdown the workqueue must ++ * be destroyed and the timer must be prevented from rearming. Unless the ++ * code has conditionals like 'if (mything->in_shutdown)' to prevent that ++ * there is no way to get this correct with timer_delete_sync(). ++ * ++ * timer_shutdown_sync() is solving the problem. The correct ordering of ++ * calls in this case is: ++ * ++ * timer_shutdown_sync(&mything->timer); ++ * workqueue_destroy(&mything->workqueue); ++ * ++ * After this 'mything' can be safely freed. ++ * ++ * This obviously implies that the timer is not required to be functional ++ * for the rest of the shutdown operation. ++ * ++ * Return: ++ * * %0 - The timer was not pending ++ * * %1 - The timer was pending ++ */ ++int timer_shutdown_sync(struct timer_list *timer) ++{ ++ return __timer_delete_sync(timer, true); ++} ++EXPORT_SYMBOL_GPL(timer_shutdown_sync); ++ + static void call_timer_fn(struct timer_list *timer, + void (*fn)(struct timer_list *), + unsigned long baseclk) diff --git a/queue-5.10/timers-rename-del_timer-to-timer_delete.patch b/queue-5.10/timers-rename-del_timer-to-timer_delete.patch new file mode 100644 index 0000000000..f8fd519c83 --- /dev/null +++ b/queue-5.10/timers-rename-del_timer-to-timer_delete.patch @@ -0,0 +1,98 @@ +From stable+bounces-217473-greg=kroah.com@vger.kernel.org Thu Feb 19 18:14:21 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:02 +0900 +Subject: timers: Rename del_timer() to timer_delete() +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-8-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit bb663f0f3c396c6d05f6c5eeeea96ced20ff112e ] + +The timer related functions do not have a strict timer_ prefixed namespace +which is really annoying. + +Rename del_timer() to timer_delete() and provide del_timer() +as a wrapper. Document that del_timer() is not for new code. + +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Steven Rostedt (Google) +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/r/20221123201625.015535022@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/timer.h | 15 ++++++++++++++- + kernel/time/timer.c | 6 +++--- + 2 files changed, 17 insertions(+), 4 deletions(-) + +--- a/include/linux/timer.h ++++ b/include/linux/timer.h +@@ -169,7 +169,6 @@ static inline int timer_pending(const st + } + + extern void add_timer_on(struct timer_list *timer, int cpu); +-extern int del_timer(struct timer_list * timer); + extern int mod_timer(struct timer_list *timer, unsigned long expires); + extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); + extern int timer_reduce(struct timer_list *timer, unsigned long expires); +@@ -184,6 +183,7 @@ extern void add_timer(struct timer_list + + extern int try_to_del_timer_sync(struct timer_list *timer); + extern int timer_delete_sync(struct timer_list *timer); ++extern int timer_delete(struct timer_list *timer); + + /** + * del_timer_sync - Delete a pending timer and wait for a running callback +@@ -198,6 +198,19 @@ static inline int del_timer_sync(struct + return timer_delete_sync(timer); + } + ++/** ++ * del_timer - Delete a pending timer ++ * @timer: The timer to be deleted ++ * ++ * See timer_delete() for detailed explanation. ++ * ++ * Do not use in new code. Use timer_delete() instead. ++ */ ++static inline int del_timer(struct timer_list *timer) ++{ ++ return timer_delete(timer); ++} ++ + extern void init_timers(void); + extern void run_local_timers(void); + struct hrtimer; +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1204,7 +1204,7 @@ void add_timer_on(struct timer_list *tim + EXPORT_SYMBOL_GPL(add_timer_on); + + /** +- * del_timer - Deactivate a timer. ++ * timer_delete - Deactivate a timer + * @timer: The timer to be deactivated + * + * The function only deactivates a pending timer, but contrary to +@@ -1217,7 +1217,7 @@ EXPORT_SYMBOL_GPL(add_timer_on); + * * %0 - The timer was not pending + * * %1 - The timer was pending and deactivated + */ +-int del_timer(struct timer_list *timer) ++int timer_delete(struct timer_list *timer) + { + struct timer_base *base; + unsigned long flags; +@@ -1233,7 +1233,7 @@ int del_timer(struct timer_list *timer) + + return ret; + } +-EXPORT_SYMBOL(del_timer); ++EXPORT_SYMBOL(timer_delete); + + /** + * try_to_del_timer_sync - Try to deactivate a timer diff --git a/queue-5.10/timers-replace-bug_on-s.patch b/queue-5.10/timers-replace-bug_on-s.patch new file mode 100644 index 0000000000..fce0316d0f --- /dev/null +++ b/queue-5.10/timers-replace-bug_on-s.patch @@ -0,0 +1,75 @@ +From aha310510@gmail.com Thu Feb 19 18:13:41 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:01 +0900 +Subject: timers: Replace BUG_ON()s +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-7-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit 82ed6f7ef58f9634fe4462dd721902c580f01569 ] + +The timer code still has a few BUG_ON()s left which are crashing the kernel +in situations where it still can recover or simply refuse to take an +action. + +Remove the one in the hotplug callback which checks for the CPU being +offline. If that happens then the whole hotplug machinery will explode in +colourful ways. + +Replace the rest with WARN_ON_ONCE() and conditional returns where +appropriate. + +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/r/20221123201624.769128888@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + kernel/time/timer.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1155,7 +1155,8 @@ EXPORT_SYMBOL(timer_reduce); + */ + void add_timer(struct timer_list *timer) + { +- BUG_ON(timer_pending(timer)); ++ if (WARN_ON_ONCE(timer_pending(timer))) ++ return; + __mod_timer(timer, timer->expires, MOD_TIMER_NOTPENDING); + } + EXPORT_SYMBOL(add_timer); +@@ -1174,7 +1175,8 @@ void add_timer_on(struct timer_list *tim + struct timer_base *new_base, *base; + unsigned long flags; + +- BUG_ON(timer_pending(timer) || !timer->function); ++ if (WARN_ON_ONCE(timer_pending(timer) || !timer->function)) ++ return; + + new_base = get_timer_cpu_base(timer->flags, cpu); + +@@ -1988,8 +1990,6 @@ int timers_dead_cpu(unsigned int cpu) + struct timer_base *new_base; + int b, i; + +- BUG_ON(cpu_online(cpu)); +- + for (b = 0; b < NR_BASES; b++) { + old_base = per_cpu_ptr(&timer_bases[b], cpu); + new_base = get_cpu_ptr(&timer_bases[b]); +@@ -2006,7 +2006,8 @@ int timers_dead_cpu(unsigned int cpu) + */ + forward_timer_base(new_base); + +- BUG_ON(old_base->running_timer); ++ WARN_ON_ONCE(old_base->running_timer); ++ old_base->running_timer = NULL; + + for (i = 0; i < WHEEL_SIZE; i++) + migrate_timer_list(new_base, old_base->vectors + i); diff --git a/queue-5.10/timers-silently-ignore-timers-with-a-null-function.patch b/queue-5.10/timers-silently-ignore-timers-with-a-null-function.patch new file mode 100644 index 0000000000..050c3ba5ed --- /dev/null +++ b/queue-5.10/timers-silently-ignore-timers-with-a-null-function.patch @@ -0,0 +1,188 @@ +From aha310510@gmail.com Thu Feb 19 18:13:54 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:04 +0900 +Subject: timers: Silently ignore timers with a NULL function +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-10-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit d02e382cef06cc73561dd32dfdc171c00dcc416d ] + +Tearing down timers which have circular dependencies to other +functionality, e.g. workqueues, where the timer can schedule work and work +can arm timers, is not trivial. + +In those cases it is desired to shutdown the timer in a way which prevents +rearming of the timer. The mechanism to do so is to set timer->function to +NULL and use this as an indicator for the timer arming functions to ignore +the (re)arm request. + +In preparation for that replace the warnings in the relevant code paths +with checks for timer->function == NULL. If the pointer is NULL, then +discard the rearm request silently. + +Add debug_assert_init() instead of the WARN_ON_ONCE(!timer->function) +checks so that debug objects can warn about non-initialized timers. + +The warning of debug objects does not warn if timer->function == NULL. It +warns when timer was not initialized using timer_setup[_on_stack]() or via +DEFINE_TIMER(). If developers fail to enable debug objects and then waste +lots of time to figure out why their non-initialized timer is not firing, +they deserve it. Same for initializing a timer with a NULL function. + +Co-developed-by: Steven Rostedt +Signed-off-by: Steven Rostedt +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/all/20220407161745.7d6754b3@gandalf.local.home +Link: https://lore.kernel.org/all/20221110064101.429013735@goodmis.org +Link: https://lore.kernel.org/r/87wn7kdann.ffs@tglx +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + kernel/time/timer.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 52 insertions(+), 5 deletions(-) + +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -964,7 +964,7 @@ __mod_timer(struct timer_list *timer, un + unsigned int idx = UINT_MAX; + int ret = 0; + +- BUG_ON(!timer->function); ++ debug_assert_init(timer); + + /* + * This is a common optimization triggered by the networking code - if +@@ -991,6 +991,14 @@ __mod_timer(struct timer_list *timer, un + * dequeue/enqueue dance. + */ + base = lock_timer_base(timer, &flags); ++ /* ++ * Has @timer been shutdown? This needs to be evaluated ++ * while holding base lock to prevent a race against the ++ * shutdown code. ++ */ ++ if (!timer->function) ++ goto out_unlock; ++ + forward_timer_base(base); + + if (timer_pending(timer) && (options & MOD_TIMER_REDUCE) && +@@ -1017,6 +1025,14 @@ __mod_timer(struct timer_list *timer, un + } + } else { + base = lock_timer_base(timer, &flags); ++ /* ++ * Has @timer been shutdown? This needs to be evaluated ++ * while holding base lock to prevent a race against the ++ * shutdown code. ++ */ ++ if (!timer->function) ++ goto out_unlock; ++ + forward_timer_base(base); + } + +@@ -1075,8 +1091,12 @@ out_unlock: + * mod_timer_pending() is the same for pending timers as mod_timer(), but + * will not activate inactive timers. + * ++ * If @timer->function == NULL then the start operation is silently ++ * discarded. ++ * + * Return: +- * * %0 - The timer was inactive and not modified ++ * * %0 - The timer was inactive and not modified or was in ++ * shutdown state and the operation was discarded + * * %1 - The timer was active and requeued to expire at @expires + */ + int mod_timer_pending(struct timer_list *timer, unsigned long expires) +@@ -1102,8 +1122,12 @@ EXPORT_SYMBOL(mod_timer_pending); + * same timer, then mod_timer() is the only safe way to modify the timeout, + * since add_timer() cannot modify an already running timer. + * ++ * If @timer->function == NULL then the start operation is silently ++ * discarded. In this case the return value is 0 and meaningless. ++ * + * Return: +- * * %0 - The timer was inactive and started ++ * * %0 - The timer was inactive and started or was in shutdown ++ * state and the operation was discarded + * * %1 - The timer was active and requeued to expire at @expires or + * the timer was active and not modified because @expires did + * not change the effective expiry time +@@ -1123,8 +1147,12 @@ EXPORT_SYMBOL(mod_timer); + * modify an enqueued timer if that would reduce the expiration time. If + * @timer is not enqueued it starts the timer. + * ++ * If @timer->function == NULL then the start operation is silently ++ * discarded. ++ * + * Return: +- * * %0 - The timer was inactive and started ++ * * %0 - The timer was inactive and started or was in shutdown ++ * state and the operation was discarded + * * %1 - The timer was active and requeued to expire at @expires or + * the timer was active and not modified because @expires + * did not change the effective expiry time such that the +@@ -1147,6 +1175,9 @@ EXPORT_SYMBOL(timer_reduce); + * The @timer->expires and @timer->function fields must be set prior + * to calling this function. + * ++ * If @timer->function == NULL then the start operation is silently ++ * discarded. ++ * + * If @timer->expires is already in the past @timer will be queued to + * expire at the next timer tick. + * +@@ -1175,7 +1206,9 @@ void add_timer_on(struct timer_list *tim + struct timer_base *new_base, *base; + unsigned long flags; + +- if (WARN_ON_ONCE(timer_pending(timer) || !timer->function)) ++ debug_assert_init(timer); ++ ++ if (WARN_ON_ONCE(timer_pending(timer))) + return; + + new_base = get_timer_cpu_base(timer->flags, cpu); +@@ -1186,6 +1219,13 @@ void add_timer_on(struct timer_list *tim + * wrong base locked. See lock_timer_base(). + */ + base = lock_timer_base(timer, &flags); ++ /* ++ * Has @timer been shutdown? This needs to be evaluated while ++ * holding base lock to prevent a race against the shutdown code. ++ */ ++ if (!timer->function) ++ goto out_unlock; ++ + if (base != new_base) { + timer->flags |= TIMER_MIGRATING; + +@@ -1199,6 +1239,7 @@ void add_timer_on(struct timer_list *tim + + debug_timer_activate(timer); + internal_add_timer(base, timer); ++out_unlock: + raw_spin_unlock_irqrestore(&base->lock, flags); + } + EXPORT_SYMBOL_GPL(add_timer_on); +@@ -1481,6 +1522,12 @@ static void expire_timers(struct timer_b + + fn = timer->function; + ++ if (WARN_ON_ONCE(!fn)) { ++ /* Should never happen. Emphasis on should! */ ++ base->running_timer = NULL; ++ continue; ++ } ++ + if (timer->flags & TIMER_IRQSAFE) { + raw_spin_unlock(&base->lock); + call_timer_fn(timer, fn, baseclk); diff --git a/queue-5.10/timers-split-del_timer-to-prepare-for-shutdown-mode.patch b/queue-5.10/timers-split-del_timer-to-prepare-for-shutdown-mode.patch new file mode 100644 index 0000000000..367dc972f1 --- /dev/null +++ b/queue-5.10/timers-split-del_timer-to-prepare-for-shutdown-mode.patch @@ -0,0 +1,230 @@ +From aha310510@gmail.com Thu Feb 19 18:13:58 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:05 +0900 +Subject: timers: Split [try_to_]del_timer[_sync]() to prepare for shutdown mode +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-11-aha310510@gmail.com> + +From: Thomas Gleixner + +[ Upstream commit 8553b5f2774a66b1f293b7d783934210afb8f23c ] + +Tearing down timers which have circular dependencies to other +functionality, e.g. workqueues, where the timer can schedule work and work +can arm timers, is not trivial. + +In those cases it is desired to shutdown the timer in a way which prevents +rearming of the timer. The mechanism to do so is to set timer->function to +NULL and use this as an indicator for the timer arming functions to ignore +the (re)arm request. + +Split the inner workings of try_do_del_timer_sync(), del_timer_sync() and +del_timer() into helper functions to prepare for implementing the shutdown +functionality. + +No functional change. + +Co-developed-by: Steven Rostedt +Signed-off-by: Steven Rostedt +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/all/20220407161745.7d6754b3@gandalf.local.home +Link: https://lore.kernel.org/all/20221110064101.429013735@goodmis.org +Link: https://lore.kernel.org/r/20221123201625.195147423@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + kernel/time/timer.c | 135 +++++++++++++++++++++++++++++++++------------------- + 1 file changed, 88 insertions(+), 47 deletions(-) + +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1245,20 +1245,14 @@ out_unlock: + EXPORT_SYMBOL_GPL(add_timer_on); + + /** +- * timer_delete - Deactivate a timer ++ * __timer_delete - Internal function: Deactivate a timer + * @timer: The timer to be deactivated + * +- * The function only deactivates a pending timer, but contrary to +- * timer_delete_sync() it does not take into account whether the timer's +- * callback function is concurrently executed on a different CPU or not. +- * It neither prevents rearming of the timer. If @timer can be rearmed +- * concurrently then the return value of this function is meaningless. +- * + * Return: + * * %0 - The timer was not pending + * * %1 - The timer was pending and deactivated + */ +-int timer_delete(struct timer_list *timer) ++static int __timer_delete(struct timer_list *timer) + { + struct timer_base *base; + unsigned long flags; +@@ -1274,25 +1268,37 @@ int timer_delete(struct timer_list *time + + return ret; + } +-EXPORT_SYMBOL(timer_delete); + + /** +- * try_to_del_timer_sync - Try to deactivate a timer +- * @timer: Timer to deactivate ++ * timer_delete - Deactivate a timer ++ * @timer: The timer to be deactivated + * +- * This function tries to deactivate a timer. On success the timer is not +- * queued and the timer callback function is not running on any CPU. ++ * The function only deactivates a pending timer, but contrary to ++ * timer_delete_sync() it does not take into account whether the timer's ++ * callback function is concurrently executed on a different CPU or not. ++ * It neither prevents rearming of the timer. If @timer can be rearmed ++ * concurrently then the return value of this function is meaningless. + * +- * This function does not guarantee that the timer cannot be rearmed right +- * after dropping the base lock. That needs to be prevented by the calling +- * code if necessary. ++ * Return: ++ * * %0 - The timer was not pending ++ * * %1 - The timer was pending and deactivated ++ */ ++int timer_delete(struct timer_list *timer) ++{ ++ return __timer_delete(timer); ++} ++EXPORT_SYMBOL(timer_delete); ++ ++/** ++ * __try_to_del_timer_sync - Internal function: Try to deactivate a timer ++ * @timer: Timer to deactivate + * + * Return: + * * %0 - The timer was not pending + * * %1 - The timer was pending and deactivated + * * %-1 - The timer callback function is running on a different CPU + */ +-int try_to_del_timer_sync(struct timer_list *timer) ++static int __try_to_del_timer_sync(struct timer_list *timer) + { + struct timer_base *base; + unsigned long flags; +@@ -1309,6 +1315,27 @@ int try_to_del_timer_sync(struct timer_l + + return ret; + } ++ ++/** ++ * try_to_del_timer_sync - Try to deactivate a timer ++ * @timer: Timer to deactivate ++ * ++ * This function tries to deactivate a timer. On success the timer is not ++ * queued and the timer callback function is not running on any CPU. ++ * ++ * This function does not guarantee that the timer cannot be rearmed right ++ * after dropping the base lock. That needs to be prevented by the calling ++ * code if necessary. ++ * ++ * Return: ++ * * %0 - The timer was not pending ++ * * %1 - The timer was pending and deactivated ++ * * %-1 - The timer callback function is running on a different CPU ++ */ ++int try_to_del_timer_sync(struct timer_list *timer) ++{ ++ return __try_to_del_timer_sync(timer); ++} + EXPORT_SYMBOL(try_to_del_timer_sync); + + #ifdef CONFIG_PREEMPT_RT +@@ -1385,6 +1412,49 @@ static inline void del_timer_wait_runnin + #endif + + /** ++ * __timer_delete_sync - Internal function: Deactivate a timer and wait ++ * for the handler to finish. ++ * @timer: The timer to be deactivated ++ * ++ * Return: ++ * * %0 - The timer was not pending ++ * * %1 - The timer was pending and deactivated ++ */ ++static int __timer_delete_sync(struct timer_list *timer) ++{ ++ int ret; ++ ++#ifdef CONFIG_LOCKDEP ++ unsigned long flags; ++ ++ /* ++ * If lockdep gives a backtrace here, please reference ++ * the synchronization rules above. ++ */ ++ local_irq_save(flags); ++ lock_map_acquire(&timer->lockdep_map); ++ lock_map_release(&timer->lockdep_map); ++ local_irq_restore(flags); ++#endif ++ /* ++ * don't use it in hardirq context, because it ++ * could lead to deadlock. ++ */ ++ WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE)); ++ ++ do { ++ ret = __try_to_del_timer_sync(timer); ++ ++ if (unlikely(ret < 0)) { ++ del_timer_wait_running(timer); ++ cpu_relax(); ++ } ++ } while (ret < 0); ++ ++ return ret; ++} ++ ++/** + * timer_delete_sync - Deactivate a timer and wait for the handler to finish. + * @timer: The timer to be deactivated + * +@@ -1425,36 +1495,7 @@ static inline void del_timer_wait_runnin + */ + int timer_delete_sync(struct timer_list *timer) + { +- int ret; +- +-#ifdef CONFIG_LOCKDEP +- unsigned long flags; +- +- /* +- * If lockdep gives a backtrace here, please reference +- * the synchronization rules above. +- */ +- local_irq_save(flags); +- lock_map_acquire(&timer->lockdep_map); +- lock_map_release(&timer->lockdep_map); +- local_irq_restore(flags); +-#endif +- /* +- * don't use it in hardirq context, because it +- * could lead to deadlock. +- */ +- WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE)); +- +- do { +- ret = try_to_del_timer_sync(timer); +- +- if (unlikely(ret < 0)) { +- del_timer_wait_running(timer); +- cpu_relax(); +- } +- } while (ret < 0); +- +- return ret; ++ return __timer_delete_sync(timer); + } + EXPORT_SYMBOL(timer_delete_sync); + diff --git a/queue-5.10/timers-update-the-documentation-to-reflect-on-the-new-timer_shutdown-api.patch b/queue-5.10/timers-update-the-documentation-to-reflect-on-the-new-timer_shutdown-api.patch new file mode 100644 index 0000000000..3b312db974 --- /dev/null +++ b/queue-5.10/timers-update-the-documentation-to-reflect-on-the-new-timer_shutdown-api.patch @@ -0,0 +1,72 @@ +From aha310510@gmail.com Thu Feb 19 18:14:11 2026 +From: Jeongjun Park +Date: Fri, 20 Feb 2026 02:13:08 +0900 +Subject: timers: Update the documentation to reflect on the new timer_shutdown() API +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, tglx@linutronix.de, Julia.Lawall@inria.fr, akpm@linux-foundation.org, anna-maria@linutronix.de, arnd@arndb.de, linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, linux@roeck-us.net, luiz.dentz@gmail.com, marcel@holtmann.org, maz@kernel.org, peterz@infradead.org, rostedt@goodmis.org, sboyd@kernel.org, viresh.kumar@linaro.org, zouyipeng@huawei.com, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller +Message-ID: <20260219171310.118170-14-aha310510@gmail.com> + +From: "Steven Rostedt (Google)" + +[ Upstream commit a31323bef2b66455920d054b160c17d4240f8fd4 ] + +In order to make sure that a timer is not re-armed after it is stopped +before freeing, a new shutdown state is added to the timer code. The API +timer_shutdown_sync() and timer_shutdown() must be called before the +object that holds the timer can be freed. + +Update the documentation to reflect this new workflow. + +[ tglx: Updated to the new semantics and updated the zh_CN version ] + +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Thomas Gleixner +Tested-by: Guenter Roeck +Reviewed-by: Jacob Keller +Reviewed-by: Anna-Maria Behnsen +Link: https://lore.kernel.org/r/20221110064147.712934793@goodmis.org +Link: https://lore.kernel.org/r/20221123201625.375284489@linutronix.de +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/RCU/Design/Requirements/Requirements.rst | 2 +- + Documentation/core-api/local_ops.rst | 2 +- + Documentation/kernel-hacking/locking.rst | 5 +++++ + 3 files changed, 7 insertions(+), 2 deletions(-) + +--- a/Documentation/RCU/Design/Requirements/Requirements.rst ++++ b/Documentation/RCU/Design/Requirements/Requirements.rst +@@ -1858,7 +1858,7 @@ unloaded. After a given module has been + one of its functions results in a segmentation fault. The module-unload + functions must therefore cancel any delayed calls to loadable-module + functions, for example, any outstanding ``mod_timer()`` must be dealt +-with via ``timer_delete_sync()`` or similar. ++with via ``timer_shutdown_sync()`` or similar. + + Unfortunately, there is no way to cancel an RCU callback; once you + invoke ``call_rcu()``, the callback function is eventually going to be +--- a/Documentation/core-api/local_ops.rst ++++ b/Documentation/core-api/local_ops.rst +@@ -191,7 +191,7 @@ Here is a sample module which implements + + static void __exit test_exit(void) + { +- timer_delete_sync(&test_timer); ++ timer_shutdown_sync(&test_timer); + } + + module_init(test_init); +--- a/Documentation/kernel-hacking/locking.rst ++++ b/Documentation/kernel-hacking/locking.rst +@@ -1016,6 +1016,11 @@ calling add_timer() at the end of their + Because this is a fairly common case which is prone to races, you should + use timer_delete_sync() (``include/linux/timer.h``) to handle this case. + ++Before freeing a timer, timer_shutdown() or timer_shutdown_sync() should be ++called which will keep it from being rearmed. Any subsequent attempt to ++rearm the timer will be silently ignored by the core code. ++ ++ + Locking Speed + ============= +