From nobody Sun Jun 14 07:40:58 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 E6B78421A06; Fri, 1 May 2026 19:40:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777664431; cv=none; b=ZAeENyAEgPu5gOBA1gmjH7vMqtP3+c3nr/x3T4XEU3YNP7NP1kIf/G9msugqxqIIMWUBf/cXkU95fHLPqsPJ2ZCJzBTkfgSDEpsaNnvMkkYF/6Jl9ZC/v6m0yVZ8nyuwg7zyDECRwNuAPv+NRR1y5MBrD/gyMk+/o/C7+/MWLfk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777664431; c=relaxed/simple; bh=UOzhKw1KkPQHs3nFI8jF7CaHYG4CFIoNfjIpFNJHFzw=; h=Date:From:To:Subject:Cc:In-Reply-To:References:MIME-Version: Message-ID:Content-Type; b=BCPRh3rZ7AKSi3yeV5g0qvbflsstLJdBu3F1SZFgehR3A4Co1JbAc/8BmRnALhwaxOCzCd096IcJTR6kLqoUDI6glivZiRnWujpZyblwdoMTpYRi6fFBuOnZX6RWIvXKijDSHOnw4S3ngB4t+6ukRawYzrlbgd987WDNPkEZjj8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=3I2Oxd7n; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=oObu762i; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="3I2Oxd7n"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="oObu762i" Date: Fri, 01 May 2026 19:40:26 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1777664427; 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=lr0Vd6odrdGeAmg3U807p11N5AGvkngXcAiqVniIgEQ=; b=3I2Oxd7nFYKXa4pMzPMxoqEDbBZcOQ8L1VNxpOJ7v2Wz7Po1X0FcfCBgjlcnAPg8Rxb9Lb Z+1+/NYptWFInvEq2Y+z9yWh2oX1I1o6EQ2VQB09FrFO4yLgUUbhYcrZM59nmWHroEN+cK ggLj5lPB/J+RfHiRUb1NvxkpfaKGwOrRDD6e8FWhF/kpyCjUEJzYpoiZQJcqeFuY6bWfpv 4Y7nqA6HzhuzfQtBiAUBXGzewiBOsADSBOQ/an1QCeiuJAVYaAr0XaE44onIqrh7KXgSd0 JnuP96fNUF6PKDlohARVTuN2W1Ziqo8uQJV5xZwIAHGLr1gXZXTtqXbLic/iTw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1777664427; 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=lr0Vd6odrdGeAmg3U807p11N5AGvkngXcAiqVniIgEQ=; b=oObu762iIvU1TRIrMFBDPkVKhNtSmDD9LvHf08YoK3W32xXtZZp1Lf/9YL4N1S6GgMV9kP jTYYPkyvgRT/o3Cw== 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] fs/timerfd: Use the new alarm/hrtimer functions Cc: Thomas Gleixner , Frederic Weisbecker , x86@kernel.org, linux-kernel@vger.kernel.org In-Reply-To: <20260408114952.469141112@kernel.org> References: <20260408114952.469141112@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <177766442631.3521451.15820637627092541324.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Precedence: bulk Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The following commit has been merged into the timers/core branch of tip: Commit-ID: 7dda99952cede01e1225f8c4c856369a2cfda6ca Gitweb: https://git.kernel.org/tip/7dda99952cede01e1225f8c4c856369a2= cfda6ca Author: Thomas Gleixner AuthorDate: Wed, 08 Apr 2026 13:54:20 +02:00 Committer: Thomas Gleixner CommitterDate: Fri, 01 May 2026 21:36:13 +02:00 fs/timerfd: Use the new alarm/hrtimer functions Like any other user controlled interface, timerfd based timers can be programmed with expiry times in the past or vary small intervals. Both hrtimer and alarmtimer provide new interfaces which return the queued state of the timer. If the timer was already expired, then let the callsite handle the timerfd context update so that the full round trip through the hrtimer interrupt is avoided. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Link: https://patch.msgid.link/20260408114952.469141112@kernel.org --- fs/timerfd.c | 117 +++++++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 49 deletions(-) diff --git a/fs/timerfd.c b/fs/timerfd.c index 73104f3..fe845af 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -55,6 +55,15 @@ static inline bool isalarm(struct timerfd_ctx *ctx) ctx->clockid =3D=3D CLOCK_BOOTTIME_ALARM; } =20 +static void __timerfd_triggered(struct timerfd_ctx *ctx) +{ + lockdep_assert_held(&ctx->wqh.lock); + + ctx->expired =3D 1; + ctx->ticks++; + wake_up_locked_poll(&ctx->wqh, EPOLLIN); +} + /* * This gets called when the timer event triggers. We set the "expired" * flag, but we do not re-arm the timer (in case it's necessary, @@ -62,13 +71,8 @@ static inline bool isalarm(struct timerfd_ctx *ctx) */ static void timerfd_triggered(struct timerfd_ctx *ctx) { - unsigned long flags; - - spin_lock_irqsave(&ctx->wqh.lock, flags); - ctx->expired =3D 1; - ctx->ticks++; - wake_up_locked_poll(&ctx->wqh, EPOLLIN); - spin_unlock_irqrestore(&ctx->wqh.lock, flags); + guard(spinlock_irqsave)(&ctx->wqh.lock); + __timerfd_triggered(ctx); } =20 static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr) @@ -184,15 +188,54 @@ static ktime_t timerfd_get_remaining(struct timerfd_c= tx *ctx) return remaining < 0 ? 0: remaining; } =20 +static void timerfd_alarm_start(struct timerfd_ctx *ctx, ktime_t exp, bool= relative) +{ + /* Start the timer. If it's expired already, handle the callback. */ + if (!alarm_start_timer(&ctx->t.alarm, exp, relative)) + __timerfd_triggered(ctx); +} + +static u64 timerfd_alarm_restart(struct timerfd_ctx *ctx) +{ + /* -1 to account for ctx->ticks++ in __timerfd_triggered() */ + u64 ticks =3D alarm_forward_now(&ctx->t.alarm, ctx->tintv) - 1; + + timerfd_alarm_start(ctx, alarm_get_expires(&ctx->t.alarm), false); + return ticks; +} + +static void timerfd_hrtimer_start(struct timerfd_ctx *ctx, ktime_t exp, + const enum hrtimer_mode mode) +{ + /* Start the timer. If it's expired already, handle the callback. */ + if (!hrtimer_start_range_ns_user(&ctx->t.tmr, exp, 0, mode)) + __timerfd_triggered(ctx); +} + +static u64 timerfd_hrtimer_restart(struct timerfd_ctx *ctx) +{ + /* -1 to account for ctx->ticks++ in __timerfd_triggered() */ + u64 ticks =3D hrtimer_forward_now(&ctx->t.tmr, ctx->tintv) - 1; + + timerfd_hrtimer_start(ctx, hrtimer_get_expires(&ctx->t.tmr), HRTIMER_MODE= _ABS); + return ticks; +} + +static u64 timerfd_restart(struct timerfd_ctx *ctx) +{ + if (isalarm(ctx)) + return timerfd_alarm_restart(ctx); + return timerfd_hrtimer_restart(ctx); +} + static int timerfd_setup(struct timerfd_ctx *ctx, int flags, const struct itimerspec64 *ktmr) { + int clockid =3D ctx->clockid; enum hrtimer_mode htmode; ktime_t texp; - int clockid =3D ctx->clockid; =20 - htmode =3D (flags & TFD_TIMER_ABSTIME) ? - HRTIMER_MODE_ABS: HRTIMER_MODE_REL; + htmode =3D (flags & TFD_TIMER_ABSTIME) ? HRTIMER_MODE_ABS: HRTIMER_MODE_R= EL; =20 texp =3D timespec64_to_ktime(ktmr->it_value); ctx->expired =3D 0; @@ -206,20 +249,15 @@ static int timerfd_setup(struct timerfd_ctx *ctx, int= flags, timerfd_alarmproc); } else { hrtimer_setup(&ctx->t.tmr, timerfd_tmrproc, clockid, htmode); - hrtimer_set_expires(&ctx->t.tmr, texp); } =20 if (texp !=3D 0) { if (flags & TFD_TIMER_ABSTIME) texp =3D timens_ktime_to_host(clockid, texp); - if (isalarm(ctx)) { - if (flags & TFD_TIMER_ABSTIME) - alarm_start(&ctx->t.alarm, texp); - else - alarm_start_relative(&ctx->t.alarm, texp); - } else { - hrtimer_start(&ctx->t.tmr, texp, htmode); - } + if (isalarm(ctx)) + timerfd_alarm_start(ctx, texp, !(flags & TFD_TIMER_ABSTIME)); + else + timerfd_hrtimer_start(ctx, texp, htmode); =20 if (timerfd_canceled(ctx)) return -ECANCELED; @@ -287,27 +325,19 @@ static ssize_t timerfd_read_iter(struct kiocb *iocb, = struct iov_iter *to) } =20 if (ctx->ticks) { - ticks =3D ctx->ticks; + unsigned int expired =3D ctx->expired; =20 - if (ctx->expired && ctx->tintv) { - /* - * If tintv !=3D 0, this is a periodic timer that - * needs to be re-armed. We avoid doing it in the timer - * callback to avoid DoS attacks specifying a very - * short timer period. - */ - if (isalarm(ctx)) { - ticks +=3D alarm_forward_now( - &ctx->t.alarm, ctx->tintv) - 1; - alarm_restart(&ctx->t.alarm); - } else { - ticks +=3D hrtimer_forward_now(&ctx->t.tmr, - ctx->tintv) - 1; - hrtimer_restart(&ctx->t.tmr); - } - } + ticks =3D ctx->ticks; ctx->expired =3D 0; ctx->ticks =3D 0; + + /* + * If tintv !=3D 0, this is a periodic timer that needs to be + * re-armed. We avoid doing it in the timer callback to avoid + * DoS attacks specifying a very short timer period. + */ + if (expired && ctx->tintv) + ticks +=3D timerfd_restart(ctx); } spin_unlock_irq(&ctx->wqh.lock); if (ticks) { @@ -526,18 +556,7 @@ static int do_timerfd_gettime(int ufd, struct itimersp= ec64 *t) spin_lock_irq(&ctx->wqh.lock); if (ctx->expired && ctx->tintv) { ctx->expired =3D 0; - - if (isalarm(ctx)) { - ctx->ticks +=3D - alarm_forward_now( - &ctx->t.alarm, ctx->tintv) - 1; - alarm_restart(&ctx->t.alarm); - } else { - ctx->ticks +=3D - hrtimer_forward_now(&ctx->t.tmr, ctx->tintv) - - 1; - hrtimer_restart(&ctx->t.tmr); - } + ctx->ticks +=3D timerfd_restart(ctx); } t->it_value =3D ktime_to_timespec64(timerfd_get_remaining(ctx)); t->it_interval =3D ktime_to_timespec64(ctx->tintv);