From nobody Sat Jun 13 15:11:35 2026 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 9338B3246E8; Wed, 6 May 2026 22:00:40 +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=1778104840; cv=none; b=IoU2ZUWt7MNkImAelXx+LjUEdrs2p/sdbo58ChcxFl6pO6NJ3sbdS423A29T63H9OysfS7k/fYha3TTjaGeWpokXnrlCLsIn/EP6qA+YV51IrNmI/VMNVa08TOHkvtmtUXiXtJec2PdOjvJOSIXY9UlOwbcLFyni88/EDwYiTvs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104840; c=relaxed/simple; bh=qO/bJBZKk+2JX7D64j+KbHrwyxEIaJ1JMMkQoGp2JnE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AwlbKQSuZ6hlxxqDUparSi1iNAnfaY50XUEZAo8c9sXGuys8aaT9089fmP29FLpZ+FiCtmuULildyDaDtbAIf1F6/C7+oF6ZhrUW2aDYB6f+8ysX0Dp9K4ipR4/NM0FYYJyKrIYJVQwwBYCHAtCfHjxWcWoAxci/aQiz9QaVBcM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=P7ypO5dF; 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="P7ypO5dF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F3676C2BCB0; Wed, 6 May 2026 22:00:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104840; bh=qO/bJBZKk+2JX7D64j+KbHrwyxEIaJ1JMMkQoGp2JnE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=P7ypO5dF3L0fBPUCnrrx6TaZenXdgGdQI7+zaewT/iX4gvhZQjbi/XtNoCeKZGSdp huZTtbG64v0FWXWbZqF45iaz77BzK7ymtNMEbsAam7fMkVTTi590vuR1SYKcr4IZoT LtPXr/16xMMQ6Ee7UQPHF2uxcwm/IMrHSnmz5pA4qJDWbApFw9ebqWXZMFUyqUI1Xy dXpKeIBIuj8GTQTqGl74bxNio3acLhxMfT5MBBtmatHZgJEtibHlvuD5eupsft6FEK wznkGnE7WBuXVotsYr+B5d73GxxhmeSldbnQtSNhWirZhDrHARwyBKrYe3GE5sAkm9 PcwXFCeFvZANQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH 1/3] rust: devres: add DevresLt for ForLt-aware device resource access Date: Wed, 6 May 2026 23:58:33 +0200 Message-ID: <20260506220012.855173-2-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506220012.855173-1-dakr@kernel.org> References: <20260506220012.855173-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" Devres stores resources as T and returns &'bound T from access(). For lifetime-parameterized types like Bar<'bound, SIZE> that are transmuted to 'static for storage, this exposes the synthetic 'static lifetime to callers -- any method on the stored type that returns a reference with its lifetime parameter would yield a &'static reference, which is unsound. Add DevresLt, a thin wrapper around Devres> that applies ForLt::cast_ref in all access methods to shorten the stored 'static lifetime to the caller's borrow lifetime. Devres remains unchanged for static resource types. Signed-off-by: Danilo Krummrich --- rust/kernel/devres.rs | 97 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 90 insertions(+), 7 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 58efe80474bd..c9c698901871 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -24,6 +24,7 @@ Arc, // }, types::{ + ForLt, ForeignOwnable, Opaque, // }, @@ -122,7 +123,7 @@ struct Inner { /// # Ok(()) /// # } /// ``` -pub struct Devres { +pub struct Devres { dev: ARef, inner: Arc>, } @@ -184,7 +185,7 @@ pub(super) unsafe fn devres_node_remove( } } =20 -impl Devres { +impl Devres { /// Creates a new [`Devres`] instance of the given `data`. /// /// The `data` encapsulated within the returned `Devres` instance' `da= ta` will be @@ -237,7 +238,7 @@ pub fn new(dev: &Device, data: impl PinInit) -> Result }) } =20 - fn data(&self) -> &Revocable { + pub(crate) fn data(&self) -> &Revocable { &self.inner.data } =20 @@ -297,15 +298,19 @@ pub fn device(&self) -> &Device { /// #![cfg(CONFIG_PCI)] /// use kernel::{ /// device::Core, - /// devres::Devres, + /// devres::DevresLt, /// io::{ /// Io, /// IoKnownSize, // /// }, - /// pci, // + /// pci, + /// types::ForLt, // /// }; /// - /// fn from_core(dev: &pci::Device, devres: Devres>) -> Result { + /// fn from_core( + /// dev: &pci::Device, + /// devres: DevresLt)>, + /// ) -> Result { /// let bar =3D devres.access(dev.as_ref())?; /// /// let _ =3D bar.read32(0x0); @@ -353,7 +358,7 @@ unsafe impl Send for Devres {} // SAFETY: `Devres` can be shared with any task, if `T: Sync`. unsafe impl Sync for Devres {} =20 -impl Drop for Devres { +impl Drop for Devres { fn drop(&mut self) { // SAFETY: When `drop` runs, it is guaranteed that nobody is acces= sing the revocable data // anymore, hence it is safe not to wait for the grace period to f= inish. @@ -369,6 +374,84 @@ fn drop(&mut self) { } } =20 +/// Guard returned by [`DevresLt::try_access`]. +/// +/// Dereferences to `F::Of<'bound>`, applying [`ForLt::cast_ref`] to short= en the lifetime of the +/// stored data to the guard's borrow lifetime. +pub struct DevresGuard<'bound, F: ForLt>(RevocableGuard<'bound, F::Of<'sta= tic>>); + +impl<'bound, F: ForLt> core::ops::Deref for DevresGuard<'bound, F> { + type Target =3D F::Of<'bound>; + + fn deref(&self) -> &Self::Target { + F::cast_ref(&*self.0) + } +} + +/// Device-managed resource with [`ForLt`](trait@ForLt)-aware access. +/// +/// `DevresLt` wraps [`Devres`] and applies [`ForLt::cast_ref`] in its acc= ess methods to shorten +/// the stored `'static` lifetime to the caller's borrow lifetime. This pr= events transmuted +/// `'static` lifetimes from leaking to users. +/// +/// Use this for resource types that implement [`ForLt`](trait@ForLt) and = are stored with a +/// transmuted `'static` lifetime (e.g. [`pci::Bar`]). +/// +/// [`pci::Bar`]: crate::pci::Bar +pub struct DevresLt(Devres>) +where + F::Of<'static>: Send; + +impl DevresLt +where + F::Of<'static>: Send, +{ + /// Creates a new [`DevresLt`] instance of the given `data`. + pub fn new(dev: &Device, data: impl PinInit, = E>) -> Result + where + Error: From, + { + Ok(Self(Devres::new(dev, data)?)) + } + + /// Return a reference of the [`Device`] this [`DevresLt`] instance ha= s been created with. + pub fn device(&self) -> &Device { + self.0.device() + } + + /// Obtain `&'bound F::Of<'bound>`, bypassing the [`Revocable`]. + /// + /// This method works like [`Devres::access`], but shortens the return= ed reference's lifetime + /// from `'static` to `'bound` via [`ForLt::cast_ref`]. + pub fn access<'bound>( + &'bound self, + dev: &'bound Device, + ) -> Result<&'bound F::Of<'bound>> { + self.0.access(dev).map(F::cast_ref) + } + + /// [`DevresLt`] accessor for [`Revocable::try_access`]. + pub fn try_access(&self) -> Option> { + self.0.data().try_access().map(DevresGuard) + } + + /// [`DevresLt`] accessor for [`Revocable::try_access_with`]. + pub fn try_access_with(&self, f: G) -> Option + where + G: for<'bound> FnOnce(&'bound F::Of<'bound>) -> R, + { + self.0.data().try_access_with(|data| f(F::cast_ref(data))) + } + + /// [`DevresLt`] accessor for [`Revocable::try_access_with_guard`]. + pub fn try_access_with_guard<'bound>( + &'bound self, + guard: &'bound rcu::Guard, + ) -> Option<&'bound F::Of<'bound>> { + self.0.data().try_access_with_guard(guard).map(F::cast_ref) + } +} + /// Consume `data` and [`Drop::drop`] `data` once `dev` is unbound. fn register_foreign

(dev: &Device, data: P) -> Result where --=20 2.54.0 From nobody Sat Jun 13 15:11:35 2026 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 640DC3B5305; Wed, 6 May 2026 22:00:47 +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=1778104847; cv=none; b=Lqlw33IGRK1+YnXaFjAHoF3stUK0KO+b9/WlBiwqY1f80jv8Er8q4xP+v9R+QCyCSS58dK+ADJefilbu2g3+mADNS89vDL67LxAJC2APx30bYsvsK7MNnp/nSftAYl0Pm2LCV3HshERi/QK/rizEiguieV4+ZOphaclbjpNNO8k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104847; c=relaxed/simple; bh=g+VFtZvKf6WOxAsZvmu6omoAgBIUzl+XzC7tNpmWzIk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mV1EFlVJNwnsZCwBHTnL8AS/5lyBJrAxlC+vZ3Gx02VfK7nB1x+i+sDo84vmfG5CayzMBQ1LVQwPWZ46EdqOKbjcr7zvG/xwuXaKm5xIl/JtZuFXDFLNRKONX8siBhVwaK3eAN1e+7H2KNDG4k4vafCeA9O5fhSda7kPHIdSL24= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=A14q5gM6; 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="A14q5gM6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9A96EC2BCB2; Wed, 6 May 2026 22:00:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104846; bh=g+VFtZvKf6WOxAsZvmu6omoAgBIUzl+XzC7tNpmWzIk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=A14q5gM6aGbC2I6AMqUEeS3HHs2BKtkXPO3aDMJZy593n38fIbQNFfr2z32OJ2HZg 8kko1Oawj/aju7hvKtu0fmNMthou/yrcayyzJ945It9C/z/BMrxEUdynLDFbbXxVcX m8tC66F9Zu2FImco+oDcVfRNZKsisY86Wm5kB05eeMRj6FQ45zxOCWhAACOudXNlch HIiAE9+Hrcr3Drfyq+8nG1GJztuNUrK3POEpgoIL13tKe2jH0uQwzabKg+bEaKO2XD WP+o9jGDTy2is5XI45w+xrDflxgjIafKI8mJSeJct/fgho30d2BEIgv3oA71aQjoMB f/+yV0jMgwwwA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH 2/3] rust: pci: return DevresLt from Bar::into_devres() Date: Wed, 6 May 2026 23:58:34 +0200 Message-ID: <20260506220012.855173-3-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506220012.855173-1-dakr@kernel.org> References: <20260506220012.855173-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" Implement ForLt for Bar<'static, SIZE> so that DevresLt can shorten the stored 'static lifetime back to the caller's borrow lifetime via ForLt::cast_ref. Without this, Devres>::access() would return &'bound Bar<'static, SIZE>, allowing the inner 'static to leak through methods like pdev(). Add a DevresBar type alias for convenience. Signed-off-by: Danilo Krummrich --- rust/kernel/pci.rs | 1 + rust/kernel/pci/io.rs | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 1335857cae94..265d06b18e42 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -48,6 +48,7 @@ ConfigSpace, ConfigSpaceKind, ConfigSpaceSize, + DevresBar, Extended, Normal, // }; diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index 5668394a155b..7a5b5210cf66 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -6,7 +6,7 @@ use crate::{ bindings, device, - devres::Devres, + devres::DevresLt, io::{ Io, IoCapable, @@ -14,7 +14,8 @@ Mmio, MmioRaw, // }, - prelude::*, // + prelude::*, + types::ForLt, // }; use core::{ marker::PhantomData, @@ -151,6 +152,18 @@ pub struct Bar<'bound, const SIZE: usize =3D 0> { num: i32, } =20 +// SAFETY: `Bar<'bound, SIZE>` is covariant over `'bound` -- it holds +// `&'bound Device`, which is covariant. Shortening the lifetime +// is therefore sound. +unsafe impl ForLt for Bar<'static, SIZE> { + type Of<'bound> =3D Bar<'bound, SIZE>; +} + +/// A device-managed PCI BAR mapping. +/// +/// See [`Bar::into_devres`]. +pub type DevresBar =3D DevresLt>; + impl<'bound, const SIZE: usize> Bar<'bound, SIZE> { pub(super) fn new(pdev: &'bound Device, num: u32, name:= &CStr) -> Result { let len =3D pdev.resource_len(num)?; @@ -219,15 +232,16 @@ fn release(&self) { =20 /// Consume the `Bar` and register it as a device-managed resource. /// - /// The returned `Devres>` can outlive the original= lifetime `'bound`. Access - /// to the BAR is revoked when the device is unbound. - pub fn into_devres(self) -> Result>> { - // SAFETY: Casting to `'static` is sound because `Devres` guarante= es the `Bar` does not + /// Access methods on the returned [`DevresLt`] shorten the inner life= time via + /// [`ForLt::cast_ref`], so the transmuted `'static` is never exposed = to callers. + pub fn into_devres(self) -> Result>> { + // SAFETY: Casting to `'static` is sound because `DevresLt` guaran= tees the `Bar` does not // actually outlive the device -- access is revoked and the resour= ce is released when the - // device is unbound. + // device is unbound. The `ForLt` encoding ensures `access()` shor= tens the lifetime back + // to the caller's borrow, preventing `'static` from leaking. let bar: Bar<'static, SIZE> =3D unsafe { core::mem::transmute(self= ) }; let pdev =3D bar.pdev; - Devres::new(pdev.as_ref(), bar) + DevresLt::new(pdev.as_ref(), bar) } } =20 --=20 2.54.0 From nobody Sat Jun 13 15:11:35 2026 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 EFD8F3B6BE5; Wed, 6 May 2026 22:00:53 +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=1778104854; cv=none; b=eKTYdZyge98GNG/qP1o4Gjp2AhTSdTGqvWGHuzMQA8af21zbyyyQhRkSaqUveXG3Q6BvXRnvbRGRJ7lnkt4RQvJmyKyivUnMNW5cw8Pxl1Xl07/hhdPCMvPgEKGC8eVvuFWWFDhY7V7SgYXBpjqpqH863iDI3Ia67XpxUuZ/W8k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104854; c=relaxed/simple; bh=on0f2dzM4OyBJJ/2FK/55nr+4xNDyqrNSyiwAHUz4Rk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BRCbHt/65ClkKK2ML1VCkfJGk9b8SNm9LN3T9c8YNfx71Uy7ygWNOKlbD6Vyhi0meEkAcLADi1Mx4vO8wD2aXdyIhJ/UYpcaDccgIFleYBQYXJK+r6MHHFAngxuXqBfDqKUrkHZSGR3xIfFMwyBJNiy4zAUxPZ19dYzTSv/fvNo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uwmnhyPM; 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="uwmnhyPM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3B396C2BCB0; Wed, 6 May 2026 22:00:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104853; bh=on0f2dzM4OyBJJ/2FK/55nr+4xNDyqrNSyiwAHUz4Rk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uwmnhyPMk0cS4CjrFv8Om71Z3XOiTp3862EkfaXMedsCh+8jyu8hE4M/tU8GHHdxV HgJLiMwSPSWzYUFik535ujPWCYhJSRLH68+Rekwy4p78bip0BYP2TDl2Ega1sllgcv +c6Co0jTLuy2Dgl9GlweTdV6Qdy20SHQlHjx1L4Bu+kTsXe5CgH9nZdc1MqgyaazWq gcBbZgcpxvHIrpg1pRKvXi9k9LOVY/bdA6RGDNwv3wY5V3ZSRPz20IzTZktGiQuYXo rCrF3vwqhaYVeErHSgO76MkiynGqsXsAWDIE39M1ToJ9Ve2+q69ranrJFXU0TvVziO NNLBOQGA9I1ag== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH 3/3] rust: io: mem: return DevresLt from IoMem/ExclusiveIoMem::into_devres() Date: Wed, 6 May 2026 23:58:35 +0200 Message-ID: <20260506220012.855173-4-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506220012.855173-1-dakr@kernel.org> References: <20260506220012.855173-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" Implement ForLt for IoMem<'static, SIZE> and ExclusiveIoMem<'static, SIZE> so that DevresLt can shorten the stored 'static lifetime back to the caller's borrow lifetime via ForLt::cast_ref. Change into_devres() to return DevresLt instead of Devres; add DevresIoMem and DevresExclusiveIoMem type aliases. Signed-off-by: Danilo Krummrich --- drivers/pwm/pwm_th1520.rs | 5 ++-- rust/kernel/io/mem.rs | 55 ++++++++++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index 3deb39d8e0fc..6b094be35310 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -24,9 +24,8 @@ use kernel::{ clk::Clk, device::{Bound, Core, Device}, - devres, io::{ - mem::IoMem, + mem::DevresIoMem, Io, // }, of, platform, @@ -92,7 +91,7 @@ struct Th1520WfHw { #[pin_data(PinnedDrop)] struct Th1520PwmDriverData { #[pin] - iomem: devres::Devres>, + iomem: DevresIoMem, clk: Clk, } =20 diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index a4cb12ee70d3..928aa7742490 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -9,7 +9,7 @@ Bound, Device, // }, - devres::Devres, + devres::DevresLt, io::{ self, resource::{ @@ -20,6 +20,7 @@ MmioRaw, // }, prelude::*, + types::ForLt, // }; =20 /// An IO request for a specific device and resource. @@ -170,6 +171,18 @@ pub struct ExclusiveIoMem<'bound, const SIZE: usize> { _region: Region, } =20 +// SAFETY: `ExclusiveIoMem<'bound, SIZE>` is covariant over `'bound` -- +// it holds an `IoMem<'bound, SIZE>`, which holds +// `&'bound Device`, which is covariant. +unsafe impl ForLt for ExclusiveIoMem<'static, SIZE> { + type Of<'bound> =3D ExclusiveIoMem<'bound, SIZE>; +} + +/// A device-managed exclusive I/O memory region. +/// +/// See [`ExclusiveIoMem::into_devres`]. +pub type DevresExclusiveIoMem =3D DevresLt>; + impl<'bound, const SIZE: usize> ExclusiveIoMem<'bound, SIZE> { /// Creates a new `ExclusiveIoMem` instance. fn ioremap(dev: &'bound Device, resource: &Resource) -> Result<= Self> { @@ -196,15 +209,16 @@ fn ioremap(dev: &'bound Device, resource: &Res= ource) -> Result { =20 /// Consume the `ExclusiveIoMem` and register it as a device-managed r= esource. /// - /// The returned `Devres>` can outlive t= he original lifetime - /// `'bound`. Access to the I/O memory is revoked when the device is u= nbound. - pub fn into_devres(self) -> Result>> { - // SAFETY: Casting to `'static` is sound because `Devres` guarante= es the + /// Access methods on the returned [`DevresLt`] shorten the inner life= time via + /// [`ForLt::cast_ref`], so the transmuted `'static` is never exposed = to callers. + pub fn into_devres(self) -> Result>> { + // SAFETY: Casting to `'static` is sound because `DevresLt` guaran= tees the // `ExclusiveIoMem` does not actually outlive the device -- access= is revoked and the - // resource is released when the device is unbound. + // resource is released when the device is unbound. The `ForLt` en= coding ensures + // `access()` shortens the lifetime back to the caller's borrow. let iomem: ExclusiveIoMem<'static, SIZE> =3D unsafe { core::mem::t= ransmute(self) }; let dev =3D iomem.iomem.dev; - Devres::new(dev, iomem) + DevresLt::new(dev, iomem) } } =20 @@ -230,6 +244,17 @@ pub struct IoMem<'bound, const SIZE: usize =3D 0> { io: MmioRaw, } =20 +// SAFETY: `IoMem<'bound, SIZE>` is covariant over `'bound` -- it holds +// `&'bound Device`, which is covariant. +unsafe impl ForLt for IoMem<'static, SIZE> { + type Of<'bound> =3D IoMem<'bound, SIZE>; +} + +/// A device-managed I/O memory region. +/// +/// See [`IoMem::into_devres`]. +pub type DevresIoMem =3D DevresLt>; + impl<'bound, const SIZE: usize> IoMem<'bound, SIZE> { fn ioremap(dev: &'bound Device, resource: &Resource) -> Result<= Self> { // Note: Some ioremap() implementations use types that depend on t= he CPU @@ -269,16 +294,16 @@ fn ioremap(dev: &'bound Device, resource: &Res= ource) -> Result { =20 /// Consume the `IoMem` and register it as a device-managed resource. /// - /// The returned `Devres>` can outlive the origin= al - /// lifetime `'bound`. Access to the I/O memory is revoked when the de= vice - /// is unbound. - pub fn into_devres(self) -> Result>> { - // SAFETY: Casting to `'static` is sound because `Devres` guarante= es the `IoMem` does not - // actually outlive the device -- access is revoked and the resour= ce is released when the - // device is unbound. + /// Access methods on the returned [`DevresLt`] shorten the inner life= time via + /// [`ForLt::cast_ref`], so the transmuted `'static` is never exposed = to callers. + pub fn into_devres(self) -> Result>> { + // SAFETY: Casting to `'static` is sound because `DevresLt` guaran= tees the `IoMem` does + // not actually outlive the device -- access is revoked and the re= source is released when + // the device is unbound. The `ForLt` encoding ensures `access()` = shortens the lifetime + // back to the caller's borrow. let iomem: IoMem<'static, SIZE> =3D unsafe { core::mem::transmute(= self) }; let dev =3D iomem.dev; - Devres::new(dev, iomem) + DevresLt::new(dev, iomem) } } =20 --=20 2.54.0