Skip to content

Commit 70a5b2d

Browse files
committed
Rust: Use a tighter inner type for Error
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]>
1 parent bfe9ec6 commit 70a5b2d

File tree

1 file changed

+37
-19
lines changed

1 file changed

+37
-19
lines changed

rust/kernel/error.rs

+37-19
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{bindings, c_types};
99
use alloc::{alloc::AllocError, collections::TryReserveError};
1010
use core::convert::From;
1111
use core::fmt;
12-
use core::num::TryFromIntError;
12+
use core::num::{NonZeroI16, TryFromIntError};
1313
use core::str::{self, Utf8Error};
1414

1515
/// Generic integer kernel error.
@@ -21,44 +21,55 @@ use core::str::{self, Utf8Error};
2121
///
2222
/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
2323
#[derive(Clone, Copy, PartialEq, Eq)]
24-
pub struct Error(c_types::c_int);
24+
pub struct Error(NonZeroI16);
25+
26+
/// DO NOT use this macro outside of Error const initializations.
27+
///
28+
/// # Safety
29+
///
30+
/// The parameter must be a valid kernel error number.
31+
macro_rules! kernel_const_to_error {
32+
($($tt:tt)*) => {{
33+
Error(unsafe {NonZeroI16::new_unchecked(-($($tt)* as i16))})
34+
}};
35+
}
2536

2637
impl Error {
2738
/// Invalid argument.
28-
pub const EINVAL: Self = Error(-(bindings::EINVAL as i32));
39+
pub const EINVAL: Self = kernel_const_to_error!(bindings::EINVAL);
2940

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

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

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

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

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

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

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

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

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

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

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

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

7788
// INVARIANT: the check above ensures the type invariant
7889
// will hold.
79-
Error(errno)
90+
let nzi16_errno = NonZeroI16::new(errno as i16).unwrap();
91+
Error(nzi16_errno)
8092
}
8193

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

93108
/// Returns the kernel error code.
94109
pub fn to_kernel_errno(self) -> c_types::c_int {
95-
self.0
110+
self.0.get().into()
96111
}
97112
}
98113

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

107122
if name.is_null() {
108123
// Print out number if no name can be found.
109-
return f.debug_tuple("Error").field(&-self.0).finish();
124+
return f
125+
.debug_tuple("Error")
126+
.field(&-self.to_kernel_errno())
127+
.finish();
110128
}
111129

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

0 commit comments

Comments
 (0)