Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c9b5ce6

Browse files
felipeaggerojeda
authored andcommittedOct 7, 2024
rust: error: optimize error type to use nonzero
Optimize `Result<(), Error>` size by changing `Error` type to `NonZero*` for niche optimization. This reduces the space used by the `Result` type, as the `NonZero*` type enables the compiler to apply more efficient memory layout. For example, the `Result<(), Error>` changes size from 8 to 4 bytes. Link: #1120 Signed-off-by: Filipe Xavier <felipe_life@live.com> Reviewed-by: Gary Guo <gary@garyguo.net> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Fiona Behrens <me@kloenk.dev> Link: https://lore.kernel.org/r/BL0PR02MB4914B9B088865CF237731207E9732@BL0PR02MB4914.namprd02.prod.outlook.com [ Removed unneeded block around `match`, added backticks in panic message and added intra-doc link. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent 6f56651 commit c9b5ce6

File tree

1 file changed

+28
-9
lines changed

1 file changed

+28
-9
lines changed
 

‎rust/kernel/error.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{alloc::AllocError, str::CStr};
99
use alloc::alloc::LayoutError;
1010

1111
use core::fmt;
12+
use core::num::NonZeroI32;
1213
use core::num::TryFromIntError;
1314
use core::str::Utf8Error;
1415

@@ -20,7 +21,11 @@ pub mod code {
2021
$(
2122
#[doc = $doc]
2223
)*
23-
pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
24+
pub const $err: super::Error =
25+
match super::Error::try_from_errno(-(crate::bindings::$err as i32)) {
26+
Some(err) => err,
27+
None => panic!("Invalid errno in `declare_err!`"),
28+
};
2429
};
2530
}
2631

@@ -88,7 +93,7 @@ pub mod code {
8893
///
8994
/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
9095
#[derive(Clone, Copy, PartialEq, Eq)]
91-
pub struct Error(core::ffi::c_int);
96+
pub struct Error(NonZeroI32);
9297

9398
impl Error {
9499
/// Creates an [`Error`] from a kernel error code.
@@ -107,45 +112,59 @@ impl Error {
107112

108113
// INVARIANT: The check above ensures the type invariant
109114
// will hold.
110-
Error(errno)
115+
// SAFETY: `errno` is checked above to be in a valid range.
116+
unsafe { Error::from_errno_unchecked(errno) }
117+
}
118+
119+
/// Creates an [`Error`] from a kernel error code.
120+
///
121+
/// Returns [`None`] if `errno` is out-of-range.
122+
const fn try_from_errno(errno: core::ffi::c_int) -> Option<Error> {
123+
if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
124+
return None;
125+
}
126+
127+
// SAFETY: `errno` is checked above to be in a valid range.
128+
Some(unsafe { Error::from_errno_unchecked(errno) })
111129
}
112130

113131
/// Creates an [`Error`] from a kernel error code.
114132
///
115133
/// # Safety
116134
///
117135
/// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
118-
unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error {
136+
const unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error {
119137
// INVARIANT: The contract ensures the type invariant
120138
// will hold.
121-
Error(errno)
139+
// SAFETY: The caller guarantees `errno` is non-zero.
140+
Error(unsafe { NonZeroI32::new_unchecked(errno) })
122141
}
123142

124143
/// Returns the kernel error code.
125144
pub fn to_errno(self) -> core::ffi::c_int {
126-
self.0
145+
self.0.get()
127146
}
128147

129148
#[cfg(CONFIG_BLOCK)]
130149
pub(crate) fn to_blk_status(self) -> bindings::blk_status_t {
131150
// SAFETY: `self.0` is a valid error due to its invariant.
132-
unsafe { bindings::errno_to_blk_status(self.0) }
151+
unsafe { bindings::errno_to_blk_status(self.0.get()) }
133152
}
134153

135154
/// Returns the error encoded as a pointer.
136155
pub fn to_ptr<T>(self) -> *mut T {
137156
#[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))]
138157
// SAFETY: `self.0` is a valid error due to its invariant.
139158
unsafe {
140-
bindings::ERR_PTR(self.0.into()) as *mut _
159+
bindings::ERR_PTR(self.0.get().into()) as *mut _
141160
}
142161
}
143162

144163
/// Returns a string representing the error, if one exists.
145164
#[cfg(not(testlib))]
146165
pub fn name(&self) -> Option<&'static CStr> {
147166
// SAFETY: Just an FFI call, there are no extra safety requirements.
148-
let ptr = unsafe { bindings::errname(-self.0) };
167+
let ptr = unsafe { bindings::errname(-self.0.get()) };
149168
if ptr.is_null() {
150169
None
151170
} else {

0 commit comments

Comments
 (0)
Failed to load comments.