xref: /linux-6.15/rust/kernel/error.rs (revision ef4dc4cc)
1247b365dSWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0
2247b365dSWedson Almeida Filho 
3247b365dSWedson Almeida Filho //! Kernel errors.
4247b365dSWedson Almeida Filho //!
5247b365dSWedson Almeida Filho //! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
6247b365dSWedson Almeida Filho 
776e2c2d9SWedson Almeida Filho use alloc::{
876e2c2d9SWedson Almeida Filho     alloc::{AllocError, LayoutError},
976e2c2d9SWedson Almeida Filho     collections::TryReserveError,
1076e2c2d9SWedson Almeida Filho };
1176e2c2d9SWedson Almeida Filho 
1276e2c2d9SWedson Almeida Filho use core::convert::From;
1376e2c2d9SWedson Almeida Filho use core::num::TryFromIntError;
1476e2c2d9SWedson Almeida Filho use core::str::Utf8Error;
15247b365dSWedson Almeida Filho 
16247b365dSWedson Almeida Filho /// Contains the C-compatible error codes.
17247b365dSWedson Almeida Filho pub mod code {
184b0c68bdSFinn Behrens     macro_rules! declare_err {
194b0c68bdSFinn Behrens         ($err:tt $(,)? $($doc:expr),+) => {
204b0c68bdSFinn Behrens             $(
214b0c68bdSFinn Behrens             #[doc = $doc]
224b0c68bdSFinn Behrens             )*
234b0c68bdSFinn Behrens             pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
244b0c68bdSFinn Behrens         };
254b0c68bdSFinn Behrens     }
264b0c68bdSFinn Behrens 
27266def2aSViktor Garske     declare_err!(EPERM, "Operation not permitted.");
28266def2aSViktor Garske     declare_err!(ENOENT, "No such file or directory.");
29266def2aSViktor Garske     declare_err!(ESRCH, "No such process.");
30266def2aSViktor Garske     declare_err!(EINTR, "Interrupted system call.");
31266def2aSViktor Garske     declare_err!(EIO, "I/O error.");
32266def2aSViktor Garske     declare_err!(ENXIO, "No such device or address.");
33266def2aSViktor Garske     declare_err!(E2BIG, "Argument list too long.");
34266def2aSViktor Garske     declare_err!(ENOEXEC, "Exec format error.");
35266def2aSViktor Garske     declare_err!(EBADF, "Bad file number.");
36266def2aSViktor Garske     declare_err!(ECHILD, "Exec format error.");
37266def2aSViktor Garske     declare_err!(EAGAIN, "Try again.");
384b0c68bdSFinn Behrens     declare_err!(ENOMEM, "Out of memory.");
39266def2aSViktor Garske     declare_err!(EACCES, "Permission denied.");
40266def2aSViktor Garske     declare_err!(EFAULT, "Bad address.");
41266def2aSViktor Garske     declare_err!(ENOTBLK, "Block device required.");
42266def2aSViktor Garske     declare_err!(EBUSY, "Device or resource busy.");
43266def2aSViktor Garske     declare_err!(EEXIST, "File exists.");
44266def2aSViktor Garske     declare_err!(EXDEV, "Cross-device link.");
45266def2aSViktor Garske     declare_err!(ENODEV, "No such device.");
46266def2aSViktor Garske     declare_err!(ENOTDIR, "Not a directory.");
47266def2aSViktor Garske     declare_err!(EISDIR, "Is a directory.");
48266def2aSViktor Garske     declare_err!(EINVAL, "Invalid argument.");
49266def2aSViktor Garske     declare_err!(ENFILE, "File table overflow.");
50266def2aSViktor Garske     declare_err!(EMFILE, "Too many open files.");
51266def2aSViktor Garske     declare_err!(ENOTTY, "Not a typewriter.");
52266def2aSViktor Garske     declare_err!(ETXTBSY, "Text file busy.");
53266def2aSViktor Garske     declare_err!(EFBIG, "File too large.");
54266def2aSViktor Garske     declare_err!(ENOSPC, "No space left on device.");
55266def2aSViktor Garske     declare_err!(ESPIPE, "Illegal seek.");
56266def2aSViktor Garske     declare_err!(EROFS, "Read-only file system.");
57266def2aSViktor Garske     declare_err!(EMLINK, "Too many links.");
58266def2aSViktor Garske     declare_err!(EPIPE, "Broken pipe.");
59266def2aSViktor Garske     declare_err!(EDOM, "Math argument out of domain of func.");
60266def2aSViktor Garske     declare_err!(ERANGE, "Math result not representable.");
61247b365dSWedson Almeida Filho }
62247b365dSWedson Almeida Filho 
63247b365dSWedson Almeida Filho /// Generic integer kernel error.
64247b365dSWedson Almeida Filho ///
65247b365dSWedson Almeida Filho /// The kernel defines a set of integer generic error codes based on C and
66247b365dSWedson Almeida Filho /// POSIX ones. These codes may have a more specific meaning in some contexts.
67247b365dSWedson Almeida Filho ///
68247b365dSWedson Almeida Filho /// # Invariants
69247b365dSWedson Almeida Filho ///
70247b365dSWedson Almeida Filho /// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
71247b365dSWedson Almeida Filho #[derive(Clone, Copy, PartialEq, Eq)]
72247b365dSWedson Almeida Filho pub struct Error(core::ffi::c_int);
73247b365dSWedson Almeida Filho 
74247b365dSWedson Almeida Filho impl Error {
756551a7feSMiguel Ojeda     /// Creates an [`Error`] from a kernel error code.
766551a7feSMiguel Ojeda     ///
776551a7feSMiguel Ojeda     /// It is a bug to pass an out-of-range `errno`. `EINVAL` would
786551a7feSMiguel Ojeda     /// be returned in such a case.
796551a7feSMiguel Ojeda     pub(crate) fn from_errno(errno: core::ffi::c_int) -> Error {
806551a7feSMiguel Ojeda         if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
816551a7feSMiguel Ojeda             // TODO: Make it a `WARN_ONCE` once available.
826551a7feSMiguel Ojeda             crate::pr_warn!(
836551a7feSMiguel Ojeda                 "attempted to create `Error` with out of range `errno`: {}",
846551a7feSMiguel Ojeda                 errno
856551a7feSMiguel Ojeda             );
866551a7feSMiguel Ojeda             return code::EINVAL;
876551a7feSMiguel Ojeda         }
886551a7feSMiguel Ojeda 
896551a7feSMiguel Ojeda         // INVARIANT: The check above ensures the type invariant
906551a7feSMiguel Ojeda         // will hold.
916551a7feSMiguel Ojeda         Error(errno)
926551a7feSMiguel Ojeda     }
936551a7feSMiguel Ojeda 
946551a7feSMiguel Ojeda     /// Creates an [`Error`] from a kernel error code.
956551a7feSMiguel Ojeda     ///
966551a7feSMiguel Ojeda     /// # Safety
976551a7feSMiguel Ojeda     ///
986551a7feSMiguel Ojeda     /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
996551a7feSMiguel Ojeda     unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error {
1006551a7feSMiguel Ojeda         // INVARIANT: The contract ensures the type invariant
1016551a7feSMiguel Ojeda         // will hold.
1026551a7feSMiguel Ojeda         Error(errno)
1036551a7feSMiguel Ojeda     }
1046551a7feSMiguel Ojeda 
105247b365dSWedson Almeida Filho     /// Returns the kernel error code.
10646384d09SAsahi Lina     pub fn to_errno(self) -> core::ffi::c_int {
107247b365dSWedson Almeida Filho         self.0
108247b365dSWedson Almeida Filho     }
109c7e20faaSAsahi Lina 
110c7e20faaSAsahi Lina     /// Returns the error encoded as a pointer.
111c7e20faaSAsahi Lina     #[allow(dead_code)]
112c7e20faaSAsahi Lina     pub(crate) fn to_ptr<T>(self) -> *mut T {
113c7e20faaSAsahi Lina         // SAFETY: self.0 is a valid error due to its invariant.
114c7e20faaSAsahi Lina         unsafe { bindings::ERR_PTR(self.0.into()) as *mut _ }
115c7e20faaSAsahi Lina     }
116247b365dSWedson Almeida Filho }
117247b365dSWedson Almeida Filho 
11876e2c2d9SWedson Almeida Filho impl From<AllocError> for Error {
11976e2c2d9SWedson Almeida Filho     fn from(_: AllocError) -> Error {
12076e2c2d9SWedson Almeida Filho         code::ENOMEM
12176e2c2d9SWedson Almeida Filho     }
12276e2c2d9SWedson Almeida Filho }
12376e2c2d9SWedson Almeida Filho 
12476e2c2d9SWedson Almeida Filho impl From<TryFromIntError> for Error {
12576e2c2d9SWedson Almeida Filho     fn from(_: TryFromIntError) -> Error {
12676e2c2d9SWedson Almeida Filho         code::EINVAL
12776e2c2d9SWedson Almeida Filho     }
12876e2c2d9SWedson Almeida Filho }
12976e2c2d9SWedson Almeida Filho 
13076e2c2d9SWedson Almeida Filho impl From<Utf8Error> for Error {
13176e2c2d9SWedson Almeida Filho     fn from(_: Utf8Error) -> Error {
13276e2c2d9SWedson Almeida Filho         code::EINVAL
13376e2c2d9SWedson Almeida Filho     }
13476e2c2d9SWedson Almeida Filho }
13576e2c2d9SWedson Almeida Filho 
136247b365dSWedson Almeida Filho impl From<TryReserveError> for Error {
137247b365dSWedson Almeida Filho     fn from(_: TryReserveError) -> Error {
138247b365dSWedson Almeida Filho         code::ENOMEM
139247b365dSWedson Almeida Filho     }
140247b365dSWedson Almeida Filho }
141247b365dSWedson Almeida Filho 
14276e2c2d9SWedson Almeida Filho impl From<LayoutError> for Error {
14376e2c2d9SWedson Almeida Filho     fn from(_: LayoutError) -> Error {
14476e2c2d9SWedson Almeida Filho         code::ENOMEM
14576e2c2d9SWedson Almeida Filho     }
14676e2c2d9SWedson Almeida Filho }
14776e2c2d9SWedson Almeida Filho 
14876e2c2d9SWedson Almeida Filho impl From<core::fmt::Error> for Error {
14976e2c2d9SWedson Almeida Filho     fn from(_: core::fmt::Error) -> Error {
15076e2c2d9SWedson Almeida Filho         code::EINVAL
15176e2c2d9SWedson Almeida Filho     }
15276e2c2d9SWedson Almeida Filho }
15376e2c2d9SWedson Almeida Filho 
15476e2c2d9SWedson Almeida Filho impl From<core::convert::Infallible> for Error {
15576e2c2d9SWedson Almeida Filho     fn from(e: core::convert::Infallible) -> Error {
15676e2c2d9SWedson Almeida Filho         match e {}
15776e2c2d9SWedson Almeida Filho     }
15876e2c2d9SWedson Almeida Filho }
15976e2c2d9SWedson Almeida Filho 
160247b365dSWedson Almeida Filho /// A [`Result`] with an [`Error`] error type.
161247b365dSWedson Almeida Filho ///
162247b365dSWedson Almeida Filho /// To be used as the return type for functions that may fail.
163247b365dSWedson Almeida Filho ///
164247b365dSWedson Almeida Filho /// # Error codes in C and Rust
165247b365dSWedson Almeida Filho ///
166247b365dSWedson Almeida Filho /// In C, it is common that functions indicate success or failure through
167247b365dSWedson Almeida Filho /// their return value; modifying or returning extra data through non-`const`
168247b365dSWedson Almeida Filho /// pointer parameters. In particular, in the kernel, functions that may fail
169247b365dSWedson Almeida Filho /// typically return an `int` that represents a generic error code. We model
170247b365dSWedson Almeida Filho /// those as [`Error`].
171247b365dSWedson Almeida Filho ///
172247b365dSWedson Almeida Filho /// In Rust, it is idiomatic to model functions that may fail as returning
173247b365dSWedson Almeida Filho /// a [`Result`]. Since in the kernel many functions return an error code,
174247b365dSWedson Almeida Filho /// [`Result`] is a type alias for a [`core::result::Result`] that uses
175247b365dSWedson Almeida Filho /// [`Error`] as its error type.
176247b365dSWedson Almeida Filho ///
177247b365dSWedson Almeida Filho /// Note that even if a function does not return anything when it succeeds,
178247b365dSWedson Almeida Filho /// it should still be modeled as returning a `Result` rather than
179247b365dSWedson Almeida Filho /// just an [`Error`].
180247b365dSWedson Almeida Filho pub type Result<T = ()> = core::result::Result<T, Error>;
181086fbfa3SWedson Almeida Filho 
182086fbfa3SWedson Almeida Filho /// Converts an integer as returned by a C kernel function to an error if it's negative, and
183086fbfa3SWedson Almeida Filho /// `Ok(())` otherwise.
184086fbfa3SWedson Almeida Filho pub fn to_result(err: core::ffi::c_int) -> Result {
185086fbfa3SWedson Almeida Filho     if err < 0 {
186086fbfa3SWedson Almeida Filho         Err(Error::from_errno(err))
187086fbfa3SWedson Almeida Filho     } else {
188086fbfa3SWedson Almeida Filho         Ok(())
189086fbfa3SWedson Almeida Filho     }
190086fbfa3SWedson Almeida Filho }
191752417b3SSven Van Asbroeck 
192752417b3SSven Van Asbroeck /// Transform a kernel "error pointer" to a normal pointer.
193752417b3SSven Van Asbroeck ///
194752417b3SSven Van Asbroeck /// Some kernel C API functions return an "error pointer" which optionally
195752417b3SSven Van Asbroeck /// embeds an `errno`. Callers are supposed to check the returned pointer
196752417b3SSven Van Asbroeck /// for errors. This function performs the check and converts the "error pointer"
197752417b3SSven Van Asbroeck /// to a normal pointer in an idiomatic fashion.
198752417b3SSven Van Asbroeck ///
199752417b3SSven Van Asbroeck /// # Examples
200752417b3SSven Van Asbroeck ///
201752417b3SSven Van Asbroeck /// ```ignore
202752417b3SSven Van Asbroeck /// # use kernel::from_err_ptr;
203752417b3SSven Van Asbroeck /// # use kernel::bindings;
204752417b3SSven Van Asbroeck /// fn devm_platform_ioremap_resource(
205752417b3SSven Van Asbroeck ///     pdev: &mut PlatformDevice,
206752417b3SSven Van Asbroeck ///     index: u32,
207752417b3SSven Van Asbroeck /// ) -> Result<*mut core::ffi::c_void> {
208752417b3SSven Van Asbroeck ///     // SAFETY: FFI call.
209752417b3SSven Van Asbroeck ///     unsafe {
210752417b3SSven Van Asbroeck ///         from_err_ptr(bindings::devm_platform_ioremap_resource(
211752417b3SSven Van Asbroeck ///             pdev.to_ptr(),
212752417b3SSven Van Asbroeck ///             index,
213752417b3SSven Van Asbroeck ///         ))
214752417b3SSven Van Asbroeck ///     }
215752417b3SSven Van Asbroeck /// }
216752417b3SSven Van Asbroeck /// ```
217752417b3SSven Van Asbroeck // TODO: Remove `dead_code` marker once an in-kernel client is available.
218752417b3SSven Van Asbroeck #[allow(dead_code)]
219752417b3SSven Van Asbroeck pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
220752417b3SSven Van Asbroeck     // CAST: Casting a pointer to `*const core::ffi::c_void` is always valid.
221752417b3SSven Van Asbroeck     let const_ptr: *const core::ffi::c_void = ptr.cast();
222752417b3SSven Van Asbroeck     // SAFETY: The FFI function does not deref the pointer.
223752417b3SSven Van Asbroeck     if unsafe { bindings::IS_ERR(const_ptr) } {
224752417b3SSven Van Asbroeck         // SAFETY: The FFI function does not deref the pointer.
225752417b3SSven Van Asbroeck         let err = unsafe { bindings::PTR_ERR(const_ptr) };
226752417b3SSven Van Asbroeck         // CAST: If `IS_ERR()` returns `true`,
227752417b3SSven Van Asbroeck         // then `PTR_ERR()` is guaranteed to return a
228752417b3SSven Van Asbroeck         // negative value greater-or-equal to `-bindings::MAX_ERRNO`,
229752417b3SSven Van Asbroeck         // which always fits in an `i16`, as per the invariant above.
230752417b3SSven Van Asbroeck         // And an `i16` always fits in an `i32`. So casting `err` to
231752417b3SSven Van Asbroeck         // an `i32` can never overflow, and is always valid.
232752417b3SSven Van Asbroeck         //
233752417b3SSven Van Asbroeck         // SAFETY: `IS_ERR()` ensures `err` is a
234752417b3SSven Van Asbroeck         // negative value greater-or-equal to `-bindings::MAX_ERRNO`.
235752417b3SSven Van Asbroeck         #[allow(clippy::unnecessary_cast)]
236752417b3SSven Van Asbroeck         return Err(unsafe { Error::from_errno_unchecked(err as core::ffi::c_int) });
237752417b3SSven Van Asbroeck     }
238752417b3SSven Van Asbroeck     Ok(ptr)
239752417b3SSven Van Asbroeck }
240*ef4dc4ccSWedson Almeida Filho 
241*ef4dc4ccSWedson Almeida Filho /// Calls a closure returning a [`crate::error::Result<T>`] and converts the result to
242*ef4dc4ccSWedson Almeida Filho /// a C integer result.
243*ef4dc4ccSWedson Almeida Filho ///
244*ef4dc4ccSWedson Almeida Filho /// This is useful when calling Rust functions that return [`crate::error::Result<T>`]
245*ef4dc4ccSWedson Almeida Filho /// from inside `extern "C"` functions that need to return an integer error result.
246*ef4dc4ccSWedson Almeida Filho ///
247*ef4dc4ccSWedson Almeida Filho /// `T` should be convertible from an `i16` via `From<i16>`.
248*ef4dc4ccSWedson Almeida Filho ///
249*ef4dc4ccSWedson Almeida Filho /// # Examples
250*ef4dc4ccSWedson Almeida Filho ///
251*ef4dc4ccSWedson Almeida Filho /// ```ignore
252*ef4dc4ccSWedson Almeida Filho /// # use kernel::from_result;
253*ef4dc4ccSWedson Almeida Filho /// # use kernel::bindings;
254*ef4dc4ccSWedson Almeida Filho /// unsafe extern "C" fn probe_callback(
255*ef4dc4ccSWedson Almeida Filho ///     pdev: *mut bindings::platform_device,
256*ef4dc4ccSWedson Almeida Filho /// ) -> core::ffi::c_int {
257*ef4dc4ccSWedson Almeida Filho ///     from_result(|| {
258*ef4dc4ccSWedson Almeida Filho ///         let ptr = devm_alloc(pdev)?;
259*ef4dc4ccSWedson Almeida Filho ///         bindings::platform_set_drvdata(pdev, ptr);
260*ef4dc4ccSWedson Almeida Filho ///         Ok(0)
261*ef4dc4ccSWedson Almeida Filho ///     })
262*ef4dc4ccSWedson Almeida Filho /// }
263*ef4dc4ccSWedson Almeida Filho /// ```
264*ef4dc4ccSWedson Almeida Filho // TODO: Remove `dead_code` marker once an in-kernel client is available.
265*ef4dc4ccSWedson Almeida Filho #[allow(dead_code)]
266*ef4dc4ccSWedson Almeida Filho pub(crate) fn from_result<T, F>(f: F) -> T
267*ef4dc4ccSWedson Almeida Filho where
268*ef4dc4ccSWedson Almeida Filho     T: From<i16>,
269*ef4dc4ccSWedson Almeida Filho     F: FnOnce() -> Result<T>,
270*ef4dc4ccSWedson Almeida Filho {
271*ef4dc4ccSWedson Almeida Filho     match f() {
272*ef4dc4ccSWedson Almeida Filho         Ok(v) => v,
273*ef4dc4ccSWedson Almeida Filho         // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`,
274*ef4dc4ccSWedson Almeida Filho         // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above,
275*ef4dc4ccSWedson Almeida Filho         // therefore a negative `errno` always fits in an `i16` and will not overflow.
276*ef4dc4ccSWedson Almeida Filho         Err(e) => T::from(e.to_errno() as i16),
277*ef4dc4ccSWedson Almeida Filho     }
278*ef4dc4ccSWedson Almeida Filho }
279