mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
rust: error: Add a helper to convert a C ERR_PTR to a Result
Some kernel C API functions return a pointer which embeds an optional `errno`. Callers are supposed to check the returned pointer with `IS_ERR()` and if this returns `true`, retrieve the `errno` using `PTR_ERR()`. Create a Rust helper function to implement the Rust equivalent: transform a `*mut T` to `Result<*mut T>`. Lina: Imported from rust-for-linux/linux, with subsequent refactoring and contributions squashed in and attributed below. Renamed the function to from_err_ptr(). Co-developed-by: Boqun Feng <boqun.feng@gmail.com> Signed-off-by: Boqun Feng <boqun.feng@gmail.com> Co-developed-by: Miguel Ojeda <ojeda@kernel.org> Signed-off-by: Miguel Ojeda <ojeda@kernel.org> Co-developed-by: Fox Chen <foxhlchen@gmail.com> Signed-off-by: Fox Chen <foxhlchen@gmail.com> Co-developed-by: Gary Guo <gary@garyguo.net> Signed-off-by: Gary Guo <gary@garyguo.net> Signed-off-by: Sven Van Asbroeck <thesven73@gmail.com> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Signed-off-by: Asahi Lina <lina@asahilina.net> Link: https://lore.kernel.org/r/20230224-rust-error-v3-5-03779bddc02b@asahilina.net [ Add a removal of `#[allow(dead_code)]`. ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
086fbfa3b3
commit
752417b3f0
@ -53,6 +53,18 @@ __force void *rust_helper_ERR_PTR(long err)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rust_helper_ERR_PTR);
|
||||
|
||||
bool rust_helper_IS_ERR(__force const void *ptr)
|
||||
{
|
||||
return IS_ERR(ptr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rust_helper_IS_ERR);
|
||||
|
||||
long rust_helper_PTR_ERR(__force const void *ptr)
|
||||
{
|
||||
return PTR_ERR(ptr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rust_helper_PTR_ERR);
|
||||
|
||||
/*
|
||||
* We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type
|
||||
* as the Rust `usize` type, so we can use it in contexts where Rust
|
||||
|
@ -96,7 +96,6 @@ impl Error {
|
||||
/// # Safety
|
||||
///
|
||||
/// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
|
||||
#[allow(dead_code)]
|
||||
unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error {
|
||||
// INVARIANT: The contract ensures the type invariant
|
||||
// will hold.
|
||||
@ -189,3 +188,52 @@ pub fn to_result(err: core::ffi::c_int) -> Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform a kernel "error pointer" to a normal pointer.
|
||||
///
|
||||
/// Some kernel C API functions return an "error pointer" which optionally
|
||||
/// embeds an `errno`. Callers are supposed to check the returned pointer
|
||||
/// for errors. This function performs the check and converts the "error pointer"
|
||||
/// to a normal pointer in an idiomatic fashion.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// # use kernel::from_err_ptr;
|
||||
/// # use kernel::bindings;
|
||||
/// fn devm_platform_ioremap_resource(
|
||||
/// pdev: &mut PlatformDevice,
|
||||
/// index: u32,
|
||||
/// ) -> Result<*mut core::ffi::c_void> {
|
||||
/// // SAFETY: FFI call.
|
||||
/// unsafe {
|
||||
/// from_err_ptr(bindings::devm_platform_ioremap_resource(
|
||||
/// pdev.to_ptr(),
|
||||
/// index,
|
||||
/// ))
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
// TODO: Remove `dead_code` marker once an in-kernel client is available.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
|
||||
// CAST: Casting a pointer to `*const core::ffi::c_void` is always valid.
|
||||
let const_ptr: *const core::ffi::c_void = ptr.cast();
|
||||
// SAFETY: The FFI function does not deref the pointer.
|
||||
if unsafe { bindings::IS_ERR(const_ptr) } {
|
||||
// SAFETY: The FFI function does not deref the pointer.
|
||||
let err = unsafe { bindings::PTR_ERR(const_ptr) };
|
||||
// CAST: If `IS_ERR()` returns `true`,
|
||||
// then `PTR_ERR()` is guaranteed to return a
|
||||
// negative value greater-or-equal to `-bindings::MAX_ERRNO`,
|
||||
// which always fits in an `i16`, as per the invariant above.
|
||||
// And an `i16` always fits in an `i32`. So casting `err` to
|
||||
// an `i32` can never overflow, and is always valid.
|
||||
//
|
||||
// SAFETY: `IS_ERR()` ensures `err` is a
|
||||
// negative value greater-or-equal to `-bindings::MAX_ERRNO`.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
return Err(unsafe { Error::from_errno_unchecked(err as core::ffi::c_int) });
|
||||
}
|
||||
Ok(ptr)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user