rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Benno Lossin" <lossin@kernel.org>
To: "Remo Senekowitsch" <remo@buenzli.dev>,
	"Rob Herring" <robh@kernel.org>,
	"Saravana Kannan" <saravanak@google.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <benno.lossin@proton.me>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	"Dirk Behme" <dirk.behme@de.bosch.com>
Cc: <linux-kernel@vger.kernel.org>, <devicetree@vger.kernel.org>,
	<rust-for-linux@vger.kernel.org>
Subject: Re: [PATCH v4 6/9] rust: device: Add bindings for reading device properties
Date: Tue, 20 May 2025 13:04:01 +0200	[thread overview]
Message-ID: <DA0XS7JK5B71.3D2CS7QVKOM52@kernel.org> (raw)
In-Reply-To: <DA0X3RE11LJI.3GDSU2DK09HQ0@buenzli.dev>

On Tue May 20, 2025 at 12:32 PM CEST, Remo Senekowitsch wrote:
> On Tue May 20, 2025 at 9:37 AM CEST, Benno Lossin wrote:
>> On Sun May 4, 2025 at 7:31 PM CEST, Remo Senekowitsch wrote:
>>> +/// Implemented for all integers that can be read as properties.
>>> +///
>>> +/// This helper trait is needed on top of the existing [`Property`]
>>> +/// trait to associate the integer types of various sizes with their
>>> +/// corresponding `fwnode_property_read_*_array` functions.
>>> +pub trait PropertyInt: Copy {
>>> +    /// # Safety
>>> +    ///
>>> +    /// Callers must uphold the same safety invariants as for the various
>>> +    /// `fwnode_property_read_*_array` functions.
>>> +    unsafe fn read_array_from_fwnode_property(
>>> +        fwnode: *const bindings::fwnode_handle,
>>> +        propname: *const ffi::c_char,
>>> +        val: *mut Self,
>>> +        nval: usize,
>>> +    ) -> ffi::c_int;
>>
>> I really, really dislike that this trait has to have an unsafe function
>> with all those raw pointer inputs.
>
> What is the concrete problem with that? Or is it just "not pretty"?
> (I'm fine with making it prettier, just making sure I understand
> correctly.)

With the design I explained below, this becomes not necessary. Less
unsafe code always is better, since there are fewer places that can go
wrong.

Also hiding all the unsafe code inside of your module as private code or
implementation detail is also much better, as you prevent people from
accidentally using it.

>>> +}
>>> +// This macro generates implementations of the traits `Property` and
>>> +// `PropertyInt` for integers of various sizes. Its input is a list
>>> +// of pairs separated by commas. The first element of the pair is the
>>> +// type of the integer, the second one is the name of its corresponding
>>> +// `fwnode_property_read_*_array` function.
>>> +macro_rules! impl_property_for_int {
>>> +    ($($int:ty: $f:ident),* $(,)?) => { $(
>>> +        impl PropertyInt for $int {
>>> +            unsafe fn read_array_from_fwnode_property(
>>> +                fwnode: *const bindings::fwnode_handle,
>>> +                propname: *const ffi::c_char,
>>> +                val: *mut Self,
>>> +                nval: usize,
>>> +            ) -> ffi::c_int {
>>> +                // SAFETY: The safety invariants on the trait require
>>> +                // callers to uphold the invariants of the functions
>>> +                // this macro is called with.
>>> +                unsafe {
>>> +                    bindings::$f(fwnode, propname, val.cast(), nval)
>>> +                }
>>> +            }
>>> +        }
>>> +    )* };
>>> +}
>>> +impl_property_for_int! {
>>> +    u8: fwnode_property_read_u8_array,
>>> +    u16: fwnode_property_read_u16_array,
>>> +    u32: fwnode_property_read_u32_array,
>>> +    u64: fwnode_property_read_u64_array,
>>> +    i8: fwnode_property_read_u8_array,
>>> +    i16: fwnode_property_read_u16_array,
>>> +    i32: fwnode_property_read_u32_array,
>>> +    i64: fwnode_property_read_u64_array,
>>> +}
>>> +/// # Safety
>>> +///
>>> +/// Callers must ensure that if `len` is non-zero, `out_param` must be
>>> +/// valid and point to memory that has enough space to hold at least
>>> +/// `len` number of elements.
>>> +unsafe fn read_array_out_param<T: PropertyInt>(
>>> +    fwnode: &FwNode,
>>> +    name: &CStr,
>>> +    out_param: *mut T,
>>> +    len: usize,
>>> +) -> ffi::c_int {
>>> +    // SAFETY: `name` is non-null and null-terminated.
>>> +    // `fwnode.as_raw` is valid because `fwnode` is valid.
>>> +    // `out_param` is valid and has enough space for at least
>>> +    // `len` number of elements as per the safety requirement.
>>> +    unsafe {
>>> +        T::read_array_from_fwnode_property(fwnode.as_raw(), name.as_char_ptr(), out_param, len)
>>> +    }
>>> +}
>>
>> Why does this function exist? It doesn't do anything and just delegates
>> the call to `T::read_array_from_fwnode_property`.
>
> It's used in three places. Taking Rust references as input reduces the
> safety requirements the callers must uphold. But I guess it's a small
> benefit, I can remove it.

That's true, but why not make the trait take references if all users
will use references anyways :)

>> This feels like you're dragging the C interface through the lower layers
>> of your Rust abstractions, which I wouldn't do. I also looked a bit at
>> the C code and saw this comment in `driver/base/property.c:324`:
>>
>>      * It's recommended to call fwnode_property_count_u8() instead of calling
>>      * this function with @val equals %NULL and @nval equals 0.
>>
>> That probably holds also for the other functions, so maybe we should do
>> that instead? (although `fwnode_property_count_u8` just delegates and
>> calls with `fwnode_property_read_u8_array`...)
>
> Yeah, I saw that too. The original implementation is from Rob. I assume
> the recommendation is for users, maybe for clarity and readability of
> the code. These Rust abstractions are pretty low level, so I thought
> it's probably fine.

Yeah it's probably fine.

>> How about we do it like this:
>>
>>     pub trait PropertyInt: Copy + Sized + private::Sealed {
>>         /// ...
>>         ///
>>         /// Returns a reference to `out` containing all written elements.
>>         fn read<'a>(
>>             fwnode: &FwNode,
>>             name: &CStr,
>>             out: &'a mut [MaybeUninit<Self>],
>>         ) -> Result<&'a mut [Self]>;
>>
>>         fn length(fwnode: &FwNode, name: &CStr) -> Result<usize>;
>>     }
>>
>> And then have a macro to implement it on all the integers.
>
> I think I tried to make the macro as small as possible and use regular
> generics on top, because I was concerned people would be put off by big
> complicated macros. I'm fine with moving the actual trait implementation
> into the macro body, seems reasonable.

Big macro bodies are rarely the issue. Lots of parsing in declarative
macros is where they become unreadable.

> But still, I'm not sure why we're trying to make the PropertyInt trait's
> interface pretty or rusty. It's not supposed to be used, implemented or
> in any way interacted with outside this module. It's just a low-level
> building block to make some functions generic, giving users type
> inference.

Sure, but if we can make it safe, we should. I could also very much
imagine that someone has a statically allocated buffer they would want
to write stuff to and this function would then allow that with much
easier `unsafe` code than the current approach.

---
Cheers,
Benno

  reply	other threads:[~2025-05-20 11:04 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-04 17:31 [PATCH v4 0/9] More Rust bindings for device property reads Remo Senekowitsch
2025-05-04 17:31 ` [PATCH v4 1/9] rust: device: Create FwNode abstraction for accessing device properties Remo Senekowitsch
2025-05-12 13:59   ` Danilo Krummrich
2025-05-12 14:12   ` Danilo Krummrich
2025-05-04 17:31 ` [PATCH v4 2/9] rust: device: Enable accessing the FwNode of a Device Remo Senekowitsch
2025-05-04 17:31 ` [PATCH v4 3/9] rust: device: Move property_present() to FwNode Remo Senekowitsch
2025-05-12 17:29   ` Rob Herring
2025-05-12 17:44     ` Danilo Krummrich
2025-05-04 17:31 ` [PATCH v4 4/9] rust: device: Enable printing fwnode name and path Remo Senekowitsch
2025-05-04 17:31 ` [PATCH v4 5/9] rust: device: Introduce PropertyGuard Remo Senekowitsch
2025-05-05  5:14   ` Dirk Behme
2025-05-05 13:02     ` Remo Senekowitsch
2025-05-05 15:37       ` Rob Herring
2025-05-05 15:53         ` Remo Senekowitsch
2025-05-05 16:12           ` Danilo Krummrich
2025-05-05 18:33           ` Rob Herring
2025-05-12 17:09   ` Rob Herring
2025-05-04 17:31 ` [PATCH v4 6/9] rust: device: Add bindings for reading device properties Remo Senekowitsch
2025-05-12 13:36   ` Danilo Krummrich
2025-05-19 15:43     ` Remo Senekowitsch
2025-05-19 16:55       ` Danilo Krummrich
2025-05-19 19:51         ` Remo Senekowitsch
2025-05-20  7:21           ` Benno Lossin
2025-05-20  7:40             ` Benno Lossin
2025-05-20 10:37               ` Remo Senekowitsch
2025-05-20  7:37   ` Benno Lossin
2025-05-20 10:32     ` Remo Senekowitsch
2025-05-20 11:04       ` Benno Lossin [this message]
2025-05-04 17:31 ` [PATCH v4 7/9] rust: device: Add child accessor and iterator Remo Senekowitsch
2025-05-04 17:31 ` [PATCH v4 8/9] rust: device: Add property_get_reference_args Remo Senekowitsch
2025-05-04 17:31 ` [PATCH v4 9/9] samples: rust: platform: Add property read examples Remo Senekowitsch
2025-05-12 13:54   ` Danilo Krummrich
2025-05-12 11:49 ` [PATCH v4 0/9] More Rust bindings for device property reads Remo Senekowitsch
2025-05-12 12:04   ` Danilo Krummrich

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=DA0XS7JK5B71.3D2CS7QVKOM52@kernel.org \
    --to=lossin@kernel.org \
    --cc=a.hindborg@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=dakr@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dirk.behme@de.bosch.com \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rafael@kernel.org \
    --cc=remo@buenzli.dev \
    --cc=robh@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=saravanak@google.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).