[PATCH v2 26/83] block: rust: change sector type from usize to u64

From: Andreas Hindborg

Date: Tue Jun 09 2026 - 15:30:33 EST


Change the `sector()` and `sectors()` methods in `Request` to return
`u64` and `u32` respectively instead of `usize`. This matches the
underlying kernel types.

Update rnull driver to handle the new sector types with appropriate
casting throughout the read, write, and discard operations.

Signed-off-by: Andreas Hindborg <a.hindborg@xxxxxxxxxx>
---
drivers/block/rnull/rnull.rs | 71 +++++++++++++++++++++++++----------------
rust/kernel/block/mq/request.rs | 8 ++---
2 files changed, 47 insertions(+), 32 deletions(-)

diff --git a/drivers/block/rnull/rnull.rs b/drivers/block/rnull/rnull.rs
index cb5b642f68e5..73f14d6e379f 100644
--- a/drivers/block/rnull/rnull.rs
+++ b/drivers/block/rnull/rnull.rs
@@ -218,6 +218,13 @@ fn new(options: NullBlkOptions<'_>) -> Result<GenDisk<Self>> {
kernel::alloc::NumaNode::new(home_node)?
};

+ let capacity_sectors = capacity_mib << (20 - block::SECTOR_SHIFT);
+
+ // Prevent overflow in usize/u64 casts
+ if usize::BITS == 32 && capacity_sectors > u32::MAX.into() {
+ return Err(code::EINVAL);
+ }
+
let tagset = Arc::pin_init(
TagSet::new(submit_queues, 256, 1, numa_node, flags),
GFP_KERNEL,
@@ -229,13 +236,13 @@ fn new(options: NullBlkOptions<'_>) -> Result<GenDisk<Self>> {
irq_mode,
completion_time,
memory_backed,
- block_size: block_size as usize,
+ block_size: block_size.into(),
}),
GFP_KERNEL,
)?;

let mut builder = gen_disk::GenDiskBuilder::new()
- .capacity_sectors(capacity_mib << (20 - block::SECTOR_SHIFT))
+ .capacity_sectors(capacity_sectors)
.logical_block_size(block_size)?
.physical_block_size(block_size)?
.rotational(rotational);
@@ -250,12 +257,13 @@ fn new(options: NullBlkOptions<'_>) -> Result<GenDisk<Self>> {
}

#[inline(always)]
- fn write(tree: &XArray<TreeNode>, mut sector: usize, mut segment: Segment<'_>) -> Result {
+ fn write(tree: &XArray<TreeNode>, mut sector: u64, mut segment: Segment<'_>) -> Result {
while !segment.is_empty() {
let page = NullBlockPage::new()?;
let mut tree = tree.lock();

- let page_idx = sector >> block::PAGE_SECTORS_SHIFT;
+ // CAST: Device size limited during setup to (2^32)-1 on 32 bit systems.
+ let page_idx = (sector >> block::PAGE_SECTORS_SHIFT) as usize;

let page = if let Some(page) = tree.get_mut(page_idx) {
page
@@ -265,43 +273,50 @@ fn write(tree: &XArray<TreeNode>, mut sector: usize, mut segment: Segment<'_>) -
};

page.set_occupied(sector);
- let page_offset = (sector & block::PAGE_SECTOR_MASK as usize) << block::SECTOR_SHIFT;
- sector +=
- segment.copy_to_page(page.page.as_pin_mut(), page_offset) >> block::SECTOR_SHIFT;
+
+ // CAST: Page offset always fits in 32 bits.
+ let page_offset =
+ ((sector & u64::from(block::PAGE_SECTOR_MASK)) << block::SECTOR_SHIFT) as usize;
+
+ // CAST: Casting from `usize` to `u64` never overflows.
+ sector += segment.copy_to_page(page.page.as_pin_mut(), page_offset) as u64
+ >> block::SECTOR_SHIFT;
}
Ok(())
}

#[inline(always)]
- fn read(tree: &XArray<TreeNode>, mut sector: usize, mut segment: Segment<'_>) -> Result {
+ fn read(tree: &XArray<TreeNode>, mut sector: u64, mut segment: Segment<'_>) -> Result {
let tree = tree.lock();

while !segment.is_empty() {
- let idx = sector >> block::PAGE_SECTORS_SHIFT;
+ // CAST: Device size limited during setup to (2^32)-1 on 32 bit systems.
+ let page_idx = (sector >> block::PAGE_SECTORS_SHIFT) as usize;

- if let Some(page) = tree.get(idx) {
+ if let Some(page) = tree.get(page_idx) {
+ // CAST: Page offset always fits in 32 bits.
let page_offset =
- (sector & block::PAGE_SECTOR_MASK as usize) << block::SECTOR_SHIFT;
- sector += segment.copy_from_page(&page.page, page_offset) >> block::SECTOR_SHIFT;
+ ((sector & u64::from(block::PAGE_SECTOR_MASK)) << block::SECTOR_SHIFT) as usize;
+
+ // CAST: Casting from `usize` to `u64` never overflows.
+ sector +=
+ segment.copy_from_page(&page.page, page_offset) as u64 >> block::SECTOR_SHIFT;
} else {
- sector += segment.zero_page() >> block::SECTOR_SHIFT;
+ // CAST: Casting from `usize` to `u64` never overflows.
+ sector += segment.zero_page() as u64 >> block::SECTOR_SHIFT;
}
}

Ok(())
}

- fn discard(
- tree: &XArray<TreeNode>,
- mut sector: usize,
- sectors: usize,
- block_size: usize,
- ) -> Result {
+ fn discard(tree: &XArray<TreeNode>, mut sector: u64, sectors: u64, block_size: u64) -> Result {
let mut remaining_bytes = sectors << SECTOR_SHIFT;
let mut tree = tree.lock();

while remaining_bytes > 0 {
- let page_idx = sector >> block::PAGE_SECTORS_SHIFT;
+ // CAST: Device size limited during setup to (2^32)-1 on 32 bit systems.
+ let page_idx = (sector >> block::PAGE_SECTORS_SHIFT) as usize;
let mut remove = false;
if let Some(page) = tree.get_mut(page_idx) {
page.set_free(sector);
@@ -326,7 +341,7 @@ fn discard(
fn transfer(
command: bindings::req_op,
tree: &XArray<TreeNode>,
- sector: usize,
+ sector: u64,
segment: Segment<'_>,
) -> Result {
match command {
@@ -356,13 +371,13 @@ fn new() -> Result<KBox<Self>> {
)?)
}

- fn set_occupied(&mut self, sector: usize) {
- let idx = sector & PAGE_SECTOR_MASK as usize;
+ fn set_occupied(&mut self, sector: u64) {
+ let idx = sector & u64::from(PAGE_SECTOR_MASK);
self.status |= 1 << idx;
}

- fn set_free(&mut self, sector: usize) {
- let idx = sector & PAGE_SECTOR_MASK as usize;
+ fn set_free(&mut self, sector: u64) {
+ let idx = sector & u64::from(PAGE_SECTOR_MASK);
self.status &= !(1 << idx);
}

@@ -380,7 +395,7 @@ struct QueueData {
irq_mode: IRQMode,
completion_time: Delta,
memory_backed: bool,
- block_size: usize,
+ block_size: u64,
}

#[pin_data]
@@ -432,14 +447,14 @@ fn queue_rq(
let mut sector = rq.sector();

if command == bindings::req_op_REQ_OP_DISCARD {
- Self::discard(tree, sector, rq.sectors(), queue_data.block_size)?;
+ Self::discard(tree, sector, rq.sectors().into(), queue_data.block_size)?;
} else {
for bio in rq.bio_iter_mut() {
let segment_iter = bio.segment_iter();
for segment in segment_iter {
let length = segment.len();
Self::transfer(command, tree, sector, segment)?;
- sector += length as usize >> block::SECTOR_SHIFT;
+ sector += u64::from(length) >> block::SECTOR_SHIFT;
}
}
}
diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request.rs
index 54fe580b7b42..9e176f015ab8 100644
--- a/rust/kernel/block/mq/request.rs
+++ b/rust/kernel/block/mq/request.rs
@@ -178,16 +178,16 @@ pub fn bio_iter_mut<'a>(self: &'a mut Owned<Self>) -> BioIterator<'a> {

/// Get the target sector for the request.
#[inline(always)]
- pub fn sector(&self) -> usize {
+ pub fn sector(&self) -> u64 {
// SAFETY: By type invariant of `Self`, `self.0` is valid and live.
- unsafe { (*self.0.get()).__sector as usize }
+ unsafe { (*self.0.get()).__sector }
}

/// Get the size of the request in number of sectors.
#[inline(always)]
- pub fn sectors(&self) -> usize {
+ pub fn sectors(&self) -> u32 {
// SAFETY: By type invariant of `Self`, `self.0` is valid and live.
- (unsafe { (*self.0.get()).__data_len as usize }) >> crate::block::SECTOR_SHIFT
+ (unsafe { (*self.0.get()).__data_len }) >> crate::block::SECTOR_SHIFT
}

/// Return a pointer to the [`RequestDataWrapper`] stored in the private area

--
2.51.2