From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 02A4A2D1F40 for ; Tue, 2 Dec 2025 18:27:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700071; cv=none; b=RdY9j4HPE1WC9SZ3lvsUI13IAHTdFmiuxul0jG/izhykYRYUj6QZMmyOmO2RcisSOlCuW3SzRJKTXO6w8UkURg5DcqwIxARtJk0baVF66CRJHbfWQcm9H6ExuY4hCJsGfwOmZOJuagQZQufqGFxgqLcmYwk1LBYkMHw10E1KigM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700071; c=relaxed/simple; bh=e+54f01/bQ8CsM9B0ZfzJgprvi3eYh809BGyxf8gUj4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HkmlqwEicrM8aYAMnn51L81vk+nKiTUNuMABwR6saLi57DcC29QOymTYnlmBJeEpZggrUbpntCR6I3RM1Zbd7ZPwz3l0/mWcLsZZvRL6Q5uS17t8ZEnECXBp3kcVmcok81v6oiV/KoQ7poscR1LGRHaosgWZekQkUb7ZsK1BnUs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=hDA4cBw7; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="hDA4cBw7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700068; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j1qXz/Oujs8inD+ylNMe0oKGUjcbsTsC0a1ifWNDHlk=; b=hDA4cBw7fvyCVC1T/UPrm4yGJ56fXFr98xgS9hOzb83UU55kUAyMOSjesBIqWJ5Qk8xVfM ObzeJt7y+Zz5mgaOWyKHW3HTWkd1qgixO3zUF0P12yumXPtcfX0klGUJUj3lGI+6BGsDLL Me7Pnj82ISq3wdv9eHtXT0QNOEyAN8Y= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-693-gVvU_-FYMkW-TfDkgprFhQ-1; Tue, 02 Dec 2025 13:27:45 -0500 X-MC-Unique: gVvU_-FYMkW-TfDkgprFhQ-1 X-Mimecast-MFC-AGG-ID: gVvU_-FYMkW-TfDkgprFhQ_1764700063 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0272F1955F2A; Tue, 2 Dec 2025 18:27:43 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D557419560B7; Tue, 2 Dec 2025 18:27:37 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 01/16] preempt: Introduce HARDIRQ_DISABLE_BITS Date: Tue, 2 Dec 2025 13:24:09 -0500 Message-ID: <20251202182720.125884-2-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" From: Boqun Feng In order to support preempt_disable()-like interrupt disabling, that is, using part of preempt_count() to track interrupt disabling nested level, change the preempt_count() layout to contain 8-bit HARDIRQ_DISABLE count. Note that HARDIRQ_BITS and NMI_BITS are reduced by 1 because of this, and it changes the maximum of their (hardirq and nmi) nesting level. Signed-off-by: Boqun Feng Signed-off-by: Lyude Paul --- V14: * Fix HARDIRQ_DISABLE_MASK definition Signed-off-by: Lyude Paul --- include/linux/preempt.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/include/linux/preempt.h b/include/linux/preempt.h index 102202185d7a2..94ebdd98b7a94 100644 --- a/include/linux/preempt.h +++ b/include/linux/preempt.h @@ -17,6 +17,7 @@ * * - bits 0-7 are the preemption count (max preemption depth: 256) * - bits 8-15 are the softirq count (max # of softirqs: 256) + * - bits 16-23 are the hardirq disable count (max # of hardirq disable: 2= 56) * * The hardirq count could in theory be the same as the number of * interrupts in the system, but we run all interrupt handlers with @@ -26,29 +27,34 @@ * * PREEMPT_MASK: 0x000000ff * SOFTIRQ_MASK: 0x0000ff00 - * HARDIRQ_MASK: 0x000f0000 - * NMI_MASK: 0x00f00000 + * HARDIRQ_DISABLE_MASK: 0x00ff0000 + * HARDIRQ_MASK: 0x07000000 + * NMI_MASK: 0x38000000 * PREEMPT_NEED_RESCHED: 0x80000000 */ #define PREEMPT_BITS 8 #define SOFTIRQ_BITS 8 -#define HARDIRQ_BITS 4 -#define NMI_BITS 4 +#define HARDIRQ_DISABLE_BITS 8 +#define HARDIRQ_BITS 3 +#define NMI_BITS 3 =20 #define PREEMPT_SHIFT 0 #define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) -#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) +#define HARDIRQ_DISABLE_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) +#define HARDIRQ_SHIFT (HARDIRQ_DISABLE_SHIFT + HARDIRQ_DISABLE_BITS) #define NMI_SHIFT (HARDIRQ_SHIFT + HARDIRQ_BITS) =20 #define __IRQ_MASK(x) ((1UL << (x))-1) =20 #define PREEMPT_MASK (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT) #define SOFTIRQ_MASK (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) +#define HARDIRQ_DISABLE_MASK (__IRQ_MASK(HARDIRQ_DISABLE_BITS) << HARDIRQ_= DISABLE_SHIFT) #define HARDIRQ_MASK (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT) #define NMI_MASK (__IRQ_MASK(NMI_BITS) << NMI_SHIFT) =20 #define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT) #define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT) +#define HARDIRQ_DISABLE_OFFSET (1UL << HARDIRQ_DISABLE_SHIFT) #define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT) #define NMI_OFFSET (1UL << NMI_SHIFT) =20 --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 3C3562D640F for ; Tue, 2 Dec 2025 18:27:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700078; cv=none; b=QZGNNieH/k3fD4/EfAmErZH1ejcfZLWeFoboFIbhC5TqpmsAHmI/4YeGDJInABWad0mRYxpS4zrZVjTf6lfozaVXDXO6SwOzHUCHPpsOZ8g1/KWHEF2C77kME0XPRCdFL4E8ylgBQTG5kaLofg/ncM3JWtcHJ4gDVoQqFPFUPBE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700078; c=relaxed/simple; bh=kM1n84730BKVFTEM7PeJ5TPJI3pyjxrrTvag66TeVKo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BiukkenwcEAoxlrbwiBPpnS14sDY0pwQxTmV+JMnYsLllO9mb9OI9oBnYUrHRPWH56hD0RtFNyuafz/ulFrkYWDI8DYTTJ1vZCmE75PEBybahfHM6tHU1vZrEvXP+WhuCNF5RHuDOVnXmXeTRfCy22G9w7ybPZ+QxHPJqrWgrUc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=KGSMoyIh; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="KGSMoyIh" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700076; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hGPbLfz8rR8ivP6PukN23Vn3ZXX8cy3B4bmTsePyJiY=; b=KGSMoyIhJSXtFfNQuCr/154bKtL/yZ2h+5YpnEBKWH8FDnZ3op5H88JQ2cgy8qHHm0yRaM bQ/j0/XgppaMKt0w6eooRWjIBnO6IyHeeqCCHeoofWJqWdNqbdlXjLEp+cARf7pH8HsIyi zsdibXUmOjAEcYTuRQYvZ6tjMZ9yOmk= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-36-OeOPheXJOGe-p5-b_F_0dg-1; Tue, 02 Dec 2025 13:27:51 -0500 X-MC-Unique: OeOPheXJOGe-p5-b_F_0dg-1 X-Mimecast-MFC-AGG-ID: OeOPheXJOGe-p5-b_F_0dg_1764700068 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 70A1C180049F; Tue, 2 Dec 2025 18:27:48 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4FD2119560A7; Tue, 2 Dec 2025 18:27:43 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long , Joel Fernandes Subject: [PATCH v15 02/16] preempt: Track NMI nesting to separate per-CPU counter Date: Tue, 2 Dec 2025 13:24:10 -0500 Message-ID: <20251202182720.125884-3-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" From: Joel Fernandes Move NMI nesting tracking from the preempt_count bits to a separate per-CPU counter (nmi_nesting). This is to free up the NMI bits in the preempt_count, allowing those bits to be repurposed for other uses. This also has the ben= efit of tracking more than 16-levels deep if there is ever a need. Reduce multiple bits in preempt_count for NMI tracking. Reduce NMI_BITS from 3 to 1, using it only to detect if we're in an NMI. Suggested-by: Boqun Feng Signed-off-by: Joel Fernandes Signed-off-by: Lyude Paul --- include/linux/hardirq.h | 16 ++++++++++++---- include/linux/preempt.h | 13 +++++++++---- kernel/softirq.c | 2 ++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index d57cab4d4c06f..cc06bda52c3e5 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -10,6 +10,8 @@ #include #include =20 +DECLARE_PER_CPU(unsigned int, nmi_nesting); + extern void synchronize_irq(unsigned int irq); extern bool synchronize_hardirq(unsigned int irq); =20 @@ -102,14 +104,16 @@ void irq_exit_rcu(void); */ =20 /* - * nmi_enter() can nest up to 15 times; see NMI_BITS. + * nmi_enter() can nest - nesting is tracked in a per-CPU counter. */ #define __nmi_enter() \ do { \ lockdep_off(); \ arch_nmi_enter(); \ - BUG_ON(in_nmi() =3D=3D NMI_MASK); \ - __preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \ + BUG_ON(__this_cpu_read(nmi_nesting) =3D=3D UINT_MAX); \ + __this_cpu_inc(nmi_nesting); \ + __preempt_count_add(HARDIRQ_OFFSET); \ + preempt_count_set(preempt_count() | NMI_MASK); \ } while (0) =20 #define nmi_enter() \ @@ -124,8 +128,12 @@ void irq_exit_rcu(void); =20 #define __nmi_exit() \ do { \ + unsigned int nesting; \ BUG_ON(!in_nmi()); \ - __preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \ + __preempt_count_sub(HARDIRQ_OFFSET); \ + nesting =3D __this_cpu_dec_return(nmi_nesting); \ + if (!nesting) \ + __preempt_count_sub(NMI_OFFSET); \ arch_nmi_exit(); \ lockdep_on(); \ } while (0) diff --git a/include/linux/preempt.h b/include/linux/preempt.h index 94ebdd98b7a94..860769a717c10 100644 --- a/include/linux/preempt.h +++ b/include/linux/preempt.h @@ -18,6 +18,8 @@ * - bits 0-7 are the preemption count (max preemption depth: 256) * - bits 8-15 are the softirq count (max # of softirqs: 256) * - bits 16-23 are the hardirq disable count (max # of hardirq disable: 2= 56) + * - bits 24-27 are the hardirq count (max # of hardirqs: 16) + * - bit 28 is the NMI flag (no nesting count, tracked separately) * * The hardirq count could in theory be the same as the number of * interrupts in the system, but we run all interrupt handlers with @@ -25,18 +27,21 @@ * there are a few palaeontologic drivers which reenable interrupts in * the handler, so we need more than one bit here. * + * NMI nesting depth is tracked in a separate per-CPU variable + * (nmi_nesting) to save bits in preempt_count. + * * PREEMPT_MASK: 0x000000ff * SOFTIRQ_MASK: 0x0000ff00 * HARDIRQ_DISABLE_MASK: 0x00ff0000 - * HARDIRQ_MASK: 0x07000000 - * NMI_MASK: 0x38000000 + * HARDIRQ_MASK: 0x0f000000 + * NMI_MASK: 0x10000000 * PREEMPT_NEED_RESCHED: 0x80000000 */ #define PREEMPT_BITS 8 #define SOFTIRQ_BITS 8 #define HARDIRQ_DISABLE_BITS 8 -#define HARDIRQ_BITS 3 -#define NMI_BITS 3 +#define HARDIRQ_BITS 4 +#define NMI_BITS 1 =20 #define PREEMPT_SHIFT 0 #define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) diff --git a/kernel/softirq.c b/kernel/softirq.c index 77198911b8dd4..af47ea23aba3b 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -88,6 +88,8 @@ EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled); EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context); #endif =20 +DEFINE_PER_CPU(unsigned int, nmi_nesting); + /* * SOFTIRQ_OFFSET usage: * --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 8A7122D29DB for ; Tue, 2 Dec 2025 18:27:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700080; cv=none; b=HZWKZrb/hhbwrWTVABzJtWWhNMrN1iPl/LvRVKVqhM2aKSRBP+CQLSQnS1kM+w6hx+kVqJ0FYkdTzleSz5YsCFoL5dtrfytTnyyQVIFDbOYnrjFBb6wu9+b6Mh8NYKjwToNCKobf3ncYPsDYMcg5pteF+/tbJ9+YpMShsYFese4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700080; c=relaxed/simple; bh=cuG7lbDjjIvawKAt878L0ivmdSzIWqjbqQvPl7AHz34=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P66J14HhPJ3ITWw5kOC1VwXthuYeHMhyypiNmmxGT+nKkTEU1ktTTW6jBs9cLNtEe6ZX3gC83kWuxmctgB+XnFhJi3CZQsLe8QKQLp79ZPF7FCIqrjdDWGE22v2nhotyrjrs62cYt4Zf81SPHryFD+nHh6uleCH+LKFspMJyCyI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=DHZxsfq3; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="DHZxsfq3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700077; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cQKnWvb+Hbkm1PL+/7ODo6Y9x9Gd6HnsIgokQuXMmLU=; b=DHZxsfq3hy9JpVnKzBZ6ODBaXsB/QEl4LcaTcmbKT2Pj7L9TgaWGt1c4Li0Bhy1qrx/U1v /Av7M2o8pcA5mr3BU7BgLiF2CdRgNVQpl8Hinp1DmwQ+4dqTFHOuipnmg0csALU/x/isKJ ldIB8hhCvFoGP4s0+dpb8SudmmYALMM= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-94-2X0xMS90Pjmjms9kPVisZQ-1; Tue, 02 Dec 2025 13:27:54 -0500 X-MC-Unique: 2X0xMS90Pjmjms9kPVisZQ-1 X-Mimecast-MFC-AGG-ID: 2X0xMS90Pjmjms9kPVisZQ_1764700071 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8F989180047F; Tue, 2 Dec 2025 18:27:51 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id AF65719560A7; Tue, 2 Dec 2025 18:27:48 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 03/16] preempt: Introduce __preempt_count_{sub, add}_return() Date: Tue, 2 Dec 2025 13:24:11 -0500 Message-ID: <20251202182720.125884-4-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" From: Boqun Feng In order to use preempt_count() to tracking the interrupt disable nesting level, __preempt_count_{add,sub}_return() are introduced, as their name suggest, these primitives return the new value of the preempt_count() after changing it. The following example shows the usage of it in local_interrupt_disable(): // increase the HARDIRQ_DISABLE bit new_count =3D __preempt_count_add_return(HARDIRQ_DISABLE_OFFSET); // if it's the first-time increment, then disable the interrupt // at hardware level. if (new_count & HARDIRQ_DISABLE_MASK =3D=3D HARDIRQ_DISABLE_OFFSET) { local_irq_save(flags); raw_cpu_write(local_interrupt_disable_state.flags, flags); } Having these primitives will avoid a read of preempt_count() after changing preempt_count() on certain architectures. Signed-off-by: Boqun Feng --- V10: * Add commit message I forgot * Rebase against latest pcpu_hot changes V11: * Remove CONFIG_PROFILE_ALL_BRANCHES workaround from __preempt_count_add_return() Signed-off-by: Lyude Paul --- arch/arm64/include/asm/preempt.h | 18 ++++++++++++++++++ arch/s390/include/asm/preempt.h | 10 ++++++++++ arch/x86/include/asm/preempt.h | 10 ++++++++++ include/asm-generic/preempt.h | 14 ++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/arch/arm64/include/asm/preempt.h b/arch/arm64/include/asm/pree= mpt.h index 932ea4b620428..0dd8221d1bef7 100644 --- a/arch/arm64/include/asm/preempt.h +++ b/arch/arm64/include/asm/preempt.h @@ -55,6 +55,24 @@ static inline void __preempt_count_sub(int val) WRITE_ONCE(current_thread_info()->preempt.count, pc); } =20 +static inline int __preempt_count_add_return(int val) +{ + u32 pc =3D READ_ONCE(current_thread_info()->preempt.count); + pc +=3D val; + WRITE_ONCE(current_thread_info()->preempt.count, pc); + + return pc; +} + +static inline int __preempt_count_sub_return(int val) +{ + u32 pc =3D READ_ONCE(current_thread_info()->preempt.count); + pc -=3D val; + WRITE_ONCE(current_thread_info()->preempt.count, pc); + + return pc; +} + static inline bool __preempt_count_dec_and_test(void) { struct thread_info *ti =3D current_thread_info(); diff --git a/arch/s390/include/asm/preempt.h b/arch/s390/include/asm/preemp= t.h index 6ccd033acfe52..5ae366e26c57d 100644 --- a/arch/s390/include/asm/preempt.h +++ b/arch/s390/include/asm/preempt.h @@ -98,6 +98,16 @@ static __always_inline bool should_resched(int preempt_o= ffset) return unlikely(READ_ONCE(get_lowcore()->preempt_count) =3D=3D preempt_of= fset); } =20 +static __always_inline int __preempt_count_add_return(int val) +{ + return val + __atomic_add(val, &get_lowcore()->preempt_count); +} + +static __always_inline int __preempt_count_sub_return(int val) +{ + return __preempt_count_add_return(-val); +} + #define init_task_preempt_count(p) do { } while (0) /* Deferred to CPU bringup time */ #define init_idle_preempt_count(p, cpu) do { } while (0) diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h index 578441db09f0b..1220656f3370b 100644 --- a/arch/x86/include/asm/preempt.h +++ b/arch/x86/include/asm/preempt.h @@ -85,6 +85,16 @@ static __always_inline void __preempt_count_sub(int val) raw_cpu_add_4(__preempt_count, -val); } =20 +static __always_inline int __preempt_count_add_return(int val) +{ + return raw_cpu_add_return_4(__preempt_count, val); +} + +static __always_inline int __preempt_count_sub_return(int val) +{ + return raw_cpu_add_return_4(__preempt_count, -val); +} + /* * Because we keep PREEMPT_NEED_RESCHED set when we do _not_ need to resch= edule * a decrement which hits zero means we have no preempt_count and should diff --git a/include/asm-generic/preempt.h b/include/asm-generic/preempt.h index 51f8f3881523a..c8683c046615d 100644 --- a/include/asm-generic/preempt.h +++ b/include/asm-generic/preempt.h @@ -59,6 +59,20 @@ static __always_inline void __preempt_count_sub(int val) *preempt_count_ptr() -=3D val; } =20 +static __always_inline int __preempt_count_add_return(int val) +{ + *preempt_count_ptr() +=3D val; + + return *preempt_count_ptr(); +} + +static __always_inline int __preempt_count_sub_return(int val) +{ + *preempt_count_ptr() -=3D val; + + return *preempt_count_ptr(); +} + static __always_inline bool __preempt_count_dec_and_test(void) { /* --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 2E8152D7D2E for ; Tue, 2 Dec 2025 18:28:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700085; cv=none; b=YxDFmdOJug31u6tJyKuaB+urwbt58qTuypjDlJB5Y48nzd3iFRv0BhqBPQCPoiqfkVoMLgBCpwEYkjpP4KL0a+TBv2KDjSL/JsOskpjNI0WcC6Yw/fG01QDDBFLLxGv7AsoIvpkCeKv8DrmLvrHlosyg1DjTdmd0paz/lA0Dy6w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700085; c=relaxed/simple; bh=UDZt15xFE8q2yHT59jnHqSlLf2qPnkm/dvUZIoTWE1E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LB6/v/RqzziBZN9Ar/fnrKXoyUFPbA1YaVjh+ymFTiaV6M8r90AqXsFGNXShVPISBYLGJ8MS7LhaS9uk+YtuSMtw4Cs8T89JW/0BEAaE3jQtcyst7Fsa3QyvDmhowBDG12Z3XsYtjj0vpSjcBDG0oQSeWg7ft9AIIFC7i+uQEFk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=CmT6DDDP; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="CmT6DDDP" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700082; h=from:from: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=XswqFfBJpp9/9UiCBq83cKmssgcSkfvc3F631w3Qg0Q=; b=CmT6DDDPKVBq5PfYxVyofNxkjdh6eppLFcPHKyPrQHqKvG+91K8EUqD366AECWUVcrO9BT kSJpr07vib7vo61lr6sIGcStE3HjankZpKpAtCie9DEJpTnwTesi7yMB0nEjUzGsCauiwe xjy73KH4pKH4FXnPkLOnVAJtuScBMGI= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-438-vcM__qU8MrSmzOa_atxsHA-1; Tue, 02 Dec 2025 13:27:57 -0500 X-MC-Unique: vcM__qU8MrSmzOa_atxsHA-1 X-Mimecast-MFC-AGG-ID: vcM__qU8MrSmzOa_atxsHA_1764700075 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id ADBCE1956095; Tue, 2 Dec 2025 18:27:54 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A90FB19560A7; Tue, 2 Dec 2025 18:27:51 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 04/16] irq & spin_lock: Add counted interrupt disabling/enabling Date: Tue, 2 Dec 2025 13:24:12 -0500 Message-ID: <20251202182720.125884-5-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 From: Boqun Feng Currently the nested interrupt disabling and enabling is present by _irqsave() and _irqrestore() APIs, which are relatively unsafe, for example: spin_lock_irqsave(l1, flag1); spin_lock_irqsave(l2, flag2); spin_unlock_irqrestore(l1, flags1); // accesses to interrupt-disable protect data will cause races. This is even easier to triggered with guard facilities: unsigned long flag2; scoped_guard(spin_lock_irqsave, l1) { spin_lock_irqsave(l2, flag2); } // l2 locked but interrupts are enabled. spin_unlock_irqrestore(l2, flag2); (Hand-to-hand locking critical sections are not uncommon for a fine-grained lock design) And because this unsafety, Rust cannot easily wrap the interrupt-disabling locks in a safe API, which complicates the design. To resolve this, introduce a new set of interrupt disabling APIs: * local_interrupt_disable(); * local_interrupt_enable(); They work like local_irq_save() and local_irq_restore() except that 1) the outermost local_interrupt_disable() call save the interrupt state into a percpu variable, so that the outermost local_interrupt_enable() can restore the state, and 2) a percpu counter is added to record the nest level of these calls, so that interrupts are not accidentally enabled inside the outermost critical section. Also add the corresponding spin_lock primitives: spin_lock_irq_disable() and spin_unlock_irq_enable(), as a result, code as follow: spin_lock_irq_disable(l1); spin_lock_irq_disable(l2); spin_unlock_irq_enable(l1); // Interrupts are still disabled. spin_unlock_irq_enable(l2); doesn't have the issue that interrupts are accidentally enabled. This also makes the wrapper of interrupt-disabling locks on Rust easier to design. Signed-off-by: Boqun Feng Signed-off-by: Lyude Paul --- V10: * Add missing __raw_spin_lock_irq_disable() definition in spinlock.c V11: * Move definition of spin_trylock_irq_disable() into this commit * Get rid of leftover space * Remove unneeded preempt_disable()/preempt_enable() V12: * Move local_interrupt_enable()/local_interrupt_disable() out of include/linux/spinlock.h, into include/linux/irqflags.h V14: * Move local_interrupt_enable()/disable() again, this time into its own header, interrupt_rc.h, in order to fix a hexagon-specific build issue caught by the CKI bot. The reason this is needed is because on most architectures, irqflags.h ends up including . This provides a definition for the raw_smp_processor_id() function which we depend on like so: local_interrupt_disable() =E2=86=92 raw_cpu_write() =E2=86=92 raw_smp= _processor_id() Unfortunately, hexagon appears to be one such architecture which does not pull in by default here - causing kernel builds to fail and claim that raw_smp_processor_id() is undefined: In file included from kernel/sched/rq-offsets.c:5: In file included from kernel/sched/sched.h:8: In file included from include/linux/sched/affinity.h:1: In file included from include/linux/sched.h:37: In file included from include/linux/spinlock.h:59: >> include/linux/irqflags.h:277:3: error: call to undeclared function 'raw_smp_processor_id'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 277 | raw_cpu_write(local_interrupt_disable_state.flags, flags); | ^ include/linux/percpu-defs.h:413:34: note: expanded from macro 'raw_cpu_write' While including in does fix the build on hexagon, it ends up breaking the build on x86_64: In file included from kernel/sched/rq-offsets.c:5: In file included from kernel/sched/sched.h:8: In file included from ./include/linux/sched/affinity.h:1: In file included from ./include/linux/sched.h:13: In file included from ./arch/x86/include/asm/processor.h:25: In file included from ./arch/x86/include/asm/special_insns.h:10: In file included from ./include/linux/irqflags.h:22: In file included from ./arch/x86/include/asm/smp.h:6: In file included from ./include/linux/thread_info.h:60: In file included from ./arch/x86/include/asm/thread_info.h:59: ./arch/x86/include/asm/cpufeature.h:110:40: error: use of undeclared identifier 'boot_cpu_data' [cap_byte] "i" (&((const char *)boot_cpu_data.x86_capability)[bit >= > 3]) ^ While boot_cpu_data is defined in , it's not possible for us to include that header in irqflags.h because we're already inside of . As a result, I just concluded there's no reasonable way of having these functions in because of how many low level ASM headers depend on it. So, we go with the solution of simply giving ourselves our own header file. V15: * Fix build error on CONFIG_SMP=3Dn reported by Kernel CI Signed-off-by: Lyude Paul --- include/linux/interrupt_rc.h | 63 ++++++++++++++++++++++++++++++++ include/linux/preempt.h | 4 ++ include/linux/spinlock.h | 25 +++++++++++++ include/linux/spinlock_api_smp.h | 27 ++++++++++++++ include/linux/spinlock_api_up.h | 8 ++++ include/linux/spinlock_rt.h | 15 ++++++++ kernel/locking/spinlock.c | 29 +++++++++++++++ kernel/softirq.c | 3 ++ 8 files changed, 174 insertions(+) create mode 100644 include/linux/interrupt_rc.h diff --git a/include/linux/interrupt_rc.h b/include/linux/interrupt_rc.h new file mode 100644 index 0000000000000..d6d05498731b2 --- /dev/null +++ b/include/linux/interrupt_rc.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * include/linux/interrupt_rc.h - refcounted local processor interrupt + * management. + * + * Since the implementation of this API currently depends on + * local_irq_save()/local_irq_restore(), we split this into it's own heade= r to + * make it easier to include without hitting circular header dependencies. + */ + +#ifndef __LINUX_INTERRUPT_RC_H +#define __LINUX_INTERRUPT_RC_H + +#include +#include +#ifdef CONFIG_SMP +#include +#endif + +/* Per-cpu interrupt disabling state for local_interrupt_{disable,enable}(= ) */ +struct interrupt_disable_state { + unsigned long flags; +}; + +DECLARE_PER_CPU(struct interrupt_disable_state, local_interrupt_disable_st= ate); + +static inline void local_interrupt_disable(void) +{ + unsigned long flags; + int new_count; + + new_count =3D hardirq_disable_enter(); + + if ((new_count & HARDIRQ_DISABLE_MASK) =3D=3D HARDIRQ_DISABLE_OFFSET) { + local_irq_save(flags); + raw_cpu_write(local_interrupt_disable_state.flags, flags); + } +} + +static inline void local_interrupt_enable(void) +{ + int new_count; + + new_count =3D hardirq_disable_exit(); + + if ((new_count & HARDIRQ_DISABLE_MASK) =3D=3D 0) { + unsigned long flags; + + flags =3D raw_cpu_read(local_interrupt_disable_state.flags); + local_irq_restore(flags); + /* + * TODO: re-read preempt count can be avoided, but it needs + * should_resched() taking another parameter as the current + * preempt count + */ +#ifdef PREEMPTION + if (should_resched(0)) + __preempt_schedule(); +#endif + } +} + +#endif /* !__LINUX_INTERRUPT_RC_H */ diff --git a/include/linux/preempt.h b/include/linux/preempt.h index 860769a717c10..2f2ee9006f544 100644 --- a/include/linux/preempt.h +++ b/include/linux/preempt.h @@ -153,6 +153,10 @@ static __always_inline unsigned char interrupt_context= _level(void) #define in_softirq() (softirq_count()) #define in_interrupt() (irq_count()) =20 +#define hardirq_disable_count() ((preempt_count() & HARDIRQ_DISABLE_MASK) = >> HARDIRQ_DISABLE_SHIFT) +#define hardirq_disable_enter() __preempt_count_add_return(HARDIRQ_DISABLE= _OFFSET) +#define hardirq_disable_exit() __preempt_count_sub_return(HARDIRQ_DISABLE_= OFFSET) + /* * The preempt_count offset after preempt_disable(); */ diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index d3561c4a080e2..bbbee61c6f5df 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -272,9 +273,11 @@ static inline void do_raw_spin_unlock(raw_spinlock_t *= lock) __releases(lock) #endif =20 #define raw_spin_lock_irq(lock) _raw_spin_lock_irq(lock) +#define raw_spin_lock_irq_disable(lock) _raw_spin_lock_irq_disable(lock) #define raw_spin_lock_bh(lock) _raw_spin_lock_bh(lock) #define raw_spin_unlock(lock) _raw_spin_unlock(lock) #define raw_spin_unlock_irq(lock) _raw_spin_unlock_irq(lock) +#define raw_spin_unlock_irq_enable(lock) _raw_spin_unlock_irq_enable(lock) =20 #define raw_spin_unlock_irqrestore(lock, flags) \ do { \ @@ -300,6 +303,13 @@ static inline void do_raw_spin_unlock(raw_spinlock_t *= lock) __releases(lock) 1 : ({ local_irq_restore(flags); 0; }); \ }) =20 +#define raw_spin_trylock_irq_disable(lock) \ +({ \ + local_interrupt_disable(); \ + raw_spin_trylock(lock) ? \ + 1 : ({ local_interrupt_enable(); 0; }); \ +}) + #ifndef CONFIG_PREEMPT_RT /* Include rwlock functions for !RT */ #include @@ -376,6 +386,11 @@ static __always_inline void spin_lock_irq(spinlock_t *= lock) raw_spin_lock_irq(&lock->rlock); } =20 +static __always_inline void spin_lock_irq_disable(spinlock_t *lock) +{ + raw_spin_lock_irq_disable(&lock->rlock); +} + #define spin_lock_irqsave(lock, flags) \ do { \ raw_spin_lock_irqsave(spinlock_check(lock), flags); \ @@ -401,6 +416,11 @@ static __always_inline void spin_unlock_irq(spinlock_t= *lock) raw_spin_unlock_irq(&lock->rlock); } =20 +static __always_inline void spin_unlock_irq_enable(spinlock_t *lock) +{ + raw_spin_unlock_irq_enable(&lock->rlock); +} + static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsig= ned long flags) { raw_spin_unlock_irqrestore(&lock->rlock, flags); @@ -421,6 +441,11 @@ static __always_inline int spin_trylock_irq(spinlock_t= *lock) raw_spin_trylock_irqsave(spinlock_check(lock), flags); \ }) =20 +static __always_inline int spin_trylock_irq_disable(spinlock_t *lock) +{ + return raw_spin_trylock_irq_disable(&lock->rlock); +} + /** * spin_is_locked() - Check whether a spinlock is locked. * @lock: Pointer to the spinlock. diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_= smp.h index 9ecb0ab504e32..92532103b9eaa 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -28,6 +28,8 @@ _raw_spin_lock_nest_lock(raw_spinlock_t *lock, struct loc= kdep_map *map) void __lockfunc _raw_spin_lock_bh(raw_spinlock_t *lock) __acquires(lock); void __lockfunc _raw_spin_lock_irq(raw_spinlock_t *lock) __acquires(lock); +void __lockfunc _raw_spin_lock_irq_disable(raw_spinlock_t *lock) + __acquires(lock); =20 unsigned long __lockfunc _raw_spin_lock_irqsave(raw_spinlock_t *lock) __acquires(lock); @@ -39,6 +41,7 @@ int __lockfunc _raw_spin_trylock_bh(raw_spinlock_t *lock); void __lockfunc _raw_spin_unlock(raw_spinlock_t *lock) __releases(lock); void __lockfunc _raw_spin_unlock_bh(raw_spinlock_t *lock) __releases(lock); void __lockfunc _raw_spin_unlock_irq(raw_spinlock_t *lock) __releases(lock= ); +void __lockfunc _raw_spin_unlock_irq_enable(raw_spinlock_t *lock) __releas= es(lock); void __lockfunc _raw_spin_unlock_irqrestore(raw_spinlock_t *lock, unsigned long flags) __releases(lock); @@ -55,6 +58,11 @@ _raw_spin_unlock_irqrestore(raw_spinlock_t *lock, unsign= ed long flags) #define _raw_spin_lock_irq(lock) __raw_spin_lock_irq(lock) #endif =20 +/* Use the same config as spin_lock_irq() temporarily. */ +#ifdef CONFIG_INLINE_SPIN_LOCK_IRQ +#define _raw_spin_lock_irq_disable(lock) __raw_spin_lock_irq_disable(lock) +#endif + #ifdef CONFIG_INLINE_SPIN_LOCK_IRQSAVE #define _raw_spin_lock_irqsave(lock) __raw_spin_lock_irqsave(lock) #endif @@ -79,6 +87,11 @@ _raw_spin_unlock_irqrestore(raw_spinlock_t *lock, unsign= ed long flags) #define _raw_spin_unlock_irq(lock) __raw_spin_unlock_irq(lock) #endif =20 +/* Use the same config as spin_unlock_irq() temporarily. */ +#ifdef CONFIG_INLINE_SPIN_UNLOCK_IRQ +#define _raw_spin_unlock_irq_enable(lock) __raw_spin_unlock_irq_enable(loc= k) +#endif + #ifdef CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE #define _raw_spin_unlock_irqrestore(lock, flags) __raw_spin_unlock_irqrest= ore(lock, flags) #endif @@ -120,6 +133,13 @@ static inline void __raw_spin_lock_irq(raw_spinlock_t = *lock) LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); } =20 +static inline void __raw_spin_lock_irq_disable(raw_spinlock_t *lock) +{ + local_interrupt_disable(); + spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); + LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); +} + static inline void __raw_spin_lock_bh(raw_spinlock_t *lock) { __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); @@ -160,6 +180,13 @@ static inline void __raw_spin_unlock_irq(raw_spinlock_= t *lock) preempt_enable(); } =20 +static inline void __raw_spin_unlock_irq_enable(raw_spinlock_t *lock) +{ + spin_release(&lock->dep_map, _RET_IP_); + do_raw_spin_unlock(lock); + local_interrupt_enable(); +} + static inline void __raw_spin_unlock_bh(raw_spinlock_t *lock) { spin_release(&lock->dep_map, _RET_IP_); diff --git a/include/linux/spinlock_api_up.h b/include/linux/spinlock_api_u= p.h index 819aeba1c87e6..d02a73671713b 100644 --- a/include/linux/spinlock_api_up.h +++ b/include/linux/spinlock_api_up.h @@ -36,6 +36,9 @@ #define __LOCK_IRQ(lock) \ do { local_irq_disable(); __LOCK(lock); } while (0) =20 +#define __LOCK_IRQ_DISABLE(lock) \ + do { local_interrupt_disable(); __LOCK(lock); } while (0) + #define __LOCK_IRQSAVE(lock, flags) \ do { local_irq_save(flags); __LOCK(lock); } while (0) =20 @@ -52,6 +55,9 @@ #define __UNLOCK_IRQ(lock) \ do { local_irq_enable(); __UNLOCK(lock); } while (0) =20 +#define __UNLOCK_IRQ_ENABLE(lock) \ + do { __UNLOCK(lock); local_interrupt_enable(); } while (0) + #define __UNLOCK_IRQRESTORE(lock, flags) \ do { local_irq_restore(flags); __UNLOCK(lock); } while (0) =20 @@ -64,6 +70,7 @@ #define _raw_read_lock_bh(lock) __LOCK_BH(lock) #define _raw_write_lock_bh(lock) __LOCK_BH(lock) #define _raw_spin_lock_irq(lock) __LOCK_IRQ(lock) +#define _raw_spin_lock_irq_disable(lock) __LOCK_IRQ_DISABLE(lock) #define _raw_read_lock_irq(lock) __LOCK_IRQ(lock) #define _raw_write_lock_irq(lock) __LOCK_IRQ(lock) #define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) @@ -80,6 +87,7 @@ #define _raw_write_unlock_bh(lock) __UNLOCK_BH(lock) #define _raw_read_unlock_bh(lock) __UNLOCK_BH(lock) #define _raw_spin_unlock_irq(lock) __UNLOCK_IRQ(lock) +#define _raw_spin_unlock_irq_enable(lock) __UNLOCK_IRQ_ENABLE(lock) #define _raw_read_unlock_irq(lock) __UNLOCK_IRQ(lock) #define _raw_write_unlock_irq(lock) __UNLOCK_IRQ(lock) #define _raw_spin_unlock_irqrestore(lock, flags) \ diff --git a/include/linux/spinlock_rt.h b/include/linux/spinlock_rt.h index f6499c37157df..074182f7cfeea 100644 --- a/include/linux/spinlock_rt.h +++ b/include/linux/spinlock_rt.h @@ -93,6 +93,11 @@ static __always_inline void spin_lock_irq(spinlock_t *lo= ck) rt_spin_lock(lock); } =20 +static __always_inline void spin_lock_irq_disable(spinlock_t *lock) +{ + rt_spin_lock(lock); +} + #define spin_lock_irqsave(lock, flags) \ do { \ typecheck(unsigned long, flags); \ @@ -116,12 +121,22 @@ static __always_inline void spin_unlock_irq(spinlock_= t *lock) rt_spin_unlock(lock); } =20 +static __always_inline void spin_unlock_irq_enable(spinlock_t *lock) +{ + rt_spin_unlock(lock); +} + static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) { rt_spin_unlock(lock); } =20 +static __always_inline int spin_trylock_irq_disable(spinlock_t *lock) +{ + return rt_spin_trylock(lock); +} + #define spin_trylock(lock) \ __cond_lock(lock, rt_spin_trylock(lock)) =20 diff --git a/kernel/locking/spinlock.c b/kernel/locking/spinlock.c index 7685defd7c526..da54b220b5a45 100644 --- a/kernel/locking/spinlock.c +++ b/kernel/locking/spinlock.c @@ -125,6 +125,19 @@ static void __lockfunc __raw_##op##_lock_bh(locktype##= _t *lock) \ */ BUILD_LOCK_OPS(spin, raw_spinlock); =20 +/* No rwlock_t variants for now, so just build this function by hand */ +static void __lockfunc __raw_spin_lock_irq_disable(raw_spinlock_t *lock) +{ + for (;;) { + local_interrupt_disable(); + if (likely(do_raw_spin_trylock(lock))) + break; + local_interrupt_enable(); + + arch_spin_relax(&lock->raw_lock); + } +} + #ifndef CONFIG_PREEMPT_RT BUILD_LOCK_OPS(read, rwlock); BUILD_LOCK_OPS(write, rwlock); @@ -172,6 +185,14 @@ noinline void __lockfunc _raw_spin_lock_irq(raw_spinlo= ck_t *lock) EXPORT_SYMBOL(_raw_spin_lock_irq); #endif =20 +#ifndef CONFIG_INLINE_SPIN_LOCK_IRQ +noinline void __lockfunc _raw_spin_lock_irq_disable(raw_spinlock_t *lock) +{ + __raw_spin_lock_irq_disable(lock); +} +EXPORT_SYMBOL_GPL(_raw_spin_lock_irq_disable); +#endif + #ifndef CONFIG_INLINE_SPIN_LOCK_BH noinline void __lockfunc _raw_spin_lock_bh(raw_spinlock_t *lock) { @@ -204,6 +225,14 @@ noinline void __lockfunc _raw_spin_unlock_irq(raw_spin= lock_t *lock) EXPORT_SYMBOL(_raw_spin_unlock_irq); #endif =20 +#ifndef CONFIG_INLINE_SPIN_UNLOCK_IRQ +noinline void __lockfunc _raw_spin_unlock_irq_enable(raw_spinlock_t *lock) +{ + __raw_spin_unlock_irq_enable(lock); +} +EXPORT_SYMBOL_GPL(_raw_spin_unlock_irq_enable); +#endif + #ifndef CONFIG_INLINE_SPIN_UNLOCK_BH noinline void __lockfunc _raw_spin_unlock_bh(raw_spinlock_t *lock) { diff --git a/kernel/softirq.c b/kernel/softirq.c index af47ea23aba3b..b681545eabbbe 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -88,6 +88,9 @@ EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled); EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context); #endif =20 +DEFINE_PER_CPU(struct interrupt_disable_state, local_interrupt_disable_sta= te); +EXPORT_PER_CPU_SYMBOL_GPL(local_interrupt_disable_state); + DEFINE_PER_CPU(unsigned int, nmi_nesting); =20 /* --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 A578F2C21E6 for ; Tue, 2 Dec 2025 18:28:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700085; cv=none; b=EMbOclhM8pfnfxxX4d5jdhYiGjp/R8Nz1h7F+TcEs0DEl3DM/N097pW3OQiCGTBmMTnYXaTWmNCQI6Uxo/AuD/xvcMoptlV3hkGylnC84pWxBNxqPEnDvtCmw8tc33M4s2Zn+ua/7yoLfafo5XfIDyOOV7tGgExaFwgYZLPmTDc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700085; c=relaxed/simple; bh=UA+7kO9qXIvCagZQNnNFP8iaT5XQT9QNyB38hIkWeZ0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=U9wL8TnGRSB/qke9Dt6fNw9ObulR9C+f81fy0nEbp7ZLiI2Y10TBdyQ9TAu4rq64W7FSDY5kn5/lp4tCN+MCWI4CMqdH8LtjODLbti+BP8pNeAy4gDgkGJMFnTgTwS6WuvdCGFz8UK1HCSIWndGEQFo9/MHXoy9iJAgE2Jnadss= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Ch/nkJt5; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Ch/nkJt5" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700082; h=from:from: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=d0ySkqyFlOejCWaamJgtEA8LN72NQ8fgPiQlLdkq/u4=; b=Ch/nkJt5WqesPg11tqCkz7XIXP9FgxNwsiy3qcIzawagiG3PaavKp4RgxQzapwBDfVI1Hl hMaazPyLV8wlvbtnzTqb1O1C5lvbdRm+FSSLi0Labtm8jsHhCuBmTDCleQw+SmDHLRkd3e PYFNifFbfU2h49+oNcezDKCWuwECAxs= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-357-WS3ZcCMXMfau6Z1lx06M7w-1; Tue, 02 Dec 2025 13:28:00 -0500 X-MC-Unique: WS3ZcCMXMfau6Z1lx06M7w-1 X-Mimecast-MFC-AGG-ID: WS3ZcCMXMfau6Z1lx06M7w_1764700077 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8A68918001FE; Tue, 2 Dec 2025 18:27:57 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id DDFFE19560B7; Tue, 2 Dec 2025 18:27:54 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 05/16] irq: Add KUnit test for refcounted interrupt enable/disable Date: Tue, 2 Dec 2025 13:24:13 -0500 Message-ID: <20251202182720.125884-6-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 While making changes to the refcounted interrupt patch series, at some point on my local branch I broke something and ended up writing some kunit tests for testing refcounted interrupts as a result. So, let's include these tests now that we have refcounted interrupts. Signed-off-by: Lyude Paul --- V13: * Add missing MODULE_DESCRIPTION/MODULE_LICENSE lines * Switch from kunit_test_suites(=E2=80=A6) to kunit_test_suite(=E2=80=A6) Signed-off-by: Lyude Paul --- kernel/irq/Makefile | 1 + kernel/irq/refcount_interrupt_test.c | 109 +++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 kernel/irq/refcount_interrupt_test.c diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 6ab3a40556670..7b5bb5510b110 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_SMP) +=3D affinity.o obj-$(CONFIG_GENERIC_IRQ_DEBUGFS) +=3D debugfs.o obj-$(CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR) +=3D matrix.o obj-$(CONFIG_IRQ_KUNIT_TEST) +=3D irq_test.o +obj-$(CONFIG_KUNIT) +=3D refcount_interrupt_test.o diff --git a/kernel/irq/refcount_interrupt_test.c b/kernel/irq/refcount_int= errupt_test.c new file mode 100644 index 0000000000000..b4f224595f261 --- /dev/null +++ b/kernel/irq/refcount_interrupt_test.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit test for refcounted interrupt enable/disables. + */ + +#include +#include + +#define TEST_IRQ_ON() KUNIT_EXPECT_FALSE(test, irqs_disabled()) +#define TEST_IRQ_OFF() KUNIT_EXPECT_TRUE(test, irqs_disabled()) + +/* =3D=3D=3D=3D=3D Test cases =3D=3D=3D=3D=3D */ +static void test_single_irq_change(struct kunit *test) +{ + local_interrupt_disable(); + TEST_IRQ_OFF(); + local_interrupt_enable(); +} + +static void test_nested_irq_change(struct kunit *test) +{ + local_interrupt_disable(); + TEST_IRQ_OFF(); + local_interrupt_disable(); + TEST_IRQ_OFF(); + local_interrupt_disable(); + TEST_IRQ_OFF(); + + local_interrupt_enable(); + TEST_IRQ_OFF(); + local_interrupt_enable(); + TEST_IRQ_OFF(); + local_interrupt_enable(); + TEST_IRQ_ON(); +} + +static void test_multiple_irq_change(struct kunit *test) +{ + local_interrupt_disable(); + TEST_IRQ_OFF(); + local_interrupt_disable(); + TEST_IRQ_OFF(); + + local_interrupt_enable(); + TEST_IRQ_OFF(); + local_interrupt_enable(); + TEST_IRQ_ON(); + + local_interrupt_disable(); + TEST_IRQ_OFF(); + local_interrupt_enable(); + TEST_IRQ_ON(); +} + +static void test_irq_save(struct kunit *test) +{ + unsigned long flags; + + local_irq_save(flags); + TEST_IRQ_OFF(); + local_interrupt_disable(); + TEST_IRQ_OFF(); + local_interrupt_enable(); + TEST_IRQ_OFF(); + local_irq_restore(flags); + TEST_IRQ_ON(); + + local_interrupt_disable(); + TEST_IRQ_OFF(); + local_irq_save(flags); + TEST_IRQ_OFF(); + local_irq_restore(flags); + TEST_IRQ_OFF(); + local_interrupt_enable(); + TEST_IRQ_ON(); +} + +static struct kunit_case test_cases[] =3D { + KUNIT_CASE(test_single_irq_change), + KUNIT_CASE(test_nested_irq_change), + KUNIT_CASE(test_multiple_irq_change), + KUNIT_CASE(test_irq_save), + {}, +}; + +/* (init and exit are the same */ +static int test_init(struct kunit *test) +{ + TEST_IRQ_ON(); + + return 0; +} + +static void test_exit(struct kunit *test) +{ + TEST_IRQ_ON(); +} + +static struct kunit_suite refcount_interrupt_test_suite =3D { + .name =3D "refcount_interrupt", + .test_cases =3D test_cases, + .init =3D test_init, + .exit =3D test_exit, +}; + +kunit_test_suite(refcount_interrupt_test_suite); +MODULE_AUTHOR("Lyude Paul "); +MODULE_DESCRIPTION("Refcounted interrupt unit test suite"); +MODULE_LICENSE("GPL"); --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 5E1EC2D24A0 for ; Tue, 2 Dec 2025 18:28:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700091; cv=none; b=VJum9RdIxfhgKOTn/kmJHXZzwWYFD4ToFs1UP9AEkt7twaRowi6zS4YY2snH56zYbtt+I7OlP+T2qnoLDQwo83jVvrQLmNOI+B85QtV5iADRuUuWBuO41/dLnX3GkaNlgzDQD+h/qG/mVvUDcyOjswOnfs0Fu8wUq/6yNtrq6qs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700091; c=relaxed/simple; bh=T9ELJOI2Mt4C2MVVuRlsbIP+iiIxt5D8oBe+iPjpRLY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=I/o9N8t0CqB8dPJnoEICHGJ8SEivfPjQPQze79jPA3JLdaUtdewV0JyHz0m7wX4R+0sg/cKNcpwDdQTqirsBxjDl+/BhhFJLoJ20f+XKLClX4//Nevo6KNXj69dc7CwUp2CJ/EEk0bg1KJVXCwaWpK29xrTntooabDySvBBaa0U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=VsLn4QEN; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="VsLn4QEN" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700088; h=from:from: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=8oobXKbEsrAG2sI7Aiq9CAEgRK97LqPKtrBS2NMBWSM=; b=VsLn4QENdtd6R7KWf8YG2fyOfqQs1drKkzbThMCarb3Bu8oHJq0QfTdKFO0LsNrnEP7rE3 FAdFu7dfGwkL+54oP3Qh05Cs9MNT5Z7ia71KTDjGypV6NVcRU7qPebbKM/bPT2EsB+DZ/y SXHfA+blUGvm9XbQLre00T9GjELWUCY= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-562-iSDkg7JMPuiaMGUy98EUNQ-1; Tue, 02 Dec 2025 13:28:05 -0500 X-MC-Unique: iSDkg7JMPuiaMGUy98EUNQ-1 X-Mimecast-MFC-AGG-ID: iSDkg7JMPuiaMGUy98EUNQ_1764700080 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4A3C9195609D; Tue, 2 Dec 2025 18:28:00 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BB22219560A7; Tue, 2 Dec 2025 18:27:57 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 06/16] rust: Introduce interrupt module Date: Tue, 2 Dec 2025 13:24:14 -0500 Message-ID: <20251202182720.125884-7-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 This introduces a module for dealing with interrupt-disabled contexts, including the ability to enable and disable interrupts along with the ability to annotate functions as expecting that IRQs are already disabled on the local CPU. [Boqun: This is based on Lyude's work on interrupt disable abstraction, I port to the new local_interrupt_disable() mechanism to make it work as a guard type. I cannot even take the credit of this design, since Lyude also brought up the same idea in zulip. Anyway, this is only for POC purpose, and of course all bugs are mine] Signed-off-by: Lyude Paul Co-developed-by: Boqun Feng Signed-off-by: Boqun Feng Reviewed-by: Benno Lossin Reviewed-by: Andreas Hindborg --- V10: * Fix documentation typos V11: * Get rid of unneeded `use bindings;` * Move ASSUME_DISABLED into assume_disabled() * Confirm using lockdep_assert_irqs_disabled() that local interrupts are in fact disabled when LocalInterruptDisabled::assume_disabled() is called. Signed-off-by: Lyude Paul --- rust/helpers/helpers.c | 1 + rust/helpers/interrupt.c | 18 +++++++++ rust/helpers/sync.c | 5 +++ rust/kernel/interrupt.rs | 86 ++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 5 files changed, 111 insertions(+) create mode 100644 rust/helpers/interrupt.c create mode 100644 rust/kernel/interrupt.rs diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 551da6c9b5064..01ffade6c0389 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -29,6 +29,7 @@ #include "err.c" #include "irq.c" #include "fs.c" +#include "interrupt.c" #include "io.c" #include "jump_label.c" #include "kunit.c" diff --git a/rust/helpers/interrupt.c b/rust/helpers/interrupt.c new file mode 100644 index 0000000000000..f2380dd461ca5 --- /dev/null +++ b/rust/helpers/interrupt.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void rust_helper_local_interrupt_disable(void) +{ + local_interrupt_disable(); +} + +void rust_helper_local_interrupt_enable(void) +{ + local_interrupt_enable(); +} + +bool rust_helper_irqs_disabled(void) +{ + return irqs_disabled(); +} diff --git a/rust/helpers/sync.c b/rust/helpers/sync.c index ff7e68b488101..45b2f519f4e2e 100644 --- a/rust/helpers/sync.c +++ b/rust/helpers/sync.c @@ -11,3 +11,8 @@ void rust_helper_lockdep_unregister_key(struct lock_class= _key *k) { lockdep_unregister_key(k); } + +void rust_helper_lockdep_assert_irqs_disabled(void) +{ + lockdep_assert_irqs_disabled(); +} diff --git a/rust/kernel/interrupt.rs b/rust/kernel/interrupt.rs new file mode 100644 index 0000000000000..6c8d2f58bca70 --- /dev/null +++ b/rust/kernel/interrupt.rs @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Interrupt controls +//! +//! This module allows Rust code to annotate areas of code where local pro= cessor interrupts should +//! be disabled, along with actually disabling local processor interrupts. +//! +//! # =E2=9A=A0=EF=B8=8F Warning! =E2=9A=A0=EF=B8=8F +//! +//! The usage of this module can be more complicated than meets the eye, e= specially surrounding +//! [preemptible kernels]. It's recommended to take care when using the fu= nctions and types defined +//! here and familiarize yourself with the various documentation we have b= efore using them, along +//! with the various documents we link to here. +//! +//! # Reading material +//! +//! - [Software interrupts and realtime (LWN)](https://lwn.net/Articles/52= 0076) +//! +//! [preemptible kernels]: https://www.kernel.org/doc/html/latest/locking/= preempt-locking.html + +use kernel::types::NotThreadSafe; + +/// A guard that represents local processor interrupt disablement on preem= ptible kernels. +/// +/// [`LocalInterruptDisabled`] is a guard type that represents that local = processor interrupts have +/// been disabled on a preemptible kernel. +/// +/// Certain functions take an immutable reference of [`LocalInterruptDisab= led`] in order to require +/// that they may only be run in local-interrupt-disabled contexts on pree= mptible kernels. +/// +/// This is a marker type; it has no size, and is simply used as a compile= -time guarantee that local +/// processor interrupts are disabled on preemptible kernels. Note that no= guarantees about the +/// state of interrupts are made by this type on non-preemptible kernels. +/// +/// # Invariants +/// +/// Local processor interrupts are disabled on preemptible kernels for as = long as an object of this +/// type exists. +pub struct LocalInterruptDisabled(NotThreadSafe); + +/// Disable local processor interrupts on a preemptible kernel. +/// +/// This function disables local processor interrupts on a preemptible ker= nel, and returns a +/// [`LocalInterruptDisabled`] token as proof of this. On non-preemptible = kernels, this function is +/// a no-op. +/// +/// **Usage of this function is discouraged** unless you are absolutely su= re you know what you are +/// doing, as kernel interfaces for rust that deal with interrupt state wi= ll typically handle local +/// processor interrupt state management on their own and managing this by= hand is quite error +/// prone. +pub fn local_interrupt_disable() -> LocalInterruptDisabled { + // SAFETY: It's always safe to call `local_interrupt_disable()`. + unsafe { bindings::local_interrupt_disable() }; + + LocalInterruptDisabled(NotThreadSafe) +} + +impl Drop for LocalInterruptDisabled { + fn drop(&mut self) { + // SAFETY: Per type invariants, a `local_interrupt_disable()` must= be called to create this + // object, hence call the corresponding `local_interrupt_enable()`= is safe. + unsafe { bindings::local_interrupt_enable() }; + } +} + +impl LocalInterruptDisabled { + /// Assume that local processor interrupts are disabled on preemptible= kernels. + /// + /// This can be used for annotating code that is known to be run in co= ntexts where local + /// processor interrupts are disabled on preemptible kernels. It makes= no changes to the local + /// interrupt state on its own. + /// + /// # Safety + /// + /// For the whole life `'a`, local interrupts must be disabled on pree= mptible kernels. This + /// could be a context like for example, an interrupt handler. + pub unsafe fn assume_disabled<'a>() -> &'a LocalInterruptDisabled { + const ASSUME_DISABLED: &LocalInterruptDisabled =3D &LocalInterrupt= Disabled(NotThreadSafe); + + // Confirm they're actually disabled if lockdep is available + // SAFETY: It's always safe to call `lockdep_assert_irqs_disabled(= )` + unsafe { bindings::lockdep_assert_irqs_disabled() }; + + ASSUME_DISABLED + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 235d0d8b1eff2..6fb8f92dfa8e8 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -96,6 +96,7 @@ pub mod fs; pub mod id_pool; pub mod init; +pub mod interrupt; pub mod io; pub mod ioctl; pub mod iov; --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 2E1EE2D8DB9 for ; Tue, 2 Dec 2025 18:28:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700091; cv=none; b=bxbj7O2TBU/xGZo1ED2oE42gEs7TT7KpHt8QzcnlpVhXa7RZldS/PCKUD38U6KRUSGeKxqp+d98np39P3j3Xd/rPt9JuZQ01C5iy2u9LIQo1j+jMFXNkPTzzN9b19Rs7WPmX2bTNuulmQvL+Tu0cvMf8NkzWsW/MTRXaBZdPGtg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700091; c=relaxed/simple; bh=Z0piJ2uMHqJvLowyoCX36ouM9fy0bcmA2oM/iZMlUr0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oaWLZxlf+Fc1MOueMNZ0f7UvL/t38xmJLpuAFXxeiwAv8dazfSSKYx6lLxEXnV5AlVuyESMtnOv1mB8Mm3ul4R+Xk7YzBLGc9AqpDtvMUIurmg+vtYv7kLTq11bbGt4DseBlE5/SidmVGDpMskGHG6XwgefVEN90Eb4wqZxwC2U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=EYH9tRvH; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="EYH9tRvH" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700089; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ctsqKiNbu9tw0Co3r3NlUOa+U4FB32iqwclFHrHc7RQ=; b=EYH9tRvHbbmrlV3MVOWG2Vz/Ed3xz5awqt3MtXBwPiUQQCSrsY9ljOM7m8K9lwEJkuG2tp PXmMO2mzPN944Sijfwn45WyS0ADhps/cyDG7JCYebimT3RMZqtIkK1C4+C1Ux54C3B0rk/ Czcgfyc/zTob4+MLQZlvOFGGT4JghXo= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-644-wzeC9FmpOFuv_REbggpGJQ-1; Tue, 02 Dec 2025 13:28:06 -0500 X-MC-Unique: wzeC9FmpOFuv_REbggpGJQ-1 X-Mimecast-MFC-AGG-ID: wzeC9FmpOFuv_REbggpGJQ_1764700083 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3C67A195605B; Tue, 2 Dec 2025 18:28:03 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7D74019560A7; Tue, 2 Dec 2025 18:28:00 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 07/16] rust: helper: Add spin_{un,}lock_irq_{enable,disable}() helpers Date: Tue, 2 Dec 2025 13:24:15 -0500 Message-ID: <20251202182720.125884-8-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" From: Boqun Feng spin_lock_irq_disable() and spin_unlock_irq_enable() are inline functions, to use them in Rust, helpers are introduced. This is for interrupt disabling lock abstraction in Rust. Signed-off-by: Boqun Feng Reviewed-by: Andreas Hindborg Signed-off-by: Lyude Paul --- rust/helpers/spinlock.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rust/helpers/spinlock.c b/rust/helpers/spinlock.c index 42c4bf01a23e4..d4e61057c2a7a 100644 --- a/rust/helpers/spinlock.c +++ b/rust/helpers/spinlock.c @@ -35,3 +35,18 @@ void rust_helper_spin_assert_is_held(spinlock_t *lock) { lockdep_assert_held(lock); } + +void rust_helper_spin_lock_irq_disable(spinlock_t *lock) +{ + spin_lock_irq_disable(lock); +} + +void rust_helper_spin_unlock_irq_enable(spinlock_t *lock) +{ + spin_unlock_irq_enable(lock); +} + +int rust_helper_spin_trylock_irq_disable(spinlock_t *lock) +{ + return spin_trylock_irq_disable(lock); +} --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 BEA8A2D9782 for ; Tue, 2 Dec 2025 18:28:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700095; cv=none; b=KtVt1KAPK4uMIajXHTR4MojiuxxoIdmYqSGvJkwrxqx8ikyUzGZFPqO/xkfiOVewAaKuBAb+t5KfhdrGOjL99QEWnmbcKgmn3E9xqT3obUfRbEdSoaNB+uMmOdjzJJzPvP4wVOtW5L0e7tWAQPsawf5c22bpgcX4FhuWPiXCXbI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700095; c=relaxed/simple; bh=tydXa9rvjS/hrueTVMn47u+aP/VzAOADtC2uMqqst9I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JK8NDZciPrZghQESHpXmUz3V4RPoh8rN/vwW8d0noqFlOqzRE5zbrDrXriVLUCf0vFZprJA5Lf9Kw9tX80U3ZwvVm2q4tr9KPZywmVRn2otE9Z+vaUzFPwJHWG4+eqb5LAUe/Iq+uYkT7g7zFMrtekIFHfwnNcB4CGpp+gEAa7Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=h85GS5yM; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="h85GS5yM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700093; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2/Nyqn9bJKoJnGMn4wA1T4B/JDlzzuBd8XwkZCM3Ztc=; b=h85GS5yMhuDt9W41qJeiyFOLtEMtuFWnwEdmXOr0FKOMqKxQMytspoK0446mTa70ZwzOT+ Z3Z1iz4AAN0koY1BMdKs/VADweO0aOyJgG7SW65J90yiSmSTHTJjogZF8MeCEMCNjXjxqc iuJFN2/zFZHTixieiVM5dgmOrRVCY0s= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-86-n_bFg_4sPGySgN71RHa3hA-1; Tue, 02 Dec 2025 13:28:08 -0500 X-MC-Unique: n_bFg_4sPGySgN71RHa3hA-1 X-Mimecast-MFC-AGG-ID: n_bFg_4sPGySgN71RHa3hA_1764700086 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C733D1956089; Tue, 2 Dec 2025 18:28:05 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 5381E19560B7; Tue, 2 Dec 2025 18:28:03 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 08/16] rust: sync: Add SpinLockIrq Date: Tue, 2 Dec 2025 13:24:16 -0500 Message-ID: <20251202182720.125884-9-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" A variant of SpinLock that is expected to be used in noirq contexts, so lock() will disable interrupts and unlock() (i.e. `Guard::drop()` will undo the interrupt disable. [Boqun: Port to use spin_lock_irq_disable() and spin_unlock_irq_enable()] Signed-off-by: Lyude Paul Co-developed-by: Boqun Feng Signed-off-by: Boqun Feng Reviewed-by: Andreas Hindborg --- V10: * Also add support to GlobalLock * Documentation fixes from Dirk V11: * Add unit test requested by Daniel Almeida V14: - Improve rustdoc for SpinLockIrqBackend Signed-off-by: Lyude Paul --- rust/kernel/sync.rs | 4 +- rust/kernel/sync/lock/global.rs | 3 + rust/kernel/sync/lock/spinlock.rs | 229 ++++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+), 1 deletion(-) diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index c94753d6413e2..847edd943c457 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -26,7 +26,9 @@ pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBac= kend, GlobalLockedBy}; pub use lock::mutex::{new_mutex, Mutex, MutexGuard}; -pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard}; +pub use lock::spinlock::{ + new_spinlock, new_spinlock_irq, SpinLock, SpinLockGuard, SpinLockIrq, = SpinLockIrqGuard, +}; pub use locked_by::LockedBy; pub use refcount::Refcount; =20 diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global= .rs index 79d0ef7fda867..b8d78ca4c0cd3 100644 --- a/rust/kernel/sync/lock/global.rs +++ b/rust/kernel/sync/lock/global.rs @@ -299,4 +299,7 @@ macro_rules! global_lock_inner { (backend SpinLock) =3D> { $crate::sync::lock::spinlock::SpinLockBackend }; + (backend SpinLockIrq) =3D> { + $crate::sync::lock::spinlock::SpinLockIrqBackend + }; } diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spin= lock.rs index d7be38ccbdc7d..3fdfb0a8a0ab1 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -3,6 +3,7 @@ //! A kernel spinlock. //! //! This module allows Rust code to use the kernel's `spinlock_t`. +use crate::prelude::*; =20 /// Creates a [`SpinLock`] initialiser with the given name and a newly-cre= ated lock class. /// @@ -139,3 +140,231 @@ unsafe fn assert_is_held(ptr: *mut Self::State) { unsafe { bindings::spin_assert_is_held(ptr) } } } + +/// Creates a [`SpinLockIrq`] initialiser with the given name and a newly-= created lock class. +/// +/// It uses the name if one is given, otherwise it generates one based on = the file name and line +/// number. +#[macro_export] +macro_rules! new_spinlock_irq { + ($inner:expr $(, $name:literal)? $(,)?) =3D> { + $crate::sync::SpinLockIrq::new( + $inner, $crate::optional_name!($($name)?), $crate::static_lock= _class!()) + }; +} +pub use new_spinlock_irq; + +/// A spinlock that may be acquired when local processor interrupts are di= sabled. +/// +/// This is a version of [`SpinLock`] that can only be used in contexts wh= ere interrupts for the +/// local CPU are disabled. It can be acquired in two ways: +/// +/// - Using [`lock()`] like any other type of lock, in which case the bind= ings will modify the +/// interrupt state to ensure that local processor interrupts remain dis= abled for at least as long +/// as the [`SpinLockIrqGuard`] exists. +/// - Using [`lock_with()`] in contexts where a [`LocalInterruptDisabled`]= token is present and +/// local processor interrupts are already known to be disabled, in whic= h case the local interrupt +/// state will not be touched. This method should be preferred if a [`Lo= calInterruptDisabled`] +/// token is present in the scope. +/// +/// For more info on spinlocks, see [`SpinLock`]. For more information on = interrupts, +/// [see the interrupt module](kernel::interrupt). +/// +/// # Examples +/// +/// The following example shows how to declare, allocate initialise and ac= cess a struct (`Example`) +/// that contains an inner struct (`Inner`) that is protected by a spinloc= k that requires local +/// processor interrupts to be disabled. +/// +/// ``` +/// use kernel::sync::{new_spinlock_irq, SpinLockIrq}; +/// +/// struct Inner { +/// a: u32, +/// b: u32, +/// } +/// +/// #[pin_data] +/// struct Example { +/// #[pin] +/// c: SpinLockIrq, +/// #[pin] +/// d: SpinLockIrq, +/// } +/// +/// impl Example { +/// fn new() -> impl PinInit { +/// pin_init!(Self { +/// c <- new_spinlock_irq!(Inner { a: 0, b: 10 }), +/// d <- new_spinlock_irq!(Inner { a: 20, b: 30 }), +/// }) +/// } +/// } +/// +/// // Allocate a boxed `Example` +/// let e =3D KBox::pin_init(Example::new(), GFP_KERNEL)?; +/// +/// // Accessing an `Example` from a context where interrupts may not be d= isabled already. +/// let c_guard =3D e.c.lock(); // interrupts are disabled now, +1 interru= pt disable refcount +/// let d_guard =3D e.d.lock(); // no interrupt state change, +1 interrupt= disable refcount +/// +/// assert_eq!(c_guard.a, 0); +/// assert_eq!(c_guard.b, 10); +/// assert_eq!(d_guard.a, 20); +/// assert_eq!(d_guard.b, 30); +/// +/// drop(c_guard); // Dropping c_guard will not re-enable interrupts just = yet, since d_guard is +/// // still in scope. +/// drop(d_guard); // Last interrupt disable reference dropped here, so in= terrupts are re-enabled +/// // now +/// # Ok::<(), Error>(()) +/// ``` +/// +/// [`lock()`]: SpinLockIrq::lock +/// [`lock_with()`]: SpinLockIrq::lock_with +pub type SpinLockIrq =3D super::Lock; + +/// A kernel `spinlock_t` lock backend that can only be acquired in interr= upt disabled contexts. +pub struct SpinLockIrqBackend; + +/// A [`Guard`] acquired from locking a [`SpinLockIrq`] using [`lock()`]. +/// +/// This is simply a type alias for a [`Guard`] returned from locking a [`= SpinLockIrq`] using +/// [`lock_with()`]. It will unlock the [`SpinLockIrq`] and decrement the = local processor's +/// interrupt disablement refcount upon being dropped. +/// +/// [`Guard`]: super::Guard +/// [`lock()`]: SpinLockIrq::lock +/// [`lock_with()`]: SpinLockIrq::lock_with +pub type SpinLockIrqGuard<'a, T> =3D super::Guard<'a, T, SpinLockIrqBacken= d>; + +// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclus= ion. `relock` uses the +// default implementation that always calls the same locking method. +unsafe impl super::Backend for SpinLockIrqBackend { + type State =3D bindings::spinlock_t; + type GuardState =3D (); + + unsafe fn init( + ptr: *mut Self::State, + name: *const crate::ffi::c_char, + key: *mut bindings::lock_class_key, + ) { + // SAFETY: The safety requirements ensure that `ptr` is valid for = writes, and `name` and + // `key` are valid for read indefinitely. + unsafe { bindings::__spin_lock_init(ptr, name, key) } + } + + unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState { + // SAFETY: The safety requirements of this function ensure that `p= tr` points to valid + // memory, and that it has been initialised before. + unsafe { bindings::spin_lock_irq_disable(ptr) } + } + + unsafe fn unlock(ptr: *mut Self::State, _guard_state: &Self::GuardStat= e) { + // SAFETY: The safety requirements of this function ensure that `p= tr` is valid and that the + // caller is the owner of the spinlock. + unsafe { bindings::spin_unlock_irq_enable(ptr) } + } + + unsafe fn try_lock(ptr: *mut Self::State) -> Option { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initial= ized before use. + let result =3D unsafe { bindings::spin_trylock_irq_disable(ptr) }; + + if result !=3D 0 { + Some(()) + } else { + None + } + } + + unsafe fn assert_is_held(ptr: *mut Self::State) { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initial= ized before use. + unsafe { bindings::spin_assert_is_held(ptr) } + } +} + +#[kunit_tests(rust_spinlock_irq_condvar)] +mod tests { + use super::*; + use crate::{ + sync::*, + workqueue::{self, impl_has_work, new_work, Work, WorkItem}, + }; + + struct TestState { + value: u32, + waiter_ready: bool, + } + + #[pin_data] + struct Test { + #[pin] + state: SpinLockIrq, + + #[pin] + state_changed: CondVar, + + #[pin] + waiter_state_changed: CondVar, + + #[pin] + wait_work: Work, + } + + impl_has_work! { + impl HasWork for Test { self.wait_work } + } + + impl Test { + pub(crate) fn new() -> Result> { + Arc::try_pin_init( + try_pin_init!( + Self { + state <- new_spinlock_irq!(TestState { + value: 1, + waiter_ready: false + }), + state_changed <- new_condvar!(), + waiter_state_changed <- new_condvar!(), + wait_work <- new_work!("IrqCondvarTest::wait_work") + } + ), + GFP_KERNEL, + ) + } + } + + impl WorkItem for Test { + type Pointer =3D Arc; + + fn run(this: Arc) { + // Wait for the test to be ready to wait for us + let mut state =3D this.state.lock(); + + while !state.waiter_ready { + this.waiter_state_changed.wait(&mut state); + } + + // Deliver the exciting value update our test has been waiting= for + state.value +=3D 1; + this.state_changed.notify_sync(); + } + } + + #[test] + fn spinlock_irq_condvar() -> Result { + let testdata =3D Test::new()?; + + let _ =3D workqueue::system().enqueue(testdata.clone()); + + // Let the updater know when we're ready to wait + let mut state =3D testdata.state.lock(); + state.waiter_ready =3D true; + testdata.waiter_state_changed.notify_sync(); + + // Wait for the exciting value update + testdata.state_changed.wait(&mut state); + assert_eq!(state.value, 2); + Ok(()) + } +} --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 71DC62DA758 for ; Tue, 2 Dec 2025 18:28:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700097; cv=none; b=jpnxV/oGWJdjSt8LkBZPvXBohhTFdGox3lg9JgOy/7atW5WSAS1O4njTCRWozTK5KRbn5PapNuLmL9qQktxNM6i39dWd5dodHyHSUQvHsbagq5FKd4OTfqrpzoOjpfOr08G4evJvgnAW/eIPxuYInEUebIUXDgD1VKDp4yXupjI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700097; c=relaxed/simple; bh=LqwZb+QJ7/CFHVDFfMH2t4MCeCQkA0TCPsc1eNxhRfw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QDjgCBJK7UYTC7MicLj9dCrf4kgb8c+hNjDcSsXGOg4dVk4mCZidXoAExgjMXUVCi9B07k7YkgXebBorqbu4IstcW0m/kCjO3Ee1eAqw4QDkqgfHDjfxL9kCNxotWuLAtCnhKt5C60pGighrUT1i6puYgx8bw/P0/RlY6gIKRPA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=ExGhsA43; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="ExGhsA43" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700094; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6ZJqTEAw/NPTICe/9g7Ikaq8Y0mDc1JyrMgmfNXdinc=; b=ExGhsA432jWgDKKnN3KSpGcdxXEetSm+J0QfYh/+DDrPK3LVwmMeX5/DaiIHayy0a9Zj39 YZW5WSX728QCTbXYWYJAmyVrZpfspbB5cHp1fbAKpygXieLwQtHEsboWmdtDwNp0EQNl6P QyDMzaRXaKcWeQr2iov0eTlXNeMbZbc= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-690-Zm0eROY6PCOf8ZIITXHHJQ-1; Tue, 02 Dec 2025 13:28:11 -0500 X-MC-Unique: Zm0eROY6PCOf8ZIITXHHJQ-1 X-Mimecast-MFC-AGG-ID: Zm0eROY6PCOf8ZIITXHHJQ_1764700088 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B7E021955E7A; Tue, 2 Dec 2025 18:28:08 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 02D9B19560A7; Tue, 2 Dec 2025 18:28:05 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 09/16] rust: sync: Introduce lock::Backend::Context Date: Tue, 2 Dec 2025 13:24:17 -0500 Message-ID: <20251202182720.125884-10-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" Now that we've introduced an `InterruptDisabled` token for marking contexts in which IRQs are disabled, we can have a way to avoid `SpinLockIrq` disabling interrupts if the interrupts have already been disabled. Basically, a `SpinLockIrq` should work like a `SpinLock` if interrupts are disabled. So a function: (&'a SpinLockIrq, &'a InterruptDisabled) -> Guard<'a, .., SpinLockBackend> makes senses. Note that due to `Guard` and `InterruptDisabled` having the same lifetime, interrupts cannot be enabled while the Guard exists. Add a `lock_with()` interface for `Lock`, and an associate type of `Backend` to describe the context. Signed-off-by: Lyude Paul Co-developed-by: Boqun Feng Signed-off-by: Boqun Feng --- V10: - Fix typos - Dirk Signed-off-by: Lyude Paul --- rust/kernel/sync/lock.rs | 12 +++++++++++- rust/kernel/sync/lock/mutex.rs | 1 + rust/kernel/sync/lock/spinlock.rs | 4 +++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 5d7991e6d3736..7df62923608b7 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -44,6 +44,9 @@ pub unsafe trait Backend { /// [`unlock`]: Backend::unlock type GuardState; =20 + /// The context which can be provided to acquire the lock with a diffe= rent backend. + type Context<'a>; + /// Initialises the lock. /// /// # Safety @@ -163,8 +166,15 @@ pub unsafe fn from_raw<'a>(ptr: *mut B::State) -> &'a = Self { } =20 impl Lock { + /// Acquires the lock with the given context and gives the caller acce= ss to the data protected + /// by it. + pub fn lock_with<'a>(&'a self, _context: B::Context<'a>) -> Guard<'a, = T, B> { + todo!() + } + /// Acquires the lock and gives the caller access to the data protecte= d by it. - pub fn lock(&self) -> Guard<'_, T, B> { + #[inline] + pub fn lock<'a>(&'a self) -> Guard<'a, T, B> { // SAFETY: The constructor of the type calls `init`, so the existe= nce of the object proves // that `init` was called. let state =3D unsafe { B::lock(self.state.get()) }; diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 581cee7ab842a..be1e2e18cf42d 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -101,6 +101,7 @@ macro_rules! new_mutex { unsafe impl super::Backend for MutexBackend { type State =3D bindings::mutex; type GuardState =3D (); + type Context<'a> =3D (); =20 unsafe fn init( ptr: *mut Self::State, diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spin= lock.rs index 3fdfb0a8a0ab1..70d19a2636afe 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -3,7 +3,7 @@ //! A kernel spinlock. //! //! This module allows Rust code to use the kernel's `spinlock_t`. -use crate::prelude::*; +use crate::{interrupt::LocalInterruptDisabled, prelude::*}; =20 /// Creates a [`SpinLock`] initialiser with the given name and a newly-cre= ated lock class. /// @@ -101,6 +101,7 @@ macro_rules! new_spinlock { unsafe impl super::Backend for SpinLockBackend { type State =3D bindings::spinlock_t; type GuardState =3D (); + type Context<'a> =3D (); =20 unsafe fn init( ptr: *mut Self::State, @@ -243,6 +244,7 @@ macro_rules! new_spinlock_irq { unsafe impl super::Backend for SpinLockIrqBackend { type State =3D bindings::spinlock_t; type GuardState =3D (); + type Context<'a> =3D &'a LocalInterruptDisabled; =20 unsafe fn init( ptr: *mut Self::State, --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 AF5EA2D24B8 for ; Tue, 2 Dec 2025 18:28:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700098; cv=none; b=fmDzZsdHUWLNbi+dxC00gflx4QlzO5qqRRGuppNo/x6Ss+tjI8xDjtEsSIm8Zbr5zAycsFVcqXodptjB/I0uL4wDCOZGecprw8gA/X0ab+5UU/lV0F7wjiHUoLc6uSAGmpdjHp8PhZip71OR+gIJHj8mkpIldFTKxj+G+HUXmfI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700098; c=relaxed/simple; bh=2fa0mpdlM7b4TXRN52ERurlM4MiXvcMStP9VkQKMxFY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lK03tBrkOZcSTLKKoONt7Vu69gGKEKV8AUVAqSGoOnj8n/0GFuab9Sv+Tkwt48ungypLrW3sJyWuyUW9VWkvj3vRfij7hzVTpUj+5O8zUIF8gvqhTKd6Dh/z4Fl7zCV+GtnzS+qNeVH342xAHU19tARU5cyQmwX8kDSKL4dxGz8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=hHFHwi/Z; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="hHFHwi/Z" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700095; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tmwbp5cxkpesJO+Zgo2yprtrs4ZHk/zucD0LwIAvThU=; b=hHFHwi/ZAxgE/HqhtXDtGJgQVYxIwFnekF97cIS9toHij2CR1vjeGtu6XhWncbgri3LUcB 6ixoU0kWoW206W+2QbmIksxYOUluMpDyIuzKrwKl+HMlwaECwWBvDf8YR6GJ+i8BBusM/3 gWZ0Nslwxph1Blop38e3tfsGZ77ARIU= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-617-1EE5J4XuNym3O9wchcQ-TQ-1; Tue, 02 Dec 2025 13:28:14 -0500 X-MC-Unique: 1EE5J4XuNym3O9wchcQ-TQ-1 X-Mimecast-MFC-AGG-ID: 1EE5J4XuNym3O9wchcQ-TQ_1764700091 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id BDB73195605A; Tue, 2 Dec 2025 18:28:11 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E922219560A7; Tue, 2 Dec 2025 18:28:08 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 10/16] rust: sync: lock: Add `Backend::BackendInContext` Date: Tue, 2 Dec 2025 13:24:18 -0500 Message-ID: <20251202182720.125884-11-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" From: Boqun Feng `SpinLockIrq` and `SpinLock` use the exact same underlying C structure, with the only real difference being that the former uses the irq_disable() and irq_enable() variants for locking/unlocking. These variants can introduce some minor overhead in contexts where we already know that local processor interrupts are disabled, and as such we want a way to be able to skip modifying processor interrupt state in said contexts in order to avoid some overhead - just like the current C API allows us to do. So, `BackendInContext` allows us to cast a lock into it's contextless version for situations where we already have whatever guarantees would be provided by `Backend::Context` in place. In some hacked-together benchmarks we ran, most of the time this did actually seem to lead to a noticeable difference in overhead: From an aarch64 VM running on a MacBook M4: lock() when irq is disabled, 100 times cost Delta { nanos: 500 } lock_with() when irq is disabled, 100 times cost Delta { nanos: 292 } lock() when irq is enabled, 100 times cost Delta { nanos: 834 } lock() when irq is disabled, 100 times cost Delta { nanos: 459 } lock_with() when irq is disabled, 100 times cost Delta { nanos: 291 } lock() when irq is enabled, 100 times cost Delta { nanos: 709 } From an x86_64 VM (qemu/kvm) running on a i7-13700H lock() when irq is disabled, 100 times cost Delta { nanos: 1002 } lock_with() when irq is disabled, 100 times cost Delta { nanos: 729 } lock() when irq is enabled, 100 times cost Delta { nanos: 1516 } lock() when irq is disabled, 100 times cost Delta { nanos: 754 } lock_with() when irq is disabled, 100 times cost Delta { nanos: 966 } lock() when irq is enabled, 100 times cost Delta { nanos: 1227 } (note that there were some runs on x86_64 where lock() on irq disabled vs. lock_with() on irq disabled had equivalent benchmarks, but it very much appeared to be a minority of test runs. While it's not clear how this affects real-world workloads yet, let's add this for the time being so we can find out. Signed-off-by: Boqun Feng Co-developed-by: Lyude Paul Signed-off-by: Lyude Paul --- V10: * Fix typos - Dirk/Lyude * Since we're adding support for context locks to GlobalLock as well, let's also make sure to cover try_lock while we're at it and add try_lock_with * Add a private function as_lock_in_context() for handling casting from a Lock to Lock so we don't have to duplicate safety comments V11: * Fix clippy::ref_as_ptr error in Lock::as_lock_in_context() V14: * Add benchmark results, rewrite commit message Signed-off-by: Lyude Paul --- rust/kernel/sync/lock.rs | 61 ++++++++++++++++++++++++++++++- rust/kernel/sync/lock/mutex.rs | 1 + rust/kernel/sync/lock/spinlock.rs | 41 +++++++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 7df62923608b7..abc7ceff35994 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -30,10 +30,15 @@ /// is owned, that is, between calls to [`lock`] and [`unlock`]. /// - Implementers must also ensure that [`relock`] uses the same locking = method as the original /// lock operation. +/// - Implementers must ensure if [`BackendInContext`] is a [`Backend`], i= t's safe to acquire the +/// lock under the [`Context`], the [`State`] of two backends must be th= e same. /// /// [`lock`]: Backend::lock /// [`unlock`]: Backend::unlock /// [`relock`]: Backend::relock +/// [`BackendInContext`]: Backend::BackendInContext +/// [`Context`]: Backend::Context +/// [`State`]: Backend::State pub unsafe trait Backend { /// The state required by the lock. type State; @@ -47,6 +52,9 @@ pub unsafe trait Backend { /// The context which can be provided to acquire the lock with a diffe= rent backend. type Context<'a>; =20 + /// The alternative backend we can use if a [`Context`](Backend::Conte= xt) is provided. + type BackendInContext: Sized; + /// Initialises the lock. /// /// # Safety @@ -166,10 +174,59 @@ pub unsafe fn from_raw<'a>(ptr: *mut B::State) -> &'a= Self { } =20 impl Lock { + /// Casts the lock as a `Lock`. + fn as_lock_in_context<'a>( + &'a self, + _context: B::Context<'a>, + ) -> &'a Lock + where + B::BackendInContext: Backend, + { + // SAFETY: + // - Per the safety guarantee of `Backend`, if `B::BackendInContex= t` and `B` should + // have the same state, the layout of the lock is the same so it= 's safe to convert one to + // another. + // - The caller provided `B::Context<'a>`, so it is safe to recast= and return this lock. + unsafe { &*(core::ptr::from_ref(self) as *const _) } + } + /// Acquires the lock with the given context and gives the caller acce= ss to the data protected /// by it. - pub fn lock_with<'a>(&'a self, _context: B::Context<'a>) -> Guard<'a, = T, B> { - todo!() + pub fn lock_with<'a>(&'a self, context: B::Context<'a>) -> Guard<'a, T= , B::BackendInContext> + where + B::BackendInContext: Backend, + { + let lock =3D self.as_lock_in_context(context); + + // SAFETY: The constructor of the type calls `init`, so the existe= nce of the object proves + // that `init` was called. Plus the safety guarantee of `Backend` = guarantees that `B::State` + // is the same as `B::BackendInContext::State`, also it's safe to = call another backend + // because there is `B::Context<'a>`. + let state =3D unsafe { B::BackendInContext::lock(lock.state.get())= }; + + // SAFETY: The lock was just acquired. + unsafe { Guard::new(lock, state) } + } + + /// Tries to acquire the lock with the given context. + /// + /// Returns a guard that can be used to access the data protected by t= he lock if successful. + pub fn try_lock_with<'a>( + &'a self, + context: B::Context<'a>, + ) -> Option> + where + B::BackendInContext: Backend, + { + let lock =3D self.as_lock_in_context(context); + + // SAFETY: The constructor of the type calls `init`, so the existe= nce of the object proves + // that `init` was called. Plus the safety guarantee of `Backend` = guarantees that `B::State` + // is the same as `B::BackendInContext::State`, also it's safe to = call another backend + // because there is `B::Context<'a>`. + unsafe { + B::BackendInContext::try_lock(lock.state.get()).map(|state| Gu= ard::new(lock, state)) + } } =20 /// Acquires the lock and gives the caller access to the data protecte= d by it. diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index be1e2e18cf42d..662a530750703 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -102,6 +102,7 @@ unsafe impl super::Backend for MutexBackend { type State =3D bindings::mutex; type GuardState =3D (); type Context<'a> =3D (); + type BackendInContext =3D (); =20 unsafe fn init( ptr: *mut Self::State, diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spin= lock.rs index 70d19a2636afe..81384ea239955 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -102,6 +102,7 @@ unsafe impl super::Backend for SpinLockBackend { type State =3D bindings::spinlock_t; type GuardState =3D (); type Context<'a> =3D (); + type BackendInContext =3D (); =20 unsafe fn init( ptr: *mut Self::State, @@ -221,6 +222,45 @@ macro_rules! new_spinlock_irq { /// # Ok::<(), Error>(()) /// ``` /// +/// The next example demonstrates locking a [`SpinLockIrq`] using [`lock_w= ith()`] in a function +/// which can only be called when local processor interrupts are already d= isabled. +/// +/// ``` +/// use kernel::sync::{new_spinlock_irq, SpinLockIrq}; +/// use kernel::interrupt::*; +/// +/// struct Inner { +/// a: u32, +/// } +/// +/// #[pin_data] +/// struct Example { +/// #[pin] +/// inner: SpinLockIrq, +/// } +/// +/// impl Example { +/// fn new() -> impl PinInit { +/// pin_init!(Self { +/// inner <- new_spinlock_irq!(Inner { a: 20 }), +/// }) +/// } +/// } +/// +/// // Accessing an `Example` from a function that can only be called in n= o-interrupt contexts. +/// fn noirq_work(e: &Example, interrupt_disabled: &LocalInterruptDisabled= ) { +/// // Because we know interrupts are disabled from interrupt_disable,= we can skip toggling +/// // interrupt state using lock_with() and the provided token +/// assert_eq!(e.inner.lock_with(interrupt_disabled).a, 20); +/// } +/// +/// # let e =3D KBox::pin_init(Example::new(), GFP_KERNEL)?; +/// # let interrupt_guard =3D local_interrupt_disable(); +/// # noirq_work(&e, &interrupt_guard); +/// # +/// # Ok::<(), Error>(()) +/// ``` +/// /// [`lock()`]: SpinLockIrq::lock /// [`lock_with()`]: SpinLockIrq::lock_with pub type SpinLockIrq =3D super::Lock; @@ -245,6 +285,7 @@ unsafe impl super::Backend for SpinLockIrqBackend { type State =3D bindings::spinlock_t; type GuardState =3D (); type Context<'a> =3D &'a LocalInterruptDisabled; + type BackendInContext =3D SpinLockBackend; =20 unsafe fn init( ptr: *mut Self::State, --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 BF6762DA76A for ; Tue, 2 Dec 2025 18:28:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700103; cv=none; b=GA3LSRgwSphM/acvk0OuUbF+sYoN47b3LayIp4KuLdC4zaouKy6QamoTk67stSzyDAAOA/+lMgQkaBB85W6i9gpT6+zekOb55GeIwL7IWKEGsTBCxUQphtCXJU709BxfF2Wi+0mvKFt8qOKeH/WTF1aJhmcoQHWErv1iO0Yhp10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700103; c=relaxed/simple; bh=rSS7CCYrU9XdQT+TYL1PT6BnQjd6/VGbKXTySPilShw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GBhlsM9BI7Bys2cTdLgGeWVLDLxYFQpjfbijZ4FKHcm+Cjt3gvML/IJMzSZwJ82FV8Laq1sg4ntNMEa9tV2Ow9GI5weSpDoTiW/yUuXVKVpeJcxznV3/YyEkUrQZmK6s8gYHXDvEJuV74fCfOzhDL+EBH2D9RR670xRlH3EmglI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=OScfKiBV; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="OScfKiBV" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700100; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=o3QwqvomQyYtHphg2lDys8v0/dFlltSrRGkZpxwdRgc=; b=OScfKiBVIKDCvoInGypno8SUcRJHMV5a5KLe3bA5WEwKaXc0rpdObGCZWlaWIn+hMvlAyR SA6bbQ7S+ne+WRBkga66PSr3AUjmnnT/SQPPT7AE1ImtV5K7r+1D+669mapiJrpFAFz189 E3OMpz07GZNayp59SQmeu4HqT5x04dQ= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-653-8uDi3oW4OUW9u_Q6BfYMRw-1; Tue, 02 Dec 2025 13:28:16 -0500 X-MC-Unique: 8uDi3oW4OUW9u_Q6BfYMRw-1 X-Mimecast-MFC-AGG-ID: 8uDi3oW4OUW9u_Q6BfYMRw_1764700094 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 54E22180035F; Tue, 2 Dec 2025 18:28:14 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D34F919560A7; Tue, 2 Dec 2025 18:28:11 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 11/16] rust: sync: lock/global: Rename B to G in trait bounds Date: Tue, 2 Dec 2025 13:24:19 -0500 Message-ID: <20251202182720.125884-12-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" Due to the introduction of Backend::BackendInContext, if we want to be able support Lock types with a Context we need to be able to handle the fact that the Backend for a returned Guard may not exactly match the Backend for the lock. Before we add this though, rename B to G in all of our trait bounds to make sure things don't become more difficult to understand once we add a Backend bound. There should be no functional changes in this patch. Signed-off-by: Lyude Paul --- rust/kernel/sync/lock/global.rs | 56 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global= .rs index b8d78ca4c0cd3..c2349347976d8 100644 --- a/rust/kernel/sync/lock/global.rs +++ b/rust/kernel/sync/lock/global.rs @@ -33,18 +33,18 @@ pub trait GlobalLockBackend { /// Type used for global locks. /// /// See [`global_lock!`] for examples. -pub struct GlobalLock { - inner: Lock, +pub struct GlobalLock { + inner: Lock, } =20 -impl GlobalLock { +impl GlobalLock { /// Creates a global lock. /// /// # Safety /// /// * Before any other method on this lock is called, [`Self::init`] m= ust be called. - /// * The type `B` must not be used with any other lock. - pub const unsafe fn new(data: B::Item) -> Self { + /// * The type `G` must not be used with any other lock. + pub const unsafe fn new(data: G::Item) -> Self { Self { inner: Lock { state: Opaque::uninit(), @@ -68,23 +68,23 @@ pub unsafe fn init(&'static self) { // `init` before using any other methods. As `init` can only be ca= lled once, all other // uses of this lock must happen after this call. unsafe { - B::Backend::init( + G::Backend::init( self.inner.state.get(), - B::NAME.as_char_ptr(), - B::get_lock_class().as_ptr(), + G::NAME.as_char_ptr(), + G::get_lock_class().as_ptr(), ) } } =20 /// Lock this global lock. - pub fn lock(&'static self) -> GlobalGuard { + pub fn lock(&'static self) -> GlobalGuard { GlobalGuard { inner: self.inner.lock(), } } =20 /// Try to lock this global lock. - pub fn try_lock(&'static self) -> Option> { + pub fn try_lock(&'static self) -> Option> { Some(GlobalGuard { inner: self.inner.try_lock()?, }) @@ -94,19 +94,19 @@ pub fn try_lock(&'static self) -> Option= > { /// A guard for a [`GlobalLock`]. /// /// See [`global_lock!`] for examples. -pub struct GlobalGuard { - inner: Guard<'static, B::Item, B::Backend>, +pub struct GlobalGuard { + inner: Guard<'static, G::Item, G::Backend>, } =20 -impl core::ops::Deref for GlobalGuard { - type Target =3D B::Item; +impl core::ops::Deref for GlobalGuard { + type Target =3D G::Item; =20 fn deref(&self) -> &Self::Target { &self.inner } } =20 -impl core::ops::DerefMut for GlobalGuard { +impl core::ops::DerefMut for GlobalGuard { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } @@ -115,33 +115,33 @@ fn deref_mut(&mut self) -> &mut Self::Target { /// A version of [`LockedBy`] for a [`GlobalLock`]. /// /// See [`global_lock!`] for examples. -pub struct GlobalLockedBy { - _backend: PhantomData, +pub struct GlobalLockedBy { + _backend: PhantomData, value: UnsafeCell, } =20 // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLock= edBy`. -unsafe impl Send for GlobalLockedBy +unsafe impl Send for GlobalLockedBy where T: ?Sized, - B: GlobalLockBackend, - LockedBy: Send, + G: GlobalLockBackend, + LockedBy: Send, { } =20 // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLock= edBy`. -unsafe impl Sync for GlobalLockedBy +unsafe impl Sync for GlobalLockedBy where T: ?Sized, - B: GlobalLockBackend, - LockedBy: Sync, + G: GlobalLockBackend, + LockedBy: Sync, { } =20 -impl GlobalLockedBy { +impl GlobalLockedBy { /// Create a new [`GlobalLockedBy`]. /// - /// The provided value will be protected by the global lock indicated = by `B`. + /// The provided value will be protected by the global lock indicated = by `G`. pub fn new(val: T) -> Self { Self { value: UnsafeCell::new(val), @@ -150,11 +150,11 @@ pub fn new(val: T) -> Self { } } =20 -impl GlobalLockedBy { +impl GlobalLockedBy { /// Access the value immutably. /// /// The caller must prove shared access to the lock. - pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard) -> &'a T { + pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard) -> &'a T { // SAFETY: The lock is globally unique, so there can only be one g= uard. unsafe { &*self.value.get() } } @@ -162,7 +162,7 @@ pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard)= -> &'a T { /// Access the value mutably. /// /// The caller must prove shared exclusive to the lock. - pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard) -> &'a mut= T { + pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard) -> &'a mut= T { // SAFETY: The lock is globally unique, so there can only be one g= uard. unsafe { &mut *self.value.get() } } --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 2FFAC2DC797 for ; Tue, 2 Dec 2025 18:28:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700104; cv=none; b=GD9mnQaqW742dWVIon+T47CyvAZDA2UNeM5OHsQqFJhhUd8EaN5XqO3ZmV98GIEqMdtdxEBhbTgzdW50oMFfF0+cdSGaV1M9CtffkjqtNZCQcwu7IKxC2Kzp/yD4vblHTWCe3STzlAVm/IzxVJISwDmvUAFr3/hLYbvUrAGhU00= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700104; c=relaxed/simple; bh=tLPDDkLEViSkLBgrE8m+TJlxSjUbsou/zGCyJe+ad6s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=arSNzetsfv3Z4Sqf0jaZE9QL2qSVvEoOpZHEj9//RB0Hafz3zU2NbI7z/ECeyTa0xMIsvvIpljdQev3Tgv3uw9IuwkfYnjIDuXwqnPmkxK8oO4oCMOQ2tbmO2KfIJskCnlbjpa7jvPVGFBwjoGCtFxAvLExfbo9gNFxdtrO8to4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=gcF1XJmm; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="gcF1XJmm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700102; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xWvvpW8Wr87PBbOYqTtSpCNr0mDcnZ263kzk42NtFLU=; b=gcF1XJmm7JqQMhoWirkaj5fbBTJw9/3zC3ByhH4mWl77TPI585Ipw279+2J1AOALBhy5En M6aHFQsBqWRCTjWPCk8L/kv68q1jpqK+i9X1ZqVSVgPCpOTSJ+N4qYLMOM+5+9ckY/vbt0 avk+QkqKFE9k+OcQ/6xF8JB30Ub1eDw= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-358-eL5mpQ_XMf-z6I0r4vmp6Q-1; Tue, 02 Dec 2025 13:28:19 -0500 X-MC-Unique: eL5mpQ_XMf-z6I0r4vmp6Q-1 X-Mimecast-MFC-AGG-ID: eL5mpQ_XMf-z6I0r4vmp6Q_1764700097 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 07AD91800561; Tue, 2 Dec 2025 18:28:17 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 866FA19560A7; Tue, 2 Dec 2025 18:28:14 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 12/16] rust: sync: Add a lifetime parameter to lock::global::GlobalGuard Date: Tue, 2 Dec 2025 13:24:20 -0500 Message-ID: <20251202182720.125884-13-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" While a GlobalLock is always going to be static, in the case of locks with explicit backend contexts the GlobalGuard will not be 'static and will instead share the lifetime of the context. So, add a lifetime parameter to GlobalGuard to allow for this so we can implement GlobalGuard support for SpinlockIrq. Signed-off-by: Lyude Paul --- rust/kernel/sync/lock/global.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global= .rs index c2349347976d8..1d279be1a2eca 100644 --- a/rust/kernel/sync/lock/global.rs +++ b/rust/kernel/sync/lock/global.rs @@ -77,14 +77,14 @@ pub unsafe fn init(&'static self) { } =20 /// Lock this global lock. - pub fn lock(&'static self) -> GlobalGuard { + pub fn lock(&'static self) -> GlobalGuard<'static, G> { GlobalGuard { inner: self.inner.lock(), } } =20 /// Try to lock this global lock. - pub fn try_lock(&'static self) -> Option> { + pub fn try_lock(&'static self) -> Option> { Some(GlobalGuard { inner: self.inner.try_lock()?, }) @@ -94,11 +94,11 @@ pub fn try_lock(&'static self) -> Option= > { /// A guard for a [`GlobalLock`]. /// /// See [`global_lock!`] for examples. -pub struct GlobalGuard { - inner: Guard<'static, G::Item, G::Backend>, +pub struct GlobalGuard<'a, G: GlobalLockBackend> { + inner: Guard<'a, G::Item, G::Backend>, } =20 -impl core::ops::Deref for GlobalGuard { +impl<'a, G: GlobalLockBackend> core::ops::Deref for GlobalGuard<'a, G> { type Target =3D G::Item; =20 fn deref(&self) -> &Self::Target { @@ -106,7 +106,7 @@ fn deref(&self) -> &Self::Target { } } =20 -impl core::ops::DerefMut for GlobalGuard { +impl<'a, G: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<'a, G> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } @@ -154,7 +154,7 @@ impl GlobalLockedBy { /// Access the value immutably. /// /// The caller must prove shared access to the lock. - pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard) -> &'a T { + pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<'_, G>) -> &'a T { // SAFETY: The lock is globally unique, so there can only be one g= uard. unsafe { &*self.value.get() } } @@ -162,7 +162,7 @@ pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard)= -> &'a T { /// Access the value mutably. /// /// The caller must prove shared exclusive to the lock. - pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard) -> &'a mut= T { + pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<'_, G>) -> &'a= mut T { // SAFETY: The lock is globally unique, so there can only be one g= uard. unsafe { &mut *self.value.get() } } @@ -232,7 +232,7 @@ pub fn get_mut(&mut self) -> &mut T { /// /// Increment the counter in this instance. /// /// /// /// The caller must hold the `MY_MUTEX` mutex. -/// fn increment(&self, guard: &mut GlobalGuard) -> u32 { +/// fn increment(&self, guard: &mut GlobalGuard<'_, MY_MUTEX>) -> u32 { /// let my_counter =3D self.my_counter.as_mut(guard); /// *my_counter +=3D 1; /// *my_counter --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 CFDD22DCBFD for ; Tue, 2 Dec 2025 18:28:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700106; cv=none; b=EOpBQosd/jHVE1FF0tUgFnsM9Y+5oZfbBg2smfFSrp63JErOa5NjnZA7wtH6DfHH6bgWsNKu8/ofF6m3LWenghJS3nDQX/diskK+sY7g9wHszos8Q2gT7GvdBdoNhir1MBO+3zdip+jJqSmPkCs4RSzaaMlQRgIp0ZhLEOzbG9E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700106; c=relaxed/simple; bh=nCFXarMFa586dGrcNAs0jKPT2h0FKQUvMN9FU4ejyb4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IIHWtN1qOkcabn5iU5P1R0nJAXtAmmYBILxRVMww64J7T2Jq29goqiVekKeenvS7RDQX6ngvQrFwuBWQSvI9fSBBMxbGjbUw6JUobnpM3En3V7p5ctlCvWkR3o66W+r+CIYgRP6Xdl5gv9j9LIa4fzw6VIyEaSr23HpPHQgEr3k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=dcqoT63z; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="dcqoT63z" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700104; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tH4YX3T1TRr9YuPAznqrV8AK+8NwB79iZ5r++1p2W4k=; b=dcqoT63zhrLL64nw9kr/jroaGqyqx4WuJXaWfLB4iB1xMRDZajViIPKYt9GC/mXbQnwYRs RjwKb3IpEkvJ7TupIVdHRqZFmpdQZH96+MnIfkxLnURRkneRsrela7ZS1FBavjBInzrF1B 5vgiTWsNkMq7Mxr0Znx0FP1ecy/VG0I= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-79-NYev_AMkMECMTpff8WUocg-1; Tue, 02 Dec 2025 13:28:22 -0500 X-MC-Unique: NYev_AMkMECMTpff8WUocg-1 X-Mimecast-MFC-AGG-ID: NYev_AMkMECMTpff8WUocg_1764700099 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C45151956088; Tue, 2 Dec 2025 18:28:19 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3928219560A7; Tue, 2 Dec 2025 18:28:17 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 13/16] rust: sync: Expose lock::Backend Date: Tue, 2 Dec 2025 13:24:21 -0500 Message-ID: <20251202182720.125884-14-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" Due to the addition of sync::lock::Backend::Context, lock guards can be returned with a different Backend than their respective lock. Since we'll be adding a trait bound for Backend to GlobalGuard in order to support this, users will need to be able to directly refer to Backend so that they can use it in trait bounds. So, let's make this easier for users and expose Backend in sync. Signed-off-by: Lyude Paul --- rust/kernel/sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 847edd943c457..e4604d21c884a 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -29,6 +29,7 @@ pub use lock::spinlock::{ new_spinlock, new_spinlock_irq, SpinLock, SpinLockGuard, SpinLockIrq, = SpinLockIrqGuard, }; +pub use lock::Backend; pub use locked_by::LockedBy; pub use refcount::Refcount; =20 --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 9D80A2DEA6E for ; Tue, 2 Dec 2025 18:28:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700110; cv=none; b=Vs4enG+TL8JhrjsIyPCU23K6gFfgqcwYtLNDBRIQAcwVMshA3Xxzx3UwYcwQ4sdjHNOD1uIUml84/IHA93Xc/hnjE9EP38J/DiD7eDktyavSpD3KaonaC8Ra1MPDACn/M7EOLNtnjlaUFd7Tm/wUkJReY/Vgziqxvm5CcwdCXvE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700110; c=relaxed/simple; bh=YP5nHpGCP5frHGxz59R99GmDjDWZ6b6Et8UTIPXjNKk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BKGleV/DnO3JHHaCDwZO6L9kLUO1IkGEyjwpu5ppXFDUqUz1G+aLom48dI/k8LptvckcD6PrdDyDeJoGTSl7kfOD455sDCR3EDOP8GIj7lPr91tnGMCoNy4XbPad52Rv/mMQubs5lzqRlgsjGXw4db1mtN4H37pyjEpWyZ+cV5Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=DTOGj1ct; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="DTOGj1ct" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700107; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sZ1dfnd87LNuY6Ybc5qdt8fOiieffMFEXtuSDQq5xRg=; b=DTOGj1cto0ztC9A4kiTXNLIpQkRMdblA+pMd6SlFiJAaycc1RtIXD3v2I2lpERF9efMR0v LuzPuDOcZMEsv1zM97kabP6s3Sq+V07s5MMnrUimW7OsHrdvu2JmDIAvSDc8WHRAObWYsT YQ+9+b5bvSM+O3ic3+bQUlYqHIkdN/0= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-694-4wVgx2d2OxSd2mno-xdd3Q-1; Tue, 02 Dec 2025 13:28:24 -0500 X-MC-Unique: 4wVgx2d2OxSd2mno-xdd3Q-1 X-Mimecast-MFC-AGG-ID: 4wVgx2d2OxSd2mno-xdd3Q_1764700102 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8087F1801233; Tue, 2 Dec 2025 18:28:22 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0014919560B7; Tue, 2 Dec 2025 18:28:19 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 14/16] rust: sync: lock/global: Add Backend parameter to GlobalGuard Date: Tue, 2 Dec 2025 13:24:22 -0500 Message-ID: <20251202182720.125884-15-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" Due to the introduction of sync::lock::Backend::Context, it's now possible for normal locks to return a Guard with a different Backend than their respective lock (e.g. Backend::BackendInContext). We want to be able to support global locks with contexts as well, so add a trait bound to explicitly specify which Backend is in use for a GlobalGuard. Signed-off-by: Lyude Paul --- rust/kernel/sync/lock/global.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global= .rs index 1d279be1a2eca..31264b68086b3 100644 --- a/rust/kernel/sync/lock/global.rs +++ b/rust/kernel/sync/lock/global.rs @@ -77,14 +77,14 @@ pub unsafe fn init(&'static self) { } =20 /// Lock this global lock. - pub fn lock(&'static self) -> GlobalGuard<'static, G> { + pub fn lock(&'static self) -> GlobalGuard<'static, G, G::Backend> { GlobalGuard { inner: self.inner.lock(), } } =20 /// Try to lock this global lock. - pub fn try_lock(&'static self) -> Option> { + pub fn try_lock(&'static self) -> Option> { Some(GlobalGuard { inner: self.inner.try_lock()?, }) @@ -94,11 +94,11 @@ pub fn try_lock(&'static self) -> Option> { /// A guard for a [`GlobalLock`]. /// /// See [`global_lock!`] for examples. -pub struct GlobalGuard<'a, G: GlobalLockBackend> { - inner: Guard<'a, G::Item, G::Backend>, +pub struct GlobalGuard<'a, G: GlobalLockBackend, B: Backend> { + inner: Guard<'a, G::Item, B>, } =20 -impl<'a, G: GlobalLockBackend> core::ops::Deref for GlobalGuard<'a, G> { +impl<'a, G: GlobalLockBackend, B: Backend> core::ops::Deref for GlobalGuar= d<'a, G, B> { type Target =3D G::Item; =20 fn deref(&self) -> &Self::Target { @@ -106,7 +106,7 @@ fn deref(&self) -> &Self::Target { } } =20 -impl<'a, G: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<'a, G> { +impl<'a, G: GlobalLockBackend, B: Backend> core::ops::DerefMut for GlobalG= uard<'a, G, B> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } @@ -154,7 +154,7 @@ impl GlobalLockedBy { /// Access the value immutably. /// /// The caller must prove shared access to the lock. - pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<'_, G>) -> &'a T { + pub fn as_ref<'a, B: Backend>(&'a self, _guard: &'a GlobalGuard<'_, G,= B>) -> &'a T { // SAFETY: The lock is globally unique, so there can only be one g= uard. unsafe { &*self.value.get() } } @@ -162,7 +162,7 @@ pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<'_,= G>) -> &'a T { /// Access the value mutably. /// /// The caller must prove shared exclusive to the lock. - pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<'_, G>) -> &'a= mut T { + pub fn as_mut<'a, B: Backend>(&'a self, _guard: &'a mut GlobalGuard<'_= , G, B>) -> &'a mut T { // SAFETY: The lock is globally unique, so there can only be one g= uard. unsafe { &mut *self.value.get() } } @@ -216,7 +216,7 @@ pub fn get_mut(&mut self) -> &mut T { /// ``` /// # mod ex { /// # use kernel::prelude::*; -/// use kernel::sync::{GlobalGuard, GlobalLockedBy}; +/// use kernel::sync::{Backend, GlobalGuard, GlobalLockedBy}; /// /// kernel::sync::global_lock! { /// // SAFETY: Initialized in module initializer before first use. @@ -232,7 +232,7 @@ pub fn get_mut(&mut self) -> &mut T { /// /// Increment the counter in this instance. /// /// /// /// The caller must hold the `MY_MUTEX` mutex. -/// fn increment(&self, guard: &mut GlobalGuard<'_, MY_MUTEX>) -> u32 { +/// fn increment(&self, guard: &mut GlobalGuard<'_, MY_MUT= EX, B>) -> u32 { /// let my_counter =3D self.my_counter.as_mut(guard); /// *my_counter +=3D 1; /// *my_counter --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 7E1C32DEA94 for ; Tue, 2 Dec 2025 18:28:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700115; cv=none; b=n3iF3RccQuQGOcVfS6NUmmPIUcxVuykqzbPUBODsCxfYa6sEhxu3MbIiA8w1RGZzOBT63a9vycPUzWA5PaTsyZcvqDI2G0VjmtQ1QwnvKcZaJMPEN3sEeRh1IL3mNjKFL7H4kjEyOYDP6xVhKOoKOSjXw2f9qakGXeVM2gmPZPk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700115; c=relaxed/simple; bh=3jXt/fS4SI88qMIEkOpFGKsFIYm7WnyWCeahW0qmUdY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EyVMeP6Ex3hGU5REVaGAAyZ8AwdfdlRvXXsVdHpE7HZvjk6o92g6O2J3GE7epOdeBW88QIZpiUnsLHPu2fqOPe9u73mV1QBuU8pbA93ftuwfrCqAcII3wfD9uuTqpQdmLLS83Yvop+1MiQYscVWo0dMsGtYTyAosbFwBHeB0sxU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=gCNa9h4K; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="gCNa9h4K" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700112; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pnEYgNaFDB1k958f3dYNKjGG3prgj19hu0N27iWNaAM=; b=gCNa9h4KWYsRUGa6wJCHWVj8sQL4DX6V0Hwm07V88f4Tz0cvg4Zy6n2SAbN/bb3d7/CnaU JHejr4Wc5ZjDobyTAXfeLMT7XigGga/RrADyqH8rTDIS7dUhPbfvOhihudV0O/s+DDJq1q Qnj1zwAdC4WgdXJrBeLSOGCkf0PU8NY= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-248-OvAE50XNNZS94w93K49X-g-1; Tue, 02 Dec 2025 13:28:28 -0500 X-MC-Unique: OvAE50XNNZS94w93K49X-g-1 X-Mimecast-MFC-AGG-ID: OvAE50XNNZS94w93K49X-g_1764700105 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7CFEB19560B2; Tue, 2 Dec 2025 18:28:25 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B23F419560A7; Tue, 2 Dec 2025 18:28:22 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 15/16] rust: sync: lock/global: Add BackendInContext support to GlobalLock Date: Tue, 2 Dec 2025 13:24:23 -0500 Message-ID: <20251202182720.125884-16-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" Now that we have the ability to provide an explicit lifetime for a GlobalGuard and an explicit Backend for a GlobalGuard, we can finally implement lock_with() and try_lock_with(). Signed-off-by: Lyude Paul --- rust/kernel/sync/lock/global.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global= .rs index 31264b68086b3..20fbe11d1a04b 100644 --- a/rust/kernel/sync/lock/global.rs +++ b/rust/kernel/sync/lock/global.rs @@ -89,6 +89,34 @@ pub fn try_lock(&'static self) -> Option> { inner: self.inner.try_lock()?, }) } + + /// Lock this global lock with the provided `context`. + pub fn lock_with<'a, B>( + &'static self, + context: ::Context<'a>, + ) -> GlobalGuard<'a, G, B> + where + G::Backend: Backend, + B: Backend, + { + GlobalGuard { + inner: self.inner.lock_with(context), + } + } + + /// Try to lock this global lock with the provided `context`. + pub fn try_lock_with<'a, B>( + &'static self, + context: ::Context<'a>, + ) -> Option> + where + G::Backend: Backend, + B: Backend, + { + Some(GlobalGuard { + inner: self.inner.try_lock_with(context)?, + }) + } } =20 /// A guard for a [`GlobalLock`]. --=20 2.52.0 From nobody Sun Feb 8 05:17:02 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 45AB02D5A19 for ; Tue, 2 Dec 2025 18:28:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700116; cv=none; b=smsljyjhtP1odgt5KGH4R7pa44F7/Bef8eiVZvuy+xfQd/KneIhsrbIslkEO6UtZyU070OE0bYb/As243mX8BVJ6C2orCGSgcihFCceL4Dy2BFYcTaa96rLefKfu6aR/9SesXACWLACtv1VwcmorRAYah11JJWBISpUShq8q4sE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764700116; c=relaxed/simple; bh=2W4clTK2M34eskJ0i4cUqdPwuUWHM0hpuVGJ5OjSCdg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hXs0OyVq3xvq/LAy5sku0ppBgK9yTTJFMGJzpHVqmpygZYC8ke1WJySfB6vP0O9TAoCrg1tdiCi8xogyXbweGbBAoadNxdyyTHSv6pssuC5oTgkDrr8OLpNeg5/6RC5zHaivdzsZBYLU8YDqbfLcYuoY8J6dPN8KluILBmpULMc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=HvzEQ7DW; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="HvzEQ7DW" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1764700114; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JIAjWCkKsIEZSb5fVKVynfXsWMHwW8pCG5bQYm4J3DU=; b=HvzEQ7DW9QDydWH0ZXczATVDdR6/AOtpCLU8vsZXybRiqsTEVUCfhSN+aQoL+l40xHLC9k knOB+nHGSMSOTNz/ADXChE3JN7IWv6vSRSnLSeewPMtwe3U5DBD2Na80y61cJ2FLHjg0TT GK/YuTA6WkDqe5O9MmIfrtFZ951vnUY= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-507-lrG3O0hpPUKbzhdA4O-D6w-1; Tue, 02 Dec 2025 13:28:33 -0500 X-MC-Unique: lrG3O0hpPUKbzhdA4O-D6w-1 X-Mimecast-MFC-AGG-ID: lrG3O0hpPUKbzhdA4O-D6w_1764700110 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7686619560A7; Tue, 2 Dec 2025 18:28:30 +0000 (UTC) Received: from chopper.lan (unknown [10.22.80.109]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D9F2019560A7; Tue, 2 Dec 2025 18:28:25 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Thomas Gleixner Cc: Boqun Feng , Daniel Almeida , Miguel Ojeda , Alex Gaynor , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Andrew Morton , Peter Zijlstra , Ingo Molnar , Will Deacon , Waiman Long Subject: [PATCH v15 16/16] locking: Switch to _irq_{disable,enable}() variants in cleanup guards Date: Tue, 2 Dec 2025 13:24:24 -0500 Message-ID: <20251202182720.125884-17-lyude@redhat.com> In-Reply-To: <20251202182720.125884-1-lyude@redhat.com> References: <20251202182720.125884-1-lyude@redhat.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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" From: Boqun Feng The semantics of various irq disabling guards match what *_irq_{disable,enable}() provide, i.e. the interrupt disabling is properly nested, therefore it's OK to switch to use *_irq_{disable,enable}() primitives. Signed-off-by: Boqun Feng --- V10: * Add PREEMPT_RT build fix from Guangbo Cui Signed-off-by: Lyude Paul --- include/linux/spinlock.h | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index bbbee61c6f5df..72bb6ae5319c7 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -568,10 +568,10 @@ DEFINE_LOCK_GUARD_1(raw_spinlock_nested, raw_spinlock= _t, raw_spin_unlock(_T->lock)) =20 DEFINE_LOCK_GUARD_1(raw_spinlock_irq, raw_spinlock_t, - raw_spin_lock_irq(_T->lock), - raw_spin_unlock_irq(_T->lock)) + raw_spin_lock_irq_disable(_T->lock), + raw_spin_unlock_irq_enable(_T->lock)) =20 -DEFINE_LOCK_GUARD_1_COND(raw_spinlock_irq, _try, raw_spin_trylock_irq(_T->= lock)) +DEFINE_LOCK_GUARD_1_COND(raw_spinlock_irq, _try, raw_spin_trylock_irq_disa= ble(_T->lock)) =20 DEFINE_LOCK_GUARD_1(raw_spinlock_bh, raw_spinlock_t, raw_spin_lock_bh(_T->lock), @@ -580,12 +580,11 @@ DEFINE_LOCK_GUARD_1(raw_spinlock_bh, raw_spinlock_t, DEFINE_LOCK_GUARD_1_COND(raw_spinlock_bh, _try, raw_spin_trylock_bh(_T->lo= ck)) =20 DEFINE_LOCK_GUARD_1(raw_spinlock_irqsave, raw_spinlock_t, - raw_spin_lock_irqsave(_T->lock, _T->flags), - raw_spin_unlock_irqrestore(_T->lock, _T->flags), - unsigned long flags) + raw_spin_lock_irq_disable(_T->lock), + raw_spin_unlock_irq_enable(_T->lock)) =20 DEFINE_LOCK_GUARD_1_COND(raw_spinlock_irqsave, _try, - raw_spin_trylock_irqsave(_T->lock, _T->flags)) + raw_spin_trylock_irq_disable(_T->lock)) =20 DEFINE_LOCK_GUARD_1(spinlock, spinlock_t, spin_lock(_T->lock), @@ -594,11 +593,11 @@ DEFINE_LOCK_GUARD_1(spinlock, spinlock_t, DEFINE_LOCK_GUARD_1_COND(spinlock, _try, spin_trylock(_T->lock)) =20 DEFINE_LOCK_GUARD_1(spinlock_irq, spinlock_t, - spin_lock_irq(_T->lock), - spin_unlock_irq(_T->lock)) + spin_lock_irq_disable(_T->lock), + spin_unlock_irq_enable(_T->lock)) =20 DEFINE_LOCK_GUARD_1_COND(spinlock_irq, _try, - spin_trylock_irq(_T->lock)) + spin_trylock_irq_disable(_T->lock)) =20 DEFINE_LOCK_GUARD_1(spinlock_bh, spinlock_t, spin_lock_bh(_T->lock), @@ -608,12 +607,11 @@ DEFINE_LOCK_GUARD_1_COND(spinlock_bh, _try, spin_trylock_bh(_T->lock)) =20 DEFINE_LOCK_GUARD_1(spinlock_irqsave, spinlock_t, - spin_lock_irqsave(_T->lock, _T->flags), - spin_unlock_irqrestore(_T->lock, _T->flags), - unsigned long flags) + spin_lock_irq_disable(_T->lock), + spin_unlock_irq_enable(_T->lock)) =20 DEFINE_LOCK_GUARD_1_COND(spinlock_irqsave, _try, - spin_trylock_irqsave(_T->lock, _T->flags)) + spin_trylock_irq_disable(_T->lock)) =20 DEFINE_LOCK_GUARD_1(read_lock, rwlock_t, read_lock(_T->lock), --=20 2.52.0