From: Andreas Hindborg <a.hindborg@kernel.org>
To: "Daniel Almeida" <daniel.almeida@collabora.com>
Cc: "Danilo Krummrich" <dakr@kernel.org>,
"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>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Joel Becker" <jlbec@evilplan.org>,
"Christoph Hellwig" <hch@lst.de>,
"Peter Zijlstra" <peterz@infradead.org>,
"Ingo Molnar" <mingo@redhat.com>, "Will Deacon" <will@kernel.org>,
"Waiman Long" <longman@redhat.com>,
"Fiona Behrens" <me@kloenk.dev>,
"Charalampos Mitrodimas" <charmitro@posteo.net>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v4 2/4] rust: configfs: introduce rust support for configfs
Date: Tue, 25 Feb 2025 13:29:57 +0100 [thread overview]
Message-ID: <8734g2w6ka.fsf@kernel.org> (raw)
In-Reply-To: <118A2077-91B6-485F-AA5F-03D54AC5771C@collabora.com> (Daniel Almeida's message of "Tue, 25 Feb 2025 07:53:19 -0300")
"Daniel Almeida" <daniel.almeida@collabora.com> writes:
[...]
>>>> +
>>>> +impl<Data> Group<Data> {
>>>> + /// Create an initializer for a new group.
>>>> + ///
>>>> + /// When instantiated, the group will appear as a directory with the name
>>>> + /// given by `name` and it will contain attributes specified by `item_type`.
>>>> + pub fn new(
>>>> + name: CString,
>>>
>>> Is it me or this can be simply &CStr? `config_item_set_name` either copies into an internal
>>> buffer or allocates, so I see no reason to pass an owned type here.
>>
>> This function returns an initializer that would be bound by the lifetime
>> of the reference you pass in. That in turn has a very negative effect on
>> the ergonomics of the function, as it would limit the places you can
>> call it and still satisfy lifetime requirements.
>>
>> We could pass in a borrow and create an owned instance from the borrow,
>> then move the owned value into the initializer. But I think taking an
>> owned parameter in the first place is better.
>
>
> Do you mean that the CString is used to guarantee that the string is alive when the initializer
> actually runs?
Exactly.
>
> If so, I did not consider that. Please disregard this comment then.
OK.
>
>>
>> [...]
>>
>>>> +
>>>> +/// # Safety
>>>> +///
>>>> +/// `this` must be a valid pointer.
>>>> +///
>>>> +/// If `this` does not represent the root group of a `configfs` subsystem,
>>>> +/// `this` must be a pointer to a `bindings::config_group` embedded in a
>>>> +/// `Group<Parent>`.
>>>> +///
>>>> +/// Otherwise, `this` must be a pointer to a `bindings::config_group` that
>>>> +/// is embedded in a `bindings::configfs_subsystem` that is embedded in a
>>>> +/// `Subsystem<Parent>`.
>>>> +unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent {
>>>> + // SAFETY: `this` is a valid pointer.
>>>> + let is_root = unsafe { (*this).cg_subsys.is_null() };
>>>> +
>>>> + if !is_root {
>>>> + // SAFETY: By C API contact, `this` is a pointer to a
>>>> + // `bindings::config_group` that we passed as a return value in from
>>>> + // `make_group`. Such a pointer is embedded within a `Group<Parent>`.
>>>
>>> This phrase is confusing.
>>
>> I am not sure how to rephrase it to be less confusing. The pointer is
>> the thing returned from `make_group`. `make_group` would only return a
>> pointer into a `Group<Parent>`.
>
> The problem is this: "that we passed as a return value in from”, to pass something as a return value
> is already hard to parse, and when you reach the “in from” part, it becomes even harder.
>
> Just say a variation of what you said above, that is perfectly understandable.
>
> What about:
>
> ```
>
> `this` is a pointer to a `bindings::config_group` that was returned from a call to `make_group`. The pointer is known
> to be embedded within a `Group<Parent>`.
>
> ```
How is this:
// SAFETY: By C API contact,`this` was returned from a call to
// `make_group`. The pointer is known to be embedded within a
// `Group<Parent>`.
[...]
>>>> +
>>>> +/// A `configfs` attribute.
>>>> +///
>>>> +/// An attribute appears as a file in configfs, inside a folder that represent
>>>> +/// the group that the attribute belongs to.
>>>> +#[repr(transparent)]
>>>> +pub struct Attribute<const ID: u64, O, Data> {
>>>
>>> The first thing I thought here is “what is O?!"
>>
>> Would you prefer a rename to "Operations"? I was told to not add trait
>> bounds on the struct, because it is not necessary.
>
> I’d prefer Operations, yes.
>
>>
>>>
>>>> + attribute: Opaque<bindings::configfs_attribute>,
>>>> + _p: PhantomData<(O, Data)>,
>>>> +}
>>>> +
>>>> +// SAFETY: We do not provide any operations on `Attribute`.
>>>> +unsafe impl<const ID: u64, O, Data> Sync for Attribute<ID, O, Data> {}
>>>> +
>>>> +// SAFETY: Ownership of `Attribute` can safely be transferred to other threads.
>>>> +unsafe impl<const ID: u64, O, Data> Send for Attribute<ID, O, Data> {}
>>>> +
>>>> +impl<const ID: u64, O, Data> Attribute<ID, O, Data>
>>>> +where
>>>> + O: AttributeOperations<ID, Data = Data>,
>>>
>>> I recommend renaming “O" into something that denotes this bound better.
>>>
>>> It can be terse as appropriate, but simply “O” is a bit *too terse* .
>>
>> Right, I agree. However, other reviewers have argued negatively about
>> using 4 letters for the "Data" bound, since generic type parameters are
>> often just single capital letters.
>
> This is a convention, that is all. As a person trying to make sense of this code, Data was *much*
> more informative than T or U, or etc. Same for `Parent`.
>
> If you see things like:
>
> ```
> impl<Data> Subsystem<Data>
> ```
>
> You already know it’s a type parameter. If you click on Data, assuming LSP support, it will also tell
> you that.
>
> This code is already a bit hard to follow as is, let’s make sure that the types actually aid in its
> comprehension and not the other way around, please.
I would agree. I believe Benno was arguing that it is difficult to see
what identifiers are generic type parameters when they are words rather
than letters.
[...]
>>>> +/// A list of attributes.
>>>> +///
>>>> +/// This type is used to construct a new [`ItemType`]. It represents a list of
>>>> +/// [`Attribute`] that will appear in the directory representing a [`Group`].
>>>> +/// Users should not directly instantiate this type, rather they should use the
>>>> +/// [`kernel::configfs_attrs`] macro to declare a static set of attributes for a
>>>> +/// group.
>>>> +#[repr(transparent)]
>>>> +pub struct AttributeList<const N: usize, Data>(
>>>> + UnsafeCell<[*mut kernel::ffi::c_void; N]>,
>>>
>>> For the sake of maintainability, can you provide some docs on this type?
>>>
>>> For example, what is the c_void here?
>>
>> As per the docstring above, is a list of `Attribute`. I can expand it a bit:
>>
>> /// Users should not directly instantiate this type, rather they should use the
>> /// [`kernel::configfs_attrs`] macro to declare a static set of attributes for a
>> /// group.
>> +///
>> +/// # Note
>> +///
>> +/// This type is constructed statically at compile time and is by the
>> +/// [`kernel::configfs_attrs`] macro.
>> #[repr(transparent)]
>> pub struct AttributeList<const N: usize, Data>(
>> + /// Null terminated Array of pointers to `Attribute`. The type is `c_void`
>> + /// to conform to the C API.
>
> Yes this is much better :)
Let's go with that then.
[...]
>>>> + $(
>>>> + static [< $data:upper _TPE >]:
>>>> + $crate::configfs::ItemType<$container, $data> =
>>>> + $crate::configfs::ItemType::<$container, $data>::
>>>> + new_with_child_ctor::<N, $child>(
>>>> + &THIS_MODULE, &[<$ data:upper _ATTRS >]
>>>> + );
>>>> + )?
>>>> +
>>>> + & [< $data:upper _TPE >]
>>>> + }
>>>> + }
>>>> + };
>>>> +
>>>> +}
>>>
>>> Andreas, just a suggestion for the sake of maintainability, can you add some docs to this macro?
>>>
>>> I think you’ll agree that there is a *lot* going on here.
>>>
>>> In fact, this patch is a bit complex, so kudos on making it work in a very simple way for the callers.
>>
>> I could write a small wall of text and do some step by step expansion of
>> the macro. But I would rather not, since we are soon (TM) going to have
>> `syn` and `quote`, and all this horror will go away.
>
> Ok, your call.
>
>>
>> One way to help parsing this mess, is using the "expand macro" feature
>> of `rust-analyzer` in an editor and looking at the expanded code.
>
> I wonder if that can’t be pasted inline with the docs for a trivial use of the macro?
>
> I will take the verbosity *any day* over trying to figure out what is going on
> manually here.
>
> Or you can wait for syn and quote, as you said, that’s OK.
>
> By the way, with the somewhat limited support for rust-analyzer in the kernel,
> I wonder whether that is in fact possible. Things are much more restricted for
> non-Cargo projects.
It is working for me at least. I build the rust-project.json with `make
rust-analyzer`. I build out of tree, so I have to move the file to the
source tree manually. No additional steps required.
Best regards,
Andreas Hindborg
next prev parent reply other threads:[~2025-02-25 12:30 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-24 13:21 [PATCH v4 0/4] rust: configfs abstractions Andreas Hindborg
2025-02-24 13:21 ` [PATCH v4 1/4] rust: sync: change `<Arc<T> as ForeignOwnable>::PointedTo` to `T` Andreas Hindborg
2025-02-24 21:22 ` Daniel Almeida
2025-02-24 13:21 ` [PATCH v4 2/4] rust: configfs: introduce rust support for configfs Andreas Hindborg
2025-02-24 22:30 ` Daniel Almeida
2025-02-25 10:11 ` Andreas Hindborg
2025-02-25 10:53 ` Daniel Almeida
2025-02-25 12:29 ` Andreas Hindborg [this message]
2025-02-25 13:01 ` Daniel Almeida
2025-02-24 13:21 ` [PATCH v4 3/4] rust: configfs: add a sample demonstrating configfs usage Andreas Hindborg
2025-02-25 9:37 ` Daniel Almeida
2025-02-25 10:23 ` Andreas Hindborg
2025-02-25 10:58 ` Daniel Almeida
2025-02-24 13:21 ` [PATCH v4 4/4] MAINTAINERS: add entry for configfs Rust abstractions Andreas Hindborg
2025-02-25 9:38 ` Daniel Almeida
2025-02-24 16:55 ` [PATCH v4 0/4] rust: configfs abstractions Daniel Almeida
2025-02-24 19:12 ` Andreas Hindborg
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=8734g2w6ka.fsf@kernel.org \
--to=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=charmitro@posteo.net \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=gary@garyguo.net \
--cc=hch@lst.de \
--cc=jlbec@evilplan.org \
--cc=linux-kernel@vger.kernel.org \
--cc=longman@redhat.com \
--cc=me@kloenk.dev \
--cc=mingo@redhat.com \
--cc=ojeda@kernel.org \
--cc=peterz@infradead.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=will@kernel.org \
/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.