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