From: "Onur Özkan" <work@onurozkan.dev>
To: Alice Ryhl <aliceryhl@google.com>
Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
daniel@sedlak.dev, dirk.behme@de.bosch.com, felipe_life@live.com,
tamird@gmail.com, dakr@kernel.org, tmgross@umich.edu,
a.hindborg@kernel.org, lossin@kernel.org,
bjorn3_gh@protonmail.com, gary@garyguo.net, boqun.feng@gmail.com,
alex.gaynor@gmail.com, ojeda@kernel.org
Subject: Re: [PATCH v2 1/1] rust: refactor to_result to return the original value
Date: Wed, 10 Sep 2025 15:47:46 +0300 [thread overview]
Message-ID: <20250910154746.03a3bc2f@nimda.home> (raw)
In-Reply-To: <CAH5fLggb=_Vtk74RONc+pQUSc1XrVi=jdD1=mHNs6-67ZCYB0A@mail.gmail.com>
On Wed, 10 Sep 2025 13:05:42 +0200
Alice Ryhl <aliceryhl@google.com> wrote:
> On Wed, Sep 10, 2025 at 12:59 PM Onur Özkan <work@onurozkan.dev>
> wrote:
> >
> > On Wed, 10 Sep 2025 06:26:27 +0000
> > Alice Ryhl <aliceryhl@google.com> wrote:
> >
> > > On Tue, Sep 09, 2025 at 08:00:13PM +0300, Onur Özkan wrote:
> > > > Current `to_result` helper takes a `c_int` and returns `Ok(())`
> > > > on success and this has some issues like:
> > > >
> > > > - Callers lose the original return value and often have to
> > > > store it in a temporary variable before calling `to_result`.
> > > >
> > > > - It only supports `c_int`, which makes callers to
> > > > unnecessarily cast when working with other types (e.g. `u16` in
> > > > phy abstractions). We even have some places that ignore to use
> > > > `to_result` helper because the input doesn't fit in `c_int`
> > > > (see [0]).
> > > >
> > > > [0]:
> > > > https://lore.kernel.org/all/20250822080252.773d6f54@nimda.home/
> > > >
> > > > This patch changes `to_result` to be generic and also return the
> > > > original value on success.
> > > >
> > > > So that the code that previously looked like:
> > > >
> > > > let ret = unsafe { bindings::some_ffi_call() };
> > > > to_result(ret).map(|()| SomeType::new(ret))
> > > >
> > > > can now be written more directly as:
> > > >
> > > > to_result(unsafe { bindings::some_ffi_call() })
> > > > .map(|ret| SomeType::new(ret))
> > > >
> > > > Similarly, code such as:
> > > >
> > > > let res: isize = $some_ffi_call();
> > > > if res < 0 {
> > > > return Err(Error::from_errno(res as i32));
> > > > }
> > > >
> > > > can now be used with `to_result` as:
> > > >
> > > > to_result($some_ffi_call())?;
> > > >
> > > > This patch only fixes the callers that broke after the changes
> > > > on `to_result`. I haven't included all the improvements made
> > > > possible by the new design since that could conflict with other
> > > > ongoing patches [1]. Once this patch is approved and applied, I
> > > > am planning to follow up with creating a "good first issue" on
> > > > [2] for those additional changes.
> > > >
> > > > [1]: https://lore.kernel.org/rust-for-linux/?q=to_result
> > > > [2]: https://github.com/Rust-for-Linux/linux
> > > >
> > > > Link:
> > > > https://rust-for-linux.zulipchat.com/#narrow/channel/288089/topic/x/near/536374456
> > > > Signed-off-by: Onur Özkan <work@onurozkan.dev>
> > >
> > > > diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
> > > > index a41de293dcd1..6563ea71e203 100644
> > > > --- a/rust/kernel/error.rs
> > > > +++ b/rust/kernel/error.rs
> > > > @@ -376,12 +376,19 @@ fn from(e: core::convert::Infallible) ->
> > > > Error { pub type Result<T = (), E = Error> =
> > > > core::result::Result<T, E>;
> > > >
> > > > /// Converts an integer as returned by a C kernel function to
> > > > an error if it's negative, and -/// `Ok(())` otherwise.
> > > > -pub fn to_result(err: crate::ffi::c_int) -> Result {
> > > > - if err < 0 {
> > > > - Err(Error::from_errno(err))
> > > > +/// returns the original value otherwise.
> > > > +pub fn to_result<T>(code: T) -> Result<T>
> > > > +where
> > > > + T: Copy + TryInto<i32>,
> > > > +{
> > > > + // Try casting into `i32`.
> > > > + let casted: crate::ffi::c_int =
> > > > code.try_into().unwrap_or(0); +
> > > > + if casted < 0 {
> > > > + Err(Error::from_errno(casted))
> > > > } else {
> > > > - Ok(())
> > > > + // Return the original input value.
> > > > + Ok(code)
> > > > }
> > > > }
> > >
> > > I don't think this is the best way to declare this function. The
> > > conversions I would want are:
> > >
> > > * i32 -> Result<u32>
> > > * isize -> Result<usize>
> > > * i64 -> Result<u64>
> > >
> > > Your commit messages mentions i16, but does the error types even
> > > fit in 16 bits? Maybe. But they don't fit in i8. That is to say,
> > > I think it should support all the types larger than i32 (the
> > > errors fit in those types too), but for the ones that are
> > > smaller, it might not make sense if the type is too small. That's
> > > the reverse of what you have now.
> > >
> > > We probably need a new trait. E.g.:
> > >
> > > trait ToResult {
> > > type Unsigned;
> > > fn to_result(self) -> Result<Self::Unsigned, Error>;
> > > }
> > >
> > > impl ToResult for i32 {
> > > type Unsigned = u32;
> > > fn to_result(self) -> Result<u32, Error> {
> > > ...
> > > }
> > > }
> > >
> > > impl ToResult for isize {
> > > type Unsigned = usize;
> > > fn to_result(self) -> Result<usize, Error> {
> > > ...
> > > }
> > > }
> > >
> > > pub fn to_result<T: ToResult>(code: T) -> Result<T::Unsigned> {
> > > T::to_result(code)
> > > }
> > >
> >
> > `Error::from_errno` is limited to i32, that's why I followed the
> > `TryInto<i32>` approach, but I like this design too.
>
> If you pass an i32 that is not a valid errno, then it becomes EINVAL.
> In the case of `isize`, I would say that if a negative isize does not
> fit in i32, then that should fall into the same scenario.
>
In that case replacing `unwrap_or(0)` with `map_err(|_| code::EINVAL)`
should do the job?
I also thought of an alternative to the custom-trait–based approach.
What do you think about something like this:
pub fn to_result<T, R>(code: T) -> Result<R>
where
T: Copy + TryInto<i32> + TryInto<R>,
{
// Try casting into `i32`.
let casted: crate::ffi::c_int = code.try_into().map_err(|_|
code::EINVAL)?;
if casted < 0 {
Err(Error::from_errno(casted))
} else {
// Return the original input value as `R`.
code.try_into().map_err(|_| code::EINVAL)
}
}
On the caller side, it would look like this:
let val: u16 = to_result(...)?;
The main difference here is that this version can be used to cast into
multiple different types, not just `i32 -> u32` or `i64 -> u64`.
Regards,
Onur
>
> > > > diff --git a/rust/kernel/miscdevice.rs
> > > > b/rust/kernel/miscdevice.rs index 6373fe183b27..22b72ae84c03
> > > > 100644 --- a/rust/kernel/miscdevice.rs
> > > > +++ b/rust/kernel/miscdevice.rs
> > > > @@ -79,7 +79,7 @@ pub fn register(opts: MiscDeviceOptions) ->
> > > > impl PinInit<Self, Error> { // the destructor of this type
> > > > deallocates the memory. // INVARIANT: If this returns `Ok(())`,
> > > > then the `slot` will contain a registered // misc device.
> > > > - to_result(unsafe {
> > > > bindings::misc_register(slot) })
> > > > + to_result(unsafe {
> > > > bindings::misc_register(slot) }).map(|_| ())
> > >
> > > This still uses the `map` pattern. Please change it too.
> > >
> > > Alice
> >
> >
> > I left that part intentionally and explained the reason in v2
> > changelog.
>
> I missed that, ok. I still prefer Ok::<...>()
next prev parent reply other threads:[~2025-09-10 12:48 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-09 17:00 [PATCH v2 0/1] rust: refactor to_result to return the original value Onur Özkan
2025-09-09 17:00 ` [PATCH v2 1/1] " Onur Özkan
2025-09-09 17:17 ` Miguel Ojeda
2025-09-09 17:43 ` Onur Özkan
2025-09-09 18:25 ` Onur
2025-09-09 18:25 ` Daniel Almeida
2025-09-09 18:53 ` Onur Özkan
2025-09-09 20:13 ` Daniel Almeida
2025-09-09 20:05 ` Miguel Ojeda
2025-09-09 20:12 ` Daniel Almeida
2025-09-09 20:25 ` Miguel Ojeda
2025-09-10 4:50 ` Onur Özkan
2025-09-10 6:26 ` Alice Ryhl
2025-09-10 10:58 ` Onur Özkan
2025-09-10 11:05 ` Alice Ryhl
2025-09-10 12:47 ` Onur Özkan [this message]
2025-09-10 12:50 ` Alice Ryhl
2025-09-10 12:55 ` Onur Özkan
2025-09-12 8:41 ` kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250910154746.03a3bc2f@nimda.home \
--to=work@onurozkan.dev \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=daniel@sedlak.dev \
--cc=dirk.behme@de.bosch.com \
--cc=felipe_life@live.com \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tamird@gmail.com \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.