From: Danilo Krummrich <dakr@redhat.com>
To: Greg KH <gregkh@linuxfoundation.org>
Cc: rafael@kernel.org, bhelgaas@google.com, ojeda@kernel.org,
alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com,
gary@garyguo.net, bjorn3_gh@protonmail.com,
benno.lossin@proton.me, a.hindborg@samsung.com,
aliceryhl@google.com, airlied@gmail.com,
fujita.tomonori@gmail.com, lina@asahilina.net,
pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com,
robh@kernel.org, daniel.almeida@collabora.com,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
Subject: Re: [PATCH v2 01/10] rust: pass module name to `Module::init`
Date: Wed, 26 Jun 2024 12:29:01 +0200 [thread overview]
Message-ID: <5d7b22c7-de22-4a8c-a122-624afc3d12f1@redhat.com> (raw)
In-Reply-To: <ZnSeAZu3IMA4fR8P@cassiopeiae>
Hi Greg,
On 6/20/24 23:24, Danilo Krummrich wrote:
This is a polite reminder about the below discussion.
> On Thu, Jun 20, 2024 at 06:36:08PM +0200, Greg KH wrote:
>> On Thu, Jun 20, 2024 at 06:10:05PM +0200, Danilo Krummrich wrote:
>>> On Thu, Jun 20, 2024 at 04:19:48PM +0200, Greg KH wrote:
>>>> On Wed, Jun 19, 2024 at 01:39:47AM +0200, Danilo Krummrich wrote:
>>>>> In a subsequent patch we introduce the `Registration` abstraction used
>>>>> to register driver structures. Some subsystems require the module name on
>>>>> driver registration (e.g. PCI in __pci_register_driver()), hence pass
>>>>> the module name to `Module::init`.
>>>>
>>>> I understand the need/want here, but it feels odd that you have to
>>>> change anything to do it.
>>>>
>>>>>
>>>>> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
>>>>> ---
>>>>> rust/kernel/lib.rs | 14 ++++++++++----
>>>>> rust/kernel/net/phy.rs | 2 +-
>>>>> rust/macros/module.rs | 3 ++-
>>>>> samples/rust/rust_minimal.rs | 2 +-
>>>>> samples/rust/rust_print.rs | 2 +-
>>>>> 5 files changed, 15 insertions(+), 8 deletions(-)
>>>>>
>>>>> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
>>>>> index a791702b4fee..5af00e072a58 100644
>>>>> --- a/rust/kernel/lib.rs
>>>>> +++ b/rust/kernel/lib.rs
>>>>> @@ -71,7 +71,7 @@ pub trait Module: Sized + Sync + Send {
>>>>> /// should do.
>>>>> ///
>>>>> /// Equivalent to the `module_init` macro in the C API.
>>>>> - fn init(module: &'static ThisModule) -> error::Result<Self>;
>>>>> + fn init(name: &'static str::CStr, module: &'static ThisModule) -> error::Result<Self>;
>>>>
>>>> Why can't the name come directly from the build system? Why must it be
>>>> passed into the init function of the module "class"? What is it going
>>>> to do with it?
>>>
>>> The name does come from the build system, that's where `Module::init` gets it
>>> from.
>>>
>>>>
>>>> A PCI, or other bus, driver "knows" it's name already by virtue of the
>>>> build system, so it can pass that string into whatever function needs
>>>
>>> Let's take pci_register_driver() as example.
>>>
>>> ```
>>> #define pci_register_driver(driver) \
>>> __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
>>> ```
>>>
>>> In C drivers this works because (1) it's a macro and (2) it's called directly
>>> from the driver code.
>>>
>>> In Rust, for very good reasons, we have abstractions for C APIs, hence the
>>> actual call to __pci_register_driver() does not come from code within the
>>> module, but from the PCI Rust abstraction `Module::init` calls into instead.
>>
>> I don't understand those reasons, sorry.
>
> Ok, good you point this out. We should definitely discuss this point then and
> build some consensus around it.
>
> I propose to focus on this point first and follow up with the discussion of the
> rest of the series afterwards.
>
> Let me explain why I am convinced that it's very important to have abstractions
> in place in general and from the get-go.
>
> In general, having abstractions for C APIs is the foundation of being able to
> make use of a lot of advantages Rust has to offer.
>
> The most obvious one are all the safety aspects. For instance, with an
> abstraction we have to get exactly one piece of code right in terms of pointer
> validity, lifetimes, type safety, API semantics, etc. and in all other places
> (e.g. drivers) we get the compiler to check those things for us through the
> abstraction.
>
> Now, the abstraction can be buggy or insufficient and hence there is no absolute
> safety guarantee. *But*, if we get this one thing right, there is nothing a
> driver can mess up by itself trying to do stupid things anymore.
>
> If we just call the C code instead we have to get it right everywhere instead.
>
> Now, you could approach this top-down instead and argue that we could at least
> benefit from Rust for the driver specific parts.
>
> Unfortunately, this doesn't really work out either. Also driver specific code is
> typically (very) closely connected to kernel APIs. If you want to use the safety
> aspects of Rust for the driver specific parts you inevitably end up writing
> abstractions for the C APIs in your driver.
>
> There are basically three options you can end up with:
>
> (1) An abstraction for the C API within your driver that is actually generic
> for every driver, and hence shouldn't be there.
> (2) Your driver specific code is full of raw pointers and `unsafe {}` calls,
> which in the end just means that you ended up baking the abstraction into
> your driver specific code.
> (3) You ignore everything, put everything in a huge `unsafe {}` block and
> compile C code with the Rust compiler. (Admittedly, maybe slightly
> overstated, but not that far off either.)
>
> The latter is also the reason why it doesn't make sense to only have
> abstractions for some things, but not for other.
>
> If an abstraction for B is based on A, but we don't start with A, then B ends up
> implementing (at least partially) the abstraction for A as well. For instance,
> if we don't implement `driver::Registration` then the PCI abstractions (and
> platform, usb, etc.) have to implement it.
>
> It really comes down to the point that it just bubbles up. We really have to do
> this bottom-up, otherwise we just end up moving those abstractions up, layer by
> layer, where they don't belong to and we re-implement them over and over again.
>
>>
>>> Consequently, we have to pass things through. This also isn't new, please note
>>> that the current code already does the same thing: `Module::init` (without this
>>> patch) is already declared as
>>>
>>> `fn init(module: &'static ThisModule) -> error::Result<Self>`
>>> passing through `ThisModule` for the exact same reason.
>>
>> Yeah, and I never quite understood that either :)
>
> Since commit 247b365dc8dc ("rust: add `kernel` crate") shows me your RB for
> that, am I good to assume that this one isn't a blocker?
>
>>
>>> Please also note that in the most common case (one driver per module) we don't
>>> see any of this anyway.
>>
>> True, but someone has to review and most importantly, maintain, this
>> glue code.
>>
>>> Just like the C macro module_pci_driver(), Rust drivers can use the
>>> `module_pci_driver!` macro.
>>>
>>> Example from Nova:
>>>
>>> ```
>>> kernel::module_pci_driver! {
>>> // The driver type that implements the corresponding probe() and
>>> // remove() driver callbacks.
>>> type: NovaDriver,
>>> name: "Nova",
>>> author: "Danilo Krummrich",
>>> description: "Nova GPU driver",
>>> license: "GPL v2",
>>> }
>>> ```
>>
>> As I said when you implemented this fun macro, don't do this yet.
>>
>> We added these "helper" macros WAY late in the development cycle of the
>> driver model, AFTER we were sure we got other parts right. There is no
>> need to attempt to implement all of what you can do in C today in Rust,
>> in fact, I would argue that we don't want to do that, just to make
>> things simpler to review the glue code, which is the most important part
>> here to get right!
>
> We're not reinventing the wheel here, we stick to the architecture the kernel
> already has.
>
> However, I understand that not starting with this macro directly makes it easier
> for you to see what's going on. I can introduce the macro in a separate patch to
> make it more obvious what's going on.
>
>>
>> Changing drivers later, to take advantage of code savings like this
>> macro can be done then, not just yet. Let's get this understood and
>> right first, no need to be tricky or complex.
>>
>> And, as I hinted at before, I don't think we should be doing this at all
>> just yet either. I still think a small "C shim" layer to wrap the
>> struct pci driver up and pass the calls to the rust portion of the
>> module is better to start with, it both saves you time and energy so
>> that you can work on what you really want to do (i.e. a driver in rust)
>> and not have to worry about the c bindings as that's the "tricky" part
>> that is stopping you from getting your driver work done.
>
> I strongly disagree here. As explained above, it just bubbles up, this approach
> would just make me end up having to write a lot of the code from the
> abstractions in the driver.
>
> However, it would indeed safe me time and energy to do just that. But that isn't
> really what I want. I also don't want to write a driver in Rust *only*.
>
> And I also don't really think that you want people, who commit to work hard to
> get things right, to just take the shortcut and create some random mess buried
> in a driver. :)
>
> What I actually want is to get to a solid foundation for Rust drivers in
> general, since I'm convinced that this provides a lot of value beyond the scope
> of a single driver.
>
> Since you've brought the topic up a few times, I am also willing to maintain
> those abstractions if this is a concern. Maybe one day the corresponding
> maintainers are comfortable enough and this isn't needed anymore, but at least
> until then, I'm happy to help out.
>
>>
>> After all, it's not the pci driver model code that is usually the tricky
>> bits to verify in C, it's the whole rest of the mess. Stick with a
>> small C file, with just the pci driver structure and device ids, and
>> then instantiate your rust stuff when probe() is called, and clean up
>> when release() is called.
>
> Again, this really bubbles up.
>
> What do we pass to Rust probe() function? A raw struct pci_dev pointer or the
> proper PCI device abstraction?
>
> How do we implement I/O memory mappings for PCI bars without PCI / I/O
> abstraction?
>
> How do we perform (boundary checked) I/O memory reads / writes without `Io`
> abstraction?
>
> How do we handle the lifetime of resources without `Devres` abstraction?
>
> How do we (properly) implement a DRM device registration abstraction without
> `Devres`?
>
> Luckily we already got the `Firmware` and `Device` abstraction in place. :)
>
>>
>> I can provide an example if needed.
>
> If you do so, please don't stop at the probe() boundary, please continue to the
> point where the Nova stub driver is. It really does just enough to show / proove
> that the abstractions tie together nicely. But it should be enough to see that
> you end up with either (1), (2) or (3) from above.
>
>>
>> thanks,
>>
>> greg k-h
>>
next prev parent reply other threads:[~2024-06-26 10:29 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-18 23:39 [PATCH v2 00/10] Device / Driver and PCI Rust abstractions Danilo Krummrich
2024-06-18 23:39 ` [PATCH v2 01/10] rust: pass module name to `Module::init` Danilo Krummrich
2024-06-20 14:19 ` Greg KH
2024-06-20 16:10 ` Danilo Krummrich
2024-06-20 16:36 ` Greg KH
2024-06-20 21:24 ` Danilo Krummrich
2024-06-26 10:29 ` Danilo Krummrich [this message]
2024-06-27 7:33 ` Greg KH
2024-06-27 7:41 ` Danilo Krummrich
2024-07-09 10:15 ` Danilo Krummrich
2024-07-10 14:02 ` Greg KH
2024-07-11 2:06 ` Danilo Krummrich
2024-07-22 11:23 ` Danilo Krummrich
2024-07-22 11:35 ` Greg KH
2024-08-02 12:06 ` Danilo Krummrich
2024-06-18 23:39 ` [PATCH v2 02/10] rust: implement generic driver registration Danilo Krummrich
2024-06-20 14:28 ` Greg KH
2024-06-20 17:12 ` Danilo Krummrich
2024-07-10 14:10 ` Greg KH
2024-07-11 2:06 ` Danilo Krummrich
2024-06-18 23:39 ` [PATCH v2 03/10] rust: implement `IdArray`, `IdTable` and `RawDeviceId` Danilo Krummrich
2024-06-20 14:31 ` Greg KH
2024-06-18 23:39 ` [PATCH v2 04/10] rust: add rcu abstraction Danilo Krummrich
2024-06-20 14:32 ` Greg KH
2024-06-18 23:39 ` [PATCH v2 05/10] rust: add `Revocable` type Danilo Krummrich
2024-06-20 14:38 ` Greg KH
2024-06-18 23:39 ` [PATCH v2 06/10] rust: add `dev_*` print macros Danilo Krummrich
2024-06-20 14:42 ` Greg KH
2024-06-18 23:39 ` [PATCH v2 07/10] rust: add `io::Io` base type Danilo Krummrich
2024-06-20 14:53 ` Greg KH
2024-06-21 9:43 ` Philipp Stanner
2024-06-21 11:47 ` Danilo Krummrich
2024-06-25 10:59 ` Andreas Hindborg
2024-06-25 13:12 ` Danilo Krummrich
2024-08-24 19:47 ` Daniel Almeida
2024-06-18 23:39 ` [PATCH v2 08/10] rust: add devres abstraction Danilo Krummrich
2024-06-20 14:58 ` Greg KH
2024-06-18 23:39 ` [PATCH v2 09/10] rust: pci: add basic PCI device / driver abstractions Danilo Krummrich
2024-06-20 15:11 ` Greg KH
2024-06-25 10:53 ` Andreas Hindborg
2024-06-25 13:33 ` Danilo Krummrich
2024-06-18 23:39 ` [PATCH v2 10/10] rust: pci: implement I/O mappable `pci::Bar` Danilo Krummrich
2024-06-19 12:04 ` [PATCH v2 00/10] Device / Driver and PCI Rust abstractions Viresh Kumar
2024-06-19 12:17 ` Greg KH
2024-06-19 12:42 ` Danilo Krummrich
2024-06-19 12:36 ` Danilo Krummrich
2024-06-20 10:05 ` Viresh Kumar
2024-06-20 11:09 ` 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=5d7b22c7-de22-4a8c-a122-624afc3d12f1@redhat.com \
--to=dakr@redhat.com \
--cc=a.hindborg@samsung.com \
--cc=airlied@gmail.com \
--cc=ajanulgu@redhat.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=daniel.almeida@collabora.com \
--cc=fujita.tomonori@gmail.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=lina@asahilina.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lyude@redhat.com \
--cc=ojeda@kernel.org \
--cc=pstanner@redhat.com \
--cc=rafael@kernel.org \
--cc=robh@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=wedsonaf@gmail.com \
/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).