linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/3] Implement TryFrom<&Device> for bus specific devices
@ 2025-03-21 21:47 Danilo Krummrich
  2025-03-21 21:47 ` [PATCH v4 1/3] rust: device: implement bus_type_raw() Danilo Krummrich
                   ` (3 more replies)
  0 siblings, 4 replies; 21+ messages in thread
From: Danilo Krummrich @ 2025-03-21 21:47 UTC (permalink / raw)
  To: bhelgaas, gregkh, rafael, ojeda, alex.gaynor, boqun.feng, gary,
	bjorn3_gh, benno.lossin, a.hindborg, aliceryhl, tmgross
  Cc: linux-pci, rust-for-linux, linux-kernel, Danilo Krummrich

This series provides a mechanism to safely convert a struct device into its
corresponding bus specific device instance, if any.

In C a generic struct device is typically converted to a specific bus device
with container_of(). This requires the caller to know whether the generic struct
device is indeed embedded within the expected bus specific device type.

In Rust we can do the same thing by implementing the TryFrom trait, e.g.

        impl TryFrom<&Device> for pci::Device

This is a safe operation, since we can check whether dev->bus equals the the
expected struct bus_type.

A branch containing the patches can be found in [1].

This is needed for the auxiliary bus abstractions and connecting nova-core with
nova-drm. [2]

[1] https://web.git.kernel.org/pub/scm/linux/kernel/git/dakr/linux.git/log/?h=rust/device
[2] https://gitlab.freedesktop.org/drm/nova/-/tree/staging/nova-drm

Changes in v4:
  - work around a minor issue in rustc < 1.82
    - https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html#safely-addressing-unsafe-statics

Changes in v3:
  - drop patch to add Device::parent(), will make it crate private and part of
    the auxbus series
  - safety comment: clarify that a device' bus type is guaranteed to be set
    correctly by the corresponding C code

Changes in v2:
  - s/unsafe { *self.as_raw() }.parent/unsafe { (*self.as_raw()).parent }/
  - expand safety comment on Device::bus_type_raw()

Danilo Krummrich (3):
  rust: device: implement bus_type_raw()
  rust: pci: impl TryFrom<&Device> for &pci::Device
  rust: platform: impl TryFrom<&Device> for &platform::Device

 rust/kernel/device.rs   |  9 +++++++++
 rust/kernel/pci.rs      | 25 +++++++++++++++++++++++--
 rust/kernel/platform.rs | 25 +++++++++++++++++++++++--
 3 files changed, 55 insertions(+), 4 deletions(-)


base-commit: 51d0de7596a458096756c895cfed6bc4a7ecac10
-- 
2.48.1


^ permalink raw reply	[flat|nested] 21+ messages in thread
* Re: [PATCH v4 2/3] rust: pci: impl TryFrom<&Device> for &pci::Device
@ 2025-04-07 15:52 Benno Lossin
  0 siblings, 0 replies; 21+ messages in thread
From: Benno Lossin @ 2025-04-07 15:52 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: Greg KH, bhelgaas, rafael, ojeda, alex.gaynor, boqun.feng, gary,
	bjorn3_gh, a.hindborg, aliceryhl, tmgross, linux-pci,
	rust-for-linux, linux-kernel

On Wed Apr 2, 2025 at 11:06 AM CEST, Danilo Krummrich wrote:
> On Wed, Apr 02, 2025 at 12:05:56AM +0000, Benno Lossin wrote:
>> On Tue Apr 1, 2025 at 3:51 PM CEST, Danilo Krummrich wrote:
>> > On Mon, Mar 24, 2025 at 06:32:53PM +0000, Benno Lossin wrote:
>> >> On Mon Mar 24, 2025 at 7:13 PM CET, Danilo Krummrich wrote:
>> >> > On Mon, Mar 24, 2025 at 05:36:45PM +0000, Benno Lossin wrote:
>> >> >> On Mon Mar 24, 2025 at 5:49 PM CET, Danilo Krummrich wrote:
>> >> >> > On Mon, Mar 24, 2025 at 04:39:25PM +0000, Benno Lossin wrote:
>> >> >> >> On Sun Mar 23, 2025 at 11:10 PM CET, Danilo Krummrich wrote:
>> >> >> >> > On Sat, Mar 22, 2025 at 11:10:57AM +0100, Danilo Krummrich wrote:
>> >> >> >> >> On Fri, Mar 21, 2025 at 08:25:07PM -0700, Greg KH wrote:
>> >> >> >> >> > Along these lines, if you can convince me that this is something that we
>> >> >> >> >> > really should be doing, in that we should always be checking every time
>> >> >> >> >> > someone would want to call to_pci_dev(), that the return value is
>> >> >> >> >> > checked, then why don't we also do this in C if it's going to be
>> >> >> >> >> > something to assure people it is going to be correct?  I don't want to
>> >> >> >> >> > see the rust and C sides get "out of sync" here for things that can be
>> >> >> >> >> > kept in sync, as that reduces the mental load of all of us as we travers
>> >> >> >> >> > across the boundry for the next 20+ years.
>> >> >> >> >> 
>> >> >> >> >> I think in this case it is good when the C and Rust side get a bit
>> >> >> >> >> "out of sync":
>> >> >> >> >
>> >> >> >> > A bit more clarification on this:
>> >> >> >> >
>> >> >> >> > What I want to say with this is, since we can cover a lot of the common cases
>> >> >> >> > through abstractions and the type system, we're left with the not so common
>> >> >> >> > ones, where the "upcasts" are not made in the context of common and well
>> >> >> >> > established patterns, but, for instance, depend on the semantics of the driver;
>> >> >> >> > those should not be unsafe IMHO.
>> >> >> >> 
>> >> >> >> I don't think that we should use `TryFrom` for stuff that should only be
>> >> >> >> used seldomly. A function that we can document properly is a much better
>> >> >> >> fit, since we can point users to the "correct" API.
>> >> >> >
>> >> >> > Most of the cases where drivers would do this conversion should be covered by
>> >> >> > the abstraction to already provide that actual bus specific device, rather than
>> >> >> > a generic one or some priv pointer, etc.
>> >> >> >
>> >> >> > So, the point is that the APIs we design won't leave drivers with a reason to
>> >> >> > make this conversion in the first place. For the cases where they have to
>> >> >> > (which should be rare), it's the right thing to do. There is not an alternative
>> >> >> > API to point to.
>> >> >> 
>> >> >> Yes, but for such a case, I wouldn't want to use `TryFrom`, since that
>> >> >> trait to me is a sign of a canonical way to convert a value.
>> >> >
>> >> > Well, it is the canonical way to convert, it's just that by the design of other
>> >> > abstractions drivers should very rarely get in the situation of needing it in
>> >> > the first place.
>> >> 
>> >> I'd still prefer it though, since one can spot a
>> >> 
>> >>     let dev = CustomDevice::checked_from(dev)?
>> >> 
>> >> much better in review than the `try_from` conversion. It also prevents
>> >> one from giving it to a generic interface expecting the `TryFrom` trait.
>> >
>> > (I plan to rebase this on my series introducing the Bound device context [1].)
>> >
>> > I thought about this for a while and I still think TryFrom is fine here.
>> 
>> What reasoning do you have?
>
> The concern in terms of abuse is that one could try to randomly guess the
> "outer" device type (if any), which obiously indicates a fundamental design
> issue.
>
> But that's not specific to devices; it is a common anti-pattern in OOP to
> randomly guess the subclass type of an object instance.
>
> So, I don't think the situation here is really that special such that it needs
> an extra highlight.

I re-read the docs on `TryFrom` and I have some new thoughts:
`TryFrom<device::Device> for pci::Device` is indeed similar to
`TryFrom<i64> for i32`. If the `device::Device` is embedded in a
`pci::Device`, then the `Ok` value is obvious. If not, then the error is
also clear and the user should do something in that case. So in this
regard, it's pretty natural to use `TryFrom`.

Now my initial thoughts were more on the side of if people should avoid
it, then it shouldn't be named `try_from`. But IIUC, most of the time
they won't be able to call `try_from`, since they already have the
correct type to begin with.

Ultimately this is your call to make, if you think that it's unlikely
that people will use the `try_from` in the wrong places, then go for it.

>> > At some point I want to replace this implementation with a macro, since the code
>> > is pretty similar for bus specific devices. I think that's a bit cleaner with
>> > TryFrom compared to with a custom method, since we'd need the bus specific
>> > device to call the macro from the generic impl, i.e.
>> >
>> > 	impl<Ctx: DeviceContext> Device<Ctx>
>> >
>> > rather than a specific one, which we can't control. We can control it for
>> > TryFrom though.
>> 
>> We could have our own trait for that.
>
> I don't think we should have a trait specific for devices for this. If we really
> think the above anti-pattern deserves special attention, then we should have a
> generic trait (e.g. FromSuper<T>) instead.
>
> But I'm not sure that we really need to put special attention on that.

That's fair, but I think then it would lose the `Device` specific docs
about not using it if there are other options.

---
Cheers,
Benno


^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2025-04-19 12:57 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-21 21:47 [PATCH v4 0/3] Implement TryFrom<&Device> for bus specific devices Danilo Krummrich
2025-03-21 21:47 ` [PATCH v4 1/3] rust: device: implement bus_type_raw() Danilo Krummrich
2025-03-22  3:10   ` Greg KH
2025-03-21 21:47 ` [PATCH v4 2/3] rust: pci: impl TryFrom<&Device> for &pci::Device Danilo Krummrich
2025-03-22  3:25   ` Greg KH
2025-03-22 10:10     ` Danilo Krummrich
2025-03-23 22:10       ` Danilo Krummrich
2025-03-24 13:54         ` Greg KH
2025-03-24 17:05           ` Danilo Krummrich
2025-03-24 16:39         ` Benno Lossin
2025-03-24 16:49           ` Danilo Krummrich
2025-03-24 17:36             ` Benno Lossin
2025-03-24 18:13               ` Danilo Krummrich
2025-03-24 18:32                 ` Benno Lossin
2025-04-01 13:51                   ` Danilo Krummrich
2025-04-02  0:05                     ` Benno Lossin
2025-04-02  9:06                       ` Danilo Krummrich
2025-03-21 21:47 ` [PATCH v4 3/3] rust: platform: impl TryFrom<&Device> for &platform::Device Danilo Krummrich
2025-03-22  3:25   ` Greg KH
2025-04-19 12:57 ` [PATCH v4 0/3] Implement TryFrom<&Device> for bus specific devices Danilo Krummrich
  -- strict thread matches above, loose matches on Subject: below --
2025-04-07 15:52 [PATCH v4 2/3] rust: pci: impl TryFrom<&Device> for &pci::Device Benno Lossin

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).