From nobody Tue Dec 16 22:28:06 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 9B85C188A0E; Fri, 30 May 2025 14:24:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615097; cv=none; b=r4+pSlpc06fdk2WWsOk34Cv9EBwHBVj7BuHM8vQbGt2CnKEM4bNy1Ib5COrKrUgaGkMQp3s7SUujoC5flcAasqtl0pV6mQlSOEhMRk5ESlZ15ujE/ffzy9918xPxwn7vznKBIlVKWqNSges6d1yfLnEVjLIUcfT9yyrdjG/+rXQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615097; c=relaxed/simple; bh=qPGJ3y/S7HIYr+nPyeDAb0tXbFUHa7n2dS4AYNlkSwY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=taD9mc0e1g0U3cTkR3p7AuehYlYAOv0FaP3gO2aUVARXaDHRRKeoFXej33R7Hcn3clCnGCWBkCpd3gl1UQ7ICapm2NdXQtO09zjTXP62W6MAC1CO0TJSXIJ/ZQzI4T3dCxOgBCgPZ5Jdnj1ywUkZjZ6ggAgjEBRiLwdxiVmbikU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RBqlLGJI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RBqlLGJI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F309CC4CEEB; Fri, 30 May 2025 14:24:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748615097; bh=qPGJ3y/S7HIYr+nPyeDAb0tXbFUHa7n2dS4AYNlkSwY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RBqlLGJIKwPG1rMMDnz8Axpoj+7NEdWvcYcyRGl3EEi/+VHMupf9205xAPTpyw7os goXJCZJzzDEeVLCvTn8cMU3YMwCy3tgMOX3LEbJbIu1NJq7oJ+ZmDdngVvo8RTIllU bvxj2tbksgOA8FsE1a+PHcPekZGSNw/mYF4rBBBgZGEfRSHRAf3ERwq8S8J7PGrOra HgYyhkafhfepavlxnkDmBchQmoVBFbSkpRNV/RSub4JwbiDoIM+mGq9YaMJdDQYCtr 3V8jX98IdptxPFyXerey2wn/CgatxW97UnrsqLJRxGo3y7JbS4p2znXhpCut5+wgy9 keRlTeuefiMRA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, chrisi.schrefl@gmail.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 1/7] rust: types: support fallible PinInit types in Opaque::pin_init Date: Fri, 30 May 2025 16:24:14 +0200 Message-ID: <20250530142447.166524-2-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250530142447.166524-1-dakr@kernel.org> References: <20250530142447.166524-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, Opaque::pin_init only supports infallible PinInit implementations, i.e. impl PinInit. This has been sufficient so far, since users such as Revocable do not support fallibility. Since this is about to change, make Opaque::pin_init() generic over the error type E. Signed-off-by: Danilo Krummrich Reviewed-by: Christian Schrefl --- rust/kernel/types.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 22985b6f6982..75c99d6facf9 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -354,13 +354,13 @@ pub const fn zeroed() -> Self { } =20 /// Create an opaque pin-initializer from the given pin-initializer. - pub fn pin_init(slot: impl PinInit) -> impl PinInit { - Self::ffi_init(|ptr: *mut T| { + pub fn pin_init(slot: impl PinInit) -> impl PinInit { + Self::try_ffi_init(|ptr: *mut T| -> Result<(), E> { // SAFETY: // - `ptr` is a valid pointer to uninitialized memory, - // - `slot` is not accessed on error; the call is infallible, + // - `slot` is not accessed on error, // - `slot` is pinned in memory. - let _ =3D unsafe { PinInit::::__pinned_init(slot, ptr) }; + unsafe { PinInit::::__pinned_init(slot, ptr) } }) } =20 --=20 2.49.0 From nobody Tue Dec 16 22:28:06 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 2502C188A0E; Fri, 30 May 2025 14:25:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615101; cv=none; b=AzRKO0AbXkaja4Jt39Okbx7nSW1JhyEG3ircKdCo4AmyraiFkMDeuHCMNQlxL1ZDLygHzgJvzP22qeHjjauFVT06j6lUZPIExdhP9n2bHc/cNczldMVH67xwtJn/omDZDFQN68LrTe90nMHDha9X4YCpT83SI6y/oztQ2mKGSe0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615101; c=relaxed/simple; bh=Fdsa9c0TznozF7NTXCN5fSMXio8uVFJkPAphFsl2jPw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mYuO3piegukLwsii/NwYueDF4dSH3yU7vhm8ZHL4sMI+bRATRcQ04v1ePUKUH67v4sJuwSEfOI6hvtTF8DddQDmH7bU4wI7712BidWWeao7o4yvXlPysN+AsH7NELuvethyYNm7ExT6F/mV4uKBNBft+XI+ONKDDzw5EafQx924= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ENFHCPF/; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ENFHCPF/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7A1DEC4CEED; Fri, 30 May 2025 14:24:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748615100; bh=Fdsa9c0TznozF7NTXCN5fSMXio8uVFJkPAphFsl2jPw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ENFHCPF/4/o2MPF6ksZAyLIY0dX9PYGIAwhqJFhJ94MCuaqbxVwfR/DKimfvRlcwA aZUJfLGWGd6+goCpwATGJe+QzDDpy7uUUsEIt4uC3h2m4JkhVGmA9/aGe3KgroUM1r BZNkjH9YVWbFEs9WM14Tdx4U49UzDnggdl2cpbrJodtN0TOTPqpDGCmJl4rVZ/pr7c CSDUqdS/0Q5sot8L1srpH3J8lgoZNHCWcZ+wDbdJnzCZ+x94FPAVZEbtTcb5CLHvO6 6rvFN4bXa0tUJMp4wRKAh3WuNcRLF1E87tp63qFuMlbv6GLK3XLGx3Psa0WLhDhtdz 5qJtUsoADj2lQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, chrisi.schrefl@gmail.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 2/7] rust: revocable: support fallible PinInit types Date: Fri, 30 May 2025 16:24:15 +0200 Message-ID: <20250530142447.166524-3-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250530142447.166524-1-dakr@kernel.org> References: <20250530142447.166524-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, Revocable::new() only supports infallible PinInit implementations, i.e. impl PinInit. This has been sufficient so far, since users such as Devres do not support fallibility. Since this is about to change, make Revocable::new() generic over the error type E. Signed-off-by: Danilo Krummrich Reviewed-by: Benno Lossin Reviewed-by: Christian Schrefl --- rust/kernel/devres.rs | 2 +- rust/kernel/revocable.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 0f79a2ec9474..2dbe17d6ea1f 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -98,7 +98,7 @@ struct DevresInner { impl DevresInner { fn new(dev: &Device, data: T, flags: Flags) -> Result>> { let inner =3D Arc::pin_init( - pin_init!( DevresInner { + try_pin_init!( DevresInner { dev: dev.into(), callback: Self::devres_callback, data <- Revocable::new(data), diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs index db4aa46bb121..ca738f75dc10 100644 --- a/rust/kernel/revocable.rs +++ b/rust/kernel/revocable.rs @@ -80,8 +80,11 @@ unsafe impl Sync for Revocable {} =20 impl Revocable { /// Creates a new revocable instance of the given data. - pub fn new(data: impl PinInit) -> impl PinInit { - pin_init!(Self { + pub fn new(data: impl PinInit) -> impl PinInit + where + Error: From, + { + try_pin_init!(Self { is_available: AtomicBool::new(true), data <- Opaque::pin_init(data), }) --=20 2.49.0 From nobody Tue Dec 16 22:28:06 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 2D58C188A0E; Fri, 30 May 2025 14:25:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615104; cv=none; b=ZLuRriL8DvJYcTXuRHjdBHLyteKX6uNHfYzHxzU5mtg+UmaPzUEHJ0HYDXxzbLeRQHW2Y0k3bKr6vnpPdaIASCCzI3cDBtJrJDwv5Teto9QPPbRrwejzfEOTHUhZ5L+vGwTgNkGPWsx+HR7bm9QqOy8FIMv0R/f3ZRkhpCgXVkI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615104; c=relaxed/simple; bh=mGiSKd4T9J6G6QXOn/6eU1w9NZ+tMNSzAqmLqysSbEM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WRN8y/3AekvUiltEefOdnMr5dVMwK1qqhpAnarHfWzkCVQb7UB00qBNcC+z8BqldoPRfLmyhllslgYLvKwS8UmJ8IgOX/tlZBV2Z2CVk0bdSmXcgAVSnMvzb/tDuDQZ3t1vKC6I8Ou8ouemcpCMUuvE/WGwWVNiJ/4ZOIFWRFek= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NC/3F1mL; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NC/3F1mL" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 00992C4CEE9; Fri, 30 May 2025 14:25:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748615104; bh=mGiSKd4T9J6G6QXOn/6eU1w9NZ+tMNSzAqmLqysSbEM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NC/3F1mLHpQNX6xsAK4ArqvUk+DOlfS21gRRBlRtnyYusmAja1ljmLFlhowhn5vfX mJC/fKP0Sa6oBzDIXnS/2VO2yTXO0irhVZRWdI8efeK+qL5NogShibbvrObLpFFx4E uX1kbkhr8H+pstT0rj5e2qQaqVbR/RHoSkzpUCnNxMcURveupSt4Oo34XI+fRKNKHT qJ8As1lnSKXkrDg1CPcVLjef4Dp9XBsx3/kdhYx+RkB87VAjolx7NKB42BRCbbtygz rIug+YMiVTZgCH5BypdViw1H7jZXVidv0MUE150IZRfKK+Ds4BGdpTBBCLMcfu53QB v2V8ygVzd3ViQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, chrisi.schrefl@gmail.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 3/7] rust: devres: support fallible in-place init for data Date: Fri, 30 May 2025 16:24:16 +0200 Message-ID: <20250530142447.166524-4-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250530142447.166524-1-dakr@kernel.org> References: <20250530142447.166524-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, Devres only supports a data argument of type T. However, DevresInner already uses pin-init to initialize the Revocable. Hence, there is no need for this limitation and we can take a data argument of type impl PinInit instead. Signed-off-by: Danilo Krummrich Reviewed-by: Benno Lossin Reviewed-by: Christian Schrefl --- rust/kernel/devres.rs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 2dbe17d6ea1f..47aeb5196dd2 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -96,9 +96,16 @@ struct DevresInner { pub struct Devres(Arc>); =20 impl DevresInner { - fn new(dev: &Device, data: T, flags: Flags) -> Result>> { - let inner =3D Arc::pin_init( - try_pin_init!( DevresInner { + fn new( + dev: &Device, + data: impl PinInit, + flags: Flags, + ) -> Result>> + where + Error: From, + { + let inner =3D Arc::pin_init::( + try_pin_init!( Self { dev: dev.into(), callback: Self::devres_callback, data <- Revocable::new(data), @@ -168,7 +175,10 @@ fn remove_action(this: &Arc) { impl Devres { /// Creates a new [`Devres`] instance of the given `data`. The `data` = encapsulated within the /// returned `Devres` instance' `data` will be revoked once the device= is detached. - pub fn new(dev: &Device, data: T, flags: Flags) -> Result= { + pub fn new(dev: &Device, data: impl PinInit, flags: Fl= ags) -> Result + where + Error: From, + { let inner =3D DevresInner::new(dev, data, flags)?; =20 Ok(Devres(inner)) @@ -176,7 +186,14 @@ pub fn new(dev: &Device, data: T, flags: Flags)= -> Result { =20 /// Same as [`Devres::new`], but does not return a `Devres` instance. = Instead the given `data` /// is owned by devres and will be revoked / dropped, once the device = is detached. - pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -= > Result { + pub fn new_foreign_owned( + dev: &Device, + data: impl PinInit, + flags: Flags, + ) -> Result + where + Error: From, + { let _ =3D DevresInner::new(dev, data, flags)?; =20 Ok(()) --=20 2.49.0 From nobody Tue Dec 16 22:28:06 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 19629231836; Fri, 30 May 2025 14:25:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615108; cv=none; b=XQbQ3BzcaGGH+IVvEHOD98yjkpriUjJ2ap4JpE5loAAhIqp9Dtf4EjsfZaLGuhMFXnEuFN7pWF+9eSYEM/QHDd+716pVA7htXJNaMESgohfMGgIGJj68ODDBNNhY53CpZva61bIy/rfpkwb0/h1JvxGsaopzxkZl8/xVlkyHGiM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615108; c=relaxed/simple; bh=HxNXcpo2opSxFgS5iz+zLkP/tQgdDrjNBAzxpDiD8C4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FBzK/cE8gRbSJSmrE6spl1wa0ZfBbKXbsKRD9nNra4sbUt2MP4JeF6M8ZwLX/VGf3f3zGw4E5neN8pf9LGOaQeNt4AGa9rntJWqozeZWHueZJdazEIN3v5fNSKQvCLvaxHmNWvbZGwCZgzs0ytkhiy7fa+q18ihskkKX4oT5buw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=oCOQa0kJ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="oCOQa0kJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7BBA9C4CEEB; Fri, 30 May 2025 14:25:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748615107; bh=HxNXcpo2opSxFgS5iz+zLkP/tQgdDrjNBAzxpDiD8C4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oCOQa0kJd5GgBQkKsclbpyO9HG34OqN3vQCSMVLFIZpmV9Fj2KyvuFokxYYofhSrj Cui2MLKX/a73GWZ7vcKgC4Kfx0pxsTKyHHKjU11omPJf+p/z8lAu/XGUiwAAQrby7t DI667zbHBg5gMN2vqYqpXhUapNjPNAB7EZl+KtAWlATxuiEe8x0SDkGPXj/DlJcu5m 4097pqAKapBv1FtIYjsVFhyL/zVY+ttuzPIdioCevtzFLJDx3ls4d13ar4+1E0Klew KM2Q70rdtU//3MGWD3j4hN5LHMaTcENDDmjD9eRbrd7AndPlnlyRJQfXrkI1aJuyWc pJVpfPx/PklQg== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, chrisi.schrefl@gmail.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 4/7] rust: faux: impl AsRef> for Registration Date: Fri, 30 May 2025 16:24:17 +0200 Message-ID: <20250530142447.166524-5-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250530142447.166524-1-dakr@kernel.org> References: <20250530142447.166524-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The device contained in a faux::Registration is always bound, hence consider this in the registrations's AsRef implementation. Signed-off-by: Danilo Krummrich --- rust/kernel/faux.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/kernel/faux.rs b/rust/kernel/faux.rs index 8a50fcd4c9bb..395cb1172cb4 100644 --- a/rust/kernel/faux.rs +++ b/rust/kernel/faux.rs @@ -50,8 +50,8 @@ fn as_raw(&self) -> *mut bindings::faux_device { } } =20 -impl AsRef for Registration { - fn as_ref(&self) -> &device::Device { +impl AsRef> for Registration { + fn as_ref(&self) -> &device::Device { // SAFETY: The underlying `device` in `faux_device` is guaranteed = by the C API to be // a valid initialized `device`. unsafe { device::Device::as_ref(addr_of_mut!((*self.as_raw()).dev)= ) } --=20 2.49.0 From nobody Tue Dec 16 22:28:06 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 97953231836; Fri, 30 May 2025 14:25:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615111; cv=none; b=CBTlu5hXEBTs1Eqc/fLvhAHrgZwuFy0cht7dGfANwyPGZj6+sUHieSOilsdskZL0lTUMHR4i4mMeO89m+Hw9TBVF3Lk5dQgvD73lu6C+aOS57DFjA3dGOmqoSQjXkA31LwNk+t1/0bW+k9MY+Ebk9XBz62nqrHyfNLsQp2hHGrk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615111; c=relaxed/simple; bh=JqCE9KxtLU73dWPfVR6Y3zqQaSqcJOaV5q9/grUl9Cc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=g9OLBM0pT+4NoNOC7GPqGWZyvPDUPw5UHAXTKKYJ9K9osKDdotr0Eru2CKpl9Q76KpwTcce3GqOnP54ejSGuus4PqtmaQPewatkpmsstemOnR/cgKLRMcadODe2aj2iBa3Z9yLN1bu1JwNcdin/qfgc6BZD3WbYOY69YsvBgs1A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mTbTlNfX; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mTbTlNfX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 02988C4CEE9; Fri, 30 May 2025 14:25:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748615111; bh=JqCE9KxtLU73dWPfVR6Y3zqQaSqcJOaV5q9/grUl9Cc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mTbTlNfXlMOudoEkl9Ie9Gqjs1KVXKWLSokeAQTbNn3wrGpkFydeck/+eQZaePcKp i9ZwYaP1CCYgDgmldmzqZ4pgdx3Jhm49tVFYD8Rpq5b9kSepxVo1yLMbQwOHvLFk3J vNyXiDJ86p5xiUSeVYncVLKoZLbvHZf5N2ukgyV8fH7vJQ2bVWoiTNCBEKws1SWYn9 BjWDQrgWGfF1X9uJ1NF4CFuhsfZ7BHi5eKJNFUrMgkBat0PKILzJS5GoKSj6wZr02v NOKU0bsKB1ufFTN2EbzsCWUjyNEvsXd6YMXttTo44fZjB7idE+ktDl9v6aEVgEt8Y4 tv0jxT7wb6s/g== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, chrisi.schrefl@gmail.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 5/7] rust: miscdevice: properly support device drivers Date: Fri, 30 May 2025 16:24:18 +0200 Message-ID: <20250530142447.166524-6-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250530142447.166524-1-dakr@kernel.org> References: <20250530142447.166524-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, the design of MiscDeviceRegistration is focused on creating and registering a misc device directly from a module and hence does not support using misc device from a device driver. However, it is important for the design of the misc device abstraction to take the driver model into account. Hence, consider the use-case of using misc device from a device driver; let's go through the design motivation bottom-up: Ideally, we want to be able to access (bus) device resources (such as I/O memory) from misc device callbacks (such as open() or ioctl()) without additional overhead, i.e. without having to go through Devres::try_access(), which implies an atomic check and an RCU read side critical section. Instead, we want to be able to use Devres::access(), which does not have any overhead, which requires a &Device to prove that we can directly access the device resource. Given that all misc device callbacks are synchronized against misc_deregister(), we can prove that the misc device's parent device is bound iff we guarantee that the misc device's registration won't out-live the parent device's unbind. This can easily be proven by using devres for the misc device's registration object itself. Since this is only applicable for the device driver use-case, abstract the actual registration instance with a Rust enum, which is either a "raw" registration or a "managed" registration. In order to avoid any penalties from a managed registration, structurally separate the registration's private data from the "raw" misc device registration (which either stays "raw" or becomes "managed") depending on whether a parent device is supplied. The advantage of this solution is that it is entirely transparent to the user -- no separate structures or functions for whether the abstraction is used directly from a module or from a device driver; instead MiscDeviceRegistration::register() gets an optional parent argument. Signed-off-by: Danilo Krummrich --- rust/kernel/miscdevice.rs | 178 ++++++++++++++++++++++++------- samples/rust/rust_misc_device.rs | 9 +- 2 files changed, 143 insertions(+), 44 deletions(-) diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index 1b5ec13868e2..6801fe72a8a6 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -10,16 +10,17 @@ =20 use crate::{ bindings, container_of, - device::Device, + device::{Bound, Device}, + devres::Devres, error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR}, ffi::{c_int, c_long, c_uint, c_ulong}, fs::File, prelude::*, seq_file::SeqFile, str::CStr, - types::{ForeignOwnable, Opaque}, + types::{ARef, ForeignOwnable, Opaque}, }; -use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin}; +use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin, ptr::NonNull}; =20 /// Options for creating a misc device. #[derive(Copy, Clone)] @@ -40,44 +41,43 @@ pub const fn into_raw(self) -> bindings:= :miscdevice { } } =20 -/// A registration of a miscdevice. -/// /// # Invariants /// -/// `inner` is a registered misc device. +/// - `inner` is a registered misc device, +/// - `data` is valid for the entire lifetime of `Self`. #[repr(C)] #[pin_data(PinnedDrop)] -pub struct MiscDeviceRegistration { +struct RawDeviceRegistration { #[pin] inner: Opaque, - #[pin] - data: Opaque, + data: NonNull, _t: PhantomData, } =20 -// SAFETY: -// - It is allowed to call `misc_deregister` on a different thread from wh= ere you called -// `misc_register`. -// - Only implements `Send` if `MiscDevice::RegistrationData` is also `Sen= d`. -unsafe impl Send for MiscDeviceRegistration where T::Reg= istrationData: Send {} - -// SAFETY: -// - All `&self` methods on this type are written to ensure that it is saf= e to call them in -// parallel. -// - `MiscDevice::RegistrationData` is always `Sync`. -unsafe impl Sync for MiscDeviceRegistration {} - -impl MiscDeviceRegistration { - /// Register a misc device. - pub fn register( +impl RawDeviceRegistration { + fn new<'a>( opts: MiscDeviceOptions, - data: impl PinInit, - ) -> impl PinInit { + parent: Option<&'a Device>, + data: &'a T::RegistrationData, + ) -> impl PinInit + 'a + where + T: 'a, + { try_pin_init!(Self { - data <- Opaque::pin_init(data), + // INVARIANT: `Self` is always embedded in a `MiscDeviceRegist= ration`, hence `data` + // is guaranteed to be valid for the entire lifetime of `Self`. + data: NonNull::from(data), inner <- Opaque::try_ffi_init(move |slot: *mut bindings::miscd= evice| { + let mut value =3D opts.into_raw::(); + + if let Some(parent) =3D parent { + // The device core code will take care to take a refer= ence of `parent` in + // `device_add()` called by `misc_register()`. + value.parent =3D parent.as_raw(); + } + // SAFETY: The initializer can write to the provided `slot= `. - unsafe { slot.write(opts.into_raw::()) }; + unsafe { slot.write(value) }; =20 // SAFETY: // * We just wrote the misc device options to the slot. Th= e miscdevice will @@ -94,12 +94,12 @@ pub fn register( } =20 /// Returns a raw pointer to the misc device. - pub fn as_raw(&self) -> *mut bindings::miscdevice { + fn as_raw(&self) -> *mut bindings::miscdevice { self.inner.get() } =20 /// Access the `this_device` field. - pub fn device(&self) -> &Device { + fn device(&self) -> &Device { // SAFETY: This can only be called after a successful register(), = which always // initialises `this_device` with a valid device. Furthermore, the= signature of this // function tells the borrow-checker that the `&Device` reference = must not outlive the @@ -108,6 +108,108 @@ pub fn device(&self) -> &Device { unsafe { Device::as_ref((*self.as_raw()).this_device) } } =20 + fn data(&self) -> &T::RegistrationData { + // SAFETY: The type invariant guarantees that `data` is valid for = the entire lifetime of + // `Self`. + unsafe { self.data.as_ref() } + } +} + +#[pinned_drop] +impl PinnedDrop for RawDeviceRegistration { + fn drop(self: Pin<&mut Self>) { + // SAFETY: We know that the device is registered by the type invar= iants. + unsafe { bindings::misc_deregister(self.inner.get()) }; + } +} + +#[expect(dead_code)] +enum DeviceRegistrationInner { + Raw(Pin>>), + Managed(Devres>), +} + +/// A registration of a miscdevice. +#[pin_data(PinnedDrop)] +pub struct MiscDeviceRegistration { + inner: DeviceRegistrationInner, + #[pin] + data: Opaque, + this_device: ARef, + _t: PhantomData, +} + +// SAFETY: +// - It is allowed to call `misc_deregister` on a different thread from wh= ere you called +// `misc_register`. +// - Only implements `Send` if `MiscDevice::RegistrationData` is also `Sen= d`. +unsafe impl Send for MiscDeviceRegistration where T::Reg= istrationData: Send {} + +// SAFETY: +// - All `&self` methods on this type are written to ensure that it is saf= e to call them in +// parallel. +// - `MiscDevice::RegistrationData` is always `Sync`. +unsafe impl Sync for MiscDeviceRegistration {} + +impl MiscDeviceRegistration { + /// Register a misc device. + pub fn register<'a>( + opts: MiscDeviceOptions, + data: impl PinInit + 'a, + parent: Option<&'a Device>, + ) -> impl PinInit + 'a + where + T: 'a, + { + let mut dev: Option> =3D None; + + try_pin_init!(&this in Self { + data <- Opaque::pin_init(data), + // TODO: make `inner` in-place when enums get supported by pin= -init. + // + // Link: https://github.com/Rust-for-Linux/pin-init/issues/59 + inner: { + // SAFETY: + // - `this` is a valid pointer to `Self`, + // - `data` was properly initialized above. + let data =3D unsafe { &*(*this.as_ptr()).data.get() }; + + let raw =3D RawDeviceRegistration::new(opts, parent, data); + + // FIXME: Work around a bug in rustc, to prevent the follo= wing warning: + // + // "warning: value captured by `dev` is never read." + // + // Link: https://github.com/rust-lang/rust/issues/141615 + let _ =3D dev; + + if let Some(parent) =3D parent { + let devres =3D Devres::new(parent, raw, GFP_KERNEL)?; + + dev =3D Some(devres.access(parent)?.device().into()); + DeviceRegistrationInner::Managed(devres) + } else { + let boxed =3D KBox::pin_init(raw, GFP_KERNEL)?; + + dev =3D Some(boxed.device().into()); + DeviceRegistrationInner::Raw(boxed) + } + }, + // Cache `this_device` within `Self` to avoid having to access= `Devres` in the managed + // case. + this_device: { + // SAFETY: `dev` is guaranteed to be set in the initialize= r of `inner` above. + unsafe { dev.unwrap_unchecked() } + }, + _t: PhantomData, + }) + } + + /// Access the `this_device` field. + pub fn device(&self) -> &Device { + &self.this_device + } + /// Access the additional data stored in this registration. pub fn data(&self) -> &T::RegistrationData { // SAFETY: @@ -120,9 +222,6 @@ pub fn data(&self) -> &T::RegistrationData { #[pinned_drop] impl PinnedDrop for MiscDeviceRegistration { fn drop(self: Pin<&mut Self>) { - // SAFETY: We know that the device is registered by the type invar= iants. - unsafe { bindings::misc_deregister(self.inner.get()) }; - // SAFETY: `self.data` is valid for dropping. unsafe { core::ptr::drop_in_place(self.data.get()) }; } @@ -137,14 +236,13 @@ pub trait MiscDevice: Sized { /// The additional data carried by the [`MiscDeviceRegistration`] for = this [`MiscDevice`]. /// If no additional data is required than the unit type `()` should b= e used. /// - /// This data can be accessed in [`MiscDevice::open()`] using - /// [`MiscDeviceRegistration::data()`]. + /// This data can be accessed in [`MiscDevice::open()`]. type RegistrationData: Sync; =20 /// Called when the misc device is opened. /// /// The returned pointer will be stored as the private data for the fi= le. - fn open(_file: &File, _misc: &MiscDeviceRegistration) -> Result<= Self::Ptr>; + fn open(_file: &File, _misc: &Device, _data: &Self::RegistrationData) = -> Result; =20 /// Called when the misc device is released. fn release(device: Self::Ptr, _file: &File) { @@ -217,17 +315,17 @@ impl MiscdeviceVTable { // SAFETY: // * `misc_open()` ensures that the `struct miscdevice` can't be u= nregistered and freed // during this call to `fops_open`. - // * The `misc_ptr` always points to the `inner` field of a `MiscD= eviceRegistration`. - // * The `MiscDeviceRegistration` is valid until the `struct mi= scdevice` was + // * The `misc_ptr` always points to the `inner` field of a `RawDe= viceRegistration`. + // * The `RawDeviceRegistration` is valid until the `struct mis= cdevice` was // unregistered. - let registration =3D unsafe { &*container_of!(misc_ptr, MiscDevice= Registration, inner) }; + let registration =3D unsafe { &*container_of!(misc_ptr, RawDeviceR= egistration, inner) }; =20 // SAFETY: // * This underlying file is valid for (much longer than) the dura= tion of `T::open`. // * There is no active fdget_pos region on the file on this threa= d. let file =3D unsafe { File::from_raw_file(raw_file) }; =20 - let ptr =3D match T::open(file, registration) { + let ptr =3D match T::open(file, registration.device(), registratio= n.data()) { Ok(ptr) =3D> ptr, Err(err) =3D> return err.to_errno(), }; diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_devi= ce.rs index 843442b0ea1d..b60fd063afa8 100644 --- a/samples/rust/rust_misc_device.rs +++ b/samples/rust/rust_misc_device.rs @@ -198,7 +198,8 @@ fn init(_module: &'static ThisModule) -> impl PinInit { try_pin_init!(Self { _miscdev <- MiscDeviceRegistration::register( options, - Arc::pin_init(new_mutex!(Inner { value: 0_i32 }), GFP_KERN= EL) + Arc::pin_init(new_mutex!(Inner { value: 0_i32 }), GFP_KERN= EL), + None, ), }) } @@ -222,15 +223,15 @@ impl MiscDevice for RustMiscDevice { =20 type RegistrationData =3D Arc>; =20 - fn open(_file: &File, misc: &MiscDeviceRegistration) -> Result>> { - let dev =3D ARef::from(misc.device()); + fn open(_file: &File, misc: &Device, data: &Self::RegistrationData) ->= Result>> { + let dev =3D ARef::from(misc); =20 dev_info!(dev, "Opening Rust Misc Device Sample\n"); =20 KBox::try_pin_init( try_pin_init! { RustMiscDevice { - shared: misc.data().clone(), + shared: data.clone(), unique <- new_mutex!(Inner { value: 0_i32 }), dev: dev, } --=20 2.49.0 From nobody Tue Dec 16 22:28:06 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 B146D23185E; Fri, 30 May 2025 14:25:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615114; cv=none; b=RDTrEleNW7PoOfxV//WKSNzmyrm+lIF8VdlPhJ8C8soCp7d9ro7YwCi/8inaDseeOxBmZVDm0giG99/CWL5mQozblMUfu48PVPoFmAY4sz44IIbaF206+jTk9wxp530UxpQBCtCeybD1Ewfz3RHqIQHg6GYnnbym/75n8mWCmbA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615114; c=relaxed/simple; bh=/FS337mlfnfbT9rDew2hnOmZCU3j3SocUNkSjBQrmy0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GTDaVcuBj/4kACEfZFbBYNoSiy89/9ZeubIPbn/DFpDKJxkyk1UxJS6blNyKNFusLbdnQM7WmjIj98+HvaM/LAKNoun1JcUh6lE6Xi1RwUTpjUj0S24U4nKZxgi/V8f6We2Nq96YLMSW5xppY9SWZg7buoPHa/K5q6x95XsBxGg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QYb5U21V; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QYb5U21V" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7DB51C4CEF0; Fri, 30 May 2025 14:25:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748615114; bh=/FS337mlfnfbT9rDew2hnOmZCU3j3SocUNkSjBQrmy0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QYb5U21Vj8yNFJKouYdsy8bDCT7jpQjjOjbYqNASe+hgbiA7D41/4ryFV0xFTZ3sf w7gZcYpmlf/Dc6wnq6itpw/r29qIN4rhs++vt74M/i4pa3KZJC31e+kcRpYuDz39FD eXKvb9ekc1m4rm+A3plKY6OoCJ9po/Ijjq1HYj/kt95QMtjCXGZHw+mjDUSfORH+cV bwTOQkkf+OUnJulMMH7VjOAwrPGMb0MWc417FTiUcJNXm2ndk02XKg9ADzlmWNS8at GU0g0OXV5IkG86r2sE5YwmrLgHZ67PPbCpHd6PGpYIj/Md3PGNCfyn1V/UUO4keQw0 YEDBKCL+esLKw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, chrisi.schrefl@gmail.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 6/7] rust: miscdevice: expose the parent device as &Device Date: Fri, 30 May 2025 16:24:19 +0200 Message-ID: <20250530142447.166524-7-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250530142447.166524-1-dakr@kernel.org> References: <20250530142447.166524-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Now that the misc device abstraction design considers device drivers, take advantage of the fact that we can safely expose the parent of the misc device as &Device within the misc device's file operations. Drivers can use this bound device reference to access device resources without additional overhead through Devres::access(). Expose the &Device parent, the &Device representation of the misc device and the registration data through a new type MiscArgs through the MiscDevice callbacks. Signed-off-by: Danilo Krummrich --- rust/kernel/miscdevice.rs | 173 ++++++++++++++++++++----------- samples/rust/rust_misc_device.rs | 20 ++-- 2 files changed, 128 insertions(+), 65 deletions(-) diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index 6801fe72a8a6..937d0945d827 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -18,7 +18,7 @@ prelude::*, seq_file::SeqFile, str::CStr, - types::{ARef, ForeignOwnable, Opaque}, + types::{ARef, Opaque}, }; use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin, ptr::NonNull}; =20 @@ -51,6 +51,7 @@ struct RawDeviceRegistration { #[pin] inner: Opaque, data: NonNull, + private: Opaque, _t: PhantomData, } =20 @@ -67,6 +68,7 @@ fn new<'a>( // INVARIANT: `Self` is always embedded in a `MiscDeviceRegist= ration`, hence `data` // is guaranteed to be valid for the entire lifetime of `Self`. data: NonNull::from(data), + private: Opaque::uninit(), inner <- Opaque::try_ffi_init(move |slot: *mut bindings::miscd= evice| { let mut value =3D opts.into_raw::(); =20 @@ -227,11 +229,21 @@ fn drop(self: Pin<&mut Self>) { } } =20 +/// The arguments passed to the file operation callbacks of a [`MiscDevice= Registration`]. +pub struct MiscArgs<'a, T: MiscDevice> { + /// The [`Device`] representation of the `struct miscdevice`. + pub device: &'a Device, + /// The parent [`Device`] of [`Self::device`]. + pub parent: Option<&'a Device>, + /// The `RegistrationData` passed to [`MiscDeviceRegistration::registe= r`]. + pub data: &'a T::RegistrationData, +} + /// Trait implemented by the private data of an open misc device. #[vtable] pub trait MiscDevice: Sized { /// What kind of pointer should `Self` be wrapped in. - type Ptr: ForeignOwnable + Send + Sync; + type Ptr: Send + Sync; =20 /// The additional data carried by the [`MiscDeviceRegistration`] for = this [`MiscDevice`]. /// If no additional data is required than the unit type `()` should b= e used. @@ -242,12 +254,7 @@ pub trait MiscDevice: Sized { /// Called when the misc device is opened. /// /// The returned pointer will be stored as the private data for the fi= le. - fn open(_file: &File, _misc: &Device, _data: &Self::RegistrationData) = -> Result; - - /// Called when the misc device is released. - fn release(device: Self::Ptr, _file: &File) { - drop(device); - } + fn open(_file: &File, _args: MiscArgs<'_, Self>) -> Result; =20 /// Handler for ioctls. /// @@ -255,7 +262,8 @@ fn release(device: Self::Ptr, _file: &File) { /// /// [`kernel::ioctl`]: mod@crate::ioctl fn ioctl( - _device: ::Borrowed<'_>, + _args: MiscArgs<'_, Self>, + _device: &Self::Ptr, _file: &File, _cmd: u32, _arg: usize, @@ -272,7 +280,8 @@ fn ioctl( /// provided, then `compat_ptr_ioctl` will be used instead. #[cfg(CONFIG_COMPAT)] fn compat_ioctl( - _device: ::Borrowed<'_>, + _args: MiscArgs<'_, Self>, + _device: &Self::Ptr, _file: &File, _cmd: u32, _arg: usize, @@ -281,11 +290,7 @@ fn compat_ioctl( } =20 /// Show info for this fd. - fn show_fdinfo( - _device: ::Borrowed<'_>, - _m: &SeqFile, - _file: &File, - ) { + fn show_fdinfo(_args: MiscArgs<'_, Self>, _device: &Self::Ptr, _m: &Se= qFile, _file: &File) { build_error!(VTABLE_DEFAULT_ERROR) } } @@ -296,16 +301,15 @@ fn show_fdinfo( impl MiscdeviceVTable { /// # Safety /// - /// `file` and `inode` must be the file and inode for a file that is u= ndergoing initialization. - /// The file must be associated with a `MiscDeviceRegistration`. - unsafe extern "C" fn open(inode: *mut bindings::inode, raw_file: *mut = bindings::file) -> c_int { - // SAFETY: The pointers are valid and for a file being opened. - let ret =3D unsafe { bindings::generic_file_open(inode, raw_file) = }; - if ret !=3D 0 { - return ret; - } - - // SAFETY: The open call of a file can access the private data. + /// This function must only be called from misc device file operations= with the `struct file` + /// pointer provided by the corresponding callback. + unsafe fn registration_from_file<'a>( + raw_file: *mut bindings::file, + ) -> &'a RawDeviceRegistration { + // SAFETY: + // * Since `raw_file` comes from a misc device file operation call= back, it is a pointer to a + // valid `struct file`. + // * All file operations can access the file's private data. let misc_ptr =3D unsafe { (*raw_file).private_data }; =20 // This is a miscdevice, so `misc_open()` sets the private data to= a pointer to the @@ -313,30 +317,57 @@ impl MiscdeviceVTable { let misc_ptr =3D misc_ptr.cast::(); =20 // SAFETY: - // * `misc_open()` ensures that the `struct miscdevice` can't be u= nregistered and freed - // during this call to `fops_open`. + // * File operation callbacks ensure that the `struct miscdevice` = can't be unregistered and + // freed during a call. // * The `misc_ptr` always points to the `inner` field of a `RawDe= viceRegistration`. // * The `RawDeviceRegistration` is valid until the `struct mis= cdevice` was // unregistered. - let registration =3D unsafe { &*container_of!(misc_ptr, RawDeviceR= egistration, inner) }; + unsafe { &*container_of!(misc_ptr, RawDeviceRegistration, inner= ) } + } + + fn args_from_registration<'a>(registration: &'a RawDeviceRegistration<= T>) -> MiscArgs<'a, T> { + let parent: Option<&'a Device> =3D registration.device().pa= rent().map(|parent| { + // SAFETY: We just convert from `&Device` into `Device`. + unsafe { Device::as_ref(parent.as_raw()) } + }); + + MiscArgs { + device: registration.device(), + parent, + data: registration.data(), + } + } + + /// # Safety + /// + /// `file` and `inode` must be the file and inode for a file that is u= ndergoing initialization. + /// The file must be associated with a `MiscDeviceRegistration`. + unsafe extern "C" fn open(inode: *mut bindings::inode, raw_file: *mut = bindings::file) -> c_int { + // SAFETY: The pointers are valid and for a file being opened. + let ret =3D unsafe { bindings::generic_file_open(inode, raw_file) = }; + if ret !=3D 0 { + return ret; + } + + // SAFETY: Called from a misc device file operation callback with = the corresponding pointer + // to a `struct file`. + let registration =3D unsafe { Self::registration_from_file(raw_fil= e) }; =20 // SAFETY: // * This underlying file is valid for (much longer than) the dura= tion of `T::open`. // * There is no active fdget_pos region on the file on this threa= d. let file =3D unsafe { File::from_raw_file(raw_file) }; =20 - let ptr =3D match T::open(file, registration.device(), registratio= n.data()) { + let ptr =3D match T::open(file, Self::args_from_registration(regis= tration)) { Ok(ptr) =3D> ptr, Err(err) =3D> return err.to_errno(), }; =20 - // This overwrites the private data with the value specified by th= e user, changing the type - // of this file's private data. All future accesses to the private= data is performed by - // other fops_* methods in this file, which all correctly cast the= private data to the new - // type. - // - // SAFETY: The open call of a file can access the private data. - unsafe { (*raw_file).private_data =3D ptr.into_foreign().cast() }; + // SAFETY: + // * We only ever write `registration.private` from `open()`, whic= h does not race with other + // file operation callbacks, i.e. there are no concurrent reads. + // * `registration.private.get()` is properly aligned. + unsafe { registration.private.get().write(ptr) }; =20 0 } @@ -346,15 +377,16 @@ impl MiscdeviceVTable { /// `file` and `inode` must be the file and inode for a file that is b= eing released. The file /// must be associated with a `MiscDeviceRegistration`. unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut = bindings::file) -> c_int { - // SAFETY: The release call of a file owns the private data. - let private =3D unsafe { (*file).private_data }.cast(); - // SAFETY: The release call of a file owns the private data. - let ptr =3D unsafe { ::from_foreign(priv= ate) }; + // SAFETY: Called from a misc device file operation callback with = the corresponding pointer + // to a `struct file`. + let registration =3D unsafe { Self::registration_from_file(file) }; =20 // SAFETY: - // * The file is valid for the duration of this call. - // * There is no active fdget_pos region on the file on this threa= d. - T::release(ptr, unsafe { File::from_raw_file(file) }); + // * There won't be any subsequent reads or writes to `registratio= n.private` once + // `release()` is called. + // * `registration.private` has been initialized in `open()`. + // * `registration.private.get()` is properly aligned. + unsafe { core::ptr::drop_in_place(registration.private.get()) }; =20 0 } @@ -363,17 +395,25 @@ impl MiscdeviceVTable { /// /// `file` must be a valid file that is associated with a `MiscDeviceR= egistration`. unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg= : c_ulong) -> c_long { - // SAFETY: The ioctl call of a file can access the private data. - let private =3D unsafe { (*file).private_data }.cast(); - // SAFETY: Ioctl calls can borrow the private data of the file. - let device =3D unsafe { ::borrow(private= ) }; + // SAFETY: Called from a misc device file operation callback with = the corresponding pointer + // to a `struct file`. + let registration =3D unsafe { Self::registration_from_file(file) }; + + // SAFETY: + // * `registration.private` is initialized in `open()`, which is g= uaranteed to called + // before this callback. + // * `registration.private.get()` is properly aligned. + // * There are no concurrent writes. + let private =3D unsafe { &*registration.private.get() }; =20 // SAFETY: // * The file is valid for the duration of this call. // * There is no active fdget_pos region on the file on this threa= d. let file =3D unsafe { File::from_raw_file(file) }; =20 - match T::ioctl(device, file, cmd, arg) { + let args =3D Self::args_from_registration(registration); + + match T::ioctl(args, private, file, cmd, arg) { Ok(ret) =3D> ret as c_long, Err(err) =3D> err.to_errno() as c_long, } @@ -388,17 +428,25 @@ impl MiscdeviceVTable { cmd: c_uint, arg: c_ulong, ) -> c_long { - // SAFETY: The compat ioctl call of a file can access the private = data. - let private =3D unsafe { (*file).private_data }.cast(); - // SAFETY: Ioctl calls can borrow the private data of the file. - let device =3D unsafe { ::borrow(private= ) }; + // SAFETY: Called from a misc device file operation callback with = the corresponding pointer + // to a `struct file`. + let registration =3D unsafe { Self::registration_from_file(file) }; + + // SAFETY: + // * `registration.private` is initialized in `open()`, which is g= uaranteed to called + // before this callback. + // * `registration.private.get()` is properly aligned. + // * There are no concurrent writes. + let private =3D unsafe { &*registration.private.get() }; =20 // SAFETY: // * The file is valid for the duration of this call. // * There is no active fdget_pos region on the file on this threa= d. let file =3D unsafe { File::from_raw_file(file) }; =20 - match T::compat_ioctl(device, file, cmd, arg) { + let args =3D Self::args_from_registration(registration); + + match T::compat_ioctl(args, private, file, cmd, arg) { Ok(ret) =3D> ret as c_long, Err(err) =3D> err.to_errno() as c_long, } @@ -409,10 +457,17 @@ impl MiscdeviceVTable { /// - `file` must be a valid file that is associated with a `MiscDevic= eRegistration`. /// - `seq_file` must be a valid `struct seq_file` that we can write t= o. unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, fi= le: *mut bindings::file) { - // SAFETY: The release call of a file owns the private data. - let private =3D unsafe { (*file).private_data }.cast(); - // SAFETY: Ioctl calls can borrow the private data of the file. - let device =3D unsafe { ::borrow(private= ) }; + // SAFETY: Called from a misc device file operation callback with = the corresponding pointer + // to a `struct file`. + let registration =3D unsafe { Self::registration_from_file(file) }; + + // SAFETY: + // * `registration.private` is initialized in `open()`, which is g= uaranteed to called + // before this callback. + // * `registration.private.get()` is properly aligned. + // * There are no concurrent writes. + let private =3D unsafe { &*registration.private.get() }; + // SAFETY: // * The file is valid for the duration of this call. // * There is no active fdget_pos region on the file on this threa= d. @@ -421,7 +476,9 @@ impl MiscdeviceVTable { // which this method is called. let m =3D unsafe { SeqFile::from_raw(seq_file) }; =20 - T::show_fdinfo(device, m, file); + let args =3D Self::args_from_registration(registration); + + T::show_fdinfo(args, private, m, file); } =20 const VTABLE: bindings::file_operations =3D bindings::file_operations { diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_devi= ce.rs index b60fd063afa8..9bf1a0f64e6e 100644 --- a/samples/rust/rust_misc_device.rs +++ b/samples/rust/rust_misc_device.rs @@ -159,7 +159,7 @@ device::Device, fs::File, ioctl::{_IO, _IOC_SIZE, _IOR, _IOW}, - miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, + miscdevice::{MiscArgs, MiscDevice, MiscDeviceOptions, MiscDeviceRegist= ration}, new_mutex, prelude::*, sync::{Arc, Mutex}, @@ -223,15 +223,15 @@ impl MiscDevice for RustMiscDevice { =20 type RegistrationData =3D Arc>; =20 - fn open(_file: &File, misc: &Device, data: &Self::RegistrationData) ->= Result>> { - let dev =3D ARef::from(misc); + fn open(_file: &File, args: MiscArgs<'_, Self>) -> Result>> { + let dev =3D ARef::from(args.device); =20 dev_info!(dev, "Opening Rust Misc Device Sample\n"); =20 KBox::try_pin_init( try_pin_init! { RustMiscDevice { - shared: data.clone(), + shared: args.data.clone(), unique <- new_mutex!(Inner { value: 0_i32 }), dev: dev, } @@ -240,8 +240,14 @@ fn open(_file: &File, misc: &Device, data: &Self::Regi= strationData) -> Result, _file: &File, cmd: u32, arg: usize)= -> Result { - dev_info!(me.dev, "IOCTLing Rust Misc Device Sample\n"); + fn ioctl( + args: MiscArgs<'_, Self>, + me: &Self::Ptr, + _file: &File, + cmd: u32, + arg: usize, + ) -> Result { + dev_info!(args.device, "IOCTLing Rust Misc Device Sample\n"); =20 let size =3D _IOC_SIZE(cmd); =20 @@ -256,7 +262,7 @@ fn ioctl(me: Pin<&RustMiscDevice>, _file: &File, cmd: u= 32, arg: usize) -> Result } RUST_MISC_DEV_HELLO =3D> me.hello()?, _ =3D> { - dev_err!(me.dev, "-> IOCTL not recognised: {}\n", cmd); + dev_err!(args.device, "-> IOCTL not recognised: {}\n", cmd= ); return Err(ENOTTY); } }; --=20 2.49.0 From nobody Tue Dec 16 22:28:06 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 55528231A3F; Fri, 30 May 2025 14:25:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615118; cv=none; b=NSlcMGL9hvyqzigRJFbiYCqv/jjmDlla3UmTRC1FyDMZ5p4kVSixG5nl1B3PyJD15DswiO1Zf/nHuAZr5z1Csfj0VgOkviC/kbnYRuUhCJyIFgfqEtGDVTmzj+cJCbR83vX0aTXbxsETsuAclHJzKNIYmt73+gHXOD3dfNiOuTk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748615118; c=relaxed/simple; bh=OemDzB7/Mo745bNLHFIg1xtCKR9iNReumwpsGuLmpEw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kzl2Q7Q9d7CDyEfwP0wgcMl0C3JP6eyDIjpsiK0OqkZMrVV5BGyjXJNGbNwPkot1EHJqlv2pS2vEhpRCYZO88MbUb0DvnGv79l6aZp34yNCAGZDmMPD7gZfkFIVZLOVXC65OGajTItvqOq0r7MEfeMKMWca3Cbn96Bc7V63Tnb8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JzBzxE+o; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JzBzxE+o" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 053E6C4CEE9; Fri, 30 May 2025 14:25:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748615118; bh=OemDzB7/Mo745bNLHFIg1xtCKR9iNReumwpsGuLmpEw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JzBzxE+oT4j7YFX/vFqu+HTQS7/xnl0B4O8d+HFMcjvzGq07ODh0FYlVjx0al4DNa 2nIcsRdxfQKECtLpBn0hl7JZP+52CvatHq9yiX+vo5lp1IENB6Edj8lnno6Zpji4vp K0StAlDL1kYurr8fIMrgt4DfZvuPjja3b10Xty9TNZC0bpAtu5l/9PDL2sYg/yzxY/ H1GT/Sas71FNWfnz3ka9O2n51DCiUje3OkVGNhkgdSgbexoEftZmkxsqBZcMomz9P5 /VwpHldscaleMGQwLWGbFufpV6YwU19xLQhnPpGpFqrp24OD8XXqv0xj/lkP2GLAHm kDuVUW1CE5p0g== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, chrisi.schrefl@gmail.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH 7/7] rust: sample: misc: implement device driver sample Date: Fri, 30 May 2025 16:24:20 +0200 Message-ID: <20250530142447.166524-8-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250530142447.166524-1-dakr@kernel.org> References: <20250530142447.166524-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In order to demonstrate and test a MiscDeviceRegistration with a parent device, introduce CONFIG_SAMPLE_RUST_MISC_DEVICE_WITH_PARENT. If CONFIG_SAMPLE_RUST_MISC_DEVICE_WITH_PARENT=3Dy the misc device sample is initialized with a parent device (faux), otherwise it is initialized without a parent device, i.e. the exact same way as without this patch. Signed-off-by: Danilo Krummrich --- samples/rust/Kconfig | 8 +++++ samples/rust/rust_misc_device.rs | 50 +++++++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index b1006ab4bc3c..9948ec0939ef 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -30,6 +30,14 @@ config SAMPLE_RUST_MISC_DEVICE =20 If unsure, say N. =20 +config SAMPLE_RUST_MISC_DEVICE_WITH_PARENT + bool "Create a misc device with a parent device" + depends on SAMPLE_RUST_MISC_DEVICE + default n + help + Say Y here if you want the misc device sample to create a misc + device with a parent device. + config SAMPLE_RUST_PRINT tristate "Printing macros" help diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_devi= ce.rs index 9bf1a0f64e6e..175638d6d341 100644 --- a/samples/rust/rust_misc_device.rs +++ b/samples/rust/rust_misc_device.rs @@ -167,6 +167,9 @@ uaccess::{UserSlice, UserSliceReader, UserSliceWriter}, }; =20 +#[cfg(CONFIG_SAMPLE_RUST_MISC_DEVICE_WITH_PARENT)] +use kernel::faux; + const RUST_MISC_DEV_HELLO: u32 =3D _IO('|' as u32, 0x80); const RUST_MISC_DEV_GET_VALUE: u32 =3D _IOR::('|' as u32, 0x81); const RUST_MISC_DEV_SET_VALUE: u32 =3D _IOW::('|' as u32, 0x82); @@ -181,19 +184,33 @@ license: "GPL", } =20 +#[cfg(not(CONFIG_SAMPLE_RUST_MISC_DEVICE_WITH_PARENT))] #[pin_data] struct RustMiscDeviceModule { #[pin] _miscdev: MiscDeviceRegistration, } =20 -impl kernel::InPlaceModule for RustMiscDeviceModule { - fn init(_module: &'static ThisModule) -> impl PinInit { +#[cfg(CONFIG_SAMPLE_RUST_MISC_DEVICE_WITH_PARENT)] +struct RustMiscDeviceModule { + _faux: faux::Registration, + _miscdev: Pin>>, +} + +impl RustMiscDeviceModule { + fn init() -> MiscDeviceOptions { pr_info!("Initializing Rust Misc Device Sample\n"); =20 - let options =3D MiscDeviceOptions { + MiscDeviceOptions { name: c_str!("rust-misc-device"), - }; + } + } +} + +#[cfg(not(CONFIG_SAMPLE_RUST_MISC_DEVICE_WITH_PARENT))] +impl kernel::InPlaceModule for RustMiscDeviceModule { + fn init(_module: &'static ThisModule) -> impl PinInit { + let options =3D Self::init(); =20 try_pin_init!(Self { _miscdev <- MiscDeviceRegistration::register( @@ -205,6 +222,31 @@ fn init(_module: &'static ThisModule) -> impl PinInit<= Self, Error> { } } =20 +#[cfg(CONFIG_SAMPLE_RUST_MISC_DEVICE_WITH_PARENT)] +impl kernel::Module for RustMiscDeviceModule { + fn init(_module: &'static ThisModule) -> Result { + let options =3D Self::init(); + let faux =3D faux::Registration::new(c_str!("rust-misc-device-samp= le"), None)?; + + // For every other bus, this would be called from Driver::probe(),= which would return a + // `Result>>`, but faux always binds to a "dummy" driv= er, hence probe() is + // not required. + let misc =3D KBox::pin_init( + MiscDeviceRegistration::register( + options, + Arc::pin_init(new_mutex!(Inner { value: 0_i32 }), GFP_KERN= EL), + Some(faux.as_ref()), + ), + GFP_KERNEL, + )?; + + Ok(Self { + _faux: faux, + _miscdev: misc, + }) + } +} + struct Inner { value: i32, } --=20 2.49.0