* [PATCH] rust: io: convert ResourceSize into a transparent newtype
@ 2026-07-12 11:36 Lorenzo Delgado
2026-07-16 21:45 ` Danilo Krummrich
0 siblings, 1 reply; 2+ messages in thread
From: Lorenzo Delgado @ 2026-07-12 11:36 UTC (permalink / raw)
To: Miguel Ojeda, Danilo Krummrich, Alice Ryhl, Daniel Almeida,
Alexandre Courbot, David Airlie, Simona Vetter
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Trevor Gross, Tamir Duberstein, Onur Özkan,
Abdiel Janulgue, Robin Murphy, John Hubbard, Timur Tabi,
rust-for-linux, linux-kernel, driver-core, dri-devel, nova-gpu,
Lorenzo Delgado
`ResourceSize` was a bare type alias for `resource_size_t`, so it
inherited every integer operation and `as` cast. That silently permits
operations that are meaningless for the size of a hardware resource:
mixing it with unrelated integers and truncating casts.
Wrap it in a `#[repr(transparent)]` newtype so each conversion at a
boundary becomes explicit and reviewable. The representation is
unchanged, so this is ABI-identical; only the spelling at the FFI
boundary changes. Provide the minimal conversion surface the call sites
need: `from_raw`/`into_raw`, `From` in both directions, and a fallible
`TryFrom<ResourceSize> for usize` for the page-count site that can
truncate on 32-bit. Update the two producers, `Resource::size` and
`SGEntry::dma_len`, and the `request_region` and nova-core consumers so
the tree builds green. Add doctest examples for the new type.
Suggested-by: Miguel Ojeda <ojeda@kernel.org>
Link: https://github.com/Rust-for-Linux/linux/issues/1203
Signed-off-by: Lorenzo Delgado <lnsdev@proton.me>
---
An earlier attempt at this conversion was posted by Moritz Zielke [1]. This
is a fresh, independent implementation that reuses none of that code; it
additionally converts the nova-core consumer and adds doctest examples.
[1] https://lore.kernel.org/all/20251203-res-size-newtype-v1-1-22ed0b8a7a18@gmail.com/
drivers/gpu/nova-core/firmware/gsp.rs | 2 +-
rust/kernel/io.rs | 73 +++++++++++++++++++++++++--
rust/kernel/io/resource.rs | 6 +--
rust/kernel/scatterlist.rs | 2 +-
4 files changed, 74 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs
index 99a302bae567..d7593888e65b 100644
--- a/drivers/gpu/nova-core/firmware/gsp.rs
+++ b/drivers/gpu/nova-core/firmware/gsp.rs
@@ -175,7 +175,7 @@ pub(crate) fn radix3_dma_handle(&self) -> DmaAddress {
fn map_into_lvl(sg_table: &SGTable<Owned<VVec<u8>>>, mut dst: VVec<u8>) -> Result<VVec<u8>> {
for sg_entry in sg_table.iter() {
// Number of pages we need to map.
- let num_pages = usize::from_safe_cast(sg_entry.dma_len()).div_ceil(GSP_PAGE_SIZE);
+ let num_pages = usize::try_from(sg_entry.dma_len())?.div_ceil(GSP_PAGE_SIZE);
for i in 0..num_pages {
let entry = sg_entry.dma_address()
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index fcc7678fd9e3..ebf00b4536d6 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -6,9 +6,12 @@
use crate::{
bindings,
+ fmt,
prelude::*, //
};
+use core::num::TryFromIntError;
+
pub mod mem;
pub mod poll;
pub mod register;
@@ -25,11 +28,73 @@
/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures.
pub type PhysAddr = bindings::phys_addr_t;
-/// Resource Size type.
+/// Resource size type.
///
-/// This is a type alias to either `u32` or `u64` depending on the config option
-/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures.
-pub type ResourceSize = bindings::resource_size_t;
+/// This wraps either `u32` or `u64` depending on the config option
+/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a `u64` even on 32-bit architectures.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::io::ResourceSize;
+///
+/// let size = ResourceSize::from_raw(0x1000);
+/// assert_eq!(size.into_raw(), 0x1000);
+///
+/// // Round-trips through the raw C type.
+/// let raw: kernel::bindings::resource_size_t = size.into();
+/// assert_eq!(ResourceSize::from(raw), size);
+///
+/// // Fallible conversion to `usize` (can truncate on 32-bit).
+/// assert_eq!(usize::try_from(size)?, 0x1000);
+/// # Ok::<(), core::num::TryFromIntError>(())
+/// ```
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct ResourceSize(bindings::resource_size_t);
+
+impl ResourceSize {
+ /// Creates a resource size from the raw C type.
+ #[inline]
+ pub const fn from_raw(value: bindings::resource_size_t) -> Self {
+ Self(value)
+ }
+
+ /// Turns this resource size into the raw C type.
+ #[inline]
+ pub const fn into_raw(self) -> bindings::resource_size_t {
+ self.0
+ }
+}
+
+impl fmt::Debug for ResourceSize {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:#x}", self.0)
+ }
+}
+
+impl From<bindings::resource_size_t> for ResourceSize {
+ #[inline]
+ fn from(value: bindings::resource_size_t) -> Self {
+ Self::from_raw(value)
+ }
+}
+
+impl From<ResourceSize> for bindings::resource_size_t {
+ #[inline]
+ fn from(value: ResourceSize) -> Self {
+ value.into_raw()
+ }
+}
+
+impl TryFrom<ResourceSize> for usize {
+ type Error = TryFromIntError;
+
+ #[inline]
+ fn try_from(value: ResourceSize) -> Result<Self, Self::Error> {
+ Self::try_from(value.into_raw())
+ }
+}
/// Raw representation of an MMIO region.
///
diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs
index 17b0c174cfc5..a33a416b289a 100644
--- a/rust/kernel/io/resource.rs
+++ b/rust/kernel/io/resource.rs
@@ -58,7 +58,7 @@ fn drop(&mut self) {
};
// SAFETY: Safe as per the invariant of `Region`.
- unsafe { release_fn(start, size) };
+ unsafe { release_fn(start, size.into_raw()) };
}
}
@@ -114,7 +114,7 @@ pub fn request_region(
bindings::__request_region(
self.0.get(),
start,
- size,
+ size.into_raw(),
name.as_char_ptr(),
flags.0 as c_int,
)
@@ -130,7 +130,7 @@ pub fn request_region(
pub fn size(&self) -> ResourceSize {
let inner = self.0.get();
// SAFETY: Safe as per the invariants of `Resource`.
- unsafe { bindings::resource_size(inner) }
+ ResourceSize::from_raw(unsafe { bindings::resource_size(inner) })
}
/// Returns the start address of the resource.
diff --git a/rust/kernel/scatterlist.rs b/rust/kernel/scatterlist.rs
index b83c468b5c63..5d67242befd8 100644
--- a/rust/kernel/scatterlist.rs
+++ b/rust/kernel/scatterlist.rs
@@ -93,7 +93,7 @@ pub fn dma_address(&self) -> dma::DmaAddress {
pub fn dma_len(&self) -> ResourceSize {
#[allow(clippy::useless_conversion)]
// SAFETY: `self.as_raw()` is a valid pointer to a `struct scatterlist`.
- unsafe { bindings::sg_dma_len(self.as_raw()) }.into()
+ ResourceSize::from_raw(unsafe { bindings::sg_dma_len(self.as_raw()) }.into())
}
}
base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
--
2.54.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] rust: io: convert ResourceSize into a transparent newtype
2026-07-12 11:36 [PATCH] rust: io: convert ResourceSize into a transparent newtype Lorenzo Delgado
@ 2026-07-16 21:45 ` Danilo Krummrich
0 siblings, 0 replies; 2+ messages in thread
From: Danilo Krummrich @ 2026-07-16 21:45 UTC (permalink / raw)
To: Lorenzo Delgado, Miguel Ojeda
Cc: Alice Ryhl, Daniel Almeida, Alexandre Courbot, David Airlie,
Simona Vetter, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Trevor Gross, Tamir Duberstein,
Onur Özkan, Abdiel Janulgue, Robin Murphy, John Hubbard,
Timur Tabi, rust-for-linux, linux-kernel, driver-core, dri-devel,
nova-gpu
On Sun Jul 12, 2026 at 1:36 PM CEST, Lorenzo Delgado wrote:
> diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs
> index 99a302bae567..d7593888e65b 100644
> --- a/drivers/gpu/nova-core/firmware/gsp.rs
> +++ b/drivers/gpu/nova-core/firmware/gsp.rs
> @@ -175,7 +175,7 @@ pub(crate) fn radix3_dma_handle(&self) -> DmaAddress {
> fn map_into_lvl(sg_table: &SGTable<Owned<VVec<u8>>>, mut dst: VVec<u8>) -> Result<VVec<u8>> {
> for sg_entry in sg_table.iter() {
> // Number of pages we need to map.
> - let num_pages = usize::from_safe_cast(sg_entry.dma_len()).div_ceil(GSP_PAGE_SIZE);
> + let num_pages = usize::try_from(sg_entry.dma_len())?.div_ceil(GSP_PAGE_SIZE);
I think this is worse, as the conversion becomes fallible.
You could implement From<ResourceSize> for u64 and then keep using
usize::from_safe_cast() in nova-core.
Alternatively, we could also consider moving the FromSafeCast trait to
rust/kernel/num.rs and add FromSafeCast<ResourceSize> impls for usize.
I originally proposed the approach [1], since in nova-core we had a lot of
fallible conversion, while our Kconfig mandates that they can never actually
fail.
However, by making it commonly availble I do see a risk with the cfg-gated impls
silently breaking the build.
Now, technically that's the feature and 0-day etc. should usually catch it, but
on the other hand we also usually try to avoid cfg-gates in the kernel.
Miguel, I think you were in favor of this as well, what do you think?
[1] https://lore.kernel.org/rust-for-linux/DDK4KADWJHMG.1FUPL3SDR26XF@kernel.org/
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-16 21:45 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-12 11:36 [PATCH] rust: io: convert ResourceSize into a transparent newtype Lorenzo Delgado
2026-07-16 21:45 ` Danilo Krummrich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox