[PATCH v6 12/20] rust: io: move `Io` methods to extension trait
From: Gary Guo
Date: Mon Jul 06 2026 - 08:54:59 EST
`Io` trait now has a single required method with many more provided
methods. Provided methods may want to rely on their implementations to not
be arbitrarily overridden by implementers for correctness or soundness.
A good example is the `size` method, it may be relied by unsafe code and
thus must be consistent with the metadata obtained from `as_ptr`.
Thus, create a new trait to host `size` method, extract existing provided
methods to the new trait, and provide a blanket implementation. This
pattern is used extensively in userspace Rust libraries e.g. `tokio` where
`AsyncRead` has minimum methods and `AsyncReadExt` is what users mostly
interact with.
To avoid changing all user imports, the base trait is renamed to `IoBase`
and the newly added trait takes the existing `Io` name.
Reviewed-by: Alexandre Courbot <acourbot@xxxxxxxxxx>
Suggested-by: Danilo Krummrich <dakr@xxxxxxxxxx>
Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
---
rust/kernel/devres.rs | 3 ++-
rust/kernel/io.rs | 34 ++++++++++++++++++++++++----------
rust/kernel/io/mem.rs | 6 +++---
rust/kernel/pci/io.rs | 6 +++---
4 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 3545ffc5345d..6e0b845b229b 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -68,6 +68,7 @@ struct Inner<T> {
/// devres::Devres,
/// io::{
/// Io,
+/// IoBase,
/// Mmio,
/// MmioRaw,
/// MmioBackend,
@@ -105,7 +106,7 @@ struct Inner<T> {
/// }
/// }
///
-/// impl<'a, const SIZE: usize> Io<'a> for &'a IoMem<SIZE> {
+/// impl<'a, const SIZE: usize> IoBase<'a> for &'a IoMem<SIZE> {
/// type Backend = MmioBackend;
/// type Target = Region<SIZE>;
///
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index c7533d605678..ab970e8b2e78 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -223,7 +223,7 @@ fn io_view<'a, IO: Io<'a>, U>(
/// operation.
pub trait IoBackend {
/// View type for this I/O backend.
- type View<'a, T: ?Sized + KnownSize>: Io<'a, Backend = Self, Target = T>;
+ type View<'a, T: ?Sized + KnownSize>: IoBase<'a, Backend = Self, Target = T>;
/// Convert a `view` to a raw pointer for projection.
///
@@ -309,15 +309,12 @@ fn offset(self) -> usize {
/// Types implementing this trait (e.g. MMIO BARs or PCI config regions)
/// can perform I/O operations on regions of memory.
///
-/// The [`Io`] trait provides:
-/// - Method to convert into [`IoBackend::View`].
-/// - Helper methods for offset validation and address calculation
-/// - Fallible (runtime checked) accessors for different data widths
-///
-/// Which I/O methods are available depends on the associated [`IoBackend`] implementation.
+/// This trait defines which backend shall be used for I/O operations and provides a method to
+/// convert into [`IoBackend::View`]. Users should use the [`Io`] trait which provides the actual
+/// methods to perform I/O operations.
///
/// This should be implemented on cheaply copyable handles, such as references or view types.
-pub trait Io<'a>: Copy {
+pub trait IoBase<'a>: Copy {
/// Type that defines all I/O operations.
type Backend: IoBackend;
@@ -326,6 +323,21 @@ pub trait Io<'a>: Copy {
/// Return a view that covers the full region.
fn as_view(self) -> <Self::Backend as IoBackend>::View<'a, Self::Target>;
+}
+
+/// Extension trait to provide I/O operation methods to types that implement [`IoBase`].
+///
+/// This trait provides:
+/// - Helper methods for offset validation and address calculation
+/// - Fallible (runtime checked) accessors for different data widths
+///
+/// Which I/O methods are available depends on the associated [`IoBackend`] implementation.
+pub trait Io<'a>: IoBase<'a> {
+ /// Returns the size of this I/O region.
+ #[inline]
+ fn size(self) -> usize {
+ KnownSize::size(Self::Backend::as_ptr(self.as_view()))
+ }
/// Fallible 8-bit read with runtime bounds check.
#[inline(always)]
@@ -779,6 +791,8 @@ fn update<T, L, F>(self, location: L, f: F)
}
}
+impl<'a, T: IoBase<'a>> Io<'a> for T {}
+
/// A view of memory-mapped I/O region.
///
/// # Invariant
@@ -819,7 +833,7 @@ unsafe impl<T: ?Sized + Sync> Send for Mmio<'_, T> {}
// SAFETY: `Mmio<'_, T>` is conceptually `&T` but in I/O memory.
unsafe impl<T: ?Sized + Sync> Sync for Mmio<'_, T> {}
-impl<'a, T: ?Sized + KnownSize> Io<'a> for Mmio<'a, T> {
+impl<'a, T: ?Sized + KnownSize> IoBase<'a> for Mmio<'a, T> {
type Backend = MmioBackend;
type Target = T;
@@ -920,7 +934,7 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: ?Sized + KnownSize>(
}
}
-impl<'a, T: ?Sized + KnownSize> Io<'a> for RelaxedMmio<'a, T> {
+impl<'a, T: ?Sized + KnownSize> IoBase<'a> for RelaxedMmio<'a, T> {
type Backend = RelaxedMmioBackend;
type Target = T;
diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs
index d9b3189d09b4..e95b769ebe47 100644
--- a/rust/kernel/io/mem.rs
+++ b/rust/kernel/io/mem.rs
@@ -14,7 +14,7 @@
Region,
Resource, //
},
- Io,
+ IoBase,
Mmio,
MmioBackend,
MmioRaw, //
@@ -210,7 +210,7 @@ pub fn into_devres(self) -> Result<Devres<ExclusiveIoMem<'static, SIZE>>> {
}
}
-impl<'a, const SIZE: usize> Io<'a> for &'a ExclusiveIoMem<'_, SIZE> {
+impl<'a, const SIZE: usize> IoBase<'a> for &'a ExclusiveIoMem<'_, SIZE> {
type Backend = MmioBackend;
type Target = super::Region<SIZE>;
@@ -292,7 +292,7 @@ fn drop(&mut self) {
}
}
-impl<'a, const SIZE: usize> Io<'a> for &'a IoMem<'_, SIZE> {
+impl<'a, const SIZE: usize> IoBase<'a> for &'a IoMem<'_, SIZE> {
type Backend = MmioBackend;
type Target = super::Region<SIZE>;
diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs
index 4be33ecb4192..4d1d0afdc491 100644
--- a/rust/kernel/pci/io.rs
+++ b/rust/kernel/pci/io.rs
@@ -8,8 +8,8 @@
device,
devres::Devres,
io::{
- Io,
IoBackend,
+ IoBase,
IoCapable,
Mmio,
MmioBackend,
@@ -144,7 +144,7 @@ fn io_write(view: ConfigSpace<'_, $ty>, value: $ty) {
impl_config_space_io_capable!(u16, pci_read_config_word, pci_write_config_word);
impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config_dword);
-impl<'a, T: ?Sized + KnownSize> Io<'a> for ConfigSpace<'a, T> {
+impl<'a, T: ?Sized + KnownSize> IoBase<'a> for ConfigSpace<'a, T> {
type Backend = ConfigSpaceBackend;
type Target = T;
@@ -267,7 +267,7 @@ fn drop(&mut self) {
}
}
-impl<'a, const SIZE: usize> Io<'a> for &'a Bar<'_, SIZE> {
+impl<'a, const SIZE: usize> IoBase<'a> for &'a Bar<'_, SIZE> {
type Backend = MmioBackend;
type Target = crate::io::Region<SIZE>;
--
2.54.0