[PATCH 37/79] block: rust: introduce `kernel::block::error`

Andreas Hindborg
2026-02-15T23:45:35Z

Block layer status codes, represented by `blk_status_t`, are only one
byte. This is different from the general kernel error codes.

Add `BlkError` and `BlkResult` to handle these status codes.

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/block.rs | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++
rust/kernel/error.rs | 3 +-
2 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/block.rs b/rust/kernel/block.rs
index 19236ab95227b..6cd83dc75a5eb 100644
--- a/rust/kernel/block.rs
+++ b/rust/kernel/block.rs
@@ -18,3 +18,97 @@
/// The difference between the size of a page and the size of a sector,
/// expressed as a power of two.
pub const PAGE_SECTORS_SHIFT: u32 = bindings::PAGE_SECTORS_SHIFT;
+
+pub mod error {
+ //! Block layer errors.
+
+ use core::num::NonZeroU8;
+
+ pub mod code {
+ //! C compatible error codes for the block subsystem.
+ macro_rules! declare_err {
+ ($err:tt $(,)? $($doc:expr),+) => {
+ $(
+ #[doc = $doc]
+ )*
+ pub const $err: super::BlkError =
+ match super::BlkError::try_from_blk_status(crate::bindings::$err as u8) {
+ Some(err) => err,
+ None => panic!("Invalid errno in `declare_err!`"),
+ };
+ };
+ }
+
+ declare_err!(BLK_STS_NOTSUPP, "Operation not supported.");
+ declare_err!(BLK_STS_IOERR, "Generic IO error.");
+ declare_err!(BLK_STS_DEV_RESOURCE, "Device resource busy. Retry later.");
+ }
+
+ /// A wrapper around a 1 byte block layer error code.
+ #[derive(Clone, Copy, PartialEq, Eq)]
+ pub struct BlkError(NonZeroU8);
+
+ impl BlkError {
+ /// Create a [`BlkError`] from a `blk_status_t`.
+ ///
+ /// If the code is not know, this function will warn and return [`code::BLK_STS_IOERR`].
+ pub fn from_blk_status(status: bindings::blk_status_t) -> Self {
+ if let Some(error) = Self::try_from_blk_status(status) {
+ error
+ } else {
+ kernel::pr_warn!("Attempted to create `BlkError` from invalid value");
+ code::BLK_STS_IOERR
+ }
+ }
+
+ /// Convert `Self` to the underlying type.
+ pub fn to_blk_status(self) -> bindings::blk_status_t {
+ self.0.into()
+ }
+
+ /// Try to create a `Self` form a `blk_status_t`.
+ ///
+ /// Returns `None` if the conversion fails.
+ const fn try_from_blk_status(errno: bindings::blk_status_t) -> Option<Self> {
+ if errno == 0 {
+ None
+ } else {
+ Some(BlkError(
+ // SAFETY: We just checked that `errno`is nonzero.
+ unsafe { NonZeroU8::new_unchecked(errno) },
+ ))
+ }
+ }
+ }
+
+ impl From<BlkError> for u8 {
+ fn from(value: BlkError) -> Self {
+ value.0.into()
+ }
+ }
+
+ impl From<BlkError> for u32 {
+ fn from(value: BlkError) -> Self {
+ let value: u8 = value.0.into();
+ value.into()
+ }
+ }
+
+ impl From<kernel::error::Error> for BlkError {
+ fn from(_value: kernel::error::Error) -> Self {
+ code::BLK_STS_IOERR
+ }
+ }
+
+ /// A result with a [`BlkError`] error type.
+ pub type BlkResult<T = ()> = Result<T, BlkError>;
+
+ /// Convert a `blk_status_t` to a `BlkResult`.
+ pub fn to_result(status: bindings::blk_status_t) -> BlkResult {
+ if status == bindings::BLK_STS_OK {
+ Ok(())
+ } else {
+ Err(BlkError::from_blk_status(status))
+ }
+ }
+}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 258b12afdcba3..e656465010d6c 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -162,8 +162,9 @@ pub fn to_errno(self) -> crate::ffi::c_int {
self.0.get()
}

+ /// Convert a generic kernel error to a block layer error.
#[cfg(CONFIG_BLOCK)]
- pub(crate) fn to_blk_status(self) -> bindings::blk_status_t {
+ pub fn to_blk_status(self) -> bindings::blk_status_t {
// SAFETY: `self.0` is a valid error due to its invariant.
unsafe { bindings::errno_to_blk_status(self.0.get()) }
}

--
2.51.2