Re: [PATCH v4 01/20] rust: io: add dynamically-sized `Region` type

From: Gary Guo

Date: Mon Jun 15 2026 - 06:05:29 EST


On Mon Jun 15, 2026 at 5:03 AM BST, Alexandre Courbot wrote:
> On Fri Jun 12, 2026 at 1:28 AM JST, Gary Guo wrote:
>> Currently many I/O related structs carry a `SIZE` parameter to denote the
>> minimum size of the I/O region, while they also carry a field indicating
>> the actual size. Proliferation of the pattern creates a lot of duplicated
>> code, and makes it hard to create typed views of I/O.
>>
>> Introduce a `Region` type that carries the `SIZE` parameter. It is a
>> wrapper of `[u8]`, which makes it dynamically sized with a metadata of
>> `usize`. This way, pointers to `Region` naturally carry size information.
>> This type is required to be 4-byte aligned.
>>
>> Expose the minimum size information via `MIN_SIZE` constant of the
>> `KnownSize` trait. Similarly, expose the minimum alignment information via
>> `KnownSize::MIN_ALIGN`.
>>
>> With these changes, it is possible to add an associated type to `Io` trait
>> to represent the type of I/O region. For untyped regions, this is the newly
>> added `Region` type. Remove `IoKnownSize` as it is no longer necessary. Use
>> the same mechanism to indicate minimum size of PCI config spaces.
>>
>> Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
>> ---
>> rust/kernel/devres.rs | 6 +--
>> rust/kernel/io.rs | 130 +++++++++++++++++++++++++++++++++-----------------
>> rust/kernel/lib.rs | 3 ++
>> rust/kernel/pci.rs | 1 -
>> rust/kernel/pci/io.rs | 40 +++++++---------
>> rust/kernel/ptr.rs | 12 +++++
>> 6 files changed, 118 insertions(+), 74 deletions(-)
>>
>> diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
>> index 11ce500e9b76..ed30ccc6e68e 100644
>> --- a/rust/kernel/devres.rs
>> +++ b/rust/kernel/devres.rs
>> @@ -68,7 +68,6 @@ struct Inner<T> {
>> /// devres::Devres,
>> /// io::{
>> /// Io,
>> -/// IoKnownSize,
>> /// Mmio,
>> /// MmioRaw,
>> /// PhysAddr, //
>> @@ -297,10 +296,7 @@ pub fn device(&self) -> &Device {
>> /// use kernel::{
>> /// device::Core,
>> /// devres::Devres,
>> - /// io::{
>> - /// Io,
>> - /// IoKnownSize, //
>> - /// },
>> + /// io::Io,
>> /// pci, //
>> /// };
>> ///
>> diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
>> index fcc7678fd9e3..bef571dad6eb 100644
>> --- a/rust/kernel/io.rs
>> +++ b/rust/kernel/io.rs
>> @@ -6,7 +6,11 @@
>>
>> use crate::{
>> bindings,
>> - prelude::*, //
>> + prelude::*,
>> + ptr::{
>> + Alignment,
>> + KnownSize, //
>> + }, //
>> };
>>
>> pub mod mem;
>> @@ -31,6 +35,58 @@
>> /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures.
>> pub type ResourceSize = bindings::resource_size_t;
>>
>> +/// Untyped I/O region.
>> +///
>> +/// This type can be used when an I/O region without known type information has a compile-time known
>> +/// minimum size (and a runtime known actual size).
>> +///
>> +/// This must be 4-byte aligned.
>> +///
>> +/// # Invariants
>> +///
>> +/// Size of the region is at least as large as the `SIZE` generic parameter.
>
> I noticed that patch 13 adds the "size must be multiple of 4" invariant.
> The doccomment for `ptr_from_raw_parts_mut` says that "size should be
> 4-bytes aligned" though, which sounds like the same to me. So should
> that second invariant be introduced in this patch instead of patch 13?

Oops, I think this is a bad `git absorb` operation that I didn't checked
carefully.

>
>> +#[repr(C, align(4))]
>> +pub struct Region<const SIZE: usize = 0> {
>> + inner: [u8],
>> +}
>> +
>> +impl<const SIZE: usize> Region<SIZE> {
>> + /// Create a raw mutable pointer from given base address and size.
>> + ///
>> + /// `size` should be at least as large as the minimum size `SIZE`, and `base` and `size` should
>> + /// be 4-byte aligned to uphold the type invariant.
>
> s/should/must? I guess we are running into all sort of issues if we
> create regions which runtime size is smaller than the compile-time one,
> and this is an invariant of `Region` itself.
>
> Maybe this method should even be made `unsafe` for this reason? The
> caller will need to write a `SAFETY` comment before dereferencing the
> pointer, but IIUC this comment is bound to cover the pointer invariants,
> not necessarily those of `Region`. Making the method `unsafe` would
> force the user to cover them here.

Note that the function implementation is completely safe, and it can be done
outside the module, too.

Thus, the real constraint is that user doing raw pointer needs to be careful.
This is true for all pointers. You can safely cast between any raw pointers, and
dereference requires you to uphold the invariant of target type. This is true
for all types with invariants, you can do

*core::ptr::from_ref(&0).cast::<NonZero<u8>>()

And the unsafe part is the dereference, not the cast.

Best,
Gary