Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2229250/?format=api
{ "id": 2229250, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229250/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pci/patch/20260427221155.2144848-15-dakr@kernel.org/", "project": { "id": 28, "url": "http://patchwork.ozlabs.org/api/1.1/projects/28/?format=api", "name": "Linux PCI development", "link_name": "linux-pci", "list_id": "linux-pci.vger.kernel.org", "list_email": "linux-pci@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null }, "msgid": "<20260427221155.2144848-15-dakr@kernel.org>", "date": "2026-04-27T22:11:12", "name": "[14/24] rust: auxiliary: generalize Registration over ForLt", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "463ad0ccddd16ac08efd67bbe088ae793641f29c", "submitter": { "id": 89037, "url": "http://patchwork.ozlabs.org/api/1.1/people/89037/?format=api", "name": "Danilo Krummrich", "email": "dakr@kernel.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-pci/patch/20260427221155.2144848-15-dakr@kernel.org/mbox/", "series": [ { "id": 501733, "url": "http://patchwork.ozlabs.org/api/1.1/series/501733/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pci/list/?series=501733", "date": "2026-04-27T22:10:58", "name": "rust: device: Higher-Ranked Lifetime Types for device drivers", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501733/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2229250/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2229250/checks/", "tags": {}, "headers": { "Return-Path": "\n <linux-pci+bounces-53282-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-pci@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=Xz60eMTw;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-pci+bounces-53282-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"Xz60eMTw\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201" ], "Received": [ "from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4J2M3cM2z1yHX\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 08:21:47 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 1464A30A9556\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 27 Apr 2026 22:14:01 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id EC28D3AE6FE;\n\tMon, 27 Apr 2026 22:13:36 +0000 (UTC)", "from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id C6E2C3AD500;\n\tMon, 27 Apr 2026 22:13:36 +0000 (UTC)", "by smtp.kernel.org (Postfix) with ESMTPSA id 9A275C19425;\n\tMon, 27 Apr 2026 22:13:30 +0000 (UTC)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777328016; cv=none;\n b=VCbYSoTOJGEwuqqANoeIw0alBiwH+EY/FM6INS3nzTgeFqBeMGD/Jb7nnbKk1sxTdja5M1EufcfNK6uW1UK6xLsD3ePP6c1BrcSC8LJDVXoZa4+mZgehGuvdG1WSSqRzzXzTFDd/MQMeWIKvHaswM/opsw1/Gud1IMF8R9+1jgU=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777328016; c=relaxed/simple;\n\tbh=fYpYyJUHzZkxcr62qUd+Bupt8j3iNvgRc3q30X3mPgE=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=nEoI+xuUqmTcNdvNCh/DR4Yl6qGRdRvvDMCkaKpEOEN8otawxZM41ei2QLytmy5z9IN+RbZbh0TmSw1/UIqBic3Ne3RliwtIRDaDMWG72ZXj5HsGvS0LS2Ygp2v1o40h8vAum2vEr9UcRfCs3SjVTZc9jF6Ja+WlurBSUVXlOHg=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=Xz60eMTw; arc=none smtp.client-ip=10.30.226.201", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1777328016;\n\tbh=fYpYyJUHzZkxcr62qUd+Bupt8j3iNvgRc3q30X3mPgE=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=Xz60eMTwi9F9Xopxl23ANXhzlrKa8KRUQ74F6VU5w+e8bzuAWSzV5TwPtI0vVpdav\n\t V3F6rNYgZ87FgkTdG0ZCLT0rzlpai178fhUXc9FeTjkhIpZOa9k/1MtAqVZ+cL8ky0\n\t PIAiAggVBi2102ji8oWmXmKIj56HEl6ijBWEDkjvdKhZzEvuLtnJZKAKUCR6vensXk\n\t 7nDSyEnfLyAwj0zG0I8VO5agWq88jJinRVQaDy7h9yi7Pxy6sEmEGdK35gWU5HJqIX\n\t r2DZ79/MVnwxsN8vWJL4PzB/iP9I4VClh+K22BlZk9QTAtPjcqhp7vCzk23Vl51EaX\n\t EocGnyooTDO0Q==", "From": "Danilo Krummrich <dakr@kernel.org>", "To": "gregkh@linuxfoundation.org,\n\trafael@kernel.org,\n\tacourbot@nvidia.com,\n\taliceryhl@google.com,\n\tdavid.m.ertman@intel.com,\n\tira.weiny@intel.com,\n\tleon@kernel.org,\n\tviresh.kumar@linaro.org,\n\tm.wilczynski@samsung.com,\n\tukleinek@kernel.org,\n\tbhelgaas@google.com,\n\tkwilczynski@kernel.org,\n\tabdiel.janulgue@gmail.com,\n\trobin.murphy@arm.com,\n\tmarkus.probst@posteo.de,\n\tojeda@kernel.org,\n\tboqun@kernel.org,\n\tgary@garyguo.net,\n\tbjorn3_gh@protonmail.com,\n\tlossin@kernel.org,\n\ta.hindborg@kernel.org,\n\ttmgross@umich.edu", "Cc": "driver-core@lists.linux.dev,\n\tlinux-kernel@vger.kernel.org,\n\tnova-gpu@lists.linux.dev,\n\tdri-devel@lists.freedesktop.org,\n\tlinux-pm@vger.kernel.org,\n\tlinux-pwm@vger.kernel.org,\n\tlinux-pci@vger.kernel.org,\n\trust-for-linux@vger.kernel.org,\n\tDanilo Krummrich <dakr@kernel.org>", "Subject": "[PATCH 14/24] rust: auxiliary: generalize Registration over ForLt", "Date": "Tue, 28 Apr 2026 00:11:12 +0200", "Message-ID": "<20260427221155.2144848-15-dakr@kernel.org>", "X-Mailer": "git-send-email 2.54.0", "In-Reply-To": "<20260427221155.2144848-1-dakr@kernel.org>", "References": "<20260427221155.2144848-1-dakr@kernel.org>", "Precedence": "bulk", "X-Mailing-List": "linux-pci@vger.kernel.org", "List-Id": "<linux-pci.vger.kernel.org>", "List-Subscribe": "<mailto:linux-pci+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-pci+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit" }, "content": "Generalize Registration<T> to Registration<F: ForLt> and\nDevice::registration_data<F: ForLt>() to return Pin<&F::Of<'_>>.\n\nThe stored 'static lifetime is shortened to the borrow lifetime of &self\nvia ForLt::cast_ref; ForLt's covariance guarantee makes this sound.\n\nSigned-off-by: Danilo Krummrich <dakr@kernel.org>\n---\n drivers/gpu/nova-core/driver.rs | 4 +-\n rust/kernel/auxiliary.rs | 80 ++++++++++++++++++---------\n samples/rust/rust_driver_auxiliary.rs | 7 ++-\n 3 files changed, 61 insertions(+), 30 deletions(-)", "diff": "diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs\nindex 815489dd92d0..2a17fc99d9b6 100644\n--- a/drivers/gpu/nova-core/driver.rs\n+++ b/drivers/gpu/nova-core/driver.rs\n@@ -21,6 +21,7 @@\n },\n Arc,\n },\n+ types::ForLt,\n };\n \n use crate::gpu::Gpu;\n@@ -32,7 +33,8 @@\n pub(crate) struct NovaCore {\n #[pin]\n pub(crate) gpu: Gpu,\n- _reg: Devres<auxiliary::Registration<()>>,\n+ #[allow(clippy::type_complexity)]\n+ _reg: Devres<auxiliary::Registration<ForLt!(())>>,\n }\n \n const BAR0_SIZE: usize = SZ_16M;\ndiff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs\nindex f593a21a16be..e27de4be4d87 100644\n--- a/rust/kernel/auxiliary.rs\n+++ b/rust/kernel/auxiliary.rs\n@@ -287,12 +287,19 @@ pub fn parent(&self) -> &device::Device<device::Bound> {\n \n /// Returns a pinned reference to the registration data set by the registering (parent) driver.\n ///\n- /// Returns [`EINVAL`] if `T` does not match the type used by the parent driver when calling\n+ /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The returned\n+ /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via\n+ /// [`ForLt::cast_ref`].\n+ ///\n+ /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling\n /// [`Registration::new()`].\n ///\n /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was\n /// registered by a C driver.\n- pub fn registration_data<T: 'static>(&self) -> Result<Pin<&T>> {\n+ pub fn registration_data<F: ForLt>(&self) -> Result<Pin<&F::Of<'_>>>\n+ where\n+ F::Of<'static>: 'static,\n+ {\n // SAFETY: By the type invariant, `self.as_raw()` is a valid `struct auxiliary_device`.\n let ptr = unsafe { (*self.as_raw()).registration_data_rust };\n if ptr.is_null() {\n@@ -305,18 +312,23 @@ pub fn registration_data<T: 'static>(&self) -> Result<Pin<&T>> {\n \n // SAFETY: `ptr` is non-null and was set via `into_foreign()` in `Registration::new()`;\n // `RegistrationData` is `#[repr(C)]` with `type_id` at offset 0, so reading a `TypeId`\n- // at the start of the allocation is valid regardless of `T`.\n+ // at the start of the allocation is valid regardless of `F`.\n let type_id = unsafe { ptr.cast::<TypeId>().read() };\n- if type_id != TypeId::of::<T>() {\n+ if type_id != TypeId::of::<F::Of<'static>>() {\n return Err(EINVAL);\n }\n \n- // SAFETY: The `TypeId` check above confirms that the stored type is `T`; `ptr` remains\n- // valid until `Registration::drop()` calls `from_foreign()`.\n- let wrapper = unsafe { Pin::<KBox<RegistrationData<T>>>::borrow(ptr) };\n+ // SAFETY: The `TypeId` check above confirms that the stored type matches\n+ // `F::Of<'static>`; `ptr` remains valid until `Registration::drop()` calls\n+ // `from_foreign()`.\n+ let wrapper = unsafe { Pin::<KBox<RegistrationData<F::Of<'static>>>>::borrow(ptr) };\n \n // SAFETY: `data` is a structurally pinned field of `RegistrationData`.\n- Ok(unsafe { wrapper.map_unchecked(|w| &w.data) })\n+ let pinned: Pin<&F::Of<'static>> = unsafe { wrapper.map_unchecked(|w| &w.data) };\n+\n+ // SAFETY: ForLt guarantees covariance, making it sound to shorten 'static to &self's\n+ // lifetime via cast_ref.\n+ Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) })\n }\n }\n \n@@ -405,43 +417,54 @@ struct RegistrationData<T> {\n /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device\n /// is unbound, the corresponding auxiliary device will be unregistered from the system.\n ///\n-/// The type parameter `T` is the type of the registration data owned by the registering (parent)\n-/// driver. It can be accessed by the auxiliary driver through\n-/// [`Device::registration_data()`].\n+/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the registration\n+/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](macro@ForLt).\n+/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`].\n ///\n /// # Invariants\n ///\n /// `self.adev` always holds a valid pointer to an initialized and registered\n /// [`struct auxiliary_device`], and `registration_data` points to a valid\n-/// `Pin<KBox<RegistrationData<T>>>`.\n-pub struct Registration<T: 'static> {\n+/// `Pin<KBox<RegistrationData<F::Of<'static>>>>`.\n+pub struct Registration<F: ForLt>\n+where\n+ F::Of<'static>: 'static,\n+{\n adev: NonNull<bindings::auxiliary_device>,\n- _data: PhantomData<T>,\n+ _data: PhantomData<F>,\n }\n \n-impl<T: Send + 'static> Registration<T> {\n+impl<F: ForLt> Registration<F>\n+where\n+ F::Of<'static>: Send + 'static,\n+{\n /// Create and register a new auxiliary device with the given registration data.\n ///\n /// The `data` is owned by the registration and can be accessed through the auxiliary device\n /// via [`Device::registration_data()`].\n- pub fn new<E>(\n- parent: &device::Device<device::Bound>,\n+ pub fn new<'a, E>(\n+ parent: &'a device::Device<device::Bound>,\n name: &CStr,\n id: u32,\n modname: &CStr,\n- data: impl PinInit<T, E>,\n+ data: impl PinInit<F::Of<'a>, E>,\n ) -> Result<Devres<Self>>\n where\n Error: From<E>,\n {\n let data = KBox::pin_init::<Error>(\n try_pin_init!(RegistrationData {\n- type_id: TypeId::of::<T>(),\n+ type_id: TypeId::of::<F::Of<'static>>(),\n data <- data,\n }),\n GFP_KERNEL,\n )?;\n \n+ // SAFETY: Lifetimes are erased and do not affect layout, so RegistrationData<F::Of<'a>>\n+ // and RegistrationData<F::Of<'static>> have identical representation.\n+ let data: Pin<KBox<RegistrationData<F::Of<'static>>>> =\n+ unsafe { core::mem::transmute(data) };\n+\n let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?;\n let adev = boxed.get();\n \n@@ -470,9 +493,11 @@ pub fn new<E>(\n let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) };\n if ret != 0 {\n // SAFETY: `registration_data` was set above via `into_foreign()`.\n- let _ = unsafe {\n- Pin::<KBox<RegistrationData<T>>>::from_foreign((*adev).registration_data_rust)\n- };\n+ drop(unsafe {\n+ Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign(\n+ (*adev).registration_data_rust,\n+ )\n+ });\n \n // SAFETY: `adev` is guaranteed to be a valid pointer to a\n // `struct auxiliary_device`, which has been initialized.\n@@ -494,7 +519,10 @@ pub fn new<E>(\n }\n }\n \n-impl<T: 'static> Drop for Registration<T> {\n+impl<F: ForLt> Drop for Registration<F>\n+where\n+ F::Of<'static>: 'static,\n+{\n fn drop(&mut self) {\n // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered\n // `struct auxiliary_device`.\n@@ -502,7 +530,7 @@ fn drop(&mut self) {\n \n // SAFETY: `registration_data` was set in `new()` via `into_foreign()`.\n drop(unsafe {\n- Pin::<KBox<RegistrationData<T>>>::from_foreign(\n+ Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign(\n (*self.adev.as_ptr()).registration_data_rust,\n )\n });\n@@ -516,7 +544,7 @@ fn drop(&mut self) {\n }\n \n // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread.\n-unsafe impl<T: Send> Send for Registration<T> {}\n+unsafe impl<F: ForLt> Send for Registration<F> where F::Of<'static>: Send {}\n \n // SAFETY: `Registration` does not expose any methods or fields that need synchronization.\n-unsafe impl<T: Send> Sync for Registration<T> {}\n+unsafe impl<F: ForLt> Sync for Registration<F> where F::Of<'static>: Send {}\ndiff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs\nindex d35963ac7fa4..4ad619c5731e 100644\n--- a/samples/rust/rust_driver_auxiliary.rs\n+++ b/samples/rust/rust_driver_auxiliary.rs\n@@ -55,9 +55,10 @@ struct Data {\n index: u32,\n }\n \n+#[allow(clippy::type_complexity)]\n struct ParentDriver {\n- _reg0: Devres<auxiliary::Registration<Data>>,\n- _reg1: Devres<auxiliary::Registration<Data>>,\n+ _reg0: Devres<auxiliary::Registration<ForLt!(Data)>>,\n+ _reg1: Devres<auxiliary::Registration<ForLt!(Data)>>,\n }\n \n kernel::pci_device_table!(\n@@ -100,7 +101,7 @@ fn connect(adev: &auxiliary::Device<Bound>) -> Result {\n let dev = adev.parent();\n let pdev: &pci::Device<Bound> = dev.try_into()?;\n \n- let data = adev.registration_data::<Data>()?;\n+ let data = adev.registration_data::<ForLt!(Data)>()?;\n \n dev_info!(\n dev,\n", "prefixes": [ "14/24" ] }