From patchwork Thu Nov 24 14:16:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: tip-bot2 for Thomas Gleixner X-Patchwork-Id: 25573 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp3426290wrr; Thu, 24 Nov 2022 06:21:54 -0800 (PST) X-Google-Smtp-Source: AA0mqf6furscU3Cp5PY/3pqiAJWNNrZzOEvEh0bb6Uy19K4RV9bJxst7hqd4oFZ7BAnWnLJnPEjp X-Received: by 2002:a17:906:bcc1:b0:73d:715c:5730 with SMTP id lw1-20020a170906bcc100b0073d715c5730mr27581115ejb.293.1669299714592; Thu, 24 Nov 2022 06:21:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669299714; cv=none; d=google.com; s=arc-20160816; b=jpeSIZmiSom6O7zYWy0WH7zwYufKNa6lk+2uJx/FYB9oEOZPhu6/8TgxnRxouy4GAQ J6fIS6P07UV1xWI78oLZbHJrr/bNbXSKkkyNCj+d0qzzZq8PXVwIwHNfOGPp/YU9Ovbz /n0O+w1CN/06M2nHFagpjj81+Iwiibfg3Hcn1yMRWNFEw4ttcf4YMPMi0dhoBdtPD7X5 81jmqZcc6jJb7myybgZorkOc9A64dkMi72JOHy0AiEHfrF7lc8/Q2cI56McDU8WN44vl bb4VWjtO+4RGaqnmGYg07iEkMyY3BH7zUOACedRu08SeVDh+qeCBKp4c8J9OFmGNyWew duWg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:robot-unsubscribe :robot-id:message-id:mime-version:references:in-reply-to:cc:subject :to:reply-to:sender:from:dkim-signature:dkim-signature:date; bh=l9/9VVNhPfMLZ0KpU0KK40qpUVbN3+y9Zu04pnH/wMM=; b=Z3AFeDD9h2s7nvjKZC4WdilDPv/0WqyxKh1zDeVb0AWI2XQpMXS9g1E1d0t/ws4EbC TAb0yvjsjs1eJjDXum11QVobAN5JRT75MZkNlyEFFMnEdYJ0E6zqF9evRJBxX7YdZSXS RlCv67vLhMC4jWFIJzjZgzmXVU2R/Cu7QW5UpWI4eiFFI5Jep3A0jQuOpQM/JyUI0jKT +zWVBEpNfX0F3nu5X//FpRV67pnCoDHTOW3GABszNU8XNbQdQQ8xYI2kkCgU40Lf7BkJ 9gCq0lsT5IuMku2BcPOwzKn9ZyDFrPxxggzSJnGglOojGYjYEYRaEKycl3LpN5ZGDkLf GzDg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b="4otQaBI/"; dkim=neutral (no key) header.i=@linutronix.de header.b=weA4HlGH; 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 eq10-20020a056402298a00b00469e712cba8si1104036edb.558.2022.11.24.06.21.30; Thu, 24 Nov 2022 06:21:54 -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="4otQaBI/"; dkim=neutral (no key) header.i=@linutronix.de header.b=weA4HlGH; 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 S230239AbiKXOQZ (ORCPT + 99 others); Thu, 24 Nov 2022 09:16:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44966 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230063AbiKXOQH (ORCPT ); Thu, 24 Nov 2022 09:16:07 -0500 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EA4ADF3922; Thu, 24 Nov 2022 06:16:05 -0800 (PST) Date: Thu, 24 Nov 2022 14:16:02 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1669299364; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l9/9VVNhPfMLZ0KpU0KK40qpUVbN3+y9Zu04pnH/wMM=; b=4otQaBI//9OT1lMD0gGn4dCqa9IvYqUEaBKCOEKV5J0jKoHzvZB86ugtfF1Xua+CBdy+B5 JeAiuOYZNdQiHKXwRJQEnAfR5jP4Smsyozzp6N5yq4b/2ZbTXAov4OLF98GQAVxU6ctR5o iCx9dqBpHREXz3Ih6p+Ivn30Zhg5RdX3wG2fxUirjULgpCpkTYLWxUEVkMyJhBcSsyBN7D Mmfpjhc+aLSacyUAOfKKYX5BOLHNaqVOxkstbPPqtk18isi0CULA3VX5QntmzvWll5Z4MB Fp1VgGlB2/FWoHWw6E8aY/LqqtqQisc1FApq6AaxbCDtSAhccOYZMw6/229xiw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1669299364; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l9/9VVNhPfMLZ0KpU0KK40qpUVbN3+y9Zu04pnH/wMM=; b=weA4HlGHrwNT73ZX03g1FB6C6klCEIvblaSZnjiBjAb9MBPlni9kzkFgkWiOznp1HRdWdp FJS8TG76RGWaBsAg== From: "tip-bot2 for Thomas Gleixner" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: timers/core] timers: Add shutdown mechanism to the internal functions Cc: Steven Rostedt , Thomas Gleixner , Guenter Roeck , Jacob Keller , "Anna-Maria Behnsen" , x86@kernel.org, linux-kernel@vger.kernel.org In-Reply-To: <20220407161745.7d6754b3@gandalf.local.home> References: <20220407161745.7d6754b3@gandalf.local.home> MIME-Version: 1.0 Message-ID: <166929936276.4906.5093007911218305596.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails 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?1750387617739082379?= X-GMAIL-MSGID: =?utf-8?q?1750387617739082379?= The following commit has been merged into the timers/core branch of tip: Commit-ID: 0cc04e80458a822300b93f82ed861a513edde194 Gitweb: https://git.kernel.org/tip/0cc04e80458a822300b93f82ed861a513edde194 Author: Thomas Gleixner AuthorDate: Wed, 23 Nov 2022 21:18:52 +01:00 Committer: Thomas Gleixner CommitterDate: Thu, 24 Nov 2022 15:09:12 +01:00 timers: Add shutdown mechanism to the internal functions 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 --- kernel/time/timer.c | 62 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index e635bb5..167e43c 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1300,12 +1300,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; @@ -1313,9 +1320,22 @@ static int __timer_delete(struct timer_list *timer) 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); } @@ -1338,20 +1358,31 @@ static int __timer_delete(struct timer_list *timer) */ 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; @@ -1363,6 +1394,8 @@ static int __try_to_del_timer_sync(struct timer_list *timer) if (base->running_timer != timer) ret = detach_if_pending(timer, base, true); + if (shutdown) + timer->function = NULL; raw_spin_unlock_irqrestore(&base->lock, flags); @@ -1387,7 +1420,7 @@ static int __try_to_del_timer_sync(struct timer_list *timer) */ 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); @@ -1468,12 +1501,25 @@ static inline void del_timer_wait_running(struct timer_list *timer) { } * __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; @@ -1503,7 +1549,7 @@ static int __timer_delete_sync(struct timer_list *timer) 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); @@ -1555,7 +1601,7 @@ static int __timer_delete_sync(struct timer_list *timer) */ int timer_delete_sync(struct timer_list *timer) { - return __timer_delete_sync(timer); + return __timer_delete_sync(timer, false); } EXPORT_SYMBOL(timer_delete_sync);