From nobody Mon Dec 1 22:36:19 2025 Received: from mail-pj1-f50.google.com (mail-pj1-f50.google.com [209.85.216.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 88082330B10 for ; Fri, 28 Nov 2025 16:06:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764346003; cv=none; b=rrsF6SsnNDwK1wHbxYg95+N916ZyxRqyf78WW4q7ul0HFsn3VL+oj18dQA1WNzQjuAiyQH3OHP3MzkmXsFlZIsSEgCAmkoRyIM7dx8YigjGhmy59Wgvo9OCzao2vtVVfbI7NGmvPlYzkrfgijjOXhXPdJL3vWMzcpWYzgCR9Qrs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764346003; c=relaxed/simple; bh=FfeWAFL01yrxGNZ9KQqmQL8U/+v/91/EffrzfYdxZZA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ZjXVirkBrmW24jcwKIurNMDkFAWpDrkBUBvJTXySXe1MPGHFT8/o7NUl9VCA3xoDkyKibYVpKr+0Ml/rzudHfc/ar2h5eoy/v1V175SKwNBCXdMS01T1OonWmQICyLPs12BNdTdKESlLx+XOlW1RwoQbHMzIFOvi33FxflNc4Mg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=btCE0S4t; arc=none smtp.client-ip=209.85.216.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="btCE0S4t" Received: by mail-pj1-f50.google.com with SMTP id 98e67ed59e1d1-3437c093ef5so2188182a91.0 for ; Fri, 28 Nov 2025 08:06:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1764346001; x=1764950801; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=j0bNeek1LW81/KG2/Q/uicdT1bV3tR+ITFKGtccSqSg=; b=btCE0S4tzM5oYyo56TYoRMXM5D8yThvODRP9kxt18z2gOB49QPdUHz2RDDT5sdjK2T kS5d+asqJmu23eIDRrqvLnIi/5kIDE0IAJtxI9Xbq/A3wysx7ktf/WS2ILWvBVR1T87A 6L4X54VWPbg9joOCODmnAudEhsZ7/OkaZn4lRodV9XNrmAiBSHJQCeiGdU9CRYJUhjrV vAS+Zi+iaJxnTN0C2J1cR+TyIf9vdtHVqdkr4AP1HIG4ig3UIFz+lxAe5dfHnYWd0tGe pAh2J2cgyYLwQ8Wc5BWHipC2w8OeVt58Bt5fauGO1GxdWHjCmaCJBfNHUg8w9iljNkgF gZrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764346001; x=1764950801; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=j0bNeek1LW81/KG2/Q/uicdT1bV3tR+ITFKGtccSqSg=; b=RiVAm+W7hPzkfZ5yEVkmOX3H+cH7Xye2cabc6WEi+nKmihYYLZId2Aky0fRzi27l/R VRjUb3k5xUh8+U6/kKTRkBHPeQx2AagS/ziHk5Y7QFP9vqYk0Ucg2VAUaJfF8JRX5DHf C/AMTgYwiFZYtSNvn4Vvy+/zn3K2ThpnvI8jIH/3oPl4qHqDgHRz+lWYrkbY1GKK1G/c CbXIXGgwhAKLaQnPhKKKDVhwTyTSouM4C4RilVkCj24KAWzpYfNFdBE+E0Vtiv5ei3gm juU0bIK5+Xdw/DQQ3mcTrAbOexnuYz24UiiEise5wFYp3i0qfGD7k73Fv0ghHX+jdrDZ jOwA== X-Forwarded-Encrypted: i=1; AJvYcCUhtxvQ51DfYmYVhkYEyA+ZjzkHFA8jWIpRV6+AIw/Kkf8nJnTz/nBinf6wR7YCURJCa7OhK9ngbgMe9lI=@vger.kernel.org X-Gm-Message-State: AOJu0Yy7HAU6wWEHUMy1TdIAVWSI6w6Aklq1feR8rfnhhVKYNOfwwoUG FvJq3+WKNFjeALhlhBM+Ji86GAhlPeCWOKaJ1t+bjaH3cfYTXgvN9iEW X-Gm-Gg: ASbGnctbkVrr9dKkXms/qgM5RPeKn1FoWypvwWdDnNRKUjIeO/YFzrmJBKg/MiQdN3x m4q1mG/OnnuvfIjaNqzwfO3vcMV9tpbZiGTvLsVhdIMlNQCbwRyfHTmPOC6rFFYnm0YRIcVB4vI 0VXXNZ2cHSFSIduKWLVer18eYeD+H1XYr5LV48eJ75wy44f6Cp3eEazjYgu/Ll7kqgCwu2vJDBw rzAgHWAL1EaC9VVP4O32O/RtcQ0yeu17oPHCo7Lo+rM33Pkh3Xfo7KpXLBscJAyD9NLj7dvCb1J /Q7kXal0lePxcL76cvsA0VLNaT3AeJp0ahginP/CQWawWJKb264YZaTS0wwkGRm07JzguRwdStZ lAroiQy7rgk1ZzjxPnyV028nks/gcjV8I5APymtr+VlWNpk6ZQlyqnnFKQ8bDnbNeXLZVd7A0bC gcTuAlAKp5RyMBDA7w4mDN3Lpzood7OJLUadaxAw== X-Google-Smtp-Source: AGHT+IGMMK/ksK1xGTlKIL49CG15hI1qCc5kwWuiMLMNCyhPjSNUAFybYnQmIenfoilVz4fFQ6RaXg== X-Received: by 2002:a17:90b:1c86:b0:33f:eca0:47c6 with SMTP id 98e67ed59e1d1-34733f23531mr24238024a91.30.1764346000442; Fri, 28 Nov 2025 08:06:40 -0800 (PST) Received: from name2965-Precision-7820-Tower.. ([121.185.186.233]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7d15f26f11fsm5408499b3a.50.2025.11.28.08.06.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Nov 2025 08:06:39 -0800 (PST) From: Jeongjun Park 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, aha310510@gmail.com, linux-staging@lists.linux.dev, Jacob Keller Subject: [PATCH 5.15.y 10/14] timers: Split [try_to_]del_timer[_sync]() to prepare for shutdown mode Date: Sat, 29 Nov 2025 01:05:35 +0900 Message-Id: <20251128160539.358938-11-aha310510@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251128160539.358938-1-aha310510@gmail.com> References: <20251128160539.358938-1-aha310510@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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 3b6624cd9507..0b76a2ab42e3 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1298,20 +1298,14 @@ void add_timer_on(struct timer_list *timer, int cpu) EXPORT_SYMBOL_GPL(add_timer_on); =20 /** - * 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) =20 return ret; } -EXPORT_SYMBOL(timer_delete); =20 /** - * 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) =20 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); =20 #ifdef CONFIG_PREEMPT_RT @@ -1438,45 +1465,15 @@ static inline void del_timer_wait_running(struct ti= mer_list *timer) { } #endif =20 /** - * timer_delete_sync - Deactivate a timer and wait for the handler to fini= sh. + * __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 =3D mytimer; - * spin_lock_irq(somelock); - * - * spin_lock(somelock); - * timer_delete_sync(mytimer); - * while (base->running_timer =3D=3D 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; =20 @@ -1506,7 +1503,7 @@ int timer_delete_sync(struct timer_list *timer) lockdep_assert_preemption_enabled(); =20 do { - ret =3D try_to_del_timer_sync(timer); + ret =3D __try_to_del_timer_sync(timer); =20 if (unlikely(ret < 0)) { del_timer_wait_running(timer); @@ -1516,6 +1513,50 @@ int timer_delete_sync(struct timer_list *timer) =20 return ret; } + +/** + * timer_delete_sync - Deactivate a timer and wait for the handler to fini= sh. + * @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 =3D mytimer; + * spin_lock_irq(somelock); + * + * spin_lock(somelock); + * timer_delete_sync(mytimer); + * while (base->running_timer =3D=3D 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); =20 static void call_timer_fn(struct timer_list *timer, --