From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mx0a-00069f02.pphosted.com (mx0a-00069f02.pphosted.com [205.220.165.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C0C943CB2D0 for ; Thu, 23 Apr 2026 09:19:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.165.32 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776935980; cv=none; b=iWJujUeoJEfo6ZwrRmAFkdScy3RI8DZZxYj2VcATBBl6JHUAtDhCPurt1U3H4msDC9KyetF77r6q3wT/Llun1Bw2FNfdifsxGqgtoQBMGjAjx8XtYcjJQ/A1/xvZeHTrvPZVapfH14UxYtZOddUceMlnYcwgKgfjMoM0Qfh656c= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776935980; c=relaxed/simple; bh=bXx/s+umxZsk+ewlgTrIW894cqEs0ID/zwh0vsI6ckI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EDjlMblNP4bXbmUXM0HQqXuZCYLgBRlrh7sYa3/GM3IN/AF0G/CJTymxxl2Jjf5R8eMNgOK9HC1QAxHjKF8+mJZTsZtWz9hiRbSAEGldQm7wRqionT8isSZhTJuY8i7QJyUKzjcGVATVLqNmx6Jd6eFbUUaW2bB3wisikl4YLek= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oracle.com; spf=pass smtp.mailfrom=oracle.com; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b=Xkejb657; arc=none smtp.client-ip=205.220.165.32 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oracle.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oracle.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="Xkejb657" Received: from pps.filterd (m0333521.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 63N7LvCu3738297; Thu, 23 Apr 2026 09:19:18 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=corp-2025-04-25; bh=AfyOm lEm+ai5HstyMoxlQeAUMnugiSmpzZNJ/mmLl54=; b=Xkejb6570Lu/sL/7Swl+e GLlmrdw47QPwlTm23WXTea28besCGfjBb9NVducQYL7gDb20+0yhCvCeB/1XCmqk i1ZnDW59mfZjwSxYlhFdVPLfmRQXPRqc+4imbC87+dJubtYh7VEOGJTCE7NyLyeP 66xF1uOpOyxb95DXymXMKqdYqm/16427FzInd4LJdSAZW3YFKn8DFZEYbeulpHSR eN33QjFoMZBMnn71O+lvMbaLz5OZyUSau5jm1IzGkLdtEuKgeJHa8j299wX6EX86 lCaspy7WZ23pYK8M3EwRVxs/X8yDZ8MQAH2yYWVQdl/1IfTQgBQu3ueIoq5+VQFf w== Received: from iadpaimrmta01.imrmtpd1.prodappiadaev1.oraclevcn.com (iadpaimrmta01.appoci.oracle.com [130.35.100.223]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 4dpenjb4d1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 23 Apr 2026 09:19:17 +0000 (GMT) Received: from pps.filterd (iadpaimrmta01.imrmtpd1.prodappiadaev1.oraclevcn.com [127.0.0.1]) by iadpaimrmta01.imrmtpd1.prodappiadaev1.oraclevcn.com (8.18.1.7/8.18.1.7) with ESMTP id 63N9GNIS012949; Thu, 23 Apr 2026 09:19:16 GMT Received: from pps.reinject (localhost [127.0.0.1]) by iadpaimrmta01.imrmtpd1.prodappiadaev1.oraclevcn.com (PPS) with ESMTPS id 4dpjjrd0p9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 23 Apr 2026 09:19:16 +0000 (GMT) Received: from iadpaimrmta01.imrmtpd1.prodappiadaev1.oraclevcn.com (iadpaimrmta01.imrmtpd1.prodappiadaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.1.12) with ESMTP id 63N9JF01021237; Thu, 23 Apr 2026 09:19:16 GMT Received: from pssatapa-ol8-test.osdevelopmeniad.oraclevcn.com (pssatapa-ol8-test.allregionaliads.osdevelopmeniad.oraclevcn.com [100.100.253.175]) by iadpaimrmta01.imrmtpd1.prodappiadaev1.oraclevcn.com (PPS) with ESMTP id 4dpjjrd0n7-2; Thu, 23 Apr 2026 09:19:15 +0000 (GMT) From: Partha Satapathy To: partha.satapathy@oracle.com, anna-maria@linutronix.de, frederic@kernel.org, tglx@kernel.org, linux-kernel@vger.kernel.org, tj@kernel.org, jiangshanlai@gmail.com Cc: notify@kernel.org Subject: [PATCH 1/2] timer: add add_timer_active_cpu() Date: Thu, 23 Apr 2026 09:19:06 +0000 Message-ID: <20260423091914.63645-2-partha.satapathy@oracle.com> X-Mailer: git-send-email 2.43.7 In-Reply-To: <20260423091914.63645-1-partha.satapathy@oracle.com> References: <20260423091914.63645-1-partha.satapathy@oracle.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-04-23_02,2026-04-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 bulkscore=0 spamscore=0 suspectscore=0 lowpriorityscore=0 adultscore=0 malwarescore=0 mlxscore=0 mlxlogscore=999 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2604200000 definitions=main-2604230090 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNDIzMDA5MCBTYWx0ZWRfX/ds74WRiKT8+ t2ms9jXzC7sQt1JISn+Gkn5xpmgX70VH2FVvY7Z+HzD+dCLScT/kPATxsbzYMEq/Xy/z2QNRwhB SkPNLsrpnJY+6Vzrgh98bZoLIrHo7MaE8rP3qDkM5OMzYhjuND0unZSN/4X99wtxIaaJOF4/Xef miiQumm5Qy7qWNPusxbgnbUIlgCCNMn9TURsCkKR9cAM4aTbJcEn8riT79G/fbWZPNFMCSbrqA0 f31tHdIMnCnFo4eaeTR4E+UEgOilOeLqwRSbDZBXzcfts16k6c2sDTnFg2SwF/9qPHEx3l2+f8d Pz/E0IrfWjl/uA4vJ6AeapSrFr5M3oulnHuaRS9aLtSdeTk4P6N0vRIBH0UEhrPY1uGjRSAnC5c zuQjWSLBJIREIYCTs69V6l6XVwfl/c9n+5Zvtvo2L1kHdUdkB0lXPBcqll9YNHyF+wsDGcaoX/S aKopx1RDQX2/0EZWnfGE72qK10pgRmja3bnQoDWw= X-Authority-Analysis: v=2.4 cv=Xay5Co55 c=1 sm=1 tr=0 ts=69e9e415 b=1 cx=c_pps a=zPCbziy225d3KhSqZt3L1A==:117 a=zPCbziy225d3KhSqZt3L1A==:17 a=A5OVakUREuEA:10 a=VkNPw1HP01LnGYTKEx00:22 a=jiCTI4zE5U7BLdzWsZGv:22 a=x0eKOSpe3m1H3M0S9YoZ:22 a=yPCof4ZbAAAA:8 a=k9ZU9dsI0lKJxH7jJukA:9 cc=ntf awl=host:12291 X-Proofpoint-ORIG-GUID: _A2zpnJgGc6v80tEIoOgf5pIPengFvhq X-Proofpoint-GUID: _A2zpnJgGc6v80tEIoOgf5pIPengFvhq From: Partha Sarathi Satapathy add_timer_on() can queue a timer on a CPU that goes offline before the timer is enqueued. When that happens, the timer remains unserviced until the CPU comes back online. Callers can try to avoid that by checking CPU state themselves, but that does not close the race with CPU hotplug. Taking the hotplug lock around every enqueue is also too expensive for users that only want CPU-local placement as a performance hint. Add add_timer_active_cpu() for callers that want to queue a timer on a specific CPU when that CPU is active, but otherwise fall back to an active CPU. Implement this by teaching the enqueue path to verify that the target timer base is active and, if not, requeue the timer on the current CPU. Leave add_timer_on() semantics unchanged for callers that require strict CPU placement. Signed-off-by: Partha Sarathi Satapathy --- include/linux/timer.h | 1 + kernel/time/timer.c | 45 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/include/linux/timer.h b/include/linux/timer.h index 62e1cea71125..8c771b367662 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -148,6 +148,7 @@ static inline int timer_pending(const struct timer_list * timer) } extern void add_timer_on(struct timer_list *timer, int cpu); +extern void add_timer_active_cpu(struct timer_list *timer, int cpu); 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); diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 1f2364126894..c73a28701a31 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -260,6 +260,7 @@ struct timer_base { bool next_expiry_recalc; bool is_idle; bool timers_pending; + bool is_active; DECLARE_BITMAP(pending_map, WHEEL_SIZE); struct hlist_head vectors[WHEEL_SIZE]; } ____cacheline_aligned; @@ -1296,7 +1297,7 @@ EXPORT_SYMBOL(add_timer_global); * * See add_timer() for further details. */ -void add_timer_on(struct timer_list *timer, int cpu) +static void __add_timer_on(struct timer_list *timer, int cpu, bool need_ol_cpu) { struct timer_base *new_base, *base; unsigned long flags; @@ -1333,6 +1334,18 @@ void add_timer_on(struct timer_list *timer, int cpu) WRITE_ONCE(timer->flags, (timer->flags & ~TIMER_BASEMASK) | cpu); } +#ifdef CONFIG_HOTPLUG_CPU + if (need_ol_cpu) { + if (!base->is_active) { + raw_spin_unlock(&base->lock); + base = this_cpu_ptr(&timer_bases[BASE_LOCAL]); + raw_spin_lock(&base->lock); + cpu = smp_processor_id(); + WRITE_ONCE(timer->flags, + (timer->flags & ~TIMER_BASEMASK) | cpu); + } + } +#endif /* CONFIG_HOTPLUG_CPU */ forward_timer_base(base); debug_timer_activate(timer); @@ -1340,8 +1353,31 @@ void add_timer_on(struct timer_list *timer, int cpu) out_unlock: raw_spin_unlock_irqrestore(&base->lock, flags); } + +void add_timer_on(struct timer_list *timer, int cpu) +{ + bool need_ol_cpu = false; + + __add_timer_on(timer, cpu, need_ol_cpu); +} EXPORT_SYMBOL_GPL(add_timer_on); +/** + * add_timer_active_cpu - Start a timer on a particular CPU if online or current + * @timer: The timer to be started + * @cpu: The CPU to start it on + * + * This is like add_timer_on(), except that it queues the timer on the + * given CPU only when that CPU is online or on the current CPU. + */ +void add_timer_active_cpu(struct timer_list *timer, int cpu) +{ + bool need_ol_cpu = true; + + __add_timer_on(timer, cpu, need_ol_cpu); +} +EXPORT_SYMBOL_GPL(add_timer_active_cpu); + /** * __timer_delete - Internal function: Deactivate a timer * @timer: The timer to be deactivated @@ -2507,6 +2543,7 @@ int timers_prepare_cpu(unsigned int cpu) base->next_expiry_recalc = false; base->timers_pending = false; base->is_idle = false; + base->is_active = true; } return 0; } @@ -2535,6 +2572,11 @@ int timers_dead_cpu(unsigned int cpu) WARN_ON_ONCE(old_base->running_timer); old_base->running_timer = NULL; + /* + * Make the dead CPU base unavailable to add_timer_on() + * when the caller wants an active target CPU. + */ + old_base->is_active = false; for (i = 0; i < WHEEL_SIZE; i++) migrate_timer_list(new_base, old_base->vectors + i); @@ -2559,6 +2601,7 @@ static void __init init_timer_cpu(int cpu) raw_spin_lock_init(&base->lock); base->clk = jiffies; base->next_expiry = base->clk + TIMER_NEXT_MAX_DELTA; + base->is_active = true; timer_base_init_expiry_lock(base); } } -- 2.43.7