Steven Rostedt
2022-Oct-27 20:34 UTC
[Bridge] [RFC][PATCH v2 19/31] timers: net: Use del_timer_shutdown() before freeing timer
On Thu, 27 Oct 2022 13:15:23 -0700 Linus Torvalds <torvalds at linux-foundation.org> wrote:> On Thu, Oct 27, 2022 at 12:55 PM Steven Rostedt <rostedt at goodmis.org> wrote: > > > > I think we need to update this code to squeeze in a del_timer_shutdown() to > > make sure that the timers are never restarted. > > So the reason the networking code does this is that it can't just do > the old 'sync()' thing, the timers are deleted in contexts where that > isn't valid. > > Which is also afaik why the networking code does that whole "timer > implies a refcount to the socket" and then does the > > if (del_timer(timer)) > sock_put() > > thing (ie if the del_timer failed - possibly because it was already > running - you leave the refcount alone).OK, so the above is assuming that the timer is always active, and del_timer() returns if it successfully removed it (where it can call sock_put()), but if del_timer() returns 0, that means the timer is currently running (or about to be), so it doesn't call sock_put().> > So the networking code cannot do the del_timer_shutdown() for the same > reason it cannot do the del_timer_sync(): it can't afford to wait for > the timer to stop running. > > I suspect it needs something like a new "del_timer_shutdown_async()" > that isn't synchronous, but does that > > - acts as del_timer in that it doesn't wait, and returns a success if > it could just remove the pending case > > - does that "mark timer for shutdown" in that success case > > or something similar. >What about del_timer_try_shutdown(), that if it removes the timer, it sets the function to NULL (making it equivalent to a successful shutdown), otherwise it does nothing. Allowing the the timer to be rearmed. I think this would work in this case. -- Steve
Linus Torvalds
2022-Oct-27 20:48 UTC
[Bridge] [RFC][PATCH v2 19/31] timers: net: Use del_timer_shutdown() before freeing timer
On Thu, Oct 27, 2022 at 1:34 PM Steven Rostedt <rostedt at goodmis.org> wrote:> > What about del_timer_try_shutdown(), that if it removes the timer, it sets > the function to NULL (making it equivalent to a successful shutdown), > otherwise it does nothing. Allowing the the timer to be rearmed.Sounds sane to me and should work, but as mentioned, I think the networking people need to say "yeah" too. And maybe that function can also disallow any future re-arming even for the case where the timer couldn't be actively removed. So any *currently* active timer wouldn't be waited for (either because locking may make that a deadlock situation, or simply due to performance issues), but at least it would guarantee that no new timer activations can happen. Because I do like the whole notion of "timer has been shutdown and cannot be used as a timer any more without re-initializing it" being a real state - even for a timer that may be "currently in flight". So this all sounds very worthwhile to me, but I'm not surprised that we have code that then knows about all the subtleties of "del_timer() might still have a running timer" and actually take advantage of it (where "advantage" is likely more of a "deal with the complexities" rather than anything really positive ;) And those existing subtle users might want particular semantics to at least make said complexities easier. Linus
Steven Rostedt
2022-Oct-27 21:07 UTC
[Bridge] [RFC][PATCH v2 19/31] timers: net: Use del_timer_shutdown() before freeing timer
On Thu, 27 Oct 2022 16:34:53 -0400 Steven Rostedt <rostedt at goodmis.org> wrote:> What about del_timer_try_shutdown(), that if it removes the timer, it sets > the function to NULL (making it equivalent to a successful shutdown), > otherwise it does nothing. Allowing the the timer to be rearmed. > > I think this would work in this case.Guenter, Can you apply this patch on top of the series, and see if it makes the warning go away? diff --git a/include/linux/timer.h b/include/linux/timer.h index d4d90149d015..e3c5f4bdd526 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -184,12 +184,23 @@ static inline int timer_pending(const struct timer_list * timer) return !hlist_unhashed_lockless(&timer->entry); } +extern int __del_timer(struct timer_list * timer, bool free); + 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); +static inline int del_timer_try_shutdown(struct timer_list *timer) +{ + return __del_timer(timer, true); +} + +static inline int del_timer(struct timer_list *timer) +{ + return __del_timer(timer, false); +} + /* * The jiffies value which is added to now, when there is no timer * in the timer wheel: diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 7305c65ad0eb..073031cb3bb9 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1255,7 +1255,7 @@ EXPORT_SYMBOL_GPL(add_timer_on); * (ie. del_timer() of an inactive timer returns 0, del_timer() of an * active timer returns 1.) */ -int del_timer(struct timer_list *timer) +int __del_timer(struct timer_list *timer, bool free) { struct timer_base *base; unsigned long flags; @@ -1266,12 +1266,16 @@ int del_timer(struct timer_list *timer) if (timer_pending(timer)) { base = lock_timer_base(timer, &flags); ret = detach_if_pending(timer, base, true); + if (free && ret) { + timer->function = NULL; + debug_timer_deactivate(timer); + } raw_spin_unlock_irqrestore(&base->lock, flags); } return ret; } -EXPORT_SYMBOL(del_timer); +EXPORT_SYMBOL(__del_timer); static int __try_to_del_timer_sync(struct timer_list *timer, bool free) { diff --git a/net/core/sock.c b/net/core/sock.c index 10cc84379d75..23a97442a0a6 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -3345,7 +3345,7 @@ EXPORT_SYMBOL(sk_reset_timer); void sk_stop_timer(struct sock *sk, struct timer_list* timer) { - if (del_timer(timer)) + if (del_timer_try_shutdown(timer)) __sock_put(sk); } EXPORT_SYMBOL(sk_stop_timer);
Guenter Roeck
2022-Oct-28 15:16 UTC
[Bridge] [RFC][PATCH v2 19/31] timers: net: Use del_timer_shutdown() before freeing timer
On 10/27/22 14:07, Steven Rostedt wrote:> On Thu, 27 Oct 2022 16:34:53 -0400 > Steven Rostedt <rostedt at goodmis.org> wrote: > >> What about del_timer_try_shutdown(), that if it removes the timer, it sets >> the function to NULL (making it equivalent to a successful shutdown), >> otherwise it does nothing. Allowing the the timer to be rearmed. >> >> I think this would work in this case. > > Guenter, > > Can you apply this patch on top of the series, and see if it makes the > warning go away? >That patch not only helps, it also fixes the crash seen with openrisc. For that crash, I was able to collect some useful data; see the log below. Thanks, Guenter --- WARNING: CPU: 0 PID: 7 at lib/debugobjects.c:502 debug_print_object+0xc0/0xe8 ODEBUG: free active (active state 0) object type: timer_list hint: rcu_lock_map+0x0/0x14 Modules linked in: CPU: 0 PID: 7 Comm: ksoftirqd/0 Not tainted 6.1.0-rc2-00145-g2c4e85e9ac93 #1 Call trace: [<048ecc8e>] dump_stack_lvl+0x44/0x80 [<c6a7029c>] dump_stack+0x1c/0x2c [<b225e4eb>] __warn+0xdc/0x118 [<1070b766>] ? debug_print_object+0xc0/0xe8 [<57923a76>] warn_slowpath_fmt+0x78/0x90 [<1070b766>] debug_print_object+0xc0/0xe8 [<b3abbcb0>] __debug_check_no_obj_freed+0x230/0x2b8 [<508d9b5a>] ? delayed_put_task_struct+0x0/0x84 [<30f5a2a0>] ? _s_kernel_ro+0x0/0x200 [<403ab082>] debug_check_no_obj_freed+0x30/0x40 [<82702c56>] free_pcp_prepare+0xc4/0x2b0 [<508d9b5a>] ? delayed_put_task_struct+0x0/0x84 [<7798b190>] free_unref_page+0x44/0x210 [<d73717e5>] __free_pages+0x108/0x124 [<a32de4eb>] slob_free_pages+0x9c/0xac [<bd51c171>] slob_free+0x40c/0x62c [<a2d26e0e>] ? thread_stack_free_rcu+0x0/0x44 [<24b2df6c>] ? rcu_process_callbacks+0x114/0x224 [<24b2df6c>] ? rcu_process_callbacks+0x114/0x224 [<7794ec75>] ? rcu_process_callbacks+0xdc/0x224 [<7794ec75>] ? rcu_process_callbacks+0xdc/0x224 [<d76fe88f>] kmem_cache_free+0x64/0xa0 [<46d25dac>] free_task+0x7c/0xe0 [<2df25813>] __put_task_struct+0xe8/0x194 [<64f9675b>] delayed_put_task_struct+0x58/0x84 [<8755437e>] rcu_process_callbacks+0xf0/0x224 [<24b2df6c>] ? rcu_process_callbacks+0x114/0x224 [<020db442>] ? rcu_process_callbacks+0x178/0x224 [<87626af4>] __do_softirq+0x11c/0x2f8 [<c3f89a50>] ? smpboot_thread_fn+0x4c/0x304 [<c3f89a50>] ? smpboot_thread_fn+0x4c/0x304 [<021b0175>] ? smpboot_thread_fn+0x188/0x304 [<f2e79ebd>] ? smpboot_thread_fn+0x158/0x304 [<966be0e6>] run_ksoftirqd+0x4c/0x80 [<4bf65f60>] smpboot_thread_fn+0x180/0x304 [<3f914d93>] ? _raw_spin_unlock_irqrestore+0x50/0x84 [<bef37779>] ? __kthread_parkme+0x60/0xdc [<b0798e10>] ? smpboot_thread_fn+0x0/0x304 [<c463cd92>] kthread+0x11c/0x144 [<3eaef0b7>] ? kthread+0x0/0x144 [<ef2f6228>] ret_from_fork+0x1c/0x84 ---[ end trace 0000000000000000 ]--- Unable to handle kernel access at virtual address 0xbd6ed6a4 Oops#: 0000 CPU #: 0 PC: c0056c78 SR: 00008679 SP: c1027c24 GPR00: 00000000 GPR01: c1027c24 GPR02: c1027c78 GPR03: 00008279 GPR04: 00000000 GPR05: 00000000 GPR06: 00000000 GPR07: 00000001 GPR08: 00000000 GPR09: c0056c64 GPR10: c1026000 GPR11: 00000000 GPR12: 00000000 GPR13: 00000001 GPR14: c05c0000 GPR15: 00000000 GPR16: 00000001 GPR17: bd6ed6a4 GPR18: ff4517b0 GPR19: fd145f00 GPR20: 00000000 GPR21: 00000000 GPR22: 00000000 GPR23: c0760000 GPR24: c10232a0 GPR25: 00000003 GPR26: 00000000 GPR27: 00000000 GPR28: c1a00458 GPR29: 00000000 GPR30: c0790000 GPR31: 00000000 RES: 00000000 oGPR11: ffffffff Process ksoftirqd/0 (pid: 7, stackpage=c10232a0) Stack: Call trace: [<6ce5cfad>] __lock_acquire.constprop.0+0xa8/0x914 [<4bc14e12>] ? __del_timer_sync+0x0/0x128 [<da915c87>] lock_acquire.part.0.isra.0+0xd4/0x1ac [<4bc14e12>] ? __del_timer_sync+0x0/0x128 [<9b341df3>] lock_acquire+0x2c/0x44 [<233b5cbc>] __del_timer_sync+0x64/0x128 [<4bc14e12>] ? __del_timer_sync+0x0/0x128 [<05cd2741>] timer_fixup_free+0x34/0x5c [<3fa496ad>] __debug_check_no_obj_freed+0x250/0x2b8 [<508d9b5a>] ? delayed_put_task_struct+0x0/0x84 [<30f5a2a0>] ? _s_kernel_ro+0x0/0x200 [<403ab082>] debug_check_no_obj_freed+0x30/0x40 [<82702c56>] free_pcp_prepare+0xc4/0x2b0 [<508d9b5a>] ? delayed_put_task_struct+0x0/0x84 [<7798b190>] free_unref_page+0x44/0x210 [<d73717e5>] __free_pages+0x108/0x124 [<a32de4eb>] slob_free_pages+0x9c/0xac [<bd51c171>] slob_free+0x40c/0x62c [<a2d26e0e>] ? thread_stack_free_rcu+0x0/0x44 [<24b2df6c>] ? rcu_process_callbacks+0x114/0x224 [<24b2df6c>] ? rcu_process_callbacks+0x114/0x224 [<7794ec75>] ? rcu_process_callbacks+0xdc/0x224 [<7794ec75>] ? rcu_process_callbacks+0xdc/0x224 [<d76fe88f>] kmem_cache_free+0x64/0xa0 [<46d25dac>] free_task+0x7c/0xe0 [<2df25813>] __put_task_struct+0xe8/0x194 [<64f9675b>] delayed_put_task_struct+0x58/0x84 [<8755437e>] rcu_process_callbacks+0xf0/0x224 [<24b2df6c>] ? rcu_process_callbacks+0x114/0x224 [<020db442>] ? rcu_process_callbacks+0x178/0x224 [<87626af4>] __do_softirq+0x11c/0x2f8 [<c3f89a50>] ? smpboot_thread_fn+0x4c/0x304 [<c3f89a50>] ? smpboot_thread_fn+0x4c/0x304 [<021b0175>] ? smpboot_thread_fn+0x188/0x304 [<f2e79ebd>] ? smpboot_thread_fn+0x158/0x304 [<966be0e6>] run_ksoftirqd+0x4c/0x80 [<4bf65f60>] smpboot_thread_fn+0x180/0x304 [<3f914d93>] ? _raw_spin_unlock_irqrestore+0x50/0x84 [<bef37779>] ? __kthread_parkme+0x60/0xdc [<b0798e10>] ? smpboot_thread_fn+0x0/0x304 [<c463cd92>] kthread+0x11c/0x144 [<3eaef0b7>] ? kthread+0x0/0x144 [<ef2f6228>] ret_from_fork+0x1c/0x84