Commit | Line | Data |
---|---|---|
247b365d WAF |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | //! Kernel errors. | |
4 | //! | |
5 | //! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h) | |
6 | ||
76e2c2d9 WAF |
7 | use alloc::{ |
8 | alloc::{AllocError, LayoutError}, | |
9 | collections::TryReserveError, | |
10 | }; | |
11 | ||
12 | use core::convert::From; | |
13 | use core::num::TryFromIntError; | |
14 | use core::str::Utf8Error; | |
247b365d WAF |
15 | |
16 | /// Contains the C-compatible error codes. | |
17 | pub mod code { | |
4b0c68bd FB |
18 | macro_rules! declare_err { |
19 | ($err:tt $(,)? $($doc:expr),+) => { | |
20 | $( | |
21 | #[doc = $doc] | |
22 | )* | |
23 | pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32)); | |
24 | }; | |
25 | } | |
26 | ||
266def2a VG |
27 | declare_err!(EPERM, "Operation not permitted."); |
28 | declare_err!(ENOENT, "No such file or directory."); | |
29 | declare_err!(ESRCH, "No such process."); | |
30 | declare_err!(EINTR, "Interrupted system call."); | |
31 | declare_err!(EIO, "I/O error."); | |
32 | declare_err!(ENXIO, "No such device or address."); | |
33 | declare_err!(E2BIG, "Argument list too long."); | |
34 | declare_err!(ENOEXEC, "Exec format error."); | |
35 | declare_err!(EBADF, "Bad file number."); | |
36 | declare_err!(ECHILD, "Exec format error."); | |
37 | declare_err!(EAGAIN, "Try again."); | |
4b0c68bd | 38 | declare_err!(ENOMEM, "Out of memory."); |
266def2a VG |
39 | declare_err!(EACCES, "Permission denied."); |
40 | declare_err!(EFAULT, "Bad address."); | |
41 | declare_err!(ENOTBLK, "Block device required."); | |
42 | declare_err!(EBUSY, "Device or resource busy."); | |
43 | declare_err!(EEXIST, "File exists."); | |
44 | declare_err!(EXDEV, "Cross-device link."); | |
45 | declare_err!(ENODEV, "No such device."); | |
46 | declare_err!(ENOTDIR, "Not a directory."); | |
47 | declare_err!(EISDIR, "Is a directory."); | |
48 | declare_err!(EINVAL, "Invalid argument."); | |
49 | declare_err!(ENFILE, "File table overflow."); | |
50 | declare_err!(EMFILE, "Too many open files."); | |
51 | declare_err!(ENOTTY, "Not a typewriter."); | |
52 | declare_err!(ETXTBSY, "Text file busy."); | |
53 | declare_err!(EFBIG, "File too large."); | |
54 | declare_err!(ENOSPC, "No space left on device."); | |
55 | declare_err!(ESPIPE, "Illegal seek."); | |
56 | declare_err!(EROFS, "Read-only file system."); | |
57 | declare_err!(EMLINK, "Too many links."); | |
58 | declare_err!(EPIPE, "Broken pipe."); | |
59 | declare_err!(EDOM, "Math argument out of domain of func."); | |
60 | declare_err!(ERANGE, "Math result not representable."); | |
247b365d WAF |
61 | } |
62 | ||
63 | /// Generic integer kernel error. | |
64 | /// | |
65 | /// The kernel defines a set of integer generic error codes based on C and | |
66 | /// POSIX ones. These codes may have a more specific meaning in some contexts. | |
67 | /// | |
68 | /// # Invariants | |
69 | /// | |
70 | /// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`). | |
71 | #[derive(Clone, Copy, PartialEq, Eq)] | |
72 | pub struct Error(core::ffi::c_int); | |
73 | ||
74 | impl Error { | |
6551a7fe MO |
75 | /// Creates an [`Error`] from a kernel error code. |
76 | /// | |
77 | /// It is a bug to pass an out-of-range `errno`. `EINVAL` would | |
78 | /// be returned in such a case. | |
6551a7fe MO |
79 | pub(crate) fn from_errno(errno: core::ffi::c_int) -> Error { |
80 | if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 { | |
81 | // TODO: Make it a `WARN_ONCE` once available. | |
82 | crate::pr_warn!( | |
83 | "attempted to create `Error` with out of range `errno`: {}", | |
84 | errno | |
85 | ); | |
86 | return code::EINVAL; | |
87 | } | |
88 | ||
89 | // INVARIANT: The check above ensures the type invariant | |
90 | // will hold. | |
91 | Error(errno) | |
92 | } | |
93 | ||
94 | /// Creates an [`Error`] from a kernel error code. | |
95 | /// | |
96 | /// # Safety | |
97 | /// | |
98 | /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`). | |
6551a7fe MO |
99 | unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error { |
100 | // INVARIANT: The contract ensures the type invariant | |
101 | // will hold. | |
102 | Error(errno) | |
103 | } | |
104 | ||
247b365d | 105 | /// Returns the kernel error code. |
46384d09 | 106 | pub fn to_errno(self) -> core::ffi::c_int { |
247b365d WAF |
107 | self.0 |
108 | } | |
c7e20faa AL |
109 | |
110 | /// Returns the error encoded as a pointer. | |
111 | #[allow(dead_code)] | |
112 | pub(crate) fn to_ptr<T>(self) -> *mut T { | |
113 | // SAFETY: self.0 is a valid error due to its invariant. | |
114 | unsafe { bindings::ERR_PTR(self.0.into()) as *mut _ } | |
115 | } | |
247b365d WAF |
116 | } |
117 | ||
76e2c2d9 WAF |
118 | impl From<AllocError> for Error { |
119 | fn from(_: AllocError) -> Error { | |
120 | code::ENOMEM | |
121 | } | |
122 | } | |
123 | ||
124 | impl From<TryFromIntError> for Error { | |
125 | fn from(_: TryFromIntError) -> Error { | |
126 | code::EINVAL | |
127 | } | |
128 | } | |
129 | ||
130 | impl From<Utf8Error> for Error { | |
131 | fn from(_: Utf8Error) -> Error { | |
132 | code::EINVAL | |
133 | } | |
134 | } | |
135 | ||
247b365d WAF |
136 | impl From<TryReserveError> for Error { |
137 | fn from(_: TryReserveError) -> Error { | |
138 | code::ENOMEM | |
139 | } | |
140 | } | |
141 | ||
76e2c2d9 WAF |
142 | impl From<LayoutError> for Error { |
143 | fn from(_: LayoutError) -> Error { | |
144 | code::ENOMEM | |
145 | } | |
146 | } | |
147 | ||
148 | impl From<core::fmt::Error> for Error { | |
149 | fn from(_: core::fmt::Error) -> Error { | |
150 | code::EINVAL | |
151 | } | |
152 | } | |
153 | ||
154 | impl From<core::convert::Infallible> for Error { | |
155 | fn from(e: core::convert::Infallible) -> Error { | |
156 | match e {} | |
157 | } | |
158 | } | |
159 | ||
247b365d WAF |
160 | /// A [`Result`] with an [`Error`] error type. |
161 | /// | |
162 | /// To be used as the return type for functions that may fail. | |
163 | /// | |
164 | /// # Error codes in C and Rust | |
165 | /// | |
166 | /// In C, it is common that functions indicate success or failure through | |
167 | /// their return value; modifying or returning extra data through non-`const` | |
168 | /// pointer parameters. In particular, in the kernel, functions that may fail | |
169 | /// typically return an `int` that represents a generic error code. We model | |
170 | /// those as [`Error`]. | |
171 | /// | |
172 | /// In Rust, it is idiomatic to model functions that may fail as returning | |
173 | /// a [`Result`]. Since in the kernel many functions return an error code, | |
174 | /// [`Result`] is a type alias for a [`core::result::Result`] that uses | |
175 | /// [`Error`] as its error type. | |
176 | /// | |
177 | /// Note that even if a function does not return anything when it succeeds, | |
178 | /// it should still be modeled as returning a `Result` rather than | |
179 | /// just an [`Error`]. | |
180 | pub type Result<T = ()> = core::result::Result<T, Error>; | |
086fbfa3 WAF |
181 | |
182 | /// Converts an integer as returned by a C kernel function to an error if it's negative, and | |
183 | /// `Ok(())` otherwise. | |
184 | pub fn to_result(err: core::ffi::c_int) -> Result { | |
185 | if err < 0 { | |
186 | Err(Error::from_errno(err)) | |
187 | } else { | |
188 | Ok(()) | |
189 | } | |
190 | } | |
752417b3 SVA |
191 | |
192 | /// Transform a kernel "error pointer" to a normal pointer. | |
193 | /// | |
194 | /// Some kernel C API functions return an "error pointer" which optionally | |
195 | /// embeds an `errno`. Callers are supposed to check the returned pointer | |
196 | /// for errors. This function performs the check and converts the "error pointer" | |
197 | /// to a normal pointer in an idiomatic fashion. | |
198 | /// | |
199 | /// # Examples | |
200 | /// | |
201 | /// ```ignore | |
202 | /// # use kernel::from_err_ptr; | |
203 | /// # use kernel::bindings; | |
204 | /// fn devm_platform_ioremap_resource( | |
205 | /// pdev: &mut PlatformDevice, | |
206 | /// index: u32, | |
207 | /// ) -> Result<*mut core::ffi::c_void> { | |
208 | /// // SAFETY: FFI call. | |
209 | /// unsafe { | |
210 | /// from_err_ptr(bindings::devm_platform_ioremap_resource( | |
211 | /// pdev.to_ptr(), | |
212 | /// index, | |
213 | /// )) | |
214 | /// } | |
215 | /// } | |
216 | /// ``` | |
217 | // TODO: Remove `dead_code` marker once an in-kernel client is available. | |
218 | #[allow(dead_code)] | |
219 | pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> { | |
220 | // CAST: Casting a pointer to `*const core::ffi::c_void` is always valid. | |
221 | let const_ptr: *const core::ffi::c_void = ptr.cast(); | |
222 | // SAFETY: The FFI function does not deref the pointer. | |
223 | if unsafe { bindings::IS_ERR(const_ptr) } { | |
224 | // SAFETY: The FFI function does not deref the pointer. | |
225 | let err = unsafe { bindings::PTR_ERR(const_ptr) }; | |
226 | // CAST: If `IS_ERR()` returns `true`, | |
227 | // then `PTR_ERR()` is guaranteed to return a | |
228 | // negative value greater-or-equal to `-bindings::MAX_ERRNO`, | |
229 | // which always fits in an `i16`, as per the invariant above. | |
230 | // And an `i16` always fits in an `i32`. So casting `err` to | |
231 | // an `i32` can never overflow, and is always valid. | |
232 | // | |
233 | // SAFETY: `IS_ERR()` ensures `err` is a | |
234 | // negative value greater-or-equal to `-bindings::MAX_ERRNO`. | |
235 | #[allow(clippy::unnecessary_cast)] | |
236 | return Err(unsafe { Error::from_errno_unchecked(err as core::ffi::c_int) }); | |
237 | } | |
238 | Ok(ptr) | |
239 | } | |
ef4dc4cc WAF |
240 | |
241 | /// Calls a closure returning a [`crate::error::Result<T>`] and converts the result to | |
242 | /// a C integer result. | |
243 | /// | |
244 | /// This is useful when calling Rust functions that return [`crate::error::Result<T>`] | |
245 | /// from inside `extern "C"` functions that need to return an integer error result. | |
246 | /// | |
247 | /// `T` should be convertible from an `i16` via `From<i16>`. | |
248 | /// | |
249 | /// # Examples | |
250 | /// | |
251 | /// ```ignore | |
252 | /// # use kernel::from_result; | |
253 | /// # use kernel::bindings; | |
254 | /// unsafe extern "C" fn probe_callback( | |
255 | /// pdev: *mut bindings::platform_device, | |
256 | /// ) -> core::ffi::c_int { | |
257 | /// from_result(|| { | |
258 | /// let ptr = devm_alloc(pdev)?; | |
259 | /// bindings::platform_set_drvdata(pdev, ptr); | |
260 | /// Ok(0) | |
261 | /// }) | |
262 | /// } | |
263 | /// ``` | |
264 | // TODO: Remove `dead_code` marker once an in-kernel client is available. | |
265 | #[allow(dead_code)] | |
266 | pub(crate) fn from_result<T, F>(f: F) -> T | |
267 | where | |
268 | T: From<i16>, | |
269 | F: FnOnce() -> Result<T>, | |
270 | { | |
271 | match f() { | |
272 | Ok(v) => v, | |
273 | // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`, | |
274 | // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above, | |
275 | // therefore a negative `errno` always fits in an `i16` and will not overflow. | |
276 | Err(e) => T::from(e.to_errno() as i16), | |
277 | } | |
278 | } |