[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Y/idMBIOfFZxXnVM@kroah.com>
Date: Fri, 24 Feb 2023 12:19:12 +0100
From: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
To: Asahi Lina <lina@...hilina.net>
Cc: Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>,
Wedson Almeida Filho <wedsonaf@...il.com>,
Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Will Deacon <will@...nel.org>,
Robin Murphy <robin.murphy@....com>,
Joerg Roedel <joro@...tes.org>,
Hector Martin <marcan@...can.st>,
Sven Peter <sven@...npeter.dev>, Arnd Bergmann <arnd@...db.de>,
"Rafael J. Wysocki" <rafael@...nel.org>,
Alyssa Rosenzweig <alyssa@...enzweig.io>,
Neal Gompa <neal@...pa.dev>, rust-for-linux@...r.kernel.org,
linux-kernel@...r.kernel.org, asahi@...ts.linux.dev
Subject: Re: [PATCH 5/5] rust: device: Add a stub abstraction for devices
On Fri, Feb 24, 2023 at 07:53:17PM +0900, Asahi Lina wrote:
> From: Wedson Almeida Filho <wedsonaf@...il.com>
>
> Add a Device type which represents an owned reference to a generic
> struct device. This minimal implementation just handles reference
> counting and allows the user to get the device name.
What good is just the device name? I'm all for proper bindings to hook
up properly to the driver core, but this feels like it's not really
doing much of anything.
Do you have a real user that we can see how this is interacting?
And what does a driver care about the device name anyway? It should
only be using the dev_*() calls to print that info out to the log, and
never messing around with it in any other format as that's what
userspace expects.
> Lina: Rewrote commit message, dropped the Amba bits, and squashed in
> simple changes to the core Device code from latter commits in
> rust-for-linux/rust. Also include the rust_helper_dev_get_drvdata
> helper which will be needed by consumers later on anyway.
>
> Co-developed-by: Miguel Ojeda <ojeda@...nel.org>
> Signed-off-by: Miguel Ojeda <ojeda@...nel.org>
> Signed-off-by: Wedson Almeida Filho <wedsonaf@...il.com>
> Signed-off-by: Asahi Lina <lina@...hilina.net>
> ---
> rust/helpers.c | 13 +++++++++
> rust/kernel/device.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 88 insertions(+), 1 deletion(-)
>
> diff --git a/rust/helpers.c b/rust/helpers.c
> index 04b9be46e887..54954fd80c77 100644
> --- a/rust/helpers.c
> +++ b/rust/helpers.c
> @@ -20,6 +20,7 @@
>
> #include <linux/bug.h>
> #include <linux/build_bug.h>
> +#include <linux/device.h>
> #include <linux/err.h>
> #include <linux/refcount.h>
>
> @@ -65,6 +66,18 @@ long rust_helper_PTR_ERR(__force const void *ptr)
> }
> EXPORT_SYMBOL_GPL(rust_helper_PTR_ERR);
>
> +void *rust_helper_dev_get_drvdata(struct device *dev)
> +{
> + return dev_get_drvdata(dev);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_dev_get_drvdata);
No matching dev_set_drvdata()? What good is getting a random void
pointer if you couldn't set it in the first place? :)
> +const char *rust_helper_dev_name(const struct device *dev)
> +{
> + return dev_name(dev);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_dev_name);
Again, why? What is going to use this?
And I don't really understand the rules you are putting on the name
string after calling this, more below:
> +
> /*
> * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type
> * as the Rust `usize` type, so we can use it in contexts where Rust
> diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
> index 9be021e393ca..e57da622d817 100644
> --- a/rust/kernel/device.rs
> +++ b/rust/kernel/device.rs
> @@ -4,7 +4,7 @@
> //!
> //! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
>
> -use crate::bindings;
> +use crate::{bindings, str::CStr};
>
> /// A raw device.
> ///
> @@ -20,4 +20,78 @@ use crate::bindings;
> pub unsafe trait RawDevice {
> /// Returns the raw `struct device` related to `self`.
> fn raw_device(&self) -> *mut bindings::device;
> +
> + /// Returns the name of the device.
> + fn name(&self) -> &CStr {
> + let ptr = self.raw_device();
> +
> + // SAFETY: `ptr` is valid because `self` keeps it alive.
> + let name = unsafe { bindings::dev_name(ptr) };
> +
> + // SAFETY: The name of the device remains valid while it is alive (because the device is
> + // never renamed, per the safety requirement of this trait). This is guaranteed to be the
> + // case because the reference to `self` outlives the one of the returned `CStr` (enforced
> + // by the compiler because of their lifetimes).
> + unsafe { CStr::from_char_ptr(name) }
Why can the device never be renamed? Devices are renamed all the time,
sometimes when you least expect it (i.e. by userspace). So how is this
considered "safe"? and actually correct?
Again, maybe seeing a real user of this might make more sense, but
as-is, this feels wrong and not needed at all.
> + }
> +}
> +
> +/// A ref-counted device.
> +///
> +/// # Invariants
> +///
> +/// `ptr` is valid, non-null, and has a non-zero reference count. One of the references is owned by
> +/// `self`, and will be decremented when `self` is dropped.
> +pub struct Device {
> + pub(crate) ptr: *mut bindings::device,
> +}
> +
> +// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
> +unsafe impl Send for Device {}
> +
> +// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
> +// from any thread.
> +unsafe impl Sync for Device {}
> +
> +impl Device {
> + /// Creates a new device instance.
> + ///
> + /// # Safety
> + ///
> + /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count.
> + pub unsafe fn new(ptr: *mut bindings::device) -> Self {
> + // SAFETY: By the safety requirements, ptr is valid and its refcounted will be incremented.
> + unsafe { bindings::get_device(ptr) };
You don't check the return value of get_device()? What if it failed
(hint, it can)?
> + // INVARIANT: The safety requirements satisfy all but one invariant, which is that `self`
> + // owns a reference. This is satisfied by the call to `get_device` above.
> + Self { ptr }
> + }
> +
> + /// Creates a new device instance from an existing [`RawDevice`] instance.
> + pub fn from_dev(dev: &dyn RawDevice) -> Self {
I am a rust newbie, but I don't understand this "RawDevice" here at all.
> + // SAFETY: The requirements are satisfied by the existence of `RawDevice` and its safety
> + // requirements.
> + unsafe { Self::new(dev.raw_device()) }
> + }
> +}
> +
> +// SAFETY: The device returned by `raw_device` is the one for which we hold a reference.
> +unsafe impl RawDevice for Device {
> + fn raw_device(&self) -> *mut bindings::device {
> + self.ptr
> + }
What does this raw device do? What is the relationship to a "real"
device? Maybe it's just my lack of rust knowledge here showing, so any
hints would be appreciated.
> +}
> +
> +impl Drop for Device {
> + fn drop(&mut self) {
> + // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> + // relinquish it now.
> + unsafe { bindings::put_device(self.ptr) };
So it is now ok for this to be freed?
One meta-comment, why is any of this needed at all? No driver should
ever be dealing with a "raw" struct device pointer at all, right? They
should be calling into subsystems that give it a pointer to a
bus-specific pointer type (gpio, usb, pci, etc.)
So I'm thinking that adding support for "raw" struct device pointers
feels ripe for abuse in a "the code should not be doing that" type of
thing.
Unless you are writing a new bus/class in rust?
thanks,
greg k-h
Powered by blists - more mailing lists