[PATCH 6.12.y 19/60] rust: error: optimize error type to use nonzero

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Filipe Xavier <felipe_life@xxxxxxxx>

commit e9759c5b9ea555d09f426c70c880e9522e9b0576 upstream.

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: https://github.com/Rust-for-Linux/linux/issues/1120
Signed-off-by: Filipe Xavier <felipe_life@xxxxxxxx>
Reviewed-by: Gary Guo <gary@xxxxxxxxxxx>
Reviewed-by: Alice Ryhl <aliceryhl@xxxxxxxxxx>
Reviewed-by: Fiona Behrens <me@xxxxxxxxxx>
Link: https://lore.kernel.org/r/BL0PR02MB4914B9B088865CF237731207E9732@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[ Removed unneeded block around `match`, added backticks in panic
  message and added intra-doc link. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@xxxxxxxxxx>
---
 rust/kernel/error.rs | 37 ++++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 2f1e4b783bfb..be6509d5f4a4 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -9,6 +9,7 @@
 use alloc::alloc::LayoutError;
 
 use core::fmt;
+use core::num::NonZeroI32;
 use core::num::TryFromIntError;
 use core::str::Utf8Error;
 
@@ -20,7 +21,11 @@ macro_rules! declare_err {
             $(
             #[doc = $doc]
             )*
-            pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
+            pub const $err: super::Error =
+                match super::Error::try_from_errno(-(crate::bindings::$err as i32)) {
+                    Some(err) => err,
+                    None => panic!("Invalid errno in `declare_err!`"),
+                };
         };
     }
 
@@ -88,7 +93,7 @@ macro_rules! declare_err {
 ///
 /// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
 #[derive(Clone, Copy, PartialEq, Eq)]
-pub struct Error(core::ffi::c_int);
+pub struct Error(NonZeroI32);
 
 impl Error {
     /// Creates an [`Error`] from a kernel error code.
@@ -107,7 +112,20 @@ pub fn from_errno(errno: core::ffi::c_int) -> Error {
 
         // INVARIANT: The check above ensures the type invariant
         // will hold.
-        Error(errno)
+        // SAFETY: `errno` is checked above to be in a valid range.
+        unsafe { Error::from_errno_unchecked(errno) }
+    }
+
+    /// Creates an [`Error`] from a kernel error code.
+    ///
+    /// Returns [`None`] if `errno` is out-of-range.
+    const fn try_from_errno(errno: core::ffi::c_int) -> Option<Error> {
+        if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
+            return None;
+        }
+
+        // SAFETY: `errno` is checked above to be in a valid range.
+        Some(unsafe { Error::from_errno_unchecked(errno) })
     }
 
     /// Creates an [`Error`] from a kernel error code.
@@ -115,21 +133,22 @@ pub fn from_errno(errno: core::ffi::c_int) -> Error {
     /// # Safety
     ///
     /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
-    unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error {
+    const unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error {
         // INVARIANT: The contract ensures the type invariant
         // will hold.
-        Error(errno)
+        // SAFETY: The caller guarantees `errno` is non-zero.
+        Error(unsafe { NonZeroI32::new_unchecked(errno) })
     }
 
     /// Returns the kernel error code.
     pub fn to_errno(self) -> core::ffi::c_int {
-        self.0
+        self.0.get()
     }
 
     #[cfg(CONFIG_BLOCK)]
     pub(crate) 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) }
+        unsafe { bindings::errno_to_blk_status(self.0.get()) }
     }
 
     /// Returns the error encoded as a pointer.
@@ -137,7 +156,7 @@ pub fn to_ptr<T>(self) -> *mut T {
         #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))]
         // SAFETY: `self.0` is a valid error due to its invariant.
         unsafe {
-            bindings::ERR_PTR(self.0.into()) as *mut _
+            bindings::ERR_PTR(self.0.get().into()) as *mut _
         }
     }
 
@@ -145,7 +164,7 @@ pub fn to_ptr<T>(self) -> *mut T {
     #[cfg(not(testlib))]
     pub fn name(&self) -> Option<&'static CStr> {
         // SAFETY: Just an FFI call, there are no extra safety requirements.
-        let ptr = unsafe { bindings::errname(-self.0) };
+        let ptr = unsafe { bindings::errname(-self.0.get()) };
         if ptr.is_null() {
             None
         } else {
-- 
2.48.1





[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux