[1/5] rust: error: Add Error::to_ptr()

Message ID 20230224-rust-error-v1-1-f8f9a9a87303@asahilina.net
State New
Headers
Series rust: error: Add missing wrappers to convert to/from kernel error codes |

Commit Message

Asahi Lina Feb. 24, 2023, 8:50 a.m. UTC
  This is the Rust equivalent to ERR_PTR(), for use in C callbacks.
Marked as #[allow(dead_code)] for now, since it does not have any
consumers yet.

Signed-off-by: Asahi Lina <lina@asahilina.net>
---
 rust/helpers.c       | 7 +++++++
 rust/kernel/error.rs | 7 +++++++
 2 files changed, 14 insertions(+)
  

Comments

Gary Guo Feb. 25, 2023, 10:14 p.m. UTC | #1
On Fri, 24 Feb 2023 17:50:19 +0900
Asahi Lina <lina@asahilina.net> wrote:

> This is the Rust equivalent to ERR_PTR(), for use in C callbacks.
> Marked as #[allow(dead_code)] for now, since it does not have any
> consumers yet.
> 
> Signed-off-by: Asahi Lina <lina@asahilina.net>
> ---
>  rust/helpers.c       | 7 +++++++
>  rust/kernel/error.rs | 7 +++++++
>  2 files changed, 14 insertions(+)
> 
> diff --git a/rust/helpers.c b/rust/helpers.c
> index 09a4d93f9d62..89f4cd1e0df3 100644
> --- a/rust/helpers.c
> +++ b/rust/helpers.c
> @@ -20,6 +20,7 @@
>  
>  #include <linux/bug.h>
>  #include <linux/build_bug.h>
> +#include <linux/err.h>
>  #include <linux/refcount.h>
>  
>  __noreturn void rust_helper_BUG(void)
> @@ -46,6 +47,12 @@ bool rust_helper_refcount_dec_and_test(refcount_t *r)
>  }
>  EXPORT_SYMBOL_GPL(rust_helper_refcount_dec_and_test);
>  
> +__force void *rust_helper_ERR_PTR(long err)
> +{
> +	return ERR_PTR(err);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_ERR_PTR);
> +

I know that we already have `IS_ERR` in helpers.c, but having to go
through FFI and helper functions for something as simple as a cast
feels awkward to me.

Given that `ERR_PTR`'s C definition is very unlike to change, would it
be problematic if we just reimplement it in Rust as

```rust
fn ERR_PTR(error: core::ffi::c_long) -> *mut core::ffi::c_void {
    error as _
    // Or `core::ptr::invalid(error as _)` with strict provenance
}
```
?

I personally think it should be fine, but I'll leave the decision to
Miguel.

Best,
Gary
  
Miguel Ojeda Feb. 26, 2023, 2:26 p.m. UTC | #2
On Sat, Feb 25, 2023 at 11:14 PM Gary Guo <gary@garyguo.net> wrote:
>
> I know that we already have `IS_ERR` in helpers.c, but having to go
> through FFI and helper functions for something as simple as a cast
> feels awkward to me.
>
> Given that `ERR_PTR`'s C definition is very unlike to change, would it
> be problematic if we just reimplement it in Rust as
>
> ```rust
> fn ERR_PTR(error: core::ffi::c_long) -> *mut core::ffi::c_void {
>     error as _
>     // Or `core::ptr::invalid(error as _)` with strict provenance
> }
> ```
> ?
>
> I personally think it should be fine, but I'll leave the decision to
> Miguel.

On one hand, we have tried to minimize duplication (and, in general,
any changes to the C side) so far where possible, especially
pre-merge, doing it only when needed, e.g. for `const` purposes.

On the other hand, being in the kernel opens up a few possibilities to
consider, and it is true it feels like some of these could get
reimplemented, even if not strictly needed. If we can show a
performance/text size difference on e.g. a non-trivial subsystem or
module, I think we should do it.

If we do it, then I think we should add a note on the C side so that
it is clear there is a duplicated implementation elsewhere, avoiding
future problems. In fact, it would be ideal to do it consistently,
e.g. also for the ioctl ones. Something like:

    /* Rust: reimplemented as `kernel::error::ERR_PTR`. */
    static inline void * __must_check ERR_PTR(long error)
    {
        return (void *) error;
    }

Or perhaps something even smaller.

But I don't want to block the rest of the work on this, which may need
some extra/parallel discussion, so let's keep the helper for the time
being. That way we can also do that change independently and justify
the change showing the difference in performance/text, if any, in the
commit message.

Cheers,
Miguel
  
Miguel Ojeda March 7, 2023, 8:21 p.m. UTC | #3
On Sun, Feb 26, 2023 at 3:26 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> But I don't want to block the rest of the work on this, which may need
> some extra/parallel discussion, so let's keep the helper for the time
> being. That way we can also do that change independently and justify
> the change showing the difference in performance/text, if any, in the
> commit message.

Opened https://github.com/Rust-for-Linux/linux/issues/984 to help to
remember it.

Cheers,
Miguel
  

Patch

diff --git a/rust/helpers.c b/rust/helpers.c
index 09a4d93f9d62..89f4cd1e0df3 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -20,6 +20,7 @@ 
 
 #include <linux/bug.h>
 #include <linux/build_bug.h>
+#include <linux/err.h>
 #include <linux/refcount.h>
 
 __noreturn void rust_helper_BUG(void)
@@ -46,6 +47,12 @@  bool rust_helper_refcount_dec_and_test(refcount_t *r)
 }
 EXPORT_SYMBOL_GPL(rust_helper_refcount_dec_and_test);
 
+__force void *rust_helper_ERR_PTR(long err)
+{
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(rust_helper_ERR_PTR);
+
 /*
  * 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
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 5b9751d7ff1d..8611758e27f4 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -76,6 +76,13 @@  impl Error {
     pub fn to_kernel_errno(self) -> core::ffi::c_int {
         self.0
     }
+
+    /// Returns the error encoded as a pointer.
+    #[allow(dead_code)]
+    pub(crate) fn to_ptr<T>(self) -> *mut T {
+        // SAFETY: Valid as long as self.0 is a valid error
+        unsafe { bindings::ERR_PTR(self.0.into()) as *mut _ }
+    }
 }
 
 impl From<AllocError> for Error {