From patchwork Fri Jul 14 09:13:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313410 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EBECAC0015E for ; Fri, 14 Jul 2023 09:32:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235764AbjGNJcV (ORCPT ); Fri, 14 Jul 2023 05:32:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55944 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235920AbjGNJcG (ORCPT ); Fri, 14 Jul 2023 05:32:06 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 781923595; Fri, 14 Jul 2023 02:31:42 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id 471AB5BC3C; Fri, 14 Jul 2023 09:14:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326052; bh=o+SeZO+TTzWLzgNWKeL/9Zv5OKicaLoX59hV3WtVOuQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=G1Wt2cxZ6pXf5tZHduVNikkCwJ3eY/lAhhmaHq//OZOo1deR9FPvpL756OTXtqF85 U8KN4XXHwq4kXASxrE4WM3foVumLTNRuyqWbxwvb3G5DVYK5urrwEpptS14bvFxNuV rM9oWkXKT6+KtlANMnhRwMIRrKKn/t+a1OQzzUInlbKfRIEEiKHfM46BpexZR3xeQo zw6WVMGuSbW3xPkeiUX1+B0n8oA2tixHQOpEQD8x35urVL0yabJLZeR9yatWjie17f HvYMnAtJzpmQQjPcKmEpSusQK/YGodFN0o0fLT0yKw6OpEZ1e/EstgBaO+Fg78oVw9 /bKFNaONUniCA== From: Asahi Lina Date: Fri, 14 Jul 2023 18:13:53 +0900 Subject: [PATCH RFC 01/11] rust: types: Add Opaque::zeroed() MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-1-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=917; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=o+SeZO+TTzWLzgNWKeL/9Zv5OKicaLoX59hV3WtVOuQ=; b=P7T19OB+nyd6yqEUa+zAXigTFInuYsRPYk1q7QrYZWp3AGBZT9g7I8/XOtzJ0ql7JeJgdOQIU c1DhSVUSWWlDIOLTjbR15WVf3RuPsnSK+ax6uw3FGMMMCpBAJ/uBqK1 X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org Opaque types are internally MaybeUninit, so it's safe to actually zero-initialize them as long as we don't claim they are initialized. This is useful for many FFI types that are expected to be zero-inited by the user. Signed-off-by: Asahi Lina Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo --- rust/kernel/types.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 1e5380b16ed5..185d3493857e 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -237,6 +237,11 @@ pub const fn uninit() -> Self { Self(MaybeUninit::uninit()) } + /// Creates a zeroed value. + pub fn zeroed() -> Self { + Self(MaybeUninit::zeroed()) + } + /// Creates a pin-initializer from the given initializer closure. /// /// The returned initializer calls the given closure with the pointer to the inner `T` of this From patchwork Fri Jul 14 09:13:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313409 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C6A76EB64DC for ; Fri, 14 Jul 2023 09:32:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235951AbjGNJcU (ORCPT ); Fri, 14 Jul 2023 05:32:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56422 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235873AbjGNJcG (ORCPT ); Fri, 14 Jul 2023 05:32:06 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 77E413594; Fri, 14 Jul 2023 02:31:42 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id 5C0EA5BC40; Fri, 14 Jul 2023 09:14:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326058; bh=y9j+fmO9oWE2TupvVpaaD80X7pDQKCp9sdvtdWdP4zM=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=y84e2wXTjy0hzmtrX37Fvo6re+l/TXA0Bs5Kqc1RccJ2w8WblDu9BBWxmI8KYN6LL 7Hyq6eJjmnUvRTpLA4aXoIYlc1haDLCjd2dxkJpGyDwe8b4QRiMjNJdJUZseGW49Rb iA8HP0D7u811zX8VDaFJgS11NguIUSnEnDszRH4HCZoVRAZIHhmysFsYsNM4Yt5C86 8PO0TP7/92gQybYXNgpEMxLGZX6LF97opbpfzb08ps5Y6KZhoYHucRMXk5jlMy61Ht xe84AHM+oAuc5F3FnZBmfUUdgCaM3DOuixY90ZzdIyLh20o9uyeERVzb+7u2eVmwTn WiIE1mlb/BQGg== From: Asahi Lina Date: Fri, 14 Jul 2023 18:13:54 +0900 Subject: [PATCH RFC 02/11] rust: lock: Add Lock::pin_init() MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-2-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=3329; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=y9j+fmO9oWE2TupvVpaaD80X7pDQKCp9sdvtdWdP4zM=; b=HldwayEzarn12NZLBONXhBl2dK70OLqVEoWxGybMgF5VMQyfeDLVYNVFYC4aOjRpascoC/fA3 nN73G79SFLMD34bCpycjN0Re4OpiEh4nng1Q4gG2YqIe/f7m9yKlLsZ X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org Allow initializing a lock using pin_init!(), instead of requiring the inner data to be passed through the stack. Signed-off-by: Asahi Lina --- rust/kernel/sync/lock.rs | 30 +++++++++++++++++++++++++++++- rust/kernel/sync/lock/mutex.rs | 13 +++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index a2216325632d..d493c5d19104 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -6,7 +6,9 @@ //! spinlocks, raw spinlocks) to be provided with minimal effort. use super::LockClassKey; -use crate::{bindings, init::PinInit, pin_init, str::CStr, types::Opaque, types::ScopeGuard}; +use crate::{ + bindings, init::PinInit, pin_init, str::CStr, try_pin_init, types::Opaque, types::ScopeGuard, +}; use core::{cell::UnsafeCell, marker::PhantomData, marker::PhantomPinned}; use macros::pin_data; @@ -87,6 +89,7 @@ pub struct Lock { _pin: PhantomPinned, /// The data protected by the lock. + #[pin] pub(crate) data: UnsafeCell, } @@ -111,6 +114,31 @@ pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinIni }), }) } + + /// Constructs a new lock initialiser taking an initialiser. + pub fn pin_init( + t: impl PinInit, + name: &'static CStr, + key: &'static LockClassKey, + ) -> impl PinInit + where + E: core::convert::From, + { + try_pin_init!(Self { + // SAFETY: We are just forwarding the initialization across a + // cast away from UnsafeCell, so the pin_init_from_closure and + // __pinned_init() requirements are in sync. + data <- unsafe { crate::init::pin_init_from_closure(move |slot: *mut UnsafeCell| { + t.__pinned_init(slot as *mut T) + })}, + _pin: PhantomPinned, + // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have + // static lifetimes so they live indefinitely. + state <- Opaque::ffi_init(|slot| unsafe { + B::init(slot, name.as_char_ptr(), key.as_ptr()) + }), + }? E) + } } impl Lock { diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 923472f04af4..06fe685501b4 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -18,6 +18,19 @@ macro_rules! new_mutex { }; } +/// Creates a [`Mutex`] initialiser with the given name and a newly-created lock class, +/// given an initialiser for the inner type. +/// +/// 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_mutex_pinned { + ($inner:expr $(, $name:literal)? $(,)?) => { + $crate::sync::Mutex::pin_init( + $inner, $crate::optional_name!($($name)?), $crate::static_lock_class!()) + }; +} + /// A mutual exclusion primitive. /// /// Exposes the kernel's [`struct mutex`]. When multiple threads attempt to lock the same mutex, From patchwork Fri Jul 14 09:13:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313411 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B2D04C001DD for ; Fri, 14 Jul 2023 09:32:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235962AbjGNJcW (ORCPT ); Fri, 14 Jul 2023 05:32:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56448 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235922AbjGNJcH (ORCPT ); Fri, 14 Jul 2023 05:32:07 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3719235A7; Fri, 14 Jul 2023 02:31:42 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id 6CA745BC42; Fri, 14 Jul 2023 09:14:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326065; bh=VAWao2XqqfaUrUG4eX38dF7EKCEUq2ZmTgp3mGFnUog=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Rv070+McVf53L+fSrNOclnynR56VOM4amtL7xuLQwcaK+e19Wsy1rNkvqbg6WcsiY 0MnUjP+vlKz8e6ztLv/VZ9thIOOFcPh0OWjANftlA2mnzK0dim3oF0fgNYG43698xB 2hdwNHSrKhAT/ten+6mJY64iGCuS7pi9/uEKjn1hjFJZSnfhXRZNDVOMVr91DxgTgi J0zWbSZ5CC8aYPK4M53RQmC7CirFTX2n9Tg6KW0Wujo0/4J7KIjn4pOV7Qtb/yJMH6 jcssZJ/U1sfZiokColgbsAoU+/s9Jf/eYAtM85nCAY7a0ZBn2JjFj9InCXH9KY+eOV 83Kma93HKnxpA== From: Asahi Lina Date: Fri, 14 Jul 2023 18:13:55 +0900 Subject: [PATCH RFC 03/11] rust: Use absolute paths to build Rust objects MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-3-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=2695; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=VAWao2XqqfaUrUG4eX38dF7EKCEUq2ZmTgp3mGFnUog=; b=Mei8TIbhg8193HQ30Z4+6AvQI9I9bSJA87f41daFHByxLcwEs3OLPMiDdbvZqxkvrxSyz2Yw4 CfwDvXCA5JUDiUEQ/kiBq9bICTiHOt+It/8iffq7+3VXjaJJiug42AT X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org We want to use caller_location to uniquely identify callsites, to automatically create lockdep classes without macros. The location filename in local code uses the relative path passed to the compiler, but if that code is generic and instantiated from another crate, the path becomes absolute. To make this work and keep the paths consistent, always pass an absolute path to the compiler. Then the Location path is always identical regardless of how the code is being compiled. Signed-off-by: Asahi Lina --- rust/Makefile | 2 +- scripts/Makefile.build | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/Makefile b/rust/Makefile index 7c9d9f11aec5..552f023099c8 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -369,7 +369,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L --emit=dep-info=$(depfile) --emit=obj=$@ \ --emit=metadata=$(dir $@)$(patsubst %.o,lib%.rmeta,$(notdir $@)) \ --crate-type rlib -L$(objtree)/$(obj) \ - --crate-name $(patsubst %.o,%,$(notdir $@)) $< \ + --crate-name $(patsubst %.o,%,$(notdir $@)) $(abspath $<) \ $(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@) rust-analyzer: diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 6413342a03f4..c925b90ebd80 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -283,27 +283,27 @@ rust_common_cmd = \ # would not match each other. quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ - cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $< + cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $(abspath $<) $(obj)/%.o: $(src)/%.rs FORCE $(call if_changed_dep,rustc_o_rs) quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ cmd_rustc_rsi_rs = \ - $(rust_common_cmd) -Zunpretty=expanded $< >$@; \ + $(rust_common_cmd) -Zunpretty=expanded $(abspath $<) >$@; \ command -v $(RUSTFMT) >/dev/null && $(RUSTFMT) $@ $(obj)/%.rsi: $(src)/%.rs FORCE $(call if_changed_dep,rustc_rsi_rs) quiet_cmd_rustc_s_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ - cmd_rustc_s_rs = $(rust_common_cmd) --emit=asm=$@ $< + cmd_rustc_s_rs = $(rust_common_cmd) --emit=asm=$@ $(abspath $<) $(obj)/%.s: $(src)/%.rs FORCE $(call if_changed_dep,rustc_s_rs) quiet_cmd_rustc_ll_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ - cmd_rustc_ll_rs = $(rust_common_cmd) --emit=llvm-ir=$@ $< + cmd_rustc_ll_rs = $(rust_common_cmd) --emit=llvm-ir=$@ $(abspath $<) $(obj)/%.ll: $(src)/%.rs FORCE $(call if_changed_dep,rustc_ll_rs) From patchwork Fri Jul 14 09:13:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313413 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 55CC3EB64DA for ; Fri, 14 Jul 2023 09:32:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235975AbjGNJcY (ORCPT ); Fri, 14 Jul 2023 05:32:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56304 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235932AbjGNJcI (ORCPT ); Fri, 14 Jul 2023 05:32:08 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 672163589; Fri, 14 Jul 2023 02:31:45 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id 824B45BC45; Fri, 14 Jul 2023 09:14:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326071; bh=dW/rT+o9mD44f+fEVFzmzv8TPDsnFz4bOu43WWTzh9o=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=k02ubK4xRgiiAfUm8flIXiwwdo9Q2O2aiDWeRfbWgEMqyf4r3gV9Xbpg6dXYeRJKG ewq0BW703FnpYiw+buBayTMUQKW+uUmnWAjP90Z0NRw8w+5ja5gWYC/Utmaz+89oxd UT3B7Nt0y3zHY62TlAIg/kl5bkGeHOuUUsQs4ZPX8143qH3/Df79rQSFjtbEU0B6fc E8rx7n5jQ4vmN4gHaFadtXBCmbUO2qCj69EGG7vjS+vU3qnF6IMMnFNCG4XbEMlzmE WlsEugFBfz65nvh9BA3WIB0Az7fcQYJvQd6bnZ9CPsgYZJU+cLX/FnA5dmtcSiDpq8 RGINMdbp2NzEA== From: Asahi Lina Date: Fri, 14 Jul 2023 18:13:56 +0900 Subject: [PATCH RFC 04/11] rust: siphash: Add a simple siphash abstraction MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-4-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=3379; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=dW/rT+o9mD44f+fEVFzmzv8TPDsnFz4bOu43WWTzh9o=; b=sqRjyizmAnsE3KuVpoOYj9JEaF1Lt40BSJc0eRr0OzWS1fgeLhLqnSxXTZWi8NqLXLFazg3H7 YPencTRLL5NBug0aYpj0Bw2qLlosSHju+JIyImsu9Uq9mSHfKPqeogn X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org This simple wrapper allows Rust code to use the Hasher interface with the kernel siphash implementation. No fancy features supported for now, just basic bag-of-bytes hashing. No guarantee that hash outputs will remain stable in the future either. Signed-off-by: Asahi Lina --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 8 ++++++++ rust/kernel/lib.rs | 1 + rust/kernel/siphash.rs | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 3e601ce2548d..52f32e423b04 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -10,6 +10,7 @@ #include #include #include +#include #include /* `bindgen` gets confused at certain things. */ diff --git a/rust/helpers.c b/rust/helpers.c index bb594da56137..1ed71315d1eb 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -135,6 +136,13 @@ void rust_helper_put_task_struct(struct task_struct *t) } EXPORT_SYMBOL_GPL(rust_helper_put_task_struct); +u64 rust_helper_siphash(const void *data, size_t len, + const siphash_key_t *key) +{ + return siphash(data, len, key); +} +EXPORT_SYMBOL_GPL(rust_helper_siphash); + /* * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type * as the Rust `usize` type, so we can use it in contexts where Rust diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 85b261209977..8fb39078b85c 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -36,6 +36,7 @@ pub mod ioctl; pub mod prelude; pub mod print; +pub mod siphash; mod static_assert; #[doc(hidden)] pub mod std_vendor; diff --git a/rust/kernel/siphash.rs b/rust/kernel/siphash.rs new file mode 100644 index 000000000000..e13a17cd5a93 --- /dev/null +++ b/rust/kernel/siphash.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! A core::hash::Hasher wrapper for the kernel siphash implementation. +//! +//! This module allows Rust code to use the kernel's siphash implementation +//! to hash Rust objects. + +use core::hash::Hasher; + +/// A Hasher implementation that uses the kernel siphash implementation. +#[derive(Default)] +pub struct SipHasher { + // SipHash state is 4xu64, but the Linux implementation + // doesn't expose incremental hashing so let's just chain + // individual SipHash calls for now, which return a u64 + // hash. + state: u64, +} + +impl SipHasher { + /// Create a new SipHasher with zeroed state. + pub fn new() -> Self { + SipHasher { state: 0 } + } +} + +impl Hasher for SipHasher { + fn finish(&self) -> u64 { + self.state + } + + fn write(&mut self, bytes: &[u8]) { + let key = bindings::siphash_key_t { + key: [self.state, 0], + }; + + self.state = unsafe { bindings::siphash(bytes.as_ptr() as *const _, bytes.len(), &key) }; + } +} From patchwork Fri Jul 14 09:13:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313404 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F4207EB64DA for ; Fri, 14 Jul 2023 09:31:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229828AbjGNJbl (ORCPT ); Fri, 14 Jul 2023 05:31:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55814 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234417AbjGNJbk (ORCPT ); Fri, 14 Jul 2023 05:31:40 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9ACC53594; Fri, 14 Jul 2023 02:31:14 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id 94E585BC46; Fri, 14 Jul 2023 09:14:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326077; bh=gnMMY1x9qq2PPTNUzBdxhYi7ww499CWLccQC4OWzTx0=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=mOUxHiDwZefAGEFyddpSP0C3sc+AGebB1164Sp4/WwaCwg0cMeyRLTWVxHoyF0dMy 6+N56AQcfNwJoKzhJCuzDLTiVI1RMbCJsdEvhr8iV6JKWgYsI+boZ8p+fKDP0PuGJh tsYRCK3HQwJ12DomTTeRBaj0nYgsJiqMzWaiMR0dHldiGmR/Rr2/qTq47LgkBuG3EH Swzgk/2goIh/JslYbAOJeaZQnIIZQuXaYcw1wZ+mTM0pPv76jTMnK26cnAbJUFfQ5L mZjStDi/cxIswFfO9cWkjCnGUFXm9X0adKBYPRYOyMaZKOCl8t/i/qnWDN3Gz/4woW BvLg/oOhqISKA== From: Asahi Lina Date: Fri, 14 Jul 2023 18:13:57 +0900 Subject: [PATCH RFC 05/11] rust: sync: Add dummy LockClassKey implementation for !CONFIG_LOCKDEP MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-5-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=3940; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=gnMMY1x9qq2PPTNUzBdxhYi7ww499CWLccQC4OWzTx0=; b=bUWCrMNd7kHfIgvXiwbCtuSH/byuJpb+njsl0PfbHBCQxpRL9xMxqT8cQPBr35CdPxPspIQkK dII2uF6hA+OBRhfkDQOkW33pZImPKdLb45I4COXTwZnB1UFS/mveMtP X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org Lock classes aren't used without lockdep. The C side declares the key as an empty struct in that case, but let's make it an explicit ZST in Rust, implemented in a separate module. This allows us to more easily guarantee that the lockdep code will be trivially optimized out without CONFIG_LOCKDEP, including LockClassKey arguments that are passed around. Depending on whether CONFIG_LOCKDEP is enabled or not, we then import the real lockdep implementation or the dummy one. Signed-off-by: Asahi Lina --- rust/kernel/sync.rs | 29 ++++++++--------------------- rust/kernel/sync/lockdep.rs | 27 +++++++++++++++++++++++++++ rust/kernel/sync/no_lockdep.rs | 19 +++++++++++++++++++ 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index d219ee518eff..352472c6b77a 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -5,37 +5,24 @@ //! This module contains the kernel APIs related to synchronisation that have been ported or //! wrapped for usage by Rust code in the kernel. -use crate::types::Opaque; - mod arc; mod condvar; pub mod lock; mod locked_by; +#[cfg(CONFIG_LOCKDEP)] +mod lockdep; +#[cfg(not(CONFIG_LOCKDEP))] +mod no_lockdep; +#[cfg(not(CONFIG_LOCKDEP))] +use no_lockdep as lockdep; + pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use condvar::CondVar; pub use lock::{mutex::Mutex, spinlock::SpinLock}; +pub use lockdep::LockClassKey; pub use locked_by::LockedBy; -/// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. -#[repr(transparent)] -pub struct LockClassKey(Opaque); - -// SAFETY: `bindings::lock_class_key` is designed to be used concurrently from multiple threads and -// provides its own synchronization. -unsafe impl Sync for LockClassKey {} - -impl LockClassKey { - /// Creates a new lock class key. - pub const fn new() -> Self { - Self(Opaque::uninit()) - } - - pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key { - self.0.get() - } -} - /// Defines a new static lock class and returns a pointer to it. #[doc(hidden)] #[macro_export] diff --git a/rust/kernel/sync/lockdep.rs b/rust/kernel/sync/lockdep.rs new file mode 100644 index 000000000000..cb68b18dc0ad --- /dev/null +++ b/rust/kernel/sync/lockdep.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Lockdep utilities. +//! +//! This module abstracts the parts of the kernel lockdep API relevant to Rust +//! modules, including lock classes. + +use crate::types::Opaque; + +/// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. +#[repr(transparent)] +pub struct LockClassKey(Opaque); + +impl LockClassKey { + /// Creates a new lock class key. + pub const fn new() -> Self { + Self(Opaque::uninit()) + } + + pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key { + self.0.get() + } +} + +// SAFETY: `bindings::lock_class_key` is designed to be used concurrently from multiple threads and +// provides its own synchronization. +unsafe impl Sync for LockClassKey {} diff --git a/rust/kernel/sync/no_lockdep.rs b/rust/kernel/sync/no_lockdep.rs new file mode 100644 index 000000000000..69d42e8d9801 --- /dev/null +++ b/rust/kernel/sync/no_lockdep.rs @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Dummy lockdep utilities. +//! +//! Takes the place of the `lockdep` module when lockdep is disabled. + +/// A dummy, zero-sized lock class. +pub struct LockClassKey(); + +impl LockClassKey { + /// Creates a new dummy lock class key. + pub const fn new() -> Self { + Self() + } + + pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key { + core::ptr::null_mut() + } +} From patchwork Fri Jul 14 09:13:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313415 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7B976C04FE0 for ; Fri, 14 Jul 2023 09:32:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235920AbjGNJc0 (ORCPT ); Fri, 14 Jul 2023 05:32:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55986 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235926AbjGNJcH (ORCPT ); Fri, 14 Jul 2023 05:32:07 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CBF163599; Fri, 14 Jul 2023 02:31:44 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id A6D035BC4B; Fri, 14 Jul 2023 09:14:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326083; bh=YQMECCDF0tMPqG41YW5GqgPmtn/MWGEIPI5Q1NaQYSY=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Phm4cOQp7dNly6KdM+1WaFltuLRCCccAdmrNa2mW1HaP5xISZ8QVF9w5oH4EHsF29 nBxlu8nN92foqpEy/Cqv9V+Z0UGM5pwEJjyWj1AD56aOJGcMUuhaPldP1A2JDaALE7 dux48++7nyiMgJ45pEG9vtiIG7qKSCHawDzfhorMgjmbMApa6ydxNSWmBV/ldFv5T8 d8tQdycNmmNXKi/iBFjfT2Or5qtatxPOK2ZTOz+Q3o5CN0Z8Z3rUOqFHKepPBgcyVZ bG27LPWiYfpBp4XRcdTNwbPU85BHVPyqxXrRlYa9QOTsyn2R5VJHIShiaQIVkFfp40 0l8klm95ruhRQ== From: Asahi Lina Date: Fri, 14 Jul 2023 18:13:58 +0900 Subject: [PATCH RFC 06/11] rust: sync: Replace static LockClassKey refs with a pointer wrapper MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-6-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=6618; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=YQMECCDF0tMPqG41YW5GqgPmtn/MWGEIPI5Q1NaQYSY=; b=DHnofK17mNqOsVKbC7EuDKWPrgQt8WOHKWeRP7sUdWZGE9Ed0qlD+ubbbZ1HJJjrCebrQ8Ru5 qfpFd+NvfkgBrKIeVDgO1ojTXJ3jFyt0CJxGcsLXh5mTChXqp5XtkUM X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org We want to be able to handle dynamic lock class creation and using pointers to things that aren't a real lock_class_key as lock classes. Doing this by casting around Rust references is difficult without accidentally invoking UB. Instead, switch LockClassKey to being a raw pointer wrapper around a lock_class_key, which means there is no UB possible on the Rust side just by creating and consuming these objects. The C code also should never actually dereference lock classes, only use their address (possibly with an offset). We still provide a dummy ZST version of this wrapper, to be used when lockdep is disabled. Signed-off-by: Asahi Lina --- rust/kernel/sync.rs | 6 +++--- rust/kernel/sync/condvar.rs | 2 +- rust/kernel/sync/lock.rs | 4 ++-- rust/kernel/sync/lockdep.rs | 27 ++++++++++++++++++++++----- rust/kernel/sync/no_lockdep.rs | 15 +++++++++++++-- rust/kernel/types.rs | 2 +- 6 files changed, 42 insertions(+), 14 deletions(-) diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 352472c6b77a..49286c3e0ff3 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -20,7 +20,7 @@ pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use condvar::CondVar; pub use lock::{mutex::Mutex, spinlock::SpinLock}; -pub use lockdep::LockClassKey; +pub use lockdep::{LockClassKey, StaticLockClassKey}; pub use locked_by::LockedBy; /// Defines a new static lock class and returns a pointer to it. @@ -28,8 +28,8 @@ #[macro_export] macro_rules! static_lock_class { () => {{ - static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new(); - &CLASS + static CLASS: $crate::sync::StaticLockClassKey = $crate::sync::StaticLockClassKey::new(); + CLASS.key() }}; } diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index ed353399c4e5..3bccb2c6ef84 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -92,7 +92,7 @@ unsafe impl Sync for CondVar {} impl CondVar { /// Constructs a new condvar initialiser. #[allow(clippy::new_ret_no_self)] - pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { + pub fn new(name: &'static CStr, key: LockClassKey) -> impl PinInit { pin_init!(Self { _pin: PhantomPinned, // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index d493c5d19104..8e71e7aa2cc1 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -103,7 +103,7 @@ unsafe impl Sync for Lock {} impl Lock { /// Constructs a new lock initialiser. #[allow(clippy::new_ret_no_self)] - pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { + pub fn new(t: T, name: &'static CStr, key: LockClassKey) -> impl PinInit { pin_init!(Self { data: UnsafeCell::new(t), _pin: PhantomPinned, @@ -119,7 +119,7 @@ pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinIni pub fn pin_init( t: impl PinInit, name: &'static CStr, - key: &'static LockClassKey, + key: LockClassKey, ) -> impl PinInit where E: core::convert::From, diff --git a/rust/kernel/sync/lockdep.rs b/rust/kernel/sync/lockdep.rs index cb68b18dc0ad..d8328f4275fb 100644 --- a/rust/kernel/sync/lockdep.rs +++ b/rust/kernel/sync/lockdep.rs @@ -9,19 +9,36 @@ /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. #[repr(transparent)] -pub struct LockClassKey(Opaque); +pub struct StaticLockClassKey(Opaque); -impl LockClassKey { +impl StaticLockClassKey { /// Creates a new lock class key. pub const fn new() -> Self { Self(Opaque::uninit()) } + /// Returns the lock class key reference for this static lock class. + pub const fn key(&self) -> LockClassKey { + LockClassKey(self.0.get()) + } +} + +// SAFETY: `bindings::lock_class_key` just represents an opaque memory location, and is never +// actually dereferenced. +unsafe impl Sync for StaticLockClassKey {} + +/// A reference to a lock class key. This is a raw pointer to a lock_class_key, +/// which is required to have a static lifetime. +#[derive(Copy, Clone)] +pub struct LockClassKey(*mut bindings::lock_class_key); + +impl LockClassKey { pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key { - self.0.get() + self.0 } } -// SAFETY: `bindings::lock_class_key` is designed to be used concurrently from multiple threads and -// provides its own synchronization. +// SAFETY: `bindings::lock_class_key` just represents an opaque memory location, and is never +// actually dereferenced. +unsafe impl Send for LockClassKey {} unsafe impl Sync for LockClassKey {} diff --git a/rust/kernel/sync/no_lockdep.rs b/rust/kernel/sync/no_lockdep.rs index 69d42e8d9801..518ec0bf9a7d 100644 --- a/rust/kernel/sync/no_lockdep.rs +++ b/rust/kernel/sync/no_lockdep.rs @@ -5,14 +5,25 @@ //! Takes the place of the `lockdep` module when lockdep is disabled. /// A dummy, zero-sized lock class. -pub struct LockClassKey(); +pub struct StaticLockClassKey(); -impl LockClassKey { +impl StaticLockClassKey { /// Creates a new dummy lock class key. pub const fn new() -> Self { Self() } + /// Returns the lock class key reference for this static lock class. + pub const fn key(&self) -> LockClassKey { + LockClassKey() + } +} + +/// A dummy reference to a lock class key. +#[derive(Copy, Clone)] +pub struct LockClassKey(); + +impl LockClassKey { pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key { core::ptr::null_mut() } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 185d3493857e..91739bf71cc3 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -262,7 +262,7 @@ pub fn ffi_init(init_func: impl FnOnce(*mut T)) -> impl PinInit { } /// Returns a raw pointer to the opaque data. - pub fn get(&self) -> *mut T { + pub const fn get(&self) -> *mut T { UnsafeCell::raw_get(self.0.as_ptr()) } From patchwork Fri Jul 14 09:13:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313414 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2E6A5C04A6A for ; Fri, 14 Jul 2023 09:32:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235377AbjGNJcZ (ORCPT ); Fri, 14 Jul 2023 05:32:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56470 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235927AbjGNJcH (ORCPT ); Fri, 14 Jul 2023 05:32:07 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8093935A4; Fri, 14 Jul 2023 02:31:44 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id B932F5BC4D; Fri, 14 Jul 2023 09:14:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326089; bh=h5ZcjRNP/lnOzM21gHn80STRsONkXYv0p7ZAO8pU3oM=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=XnGfNCkqzklKe5FA35nMn5o1AnUb1N0/lrladszzUQmGAgYYGH2nEgPuuamr4o8SC 0ZWc975OCW/Eb58iLv57fib/xyJ6hfjWnV0QGUe2BnxCgYwOFdScYzoZgc+uCm6h/n 6wZIeptGIkHkK/PiEKgawTs+Pwj/83A6WCK7/l0ssjn9INPLEomAL5KpEHd9E+CcLZ 3Pu/gXuUFgSZnHL9GU+SQS+2HYfAm8PiQxg53aQKe4HOQFXUQnUw+2E3PIJe9ja7W7 Z4v0ho5J/1+9D9L9WhxV8QbwieJfhboe1oFMogZgaiPTUEJXJi0lV8+pnydeMvxaMs GgF6Tt74gxc0A== From: Asahi Lina Date: Fri, 14 Jul 2023 18:13:59 +0900 Subject: [PATCH RFC 07/11] rust: sync: Implement dynamic lockdep class creation MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-7-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=7059; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=h5ZcjRNP/lnOzM21gHn80STRsONkXYv0p7ZAO8pU3oM=; b=7sJJXnqbnTBFivUGqqNlSAIdFBChLMnlE3/RL90rl5Nl++csZYeE1q2ObkdjRjEQTa3PqlYfr kRTJlpnLvuCC34gIfHsG2lO2nKkQB69ZxLBLKzOhnzzZ+Y/TP6sIKS5 X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org Using macros to create lock classes all over the place is unergonomic, and makes it impossible to add new features that require lock classes to code such as Arc<> without changing all callers. Rust has the ability to track the caller's identity by file/line/column number, and we can use that to dynamically generate lock classes instead. Signed-off-by: Asahi Lina --- rust/kernel/sync/lockdep.rs | 147 ++++++++++++++++++++++++++++++++++++++++- rust/kernel/sync/no_lockdep.rs | 8 +++ 2 files changed, 154 insertions(+), 1 deletion(-) diff --git a/rust/kernel/sync/lockdep.rs b/rust/kernel/sync/lockdep.rs index d8328f4275fb..fbf9f6ed403d 100644 --- a/rust/kernel/sync/lockdep.rs +++ b/rust/kernel/sync/lockdep.rs @@ -5,7 +5,19 @@ //! This module abstracts the parts of the kernel lockdep API relevant to Rust //! modules, including lock classes. -use crate::types::Opaque; +use crate::{ + c_str, fmt, + init::InPlaceInit, + new_mutex, + prelude::{Box, Result, Vec}, + str::{CStr, CString}, + sync::Mutex, + types::Opaque, +}; + +use core::hash::{Hash, Hasher}; +use core::pin::Pin; +use core::sync::atomic::{AtomicPtr, Ordering}; /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. #[repr(transparent)] @@ -42,3 +54,136 @@ pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key { // actually dereferenced. unsafe impl Send for LockClassKey {} unsafe impl Sync for LockClassKey {} + +// Location is 'static but not really, since module unloads will +// invalidate existing static Locations within that module. +// To avoid breakage, we maintain our own location struct which is +// dynamically allocated on first reference. We store a hash of the +// whole location (including the filename string), as well as the +// line and column separately. The assumption is that this whole +// struct is highly unlikely to ever collide with a reasonable +// hash (this saves us from having to check the filename string +// itself). +#[derive(PartialEq, Debug)] +struct LocationKey { + hash: u64, + line: u32, + column: u32, +} + +struct DynLockClassKey { + key: Opaque, + loc: LocationKey, + name: CString, +} + +impl LocationKey { + fn new(loc: &'static core::panic::Location<'static>) -> Self { + let mut hasher = crate::siphash::SipHasher::new(); + loc.hash(&mut hasher); + + LocationKey { + hash: hasher.finish(), + line: loc.line(), + column: loc.column(), + } + } +} + +impl DynLockClassKey { + fn key(&'static self) -> LockClassKey { + LockClassKey(self.key.get()) + } + + fn name(&'static self) -> &CStr { + &self.name + } +} + +const LOCK_CLASS_BUCKETS: usize = 1024; + +#[track_caller] +fn caller_lock_class_inner() -> Result<&'static DynLockClassKey> { + // This is just a hack to make the below static array initialization work. + #[allow(clippy::declare_interior_mutable_const)] + const ATOMIC_PTR: AtomicPtr>> = + AtomicPtr::new(core::ptr::null_mut()); + + #[allow(clippy::complexity)] + static LOCK_CLASSES: [AtomicPtr>>; LOCK_CLASS_BUCKETS] = + [ATOMIC_PTR; LOCK_CLASS_BUCKETS]; + + let loc = core::panic::Location::caller(); + let loc_key = LocationKey::new(loc); + + let index = (loc_key.hash % (LOCK_CLASS_BUCKETS as u64)) as usize; + let slot = &LOCK_CLASSES[index]; + + let mut ptr = slot.load(Ordering::Relaxed); + if ptr.is_null() { + let new_element = Box::pin_init(new_mutex!(Vec::new()))?; + + if let Err(e) = slot.compare_exchange( + core::ptr::null_mut(), + // SAFETY: We never move out of this Box + Box::into_raw(unsafe { Pin::into_inner_unchecked(new_element) }), + Ordering::Relaxed, + Ordering::Relaxed, + ) { + // SAFETY: We just got this pointer from `into_raw()` + unsafe { Box::from_raw(e) }; + } + + ptr = slot.load(Ordering::Relaxed); + assert!(!ptr.is_null()); + } + + // SAFETY: This mutex was either just created above or previously allocated, + // and we never free these objects so the pointer is guaranteed to be valid. + let mut guard = unsafe { (*ptr).lock() }; + + for i in guard.iter() { + if i.loc == loc_key { + return Ok(i); + } + } + + // We immediately leak the class, so it becomes 'static + let new_class = Box::leak(Box::try_new(DynLockClassKey { + key: Opaque::zeroed(), + loc: loc_key, + name: CString::try_from_fmt(fmt!("{}:{}:{}", loc.file(), loc.line(), loc.column()))?, + })?); + + // SAFETY: This is safe to call with a pointer to a dynamically allocated lockdep key, + // and we never free the objects so it is safe to never unregister the key. + unsafe { bindings::lockdep_register_key(new_class.key.get()) }; + + guard.try_push(new_class)?; + + Ok(new_class) +} + +#[track_caller] +pub(crate) fn caller_lock_class() -> (LockClassKey, &'static CStr) { + match caller_lock_class_inner() { + Ok(a) => (a.key(), a.name()), + Err(_) => { + crate::pr_err!( + "Failed to dynamically allocate lock class, lockdep may be unreliable.\n" + ); + + let loc = core::panic::Location::caller(); + // SAFETY: LockClassKey is opaque and the lockdep implementation only needs + // unique addresses for statically allocated keys, so it is safe to just cast + // the Location reference directly into a LockClassKey. However, this will + // result in multiple keys for the same callsite due to monomorphization, + // as well as spuriously destroyed keys when the static key is allocated in + // the wrong module, which is what makes this unreliable. + ( + LockClassKey(loc as *const _ as *mut _), + c_str!("fallback_lock_class"), + ) + } + } +} diff --git a/rust/kernel/sync/no_lockdep.rs b/rust/kernel/sync/no_lockdep.rs index 518ec0bf9a7d..de53c4de7fbe 100644 --- a/rust/kernel/sync/no_lockdep.rs +++ b/rust/kernel/sync/no_lockdep.rs @@ -4,6 +4,8 @@ //! //! Takes the place of the `lockdep` module when lockdep is disabled. +use crate::{c_str, str::CStr}; + /// A dummy, zero-sized lock class. pub struct StaticLockClassKey(); @@ -28,3 +30,9 @@ pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key { core::ptr::null_mut() } } + +pub(crate) fn caller_lock_class() -> (LockClassKey, &'static CStr) { + static DUMMY_LOCK_CLASS: StaticLockClassKey = StaticLockClassKey::new(); + + (DUMMY_LOCK_CLASS.key(), c_str!("dummy")) +} From patchwork Fri Jul 14 09:14:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313412 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 80781C04A94 for ; Fri, 14 Jul 2023 09:32:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235965AbjGNJcX (ORCPT ); Fri, 14 Jul 2023 05:32:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56292 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235886AbjGNJcH (ORCPT ); Fri, 14 Jul 2023 05:32:07 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3704435A6; Fri, 14 Jul 2023 02:31:42 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id CB8C15BC8E; Fri, 14 Jul 2023 09:14:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326095; bh=qTjhfjiBkJU6f/AjrudTz4vasN/1yBaW+jjwT+W1pRI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=ghyYl6hi59GB1zxU9EMKMTlNPTziYGtruW4r5bUMuWNTtpjDGLU/XI/AT6a15Asla JtX/YknnFQoDmNi28BM1eFj1SnlUPdlO1/EsHBHVS/hklm1TzRjgATLpv4+BUenGuQ ssNCYPINuX8DnbxyGr5S7f7LyTLi+7c9cQ6XTUKxku4AB19CU3af1qfljwckOHhl+H kt1fiDElfFWCNNsDtnMfHkp8bCiRR3RgXUehiQfzdw94AfncR5aRC8EvNRtJov+ti5 LdyWP/RD3w1XBlPUGjrWF7WgiWcJaiFIW9r6nbtkd64Id2m1WuFVjQhI/MoZkIid4e prYMHZDA4vqcQ== From: Asahi Lina Date: Fri, 14 Jul 2023 18:14:00 +0900 Subject: [PATCH RFC 08/11] rust: sync: Classless Lock::new() and pin_init() MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-8-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=4989; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=qTjhfjiBkJU6f/AjrudTz4vasN/1yBaW+jjwT+W1pRI=; b=VSgLrpW0d/2c9lqEZuqEzHhPFcBQpRyst3tQBod3DJegwz60yvk/KCW+S7R7BF0NS1ztjhNlJ wbNq5gOaViABiSAPh+PUQmPAelov6UL1FovyDB/E6yGZEHhOXUUvmNx X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org Use the new automagic lock class code to remove the lock class and name parameters from Lock::new() and Lock::pin_init(). The old functions are renamed to new_with_class() and pin_init_with_class() respectively. The new approach uses the caller tracking machinery in Rust, which means it can be trivially wrapped by adding #[track_caller] to any functions that should bubble up lock class creation to their caller. This, for example, allows a type using multiple Mutexes to create separate lock classes for every user of the type, simply by adding that attribute to the mutex creation code paths. Signed-off-by: Asahi Lina --- rust/kernel/sync/lock.rs | 42 +++++++++++++++++++++++++++++++++++---- rust/kernel/sync/lock/mutex.rs | 4 ++-- rust/kernel/sync/lock/spinlock.rs | 2 +- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 8e71e7aa2cc1..8849741c1d9a 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -5,7 +5,7 @@ //! It contains a generic Rust lock and guard that allow for different backends (e.g., mutexes, //! spinlocks, raw spinlocks) to be provided with minimal effort. -use super::LockClassKey; +use super::{lockdep::caller_lock_class, LockClassKey}; use crate::{ bindings, init::PinInit, pin_init, str::CStr, try_pin_init, types::Opaque, types::ScopeGuard, }; @@ -103,7 +103,40 @@ unsafe impl Sync for Lock {} impl Lock { /// Constructs a new lock initialiser. #[allow(clippy::new_ret_no_self)] - pub fn new(t: T, name: &'static CStr, key: LockClassKey) -> impl PinInit { + #[track_caller] + pub fn new(t: T) -> impl PinInit { + let (key, name) = caller_lock_class(); + Self::new_with_key(t, name, key) + } + + /// Constructs a new lock initialiser taking an initialiser/ + pub fn pin_init(t: impl PinInit) -> impl PinInit + where + E: core::convert::From, + { + let (key, name) = caller_lock_class(); + Self::pin_init_with_key(t, name, key) + } + + /// Constructs a new lock initialiser. + #[allow(clippy::new_ret_no_self)] + #[track_caller] + pub fn new_named(t: T, name: &'static CStr) -> impl PinInit { + let (key, _) = caller_lock_class(); + Self::new_with_key(t, name, key) + } + + /// Constructs a new lock initialiser taking an initialiser/ + pub fn pin_init_named(t: impl PinInit, name: &'static CStr) -> impl PinInit + where + E: core::convert::From, + { + let (key, _) = caller_lock_class(); + Self::pin_init_with_key(t, name, key) + } + + /// Constructs a new lock initialiser given a particular name and lock class key. + pub fn new_with_key(t: T, name: &'static CStr, key: LockClassKey) -> impl PinInit { pin_init!(Self { data: UnsafeCell::new(t), _pin: PhantomPinned, @@ -115,8 +148,9 @@ pub fn new(t: T, name: &'static CStr, key: LockClassKey) -> impl PinInit { }) } - /// Constructs a new lock initialiser taking an initialiser. - pub fn pin_init( + /// Constructs a new lock initialiser taking an initialiser given a particular + /// name and lock class key. + pub fn pin_init_with_key( t: impl PinInit, name: &'static CStr, key: LockClassKey, diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 06fe685501b4..15ea70fa3933 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -13,7 +13,7 @@ #[macro_export] macro_rules! new_mutex { ($inner:expr $(, $name:literal)? $(,)?) => { - $crate::sync::Mutex::new( + $crate::sync::Mutex::new_with_key( $inner, $crate::optional_name!($($name)?), $crate::static_lock_class!()) }; } @@ -26,7 +26,7 @@ macro_rules! new_mutex { #[macro_export] macro_rules! new_mutex_pinned { ($inner:expr $(, $name:literal)? $(,)?) => { - $crate::sync::Mutex::pin_init( + $crate::sync::Mutex::pin_init_with_key( $inner, $crate::optional_name!($($name)?), $crate::static_lock_class!()) }; } diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index 979b56464a4e..9f6137f047ee 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -13,7 +13,7 @@ #[macro_export] macro_rules! new_spinlock { ($inner:expr $(, $name:literal)? $(,)?) => { - $crate::sync::SpinLock::new( + $crate::sync::SpinLock::new_with_class( $inner, $crate::optional_name!($($name)?), $crate::static_lock_class!()) }; } From patchwork Fri Jul 14 09:14:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313408 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 08AE5EB64DA for ; Fri, 14 Jul 2023 09:32:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235895AbjGNJcC (ORCPT ); Fri, 14 Jul 2023 05:32:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55886 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235853AbjGNJbp (ORCPT ); Fri, 14 Jul 2023 05:31:45 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A779435A2; Fri, 14 Jul 2023 02:31:14 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id DDFCB5BC90; Fri, 14 Jul 2023 09:14:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326101; bh=pmERp6GwnOCWkgphnzptIlYb6DLdsFhpRouByq625cQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=kdLKIFgKGIwIntnz0AYgYdJvrgRLnnaI9MlYtqgh04f6DRCdyEJsf1wCQz/bICx4h Qu4xtfwtlzbagPh3ny4EsL9dxxSnfv+odIkxV5lscrKYPAe64NHpifx3W+U6dxLi/G Y6Nf0R3QOG2AJzHVEDQrrYB2I44moYV9sGHdVr9SPiJmfeJHwO7nJfPZvQGwEU/GRw xFmwpIZbCmFnjfQP8D2EA1pMZVkNmfCfJJK7WILd4XjK51yJSynQKWMOqPwseqwtDg G7pIumuQWNqHZQm0ZE5G2V98/nyldQKujWMnfE011Uau369ialqAGfMq8vU9oS9Kwf pGlz20dcsxNmw== From: Asahi Lina Date: Fri, 14 Jul 2023 18:14:01 +0900 Subject: [PATCH RFC 09/11] rust: init: Update documentation for new mutex init style MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-9-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=2511; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=pmERp6GwnOCWkgphnzptIlYb6DLdsFhpRouByq625cQ=; b=SSD6fmaYAIs7/HNgGcRACQ89lpuCPIOoeaRkkZ2UkBP8Q1hptBMoz/GGwxRAszksq/cVul+Uq V3ShxAHSYKjA01dNJeNpjtApErQmrziR42b2PVrJ58GJ9xhMTUqfHrU X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org Now that we have classless Mutex creation, update the docs to reflect the new API. Signed-off-by: Asahi Lina --- rust/kernel/init.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index b4332a4ec1f4..f190bbd0bab1 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -36,7 +36,7 @@ //! //! ```rust //! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -//! use kernel::{prelude::*, sync::Mutex, new_mutex}; +//! use kernel::{prelude::*, sync::Mutex}; //! # use core::pin::Pin; //! #[pin_data] //! struct Foo { @@ -46,7 +46,7 @@ //! } //! //! let foo = pin_init!(Foo { -//! a <- new_mutex!(42, "Foo::a"), +//! a <- Mutex::new_named(42, "Foo::a"), //! b: 24, //! }); //! ``` @@ -56,7 +56,7 @@ //! //! ```rust //! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -//! # use kernel::{prelude::*, sync::Mutex, new_mutex}; +//! # use kernel::{prelude::*, sync::Mutex}; //! # use core::pin::Pin; //! # #[pin_data] //! # struct Foo { @@ -65,7 +65,7 @@ //! # b: u32, //! # } //! # let foo = pin_init!(Foo { -//! # a <- new_mutex!(42, "Foo::a"), +//! # a <- Mutex::new_named(42, "Foo::a"), //! # b: 24, //! # }); //! let foo: Result>> = Box::pin_init(foo); @@ -98,7 +98,7 @@ //! impl DriverData { //! fn new() -> impl PinInit { //! try_pin_init!(Self { -//! status <- new_mutex!(0, "DriverData::status"), +//! status <- Mutex::new_named(0, "DriverData::status"), //! buffer: Box::init(kernel::init::zeroed())?, //! }) //! } @@ -242,7 +242,7 @@ /// } /// /// stack_pin_init!(let foo = pin_init!(Foo { -/// a <- new_mutex!(42), +/// a <- Mutex::new(42), /// b: Bar { /// x: 64, /// }, @@ -294,7 +294,7 @@ macro_rules! stack_pin_init { /// } /// /// stack_try_pin_init!(let foo: Result, AllocError> = pin_init!(Foo { -/// a <- new_mutex!(42), +/// a <- Mutex::new(42), /// b: Box::try_new(Bar { /// x: 64, /// })?, @@ -320,7 +320,7 @@ macro_rules! stack_pin_init { /// } /// /// stack_try_pin_init!(let foo: Pin<&mut Foo> =? pin_init!(Foo { -/// a <- new_mutex!(42), +/// a <- Mutex::new(42), /// b: Box::try_new(Bar { /// x: 64, /// })?, From patchwork Fri Jul 14 09:14:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313405 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A1372C0015E for ; Fri, 14 Jul 2023 09:31:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235633AbjGNJbm (ORCPT ); Fri, 14 Jul 2023 05:31:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55826 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235307AbjGNJbl (ORCPT ); Fri, 14 Jul 2023 05:31:41 -0400 Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5EA7435A3; Fri, 14 Jul 2023 02:31:14 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id F34395BC96; Fri, 14 Jul 2023 09:15:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326107; bh=iunu/MEktIfyC9aBXASL3Y+DNDi/HoqbZYswDE31qjY=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=fGwsQoHqMFsrJDlFFDPR0k3MaE5WXRU8RB0KWzOUSDcHpsn22IQyGC3HN2lCwncyK wAuqBSwsU1wpop8HxHZZxntrScSS3ywoUW/fICNk8UmtKb6muutZNMoWZ+UcszLYHQ M+MSrjQttyZZqxSDaex5VDxabG/Ko11qdgQZOCoFPbKhO+Vjs9pYmCrlIlGj7ggUsr BvO2xfMlOB9+4V01CgzNjQgUzvvmG7Sld8Qn/tdtTxtZuPu/XThvbbVBE0MUoxrHM/ bX5ZWLPWUJJi1j1mSbgEirahVhQ5ap9KDWfGVt536mxdO/c9hzyPFZPJ2SUBaK+FOX g+Pc+qui1Bz3w== From: Asahi Lina Date: Fri, 14 Jul 2023 18:14:02 +0900 Subject: [PATCH RFC 10/11] rust: sync: Add LockdepMap abstraction MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-10-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=3708; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=iunu/MEktIfyC9aBXASL3Y+DNDi/HoqbZYswDE31qjY=; b=04lyCEBPyQa9PMDV9CRJ+d48EyVHc5I664n8RdVhvo5ioHbmWbeIlQUoXCgobM9ilIo2P40ht W2v4aU2ydo8CA+EolWeYDtyrdSPo3/F+5Rv8SBH/RL8TWwoGEWLzZtg X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org Add a simple abstraction for creating new lockdep maps. This allows Rust code to explicitly integrate types with lockdep. There's some voodoo compiler intrinsic magic to get the caller return address on the C side. I have no idea how to plumb that through in Rust if that's even possible, so let's just wrap it in a C helper for now. That gives us the callsite from the Rust abstraction instead of its user, but that's probably okay for now. Signed-off-by: Asahi Lina --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 16 ++++++++++++++++ rust/kernel/sync/lockdep.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 52f32e423b04..5c28de44e528 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/rust/helpers.c b/rust/helpers.c index 1ed71315d1eb..392f5359677a 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -143,6 +145,20 @@ u64 rust_helper_siphash(const void *data, size_t len, } EXPORT_SYMBOL_GPL(rust_helper_siphash); +void rust_helper_lock_acquire_ret(struct lockdep_map *lock, unsigned int subclass, + int trylock, int read, int check, + struct lockdep_map *nest_lock) +{ + lock_acquire(lock, subclass, trylock, read, check, nest_lock, _RET_IP_); +} +EXPORT_SYMBOL_GPL(rust_helper_lock_acquire_ret); + +void rust_helper_lock_release_ret(struct lockdep_map *lock) +{ + lock_release(lock, _RET_IP_); +} +EXPORT_SYMBOL_GPL(rust_helper_lock_release_ret); + /* * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type * as the Rust `usize` type, so we can use it in contexts where Rust diff --git a/rust/kernel/sync/lockdep.rs b/rust/kernel/sync/lockdep.rs index fbf9f6ed403d..ca32aa833e10 100644 --- a/rust/kernel/sync/lockdep.rs +++ b/rust/kernel/sync/lockdep.rs @@ -187,3 +187,43 @@ pub(crate) fn caller_lock_class() -> (LockClassKey, &'static CStr) { } } } + +pub(crate) struct LockdepMap(Opaque); +pub(crate) struct LockdepGuard<'a>(&'a LockdepMap); + +#[allow(dead_code)] +impl LockdepMap { + #[track_caller] + pub(crate) fn new() -> Self { + let map = Opaque::uninit(); + let (key, name) = caller_lock_class(); + + unsafe { + bindings::lockdep_init_map_type( + map.get(), + name.as_char_ptr(), + key.as_ptr(), + 0, + bindings::lockdep_wait_type_LD_WAIT_INV as _, + bindings::lockdep_wait_type_LD_WAIT_INV as _, + bindings::lockdep_lock_type_LD_LOCK_NORMAL as _, + ) + }; + + LockdepMap(map) + } + + #[inline(always)] + pub(crate) fn lock(&self) -> LockdepGuard<'_> { + unsafe { bindings::lock_acquire_ret(self.0.get(), 0, 0, 1, 1, core::ptr::null_mut()) }; + + LockdepGuard(self) + } +} + +impl<'a> Drop for LockdepGuard<'a> { + #[inline(always)] + fn drop(&mut self) { + unsafe { bindings::lock_release_ret(self.0 .0.get()) }; + } +} From patchwork Fri Jul 14 09:14:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asahi Lina X-Patchwork-Id: 13313406 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 65B00EB64DC for ; Fri, 14 Jul 2023 09:31:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235713AbjGNJbp (ORCPT ); Fri, 14 Jul 2023 05:31:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55858 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235830AbjGNJbn (ORCPT ); Fri, 14 Jul 2023 05:31:43 -0400 X-Greylist: delayed 1026 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 14 Jul 2023 02:31:14 PDT Received: from mail.marcansoft.com (marcansoft.com [212.63.210.85]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4A72C3590; Fri, 14 Jul 2023 02:31:14 -0700 (PDT) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: linasend@asahilina.net) by mail.marcansoft.com (Postfix) with ESMTPSA id 108575BC98; Fri, 14 Jul 2023 09:15:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=asahilina.net; s=default; t=1689326113; bh=xFmFsNBqZRVhSlLGxOxfGwL4iDHemYFsL2oqYKGuVP4=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=wK0ljBsFst8i0xkuxG7oq39DkGfVspC5HFRt2W633aBvgSzpi5qluTbuFVsPce9jh Mz2KmGoO56pQOvijBOMvAvifknWm2Ih/gfYXfMLVXmVpCWD89rpIgri0/ifWxcr4Z7 SpRm+Kn6lAiSJ6vTsMixyc/5gju+Z0DGxC89fi2ItnTFRPCTDVbZRmLZvRXFloKrcF x53U4//VdgjZEhd5eidAQ/cBG3uv2Xu5W6FujgBOhBpLifHVZB20r6qcgry7uADMF6 IQEsXiZSnf7CCF945+uZrOvtSyzFfBhb6ZQ4Y/0LZX/BCdmjCEsVnE0hC/lHiZ9kur 9BYxeA68EVMlQ== From: Asahi Lina Date: Fri, 14 Jul 2023 18:14:03 +0900 Subject: [PATCH RFC 11/11] rust: sync: arc: Add lockdep integration MIME-Version: 1.0 Message-Id: <20230714-classless_lockdep-v1-11-229b9671ce31@asahilina.net> References: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> In-Reply-To: <20230714-classless_lockdep-v1-0-229b9671ce31@asahilina.net> To: Miguel Ojeda , Alex Gaynor , Wedson Almeida Filho , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Masahiro Yamada , Nathan Chancellor , Nick Desaulniers , Nicolas Schier , Tom Rix , Daniel Vetter Cc: Hector Martin , Sven Peter , Alyssa Rosenzweig , asahi@lists.linux.dev, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, llvm@lists.linux.dev, Asahi Lina X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1689326040; l=9475; i=lina@asahilina.net; s=20230221; h=from:subject:message-id; bh=xFmFsNBqZRVhSlLGxOxfGwL4iDHemYFsL2oqYKGuVP4=; b=8TCIgQoDOtdlDTOQ1KYaZ8W1ZUNnhtcHdIS+D+qL5Te5R/4lrDe6FQbsX1YbKI9BxQYDYrMAb aKYIHM43XL5AVkNA2yxwidTkvKcj/2NQd8zidbM7/YKf3qfwueVPIE+ X-Developer-Key: i=lina@asahilina.net; a=ed25519; pk=Qn8jZuOtR1m5GaiDfTrAoQ4NE1XoYVZ/wmt5YtXWFC4= Precedence: bulk List-ID: X-Mailing-List: linux-kbuild@vger.kernel.org Now that we have magic lock class support and a LockdepMap that can be hooked up into arbitrary Rust types, we can integrate lockdep support directly into the Rust Arc type. This means we can catch potential Drop codepaths that could result in a locking error, even if those codepaths never actually execute due to the reference count being nonzero at that point. Signed-off-by: Asahi Lina --- lib/Kconfig.debug | 8 ++++++ rust/kernel/init.rs | 6 +++++ rust/kernel/sync/arc.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index fbc89baf7de6..ff4f06df88ee 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -3010,6 +3010,14 @@ config RUST_BUILD_ASSERT_ALLOW If unsure, say N. +config RUST_EXTRA_LOCKDEP + bool "Extra lockdep checking" + depends on RUST && PROVE_LOCKING + help + Enabled additional lockdep integration with certain Rust types. + + If unsure, say N. + endmenu # "Rust" endmenu # Kernel hacking diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index f190bbd0bab1..b64a507f0a34 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -1208,6 +1208,7 @@ pub trait InPlaceInit: Sized { /// type. /// /// If `T: !Unpin` it will not be able to move afterwards. + #[track_caller] fn try_pin_init(init: impl PinInit) -> Result, E> where E: From; @@ -1216,6 +1217,7 @@ fn try_pin_init(init: impl PinInit) -> Result, E> /// type. /// /// If `T: !Unpin` it will not be able to move afterwards. + #[track_caller] fn pin_init(init: impl PinInit) -> error::Result> where Error: From, @@ -1228,11 +1230,13 @@ fn pin_init(init: impl PinInit) -> error::Result> } /// Use the given initializer to in-place initialize a `T`. + #[track_caller] fn try_init(init: impl Init) -> Result where E: From; /// Use the given initializer to in-place initialize a `T`. + #[track_caller] fn init(init: impl Init) -> error::Result where Error: From, @@ -1277,6 +1281,7 @@ fn try_init(init: impl Init) -> Result impl InPlaceInit for UniqueArc { #[inline] + #[track_caller] fn try_pin_init(init: impl PinInit) -> Result, E> where E: From, @@ -1291,6 +1296,7 @@ fn try_pin_init(init: impl PinInit) -> Result, E> } #[inline] + #[track_caller] fn try_init(init: impl Init) -> Result where E: From, diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index a89843cacaad..3bb73b614fd1 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -34,6 +34,9 @@ }; use macros::pin_data; +#[cfg(CONFIG_RUST_EXTRA_LOCKDEP)] +use crate::sync::lockdep::LockdepMap; + mod std_vendor; /// A reference-counted pointer to an instance of `T`. @@ -127,6 +130,17 @@ pub struct Arc { _p: PhantomData>, } +#[cfg(CONFIG_RUST_EXTRA_LOCKDEP)] +#[pin_data] +#[repr(C)] +struct ArcInner { + refcount: Opaque, + lockdep_map: LockdepMap, + data: T, +} + +// FIXME: pin_data does not work well with cfg attributes within the struct definition. +#[cfg(not(CONFIG_RUST_EXTRA_LOCKDEP))] #[pin_data] #[repr(C)] struct ArcInner { @@ -159,11 +173,14 @@ unsafe impl Sync for Arc {} impl Arc { /// Constructs a new reference counted instance of `T`. + #[track_caller] pub fn try_new(contents: T) -> Result { // INVARIANT: The refcount is initialised to a non-zero value. let value = ArcInner { // SAFETY: There are no safety requirements for this FFI call. refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }), + #[cfg(CONFIG_RUST_EXTRA_LOCKDEP)] + lockdep_map: LockdepMap::new(), data: contents, }; @@ -178,6 +195,7 @@ pub fn try_new(contents: T) -> Result { /// /// If `T: !Unpin` it will not be able to move afterwards. #[inline] + #[track_caller] pub fn pin_init(init: impl PinInit) -> error::Result where Error: From, @@ -189,6 +207,7 @@ pub fn pin_init(init: impl PinInit) -> error::Result /// /// This is equivalent to [`Arc::pin_init`], since an [`Arc`] is always pinned. #[inline] + #[track_caller] pub fn init(init: impl Init) -> error::Result where Error: From, @@ -292,15 +311,46 @@ fn drop(&mut self) { // freed/invalid memory as long as it is never dereferenced. let refcount = unsafe { self.ptr.as_ref() }.refcount.get(); + // SAFETY: By the type invariant, there is necessarily a reference to the object. + // We cannot hold the map lock across the reference decrement, as we might race + // another thread. Therefore, we lock and immediately drop the guard here. This + // only serves to inform lockdep of the dependency up the call stack. + #[cfg(CONFIG_RUST_EXTRA_LOCKDEP)] + unsafe { self.ptr.as_ref() }.lockdep_map.lock(); + // INVARIANT: If the refcount reaches zero, there are no other instances of `Arc`, and // this instance is being dropped, so the broken invariant is not observable. // SAFETY: Also by the type invariant, we are allowed to decrement the refcount. let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) }; + if is_zero { // The count reached zero, we must free the memory. - // - // SAFETY: The pointer was initialised from the result of `Box::leak`. - unsafe { Box::from_raw(self.ptr.as_ptr()) }; + + // SAFETY: If we get this far, we had the last reference to the object. + // That means we are responsible for freeing it, so we can safely lock + // the fake lock again. This wraps dropping the inner object, which + // informs lockdep of the dependencies down the call stack. + #[cfg(CONFIG_RUST_EXTRA_LOCKDEP)] + let guard = unsafe { self.ptr.as_ref() }.lockdep_map.lock(); + + // SAFETY: The pointer was initialised from the result of `Box::leak`, + // and the value is valid. + unsafe { core::ptr::drop_in_place(&mut self.ptr.as_mut().data) }; + + // We need to drop the lock guard before freeing the LockdepMap itself + #[cfg(CONFIG_RUST_EXTRA_LOCKDEP)] + core::mem::drop(guard); + + // SAFETY: The pointer was initialised from the result of `Box::leak`, + // and the lockdep map is valid. + #[cfg(CONFIG_RUST_EXTRA_LOCKDEP)] + unsafe { + core::ptr::drop_in_place(&mut self.ptr.as_mut().lockdep_map) + }; + + // SAFETY: The pointer was initialised from the result of `Box::leak`, and + // a ManuallyDrop is compatible. We already dropped the contents above. + unsafe { Box::from_raw(self.ptr.as_ptr() as *mut ManuallyDrop>) }; } } } @@ -512,6 +562,7 @@ pub struct UniqueArc { impl UniqueArc { /// Tries to allocate a new [`UniqueArc`] instance. + #[track_caller] pub fn try_new(value: T) -> Result { Ok(Self { // INVARIANT: The newly-created object has a ref-count of 1. @@ -520,13 +571,27 @@ pub fn try_new(value: T) -> Result { } /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet. + #[track_caller] pub fn try_new_uninit() -> Result>, AllocError> { // INVARIANT: The refcount is initialised to a non-zero value. + #[cfg(CONFIG_RUST_EXTRA_LOCKDEP)] + let inner = { + let map = LockdepMap::new(); + Box::try_init::(try_init!(ArcInner { + // SAFETY: There are no safety requirements for this FFI call. + refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }), + lockdep_map: map, + data <- init::uninit::(), + }? AllocError))? + }; + // FIXME: try_init!() does not work with cfg attributes. + #[cfg(not(CONFIG_RUST_EXTRA_LOCKDEP))] let inner = Box::try_init::(try_init!(ArcInner { // SAFETY: There are no safety requirements for this FFI call. refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }), data <- init::uninit::(), }? AllocError))?; + Ok(UniqueArc { // INVARIANT: The newly-created object has a ref-count of 1. // SAFETY: The pointer from the `Box` is valid.