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 02/10] rust: implement generic driver registration
Date: Thu, 11 Jul 2024 04:06:35 +0200 [thread overview]
Message-ID: <Zo8-K7vKECn0X9cR@pollux> (raw)
In-Reply-To: <2024071052-bunion-kinswoman-6577@gregkh>
(Please read my reply to Patch 1 first)
On Wed, Jul 10, 2024 at 04:10:40PM +0200, Greg KH wrote:
> On Thu, Jun 20, 2024 at 07:12:42PM +0200, Danilo Krummrich wrote:
> > On Thu, Jun 20, 2024 at 04:28:23PM +0200, Greg KH wrote:
> > > On Wed, Jun 19, 2024 at 01:39:48AM +0200, Danilo Krummrich wrote:
> > > > Implement the generic `Registration` type and the `DriverOps` trait.
> > >
> > > I don't think this is needed, more below...
> > >
> > > > The `Registration` structure is the common type that represents a driver
> > > > registration and is typically bound to the lifetime of a module. However,
> > > > it doesn't implement actual calls to the kernel's driver core to register
> > > > drivers itself.
> > >
> > > But that's not what normally happens, more below...
> >
> > I can't find below a paragraph that seems related to this, hence I reply here.
> >
> > The above is just different wording for: A driver is typically registered in
> > module_init() and unregistered in module_exit().
> >
> > Isn't that what happens normally?
>
> Yes, but it's nothing we have ever used in the kernel before. You are
> defining new terms in some places, and renaming existing ones in others,
> which is going to do nothing but confuse us all.
We're not renaming anything, but...
New terms, yes, because it's new structures that aren't needed in C, but in
Rust. Why do we need those things in Rust, but not in C you may ask.
Let me try to explain it while trying to clarify what the `Registration` and
`DriverOps` types are actually used for, as promised in my reply to Patch 1.
The first misunderstanding may be that they abstract something in drivers/base/,
but that's not the case. In fact, those are not abstractions around C
structures themselfes. Think of them as small helpers to implement driver
abstractions in general (e.g. PCI, platform, etc.), which is why they are in a
file named driver.rs.
Now, what are `DriverOps`? It's just an interface that asks the implementer of
the interface to implement a register() and an unregister() function. PCI
obviously does implement this as pci_register_driver() and
pci_unregister_driver().
Having that said, I agree with you that `DriverOps` is a bad name, I think it
should be `RegistrationOps` instead - it represents the operations to register()
and unregister() a driver. I will use this name in the following instead, it is
less confusing.
In terms of what a `Registration` does and why we need this in Rust, but not in
C it is easiest to see from an example with some inline comments:
```
struct MyDriver;
impl pci::Driver for MyDriver {
define_pci_id_table! {
bindings::PCI_VENDOR_ID_FOO, bindings::PCI_ANY_ID,
None,
}
fn probe(dev: ARef<pci::Device>) {}
fn remove() {}
}
struct MyModule {
// `pci::RegOps` is the PCI implementation of `RegistrationOps`, i.e.
// `pci::Ops::register()` calls pci_register_driver() and
// `pci::Ops::unregister()` calls pci_unregister_driver().
//
// `pci::RegOps` also creates the `struct pci_dev` setting probe() to
// `MyDriver::probe` and remove() to `MyDriver::remove()`.
reg: Registration<pci::RegOps<MyDriver>>,
}
impl kernel::Moduke for MyModule {
fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
Ok(MyModule {
reg: Registration::<pci::RegOps<MyDriver>>::new(name, module),
})
}
}
```
This code is equivalent to the following C code:
```
static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) {}
static void remove(struct pci_dev *pdev) {}
static struct pci_driver my_pci_driver {
.name = "my_driver",
.id_table = pci_ids,
.probe = probe,
.remove = remove,
};
static int __init my_module_init(void)
{
pci_register_driver(my_pci_driver);
}
module_init(my_module_init);
static void __exit my_module_exit(void)
{
pci_unregister_driver(my_pci_driver();
}
module_exit(my_module_exit);
```
You may have noticed that the Rust code doesn't need `Module::exit` at all. And
the reason is the `Registration` type.
`Registration` is implemented as:
```
struct Registration<T: RegistrationOps> {
// In the example above `T::DriverType` is struct pci_dev.
drv: T::DriverType,
}
impl<T: RegistrationOps> Registration<T> {
pub fn new(name: &'static Cstr, module &'static ThisModule) -> Self {
// SAFETY: `T::DriverType` is a C type (e.g. struct pci_dev) and
// can be zero initialized.
// This is a bit simplified, to not bloat the example with
// pinning.
let drv: T::DriverType = unsafe { core::mem::zeroed() };
// In this example, this calls `pci::RegOps::register`, which
// initializes the struct pci_dev and calls
// pci_register_driver().
T::register(drv, name, module);
}
}
impl<T: RegistrationOps> Drop for Registration<T> {
fn drop(&mut self) {
// This calls pci_unregister_driver() on the struct pci_dev
// stored in `self.drv`.
T::unregister(self.drv);
}
}
```
As you can see, once the `Registration` goes out of scope the driver is
automatically unregistered due to the drop() implementation, which is why we
don't need `Module::exit`.
This also answers why we need a `Registration` structure in Rust, but not in C.
Rust uses different programming paradigms than C, and it uses type
representations with `Drop` traits to clean things up, rather than relying on
the user of the API doing it manually.
I really hope this explanation and example helps and contributes to progress.
As you can see I really put a lot of effort and dedication into this work.
- Danilo
--
Just for completeness, please find the relevant parts of `pci::RegOps` below.
```
impl<T: Driver> driver::DriverOps for Adapter<T> {
type DriverType = bindings::pci_driver;
fn register(
pdrv: &mut bindings::pci_driver,
name: &'static CStr,
module: &'static ThisModule,
) -> Result {
pdrv.name = name.as_char_ptr();
pdrv.probe = Some(Self::probe_callback);
pdrv.remove = Some(Self::remove_callback);
pdrv.id_table = T::ID_TABLE.as_ref();
// SAFETY: `pdrv` is guaranteed to be a valid `RegType`.
to_result(unsafe {
bindings::__pci_register_driver(pdrv as _, module.0, name.as_char_ptr())
})
}
fn unregister(pdrv: &mut Self::RegType) {
// SAFETY: `pdrv` is guaranteed to be a valid `DriverType`.
unsafe { bindings::pci_unregister_driver(pdrv) }
}
}
```
(cutting the rest of the mail, since everything else is covered already)
next prev parent reply other threads:[~2024-07-11 2:06 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
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 [this message]
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=Zo8-K7vKECn0X9cR@pollux \
--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