From 4a59081c09cbfe17505baf3db50ebb9b97290bae Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 2 May 2023 12:40:15 +0000 Subject: rust: error: allow specifying error type on `Result` Currently, if the `kernel::error::Result` type is in scope (which is often is, since it's in the kernel's prelude), you cannot write `Result` when you want to use a different error type than `kernel::error::Error`. To solve this we change the error type from being hard-coded to just being a default generic parameter. This still lets you write `Result` when you just want to use the `Error` error type, but also lets you write `Result` when necessary. Signed-off-by: Alice Ryhl Reviewed-by: Benno Lossin Reviewed-by: Asahi Lina Reviewed-by: Andreas Hindborg Reviewed-by: Gary Guo Link: https://lore.kernel.org/r/20230502124015.356001-1-aliceryhl@google.com Signed-off-by: Miguel Ojeda --- rust/kernel/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/kernel/error.rs') diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 5f4114b30b94..01dd4d2f63d2 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -177,7 +177,7 @@ impl From for Error { /// Note that even if a function does not return anything when it succeeds, /// it should still be modeled as returning a `Result` rather than /// just an [`Error`]. -pub type Result = core::result::Result; +pub type Result = core::result::Result; /// Converts an integer as returned by a C kernel function to an error if it's negative, and /// `Ok(())` otherwise. -- cgit From e37b654c379e514357ccadb22c6291d3471fa5e5 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 4 May 2023 06:48:54 +0000 Subject: rust: error: add missing error codes This adds the error codes from `include/linux/errno.h` to the list of Rust error constants. These errors were not included originally, because they are not supposed to be visible from userspace. However, they are still a perfectly valid error to use when writing a kernel driver. For example, you might want to return ERESTARTSYS if you receive a signal during a call to `schedule`. This patch inserts an annotation to skip rustfmt on the list of error codes. Without it, three of the error codes are split over several lines, which looks terribly inconsistent. Signed-off-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo Link: https://lore.kernel.org/r/20230504064854.774820-1-aliceryhl@google.com Signed-off-by: Miguel Ojeda --- rust/kernel/error.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'rust/kernel/error.rs') diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 01dd4d2f63d2..7c1ce2bccd08 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -14,6 +14,7 @@ use core::num::TryFromIntError; use core::str::Utf8Error; /// Contains the C-compatible error codes. +#[rustfmt::skip] pub mod code { macro_rules! declare_err { ($err:tt $(,)? $($doc:expr),+) => { @@ -58,6 +59,25 @@ pub mod code { declare_err!(EPIPE, "Broken pipe."); declare_err!(EDOM, "Math argument out of domain of func."); declare_err!(ERANGE, "Math result not representable."); + declare_err!(ERESTARTSYS, "Restart the system call."); + declare_err!(ERESTARTNOINTR, "System call was interrupted by a signal and will be restarted."); + declare_err!(ERESTARTNOHAND, "Restart if no handler."); + declare_err!(ENOIOCTLCMD, "No ioctl command."); + declare_err!(ERESTART_RESTARTBLOCK, "Restart by calling sys_restart_syscall."); + declare_err!(EPROBE_DEFER, "Driver requests probe retry."); + declare_err!(EOPENSTALE, "Open found a stale dentry."); + declare_err!(ENOPARAM, "Parameter not supported."); + declare_err!(EBADHANDLE, "Illegal NFS file handle."); + declare_err!(ENOTSYNC, "Update synchronization mismatch."); + declare_err!(EBADCOOKIE, "Cookie is stale."); + declare_err!(ENOTSUPP, "Operation is not supported."); + declare_err!(ETOOSMALL, "Buffer or request is too small."); + declare_err!(ESERVERFAULT, "An untranslatable error occurred."); + declare_err!(EBADTYPE, "Type not supported by server."); + declare_err!(EJUKEBOX, "Request initiated, but will not complete before timeout."); + declare_err!(EIOCBQUEUED, "iocb queued, will get completion event."); + declare_err!(ERECALLCONFLICT, "Conflict with recalled state."); + declare_err!(ENOGRACE, "NFS file lock reclaim refused."); } /// Generic integer kernel error. -- cgit From d2e3115d717197cb2bc020dd1f06b06538474ac3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 31 May 2023 17:44:50 +0000 Subject: rust: error: `impl Debug` for `Error` with `errname()` integration Integrate the `Error` type with `errname()` by providing a new `name()` method. Then, implement `Debug` for the type using the new method. [ Miguel: under `CONFIG_SYMBOLIC_ERRNAME=n`, `errname()` is a `static inline`, so added a helper to support that case, like we had in the `rust` branch. Also moved `#include` up and reworded commit message for clarity. ] Co-developed-by: Wedson Almeida Filho Signed-off-by: Wedson Almeida Filho Co-developed-by: Sven Van Asbroeck Signed-off-by: Sven Van Asbroeck Signed-off-by: Gary Guo Signed-off-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo Link: https://lore.kernel.org/r/20230531174450.3733220-1-aliceryhl@google.com Signed-off-by: Miguel Ojeda --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 7 +++++++ rust/kernel/error.rs | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) (limited to 'rust/kernel/error.rs') diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 50e7a76d5455..3e601ce2548d 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -6,6 +6,7 @@ * Sorted alphabetically. */ +#include #include #include #include diff --git a/rust/helpers.c b/rust/helpers.c index 81e80261d597..bb594da56137 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,12 @@ long rust_helper_PTR_ERR(__force const void *ptr) } EXPORT_SYMBOL_GPL(rust_helper_PTR_ERR); +const char *rust_helper_errname(int err) +{ + return errname(err); +} +EXPORT_SYMBOL_GPL(rust_helper_errname); + struct task_struct *rust_helper_get_current(void) { return current; diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 7c1ce2bccd08..05fcab6abfe6 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -4,12 +4,15 @@ //! //! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h) +use crate::str::CStr; + use alloc::{ alloc::{AllocError, LayoutError}, collections::TryReserveError, }; use core::convert::From; +use core::fmt; use core::num::TryFromIntError; use core::str::Utf8Error; @@ -133,6 +136,42 @@ impl Error { // SAFETY: self.0 is a valid error due to its invariant. unsafe { bindings::ERR_PTR(self.0.into()) as *mut _ } } + + /// Returns a string representing the error, if one exists. + #[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) }; + if ptr.is_null() { + None + } else { + // SAFETY: The string returned by `errname` is static and `NUL`-terminated. + Some(unsafe { CStr::from_char_ptr(ptr) }) + } + } + + /// Returns a string representing the error, if one exists. + /// + /// When `testlib` is configured, this always returns `None` to avoid the dependency on a + /// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still + /// run in userspace. + #[cfg(testlib)] + pub fn name(&self) -> Option<&'static CStr> { + None + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.name() { + // Print out number if no name can be found. + None => f.debug_tuple("Error").field(&-self.0).finish(), + // SAFETY: These strings are ASCII-only. + Some(name) => f + .debug_tuple(unsafe { core::str::from_utf8_unchecked(name) }) + .finish(), + } + } } impl From for Error { -- cgit