From patchwork Tue Nov 15 20:28:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Gleixner X-Patchwork-Id: 20550 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp2932386wru; Tue, 15 Nov 2022 12:43:31 -0800 (PST) X-Google-Smtp-Source: AA0mqf42ScCvF0sJZVTDna2rD+R6fXmzWCZai5fb60PueKvtWJmF1QUJtV7iMtx6IrBYXEOA/5c2 X-Received: by 2002:aa7:d803:0:b0:467:67e1:ca61 with SMTP id v3-20020aa7d803000000b0046767e1ca61mr16019163edq.27.1668545011145; Tue, 15 Nov 2022 12:43:31 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668545011; cv=none; d=google.com; s=arc-20160816; b=uuFv2eIgU8DuYzWLTeGkqE3pWl/tCwaInRRXovoexkNYLCXRfeCScCltilfxM1gnft ubpekzwVlMyWjFgMX8DWa37EoI2OoU9AWSKGo9CDtpxK32e8BHvzTAOi6ipMcXn8/aON /NebbjX+Wgh5JgUhlgNCSu/BJmAmy4vAaK+N2IVeEDk08Wpo/xdak0LasnjUjJ3gYwmd khN/VmIc6yivQWBKo/GeVPG0I2v2wew0WgC1qBRYmpMthwP7dq3zJwL0Goqs1ciG8NZ8 Hcp3KsuVHcfL4K0XSOVnaKn6wefR4fD6l32xU/lB/Bw5juEbNCqPjj/KLOo8Veb2foff 0Rbw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:date:mime-version:references:subject:cc:to:from :dkim-signature:dkim-signature:message-id; bh=CMA3/F6shbK4k7ry5l4qNuN5eRgfA3B1IvghuSgAvLA=; b=Vi9Smxid8oO1NkAmIiw0bljzIfKgq+w9zJxdL8ngB97tX+TULQtvK52RB8b26/9YHT 2WvYPepORN97KxgE29wsGWxJyydZ6INMGFzA7m3eHlcXb1+k+BUezNCarT0HjAHiWFl5 +qqoxzOnUjdkXUJRhcXlFl/JgIntEDvKbnLrw2ZR/VwnBxqaRmkjTgHIkUXGH8tjGcyk EC3lKNUkYRE12uteO9U5TKQI+Vuo6UA+7No3D9F5uqMyjwOW0ld/gP7aEbEZC7c4c5Ph pbWiwoHdNRIXtiQ26mJmTmHWp2E83CV7prk7wiCBwMqapETi7HJEdKn/ip4m/AFZSnx3 hWiw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=yXmSHTSo; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id c11-20020a05640227cb00b0046151310d6dsi6312992ede.498.2022.11.15.12.43.06; Tue, 15 Nov 2022 12:43:31 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=yXmSHTSo; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238429AbiKOUaj (ORCPT + 99 others); Tue, 15 Nov 2022 15:30:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39590 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232203AbiKOU3y (ORCPT ); Tue, 15 Nov 2022 15:29:54 -0500 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 32A7F2F39B; Tue, 15 Nov 2022 12:28:54 -0800 (PST) Message-ID: <20221115202117.677534558@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1668544133; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=CMA3/F6shbK4k7ry5l4qNuN5eRgfA3B1IvghuSgAvLA=; b=yXmSHTSo1ZQBpUliMVqpYYG71tsCxggZcVcgvKFqSOyHDhC63Uqh3jC+og91pGV0qu7F/d 7dkIqQWHMbFpczm9+SdH3WrXhNO+gmXjwsDHL7tn7X/LQQKKbuk1zbNfPdP1Kgf/E6rJ7M C4vR+d6yklxYLcl/St5gAeP7zOvynm+KSdvxU8A0IhkBWun9QONlQWp0hwXvMXGJ35XZQP mV6ZDj4bn4N/wl0e9ngYMZmhabiXlqSADctDCm/6yNQqkXewNTeRbFug6bdJNrf4oY8AK0 mKuV87A5OUW6EKbP3ayxghf/pnHwj1cjuvT/sq+oburuNOJo23eatGhyBiGJ1w== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1668544133; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: references:references; bh=CMA3/F6shbK4k7ry5l4qNuN5eRgfA3B1IvghuSgAvLA=; b=0Hc8vR2pcI5jKQgmf03VNuXybj0omi1sTaKONPNs1f9g+9R23oUxHa98ZNt+5iOhYyO9GI FNnH4uXINeUStgAg== From: Thomas Gleixner To: LKML Cc: Linus Torvalds , Steven Rostedt , Anna-Maria Behnsen , Peter Zijlstra , Stephen Boyd , Guenter Roeck , Andrew Morton , Julia Lawall , Arnd Bergmann , Viresh Kumar , Marc Zyngier , Marcel Holtmann , Johan Hedberg , Luiz Augusto von Dentz , linux-bluetooth@vger.kernel.org, "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , netdev@vger.kernel.org Subject: [patch 12/15] timers: Add shutdown mechanism to the internal functions References: <20221115195802.415956561@linutronix.de> MIME-Version: 1.0 Date: Tue, 15 Nov 2022 21:28:52 +0100 (CET) X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1749596253185787535?= X-GMAIL-MSGID: =?utf-8?q?1749596253185787535?= 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 it 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 Link: https://lore.kernel.org/all/20220407161745.7d6754b3@gandalf.local.home Link: https://lore.kernel.org/all/20221110064101.429013735@goodmis.org --- kernel/time/timer.c | 64 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 9 deletions(-) --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1293,14 +1293,21 @@ void add_timer_on(struct timer_list *tim EXPORT_SYMBOL_GPL(add_timer_on); /** - * __timer_delete - Internal function: Deactivate a timer. + * __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; @@ -1308,9 +1315,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); } @@ -1332,20 +1352,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; @@ -1357,6 +1388,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); @@ -1379,7 +1412,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); @@ -1460,12 +1493,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; @@ -1495,7 +1541,7 @@ static int __timer_delete_sync(struct ti lockdep_assert_preemption_enabled(); 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); @@ -1547,7 +1593,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);