Skip to content

Commit

Permalink
Rust: Use a tighter inner type for Error
Browse files Browse the repository at this point in the history
Use NonZeroI16 as the inner type. This allows Result<()> to fit in
16-bit, instead of 64-bit.

Signed-off-by: Fox Chen <[email protected]>
  • Loading branch information
foxhlchen committed Jun 5, 2021
1 parent bfe9ec6 commit 70a5b2d
Showing 1 changed file with 37 additions and 19 deletions.
56 changes: 37 additions & 19 deletions rust/kernel/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{bindings, c_types};
use alloc::{alloc::AllocError, collections::TryReserveError};
use core::convert::From;
use core::fmt;
use core::num::TryFromIntError;
use core::num::{NonZeroI16, TryFromIntError};
use core::str::{self, Utf8Error};

/// Generic integer kernel error.
Expand All @@ -21,44 +21,55 @@ use core::str::{self, Utf8Error};
///
/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Error(c_types::c_int);
pub struct Error(NonZeroI16);

/// DO NOT use this macro outside of Error const initializations.
///
/// # Safety
///
/// The parameter must be a valid kernel error number.
macro_rules! kernel_const_to_error {
($($tt:tt)*) => {{
Error(unsafe {NonZeroI16::new_unchecked(-($($tt)* as i16))})
}};
}

impl Error {
/// Invalid argument.
pub const EINVAL: Self = Error(-(bindings::EINVAL as i32));
pub const EINVAL: Self = kernel_const_to_error!(bindings::EINVAL);

/// Out of memory.
pub const ENOMEM: Self = Error(-(bindings::ENOMEM as i32));
pub const ENOMEM: Self = kernel_const_to_error!(bindings::ENOMEM);

/// Bad address.
pub const EFAULT: Self = Error(-(bindings::EFAULT as i32));
pub const EFAULT: Self = kernel_const_to_error!(bindings::EFAULT);

/// Illegal seek.
pub const ESPIPE: Self = Error(-(bindings::ESPIPE as i32));
pub const ESPIPE: Self = kernel_const_to_error!(bindings::ESPIPE);

/// Try again.
pub const EAGAIN: Self = Error(-(bindings::EAGAIN as i32));
pub const EAGAIN: Self = kernel_const_to_error!(bindings::EAGAIN);

/// Device or resource busy.
pub const EBUSY: Self = Error(-(bindings::EBUSY as i32));
pub const EBUSY: Self = kernel_const_to_error!(bindings::EBUSY);

/// Restart the system call.
pub const ERESTARTSYS: Self = Error(-(bindings::ERESTARTSYS as i32));
pub const ERESTARTSYS: Self = kernel_const_to_error!(bindings::ERESTARTSYS);

/// Operation not permitted.
pub const EPERM: Self = Error(-(bindings::EPERM as i32));
pub const EPERM: Self = kernel_const_to_error!(bindings::EPERM);

/// No such process.
pub const ESRCH: Self = Error(-(bindings::ESRCH as i32));
pub const ESRCH: Self = kernel_const_to_error!(bindings::ESRCH);

/// No such file or directory.
pub const ENOENT: Self = Error(-(bindings::ENOENT as i32));
pub const ENOENT: Self = kernel_const_to_error!(bindings::ENOENT);

/// Interrupted system call.
pub const EINTR: Self = Error(-(bindings::EINTR as i32));
pub const EINTR: Self = kernel_const_to_error!(bindings::EINTR);

/// Bad file number.
pub const EBADF: Self = Error(-(bindings::EBADF as i32));
pub const EBADF: Self = kernel_const_to_error!(bindings::EBADF);

/// Creates an [`Error`] from a kernel error code.
///
Expand All @@ -76,7 +87,8 @@ impl Error {

// INVARIANT: the check above ensures the type invariant
// will hold.
Error(errno)
let nzi16_errno = NonZeroI16::new(errno as i16).unwrap();
Error(nzi16_errno)
}

/// Creates an [`Error`] from a kernel error code.
Expand All @@ -87,12 +99,15 @@ impl Error {
pub(crate) unsafe fn from_kernel_errno_unchecked(errno: c_types::c_int) -> Error {
// INVARIANT: the contract ensures the type invariant
// will hold.
Error(errno)
//
// Safety: `errno` must not be zero, which is guaranteed by the contract
// of this function.
Error(unsafe { NonZeroI16::new_unchecked(errno as i16) })
}

/// Returns the kernel error code.
pub fn to_kernel_errno(self) -> c_types::c_int {
self.0
self.0.get().into()
}
}

Expand All @@ -102,11 +117,14 @@ impl fmt::Debug for Error {
fn rust_helper_errname(err: c_types::c_int) -> *const c_types::c_char;
}
// SAFETY: FFI call.
let name = unsafe { rust_helper_errname(-self.0) };
let name = unsafe { rust_helper_errname(-self.to_kernel_errno()) };

if name.is_null() {
// Print out number if no name can be found.
return f.debug_tuple("Error").field(&-self.0).finish();
return f
.debug_tuple("Error")
.field(&-self.to_kernel_errno())
.finish();
}

// SAFETY: `'static` string from C, and is not NULL.
Expand Down

0 comments on commit 70a5b2d

Please sign in to comment.