From patchwork Thu Nov 24 14:16:04 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: 25570 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp3426202wrr; Thu, 24 Nov 2022 06:21:45 -0800 (PST) X-Google-Smtp-Source: AA0mqf7NbriRE8OYT3XNfpcqhbhql85awlU8WqfjL1FCmlw9IJY1Ts4zKAzYC4Wte96ypQL0Pkg9 X-Received: by 2002:a63:d909:0:b0:440:5517:5d8a with SMTP id r9-20020a63d909000000b0044055175d8amr13861403pgg.200.1669299704949; Thu, 24 Nov 2022 06:21:44 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669299704; cv=none; d=google.com; s=arc-20160816; b=wUYwsq40JWzpuWnzRvBOh86z0V2XN2HkTp+ZdOj6t1iHwwWLCOGnyrs4cdCerctjHt u7B0LIgMaJt5yz9xD1p90RDH3TT7nLjDedqUkD7KTqAhlMRXvobgH+/7535iK3jElrRe ddeSo7uQri2ERs3RTsf1mkwe3W1Sq/jLeamtpYkfnjVj3bKK080z5sykatU1OppfrDiO p2qgkl9tLqmF/ZzG2Ww4hHrWKx+uN+O+2tuZ8OaqW83mvHzCtyM4hKiVnPB1PpEoi8v6 INlWzLHRywl28kdPWx+cug4TcCSPNb7rmpKOQ6SrkmXs+bhnHV78vsy5cM1TkoVeEumZ 4QIQ== 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=ScAcSgiAwWLVu0dRynYOFEe8XNYaPQIeAs1cO6vxmNM=; b=QzTiVbSEtau+RIdAdqkEwt169n3v/1Oyaf/KIS1JMD4TpAsisZfXhZcp5Tnk3waTJV vn9IGDAvYt/mvaRrNZgG2l92M+C5sdTV4Y2yuEYms2N481csV8PI5Jbb+wGUnfjwBESt H3ZtywCoOD7GgE7APT3dtV2oYGdMSdIERwb4JHarVwfiZ+3sOG4dZ3zbq+yw38lb3W/O Rl02mM5qcGjy1NT1LGkhH8Uu4BBXTH8zb8c6YcMl5Y73Kx7tRJr5ylZC0T+HyTnXMuPq wQttCPPUlSORVyGV01Qjj94ShlSXXs1o+69RpKw+7dPiDpCxqkKo2mNN5YdnVjiwodp5 7BTw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=Vf0wHujm; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e header.b=kxb9DTWe; 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 c14-20020a63d14e000000b0045706a2a5f3si1399626pgj.439.2022.11.24.06.21.30; Thu, 24 Nov 2022 06:21:44 -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=Vf0wHujm; dkim=neutral (no key) header.i=@linutronix.de header.s=2020e header.b=kxb9DTWe; 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 S230247AbiKXOQ2 (ORCPT + 99 others); Thu, 24 Nov 2022 09:16:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44990 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229784AbiKXOQI (ORCPT ); Thu, 24 Nov 2022 09:16:08 -0500 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2B38BD9BB8; Thu, 24 Nov 2022 06:16:07 -0800 (PST) Date: Thu, 24 Nov 2022 14:16:04 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1669299365; 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=ScAcSgiAwWLVu0dRynYOFEe8XNYaPQIeAs1cO6vxmNM=; b=Vf0wHujmdl8Jln3xomAN7k93CYQWvXIp2TOA4ygDjlJ4XiPYn1xGhI9jeo2COcRiVKKXCs ve8wyeOql+3pp0uIR1a781gF38AkblGuqSZQbjpOD6U+T0pYa5Q8rGoB9WHtcZrP20nk5O jCL26FrdCSkI52KDYnze1GmemSohxh9phj6Umpy27UVlssqLwrrbKkKekJEg50SptUg5Hw XjvmzT+WnEGD6Btb5CpBrlEJO3gdRmqjW1xw5xul7ecogVDVuWnDsutGltwfVd/wTugzRO Rgbr3GkEJdh2BVQm1GO1QfONYRCF193MyUi2LSHHOrAC+dVGiT6F3fx1El4QyQ== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1669299365; 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=ScAcSgiAwWLVu0dRynYOFEe8XNYaPQIeAs1cO6vxmNM=; b=kxb9DTWecIv7TruTjyZwDSXj0uExRXRf0SukoW/8b60AbaRtRvaD5yRi6ypC2VXK3h3wRp BL/qYRHwkIHv5sCQ== 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: Split [try_to_]del_timer[_sync]() to prepare for shutdown mode 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: <166929936440.4906.2223890805423305572.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?1750387607675814402?= X-GMAIL-MSGID: =?utf-8?q?1750387607675814402?= The following commit has been merged into the timers/core branch of tip: Commit-ID: 8553b5f2774a66b1f293b7d783934210afb8f23c Gitweb: https://git.kernel.org/tip/8553b5f2774a66b1f293b7d783934210afb8f23c Author: Thomas Gleixner AuthorDate: Wed, 23 Nov 2022 21:18:50 +01:00 Committer: Thomas Gleixner CommitterDate: Thu, 24 Nov 2022 15:09:12 +01:00 timers: Split [try_to_]del_timer[_sync]() to prepare for shutdown mode 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 --- kernel/time/timer.c | 143 +++++++++++++++++++++++++++---------------- 1 file changed, 92 insertions(+), 51 deletions(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index e4fcf56..e635bb5 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1298,20 +1298,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; @@ -1327,25 +1321,37 @@ int timer_delete(struct timer_list *timer) 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; @@ -1362,6 +1368,27 @@ int try_to_del_timer_sync(struct timer_list *timer) 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 @@ -1438,45 +1465,15 @@ static inline void del_timer_wait_running(struct timer_list *timer) { } #endif /** - * timer_delete_sync - Deactivate a timer and wait for the handler to finish. + * __timer_delete_sync - Internal function: Deactivate a timer and wait + * for the handler to finish. * @timer: The timer to be deactivated * - * Synchronization rules: Callers must prevent restarting of the timer, - * otherwise this function is meaningless. It must not be called from - * interrupt contexts unless the timer is an irqsafe one. The caller must - * not hold locks which would prevent completion of the timer's callback - * function. The timer's handler must not call add_timer_on(). Upon exit - * the timer is not queued and the handler is not running on any CPU. - * - * For !irqsafe timers, the caller must not hold locks that are held in - * interrupt context. Even if the lock has nothing to do with the timer in - * question. Here's why:: - * - * CPU0 CPU1 - * ---- ---- - * - * call_timer_fn(); - * base->running_timer = mytimer; - * spin_lock_irq(somelock); - * - * spin_lock(somelock); - * timer_delete_sync(mytimer); - * while (base->running_timer == mytimer); - * - * Now timer_delete_sync() will never return and never release somelock. - * The interrupt on the other CPU is waiting to grab somelock but it has - * interrupted the softirq that CPU0 is waiting to finish. - * - * This function cannot guarantee that the timer is not rearmed again by - * some concurrent or preempting code, right after it dropped the base - * lock. If there is the possibility of a concurrent rearm then the return - * value of the function is meaningless. - * * Return: * * %0 - The timer was not pending * * %1 - The timer was pending and deactivated */ -int timer_delete_sync(struct timer_list *timer) +static int __timer_delete_sync(struct timer_list *timer) { int ret; @@ -1506,7 +1503,7 @@ 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); if (unlikely(ret < 0)) { del_timer_wait_running(timer); @@ -1516,6 +1513,50 @@ int timer_delete_sync(struct timer_list *timer) return ret; } + +/** + * timer_delete_sync - Deactivate a timer and wait for the handler to finish. + * @timer: The timer to be deactivated + * + * Synchronization rules: Callers must prevent restarting of the timer, + * otherwise this function is meaningless. It must not be called from + * interrupt contexts unless the timer is an irqsafe one. The caller must + * not hold locks which would prevent completion of the timer's callback + * function. The timer's handler must not call add_timer_on(). Upon exit + * the timer is not queued and the handler is not running on any CPU. + * + * For !irqsafe timers, the caller must not hold locks that are held in + * interrupt context. Even if the lock has nothing to do with the timer in + * question. Here's why:: + * + * CPU0 CPU1 + * ---- ---- + * + * call_timer_fn(); + * base->running_timer = mytimer; + * spin_lock_irq(somelock); + * + * spin_lock(somelock); + * timer_delete_sync(mytimer); + * while (base->running_timer == mytimer); + * + * Now timer_delete_sync() will never return and never release somelock. + * The interrupt on the other CPU is waiting to grab somelock but it has + * interrupted the softirq that CPU0 is waiting to finish. + * + * This function cannot guarantee that the timer is not rearmed again by + * some concurrent or preempting code, right after it dropped the base + * lock. If there is the possibility of a concurrent rearm then the return + * value of the function is meaningless. + * + * Return: + * * %0 - The timer was not pending + * * %1 - The timer was pending and deactivated + */ +int timer_delete_sync(struct timer_list *timer) +{ + return __timer_delete_sync(timer); +} EXPORT_SYMBOL(timer_delete_sync); static void call_timer_fn(struct timer_list *timer,