[PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device

Lee Jones posted 5 patches 1 year ago
There is a newer version of this series
[PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Lee Jones 1 year ago
There are situations where a pointer to a `struct device` will become
necessary (e.g. for calling into dev_*() functions).  This accessor
allows callers to pull this out from the `struct miscdevice`.

Signed-off-by: Lee Jones <lee@kernel.org>
---
 rust/kernel/miscdevice.rs | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
index 7e2a79b3ae26..55340f316006 100644
--- a/rust/kernel/miscdevice.rs
+++ b/rust/kernel/miscdevice.rs
@@ -10,11 +10,13 @@
 
 use crate::{
     bindings,
+    device::Device,
     error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
     prelude::*,
     str::CStr,
     types::{ForeignOwnable, Opaque},
 };
+
 use core::{
     ffi::{c_int, c_long, c_uint, c_ulong},
     marker::PhantomData,
@@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
     pub fn as_raw(&self) -> *mut bindings::miscdevice {
         self.inner.get()
     }
+
+    /// Returns a pointer to the current Device
+    pub fn device(&self) -> &Device {
+        // SAFETY: This is only accessible after a successful register() which always
+        // initialises this_device with a valid device.
+        unsafe { Device::as_ref((*self.as_raw()).this_device) }
+    }
 }
 
 #[pinned_drop]
-- 
2.47.0.338.g60cca15819-goog
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Greg KH 1 year ago
On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> There are situations where a pointer to a `struct device` will become
> necessary (e.g. for calling into dev_*() functions).  This accessor
> allows callers to pull this out from the `struct miscdevice`.
> 
> Signed-off-by: Lee Jones <lee@kernel.org>
> ---
>  rust/kernel/miscdevice.rs | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> index 7e2a79b3ae26..55340f316006 100644
> --- a/rust/kernel/miscdevice.rs
> +++ b/rust/kernel/miscdevice.rs
> @@ -10,11 +10,13 @@
>  
>  use crate::{
>      bindings,
> +    device::Device,
>      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
>      prelude::*,
>      str::CStr,
>      types::{ForeignOwnable, Opaque},
>  };
> +
>  use core::{
>      ffi::{c_int, c_long, c_uint, c_ulong},
>      marker::PhantomData,
> @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
>      pub fn as_raw(&self) -> *mut bindings::miscdevice {
>          self.inner.get()
>      }
> +
> +    /// Returns a pointer to the current Device
> +    pub fn device(&self) -> &Device {
> +        // SAFETY: This is only accessible after a successful register() which always
> +        // initialises this_device with a valid device.
> +        unsafe { Device::as_ref((*self.as_raw()).this_device) }

A "raw" pointer that you can do something with without incrementing the
reference count of it?  Oh wait, no, it's the rust device structure.
If so, why isn't this calling the get_device() interface instead?  That
way it's properly incremented and decremented when it "leaves the scope"
right?

Or am I missing something here as to why that wouldn't work and this is
the only way to get access to the 'struct device' of this miscdevice?

thanks,

greg k-h
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Lee Jones 1 year ago
On Fri, 06 Dec 2024, Greg KH wrote:

> On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> > There are situations where a pointer to a `struct device` will become
> > necessary (e.g. for calling into dev_*() functions).  This accessor
> > allows callers to pull this out from the `struct miscdevice`.
> > 
> > Signed-off-by: Lee Jones <lee@kernel.org>
> > ---
> >  rust/kernel/miscdevice.rs | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> > 
> > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > index 7e2a79b3ae26..55340f316006 100644
> > --- a/rust/kernel/miscdevice.rs
> > +++ b/rust/kernel/miscdevice.rs
> > @@ -10,11 +10,13 @@
> >  
> >  use crate::{
> >      bindings,
> > +    device::Device,
> >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> >      prelude::*,
> >      str::CStr,
> >      types::{ForeignOwnable, Opaque},
> >  };
> > +
> >  use core::{
> >      ffi::{c_int, c_long, c_uint, c_ulong},
> >      marker::PhantomData,
> > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> >          self.inner.get()
> >      }
> > +
> > +    /// Returns a pointer to the current Device
> > +    pub fn device(&self) -> &Device {
> > +        // SAFETY: This is only accessible after a successful register() which always
> > +        // initialises this_device with a valid device.
> > +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> 
> A "raw" pointer that you can do something with without incrementing the
> reference count of it?  Oh wait, no, it's the rust device structure.
> If so, why isn't this calling the get_device() interface instead?  That
> way it's properly incremented and decremented when it "leaves the scope"
> right?
> 
> Or am I missing something here as to why that wouldn't work and this is
> the only way to get access to the 'struct device' of this miscdevice?

Fair point.  I'll speak to Alice.

Another reason why using dev_info() is not possible at the moment.

-- 
Lee Jones [李琼斯]
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Lee Jones 1 year ago
On Fri, 06 Dec 2024, Lee Jones wrote:

> On Fri, 06 Dec 2024, Greg KH wrote:
> 
> > On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> > > There are situations where a pointer to a `struct device` will become
> > > necessary (e.g. for calling into dev_*() functions).  This accessor
> > > allows callers to pull this out from the `struct miscdevice`.
> > > 
> > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > ---
> > >  rust/kernel/miscdevice.rs | 9 +++++++++
> > >  1 file changed, 9 insertions(+)
> > > 
> > > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > > index 7e2a79b3ae26..55340f316006 100644
> > > --- a/rust/kernel/miscdevice.rs
> > > +++ b/rust/kernel/miscdevice.rs
> > > @@ -10,11 +10,13 @@
> > >  
> > >  use crate::{
> > >      bindings,
> > > +    device::Device,
> > >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> > >      prelude::*,
> > >      str::CStr,
> > >      types::{ForeignOwnable, Opaque},
> > >  };
> > > +
> > >  use core::{
> > >      ffi::{c_int, c_long, c_uint, c_ulong},
> > >      marker::PhantomData,
> > > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> > >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> > >          self.inner.get()
> > >      }
> > > +
> > > +    /// Returns a pointer to the current Device
> > > +    pub fn device(&self) -> &Device {
> > > +        // SAFETY: This is only accessible after a successful register() which always
> > > +        // initialises this_device with a valid device.
> > > +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> > 
> > A "raw" pointer that you can do something with without incrementing the
> > reference count of it?  Oh wait, no, it's the rust device structure.
> > If so, why isn't this calling the get_device() interface instead?  That
> > way it's properly incremented and decremented when it "leaves the scope"
> > right?
> > 
> > Or am I missing something here as to why that wouldn't work and this is
> > the only way to get access to the 'struct device' of this miscdevice?
> 
> Fair point.  I'll speak to Alice.

Alice isn't available yet, so I may be talking out of turn at this
point, but I just found this is the Device documentation:

  /// A `Device` instance represents a valid `struct device` created by the C portion of the kernel.
  ///
  /// Instances of this type are always reference-counted, that is, a call to `get_device` ensures
  /// that the allocation remains valid at least until the matching call to `put_device`.

And:

  // SAFETY: Instances of `Device` are always reference-counted.

Ready for some analysis from this beginner?

Since this impl for Device is AlwaysRefCounted, when any references are
taken i.e. in the Device::as_ref line above, inc_ref() is implicitly
called to increase the refcount.  The same will be true of dec_ref()
once it goes out of scope.

  // SAFETY: Instances of `Device` are always reference-counted.
  unsafe impl crate::types::AlwaysRefCounted for Device {
      fn inc_ref(&self) {
          // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
          unsafe { bindings::get_device(self.as_raw()) };
      }

      unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
          // SAFETY: The safety requirements guarantee that the refcount is non-zero.
          unsafe { bindings::put_device(obj.cast().as_ptr()) }
  }

-- 
Lee Jones [李琼斯]
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Boqun Feng 1 year ago
On Fri, Dec 06, 2024 at 07:33:09AM +0000, Lee Jones wrote:
> On Fri, 06 Dec 2024, Lee Jones wrote:
> 
> > On Fri, 06 Dec 2024, Greg KH wrote:
> > 
> > > On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> > > > There are situations where a pointer to a `struct device` will become
> > > > necessary (e.g. for calling into dev_*() functions).  This accessor
> > > > allows callers to pull this out from the `struct miscdevice`.
> > > > 
> > > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > > ---
> > > >  rust/kernel/miscdevice.rs | 9 +++++++++
> > > >  1 file changed, 9 insertions(+)
> > > > 
> > > > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > > > index 7e2a79b3ae26..55340f316006 100644
> > > > --- a/rust/kernel/miscdevice.rs
> > > > +++ b/rust/kernel/miscdevice.rs
> > > > @@ -10,11 +10,13 @@
> > > >  
> > > >  use crate::{
> > > >      bindings,
> > > > +    device::Device,
> > > >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> > > >      prelude::*,
> > > >      str::CStr,
> > > >      types::{ForeignOwnable, Opaque},
> > > >  };
> > > > +
> > > >  use core::{
> > > >      ffi::{c_int, c_long, c_uint, c_ulong},
> > > >      marker::PhantomData,
> > > > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> > > >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> > > >          self.inner.get()
> > > >      }
> > > > +
> > > > +    /// Returns a pointer to the current Device
> > > > +    pub fn device(&self) -> &Device {
> > > > +        // SAFETY: This is only accessible after a successful register() which always
> > > > +        // initialises this_device with a valid device.
> > > > +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> > > 
> > > A "raw" pointer that you can do something with without incrementing the
> > > reference count of it?  Oh wait, no, it's the rust device structure.
> > > If so, why isn't this calling the get_device() interface instead?  That
> > > way it's properly incremented and decremented when it "leaves the scope"
> > > right?
> > > 
> > > Or am I missing something here as to why that wouldn't work and this is
> > > the only way to get access to the 'struct device' of this miscdevice?
> > 
> > Fair point.  I'll speak to Alice.
> 
> Alice isn't available yet, so I may be talking out of turn at this
> point, but I just found this is the Device documentation:
> 
>   /// A `Device` instance represents a valid `struct device` created by the C portion of the kernel.
>   ///
>   /// Instances of this type are always reference-counted, that is, a call to `get_device` ensures
>   /// that the allocation remains valid at least until the matching call to `put_device`.
> 
> And:
> 
>   // SAFETY: Instances of `Device` are always reference-counted.
> 
> Ready for some analysis from this beginner?
> 
> Since this impl for Device is AlwaysRefCounted, when any references are
> taken i.e. in the Device::as_ref line above, inc_ref() is implicitly
> called to increase the refcount.  The same will be true of dec_ref()

No, inc_ref() is not called implicitly in Device::as_ref().

The thing that might "keep" the original `miscdevice::Device` alive is
the lifetime, since the returned `device::Device` reference has the
same life at the input parameter `miscdevice::Device` reference (i.e.
`&self`), so the returned reference cannot outlive `&self`. That means
if compilers find `&self` go out of scope while the returned reference
be still alive, it will report an error.

Regards,
Boqun

> once it goes out of scope.
> 
>   // SAFETY: Instances of `Device` are always reference-counted.
>   unsafe impl crate::types::AlwaysRefCounted for Device {
>       fn inc_ref(&self) {
>           // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
>           unsafe { bindings::get_device(self.as_raw()) };
>       }
> 
>       unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
>           // SAFETY: The safety requirements guarantee that the refcount is non-zero.
>           unsafe { bindings::put_device(obj.cast().as_ptr()) }
>   }
> 
> -- 
> Lee Jones [李琼斯]
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Lee Jones 1 year ago
On Fri, 06 Dec 2024, Boqun Feng wrote:

> On Fri, Dec 06, 2024 at 07:33:09AM +0000, Lee Jones wrote:
> > On Fri, 06 Dec 2024, Lee Jones wrote:
> > 
> > > On Fri, 06 Dec 2024, Greg KH wrote:
> > > 
> > > > On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> > > > > There are situations where a pointer to a `struct device` will become
> > > > > necessary (e.g. for calling into dev_*() functions).  This accessor
> > > > > allows callers to pull this out from the `struct miscdevice`.
> > > > > 
> > > > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > > > ---
> > > > >  rust/kernel/miscdevice.rs | 9 +++++++++
> > > > >  1 file changed, 9 insertions(+)
> > > > > 
> > > > > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > > > > index 7e2a79b3ae26..55340f316006 100644
> > > > > --- a/rust/kernel/miscdevice.rs
> > > > > +++ b/rust/kernel/miscdevice.rs
> > > > > @@ -10,11 +10,13 @@
> > > > >  
> > > > >  use crate::{
> > > > >      bindings,
> > > > > +    device::Device,
> > > > >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> > > > >      prelude::*,
> > > > >      str::CStr,
> > > > >      types::{ForeignOwnable, Opaque},
> > > > >  };
> > > > > +
> > > > >  use core::{
> > > > >      ffi::{c_int, c_long, c_uint, c_ulong},
> > > > >      marker::PhantomData,
> > > > > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> > > > >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> > > > >          self.inner.get()
> > > > >      }
> > > > > +
> > > > > +    /// Returns a pointer to the current Device
> > > > > +    pub fn device(&self) -> &Device {
> > > > > +        // SAFETY: This is only accessible after a successful register() which always
> > > > > +        // initialises this_device with a valid device.
> > > > > +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> > > > 
> > > > A "raw" pointer that you can do something with without incrementing the
> > > > reference count of it?  Oh wait, no, it's the rust device structure.
> > > > If so, why isn't this calling the get_device() interface instead?  That
> > > > way it's properly incremented and decremented when it "leaves the scope"
> > > > right?
> > > > 
> > > > Or am I missing something here as to why that wouldn't work and this is
> > > > the only way to get access to the 'struct device' of this miscdevice?
> > > 
> > > Fair point.  I'll speak to Alice.
> > 
> > Alice isn't available yet, so I may be talking out of turn at this
> > point, but I just found this is the Device documentation:
> > 
> >   /// A `Device` instance represents a valid `struct device` created by the C portion of the kernel.
> >   ///
> >   /// Instances of this type are always reference-counted, that is, a call to `get_device` ensures
> >   /// that the allocation remains valid at least until the matching call to `put_device`.
> > 
> > And:
> > 
> >   // SAFETY: Instances of `Device` are always reference-counted.
> > 
> > Ready for some analysis from this beginner?
> > 
> > Since this impl for Device is AlwaysRefCounted, when any references are
> > taken i.e. in the Device::as_ref line above, inc_ref() is implicitly
> > called to increase the refcount.  The same will be true of dec_ref()
> 
> No, inc_ref() is not called implicitly in Device::as_ref().
> 
> The thing that might "keep" the original `miscdevice::Device` alive is
> the lifetime, since the returned `device::Device` reference has the
> same life at the input parameter `miscdevice::Device` reference (i.e.
> `&self`), so the returned reference cannot outlive `&self`. That means
> if compilers find `&self` go out of scope while the returned reference
> be still alive, it will report an error.

Okay, so is there something I need to do to ensure we increase the
refcount?  Does inc_ref() need calling manually?

-- 
Lee Jones [李琼斯]
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Boqun Feng 1 year ago
On Fri, Dec 06, 2024 at 08:07:51AM +0000, Lee Jones wrote:
> On Fri, 06 Dec 2024, Boqun Feng wrote:
> 
> > On Fri, Dec 06, 2024 at 07:33:09AM +0000, Lee Jones wrote:
> > > On Fri, 06 Dec 2024, Lee Jones wrote:
> > > 
> > > > On Fri, 06 Dec 2024, Greg KH wrote:
> > > > 
> > > > > On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> > > > > > There are situations where a pointer to a `struct device` will become
> > > > > > necessary (e.g. for calling into dev_*() functions).  This accessor
> > > > > > allows callers to pull this out from the `struct miscdevice`.
> > > > > > 
> > > > > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > > > > ---
> > > > > >  rust/kernel/miscdevice.rs | 9 +++++++++
> > > > > >  1 file changed, 9 insertions(+)
> > > > > > 
> > > > > > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > > > > > index 7e2a79b3ae26..55340f316006 100644
> > > > > > --- a/rust/kernel/miscdevice.rs
> > > > > > +++ b/rust/kernel/miscdevice.rs
> > > > > > @@ -10,11 +10,13 @@
> > > > > >  
> > > > > >  use crate::{
> > > > > >      bindings,
> > > > > > +    device::Device,
> > > > > >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> > > > > >      prelude::*,
> > > > > >      str::CStr,
> > > > > >      types::{ForeignOwnable, Opaque},
> > > > > >  };
> > > > > > +
> > > > > >  use core::{
> > > > > >      ffi::{c_int, c_long, c_uint, c_ulong},
> > > > > >      marker::PhantomData,
> > > > > > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> > > > > >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> > > > > >          self.inner.get()
> > > > > >      }
> > > > > > +
> > > > > > +    /// Returns a pointer to the current Device
> > > > > > +    pub fn device(&self) -> &Device {
> > > > > > +        // SAFETY: This is only accessible after a successful register() which always
> > > > > > +        // initialises this_device with a valid device.
> > > > > > +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> > > > > 
> > > > > A "raw" pointer that you can do something with without incrementing the
> > > > > reference count of it?  Oh wait, no, it's the rust device structure.
> > > > > If so, why isn't this calling the get_device() interface instead?  That
> > > > > way it's properly incremented and decremented when it "leaves the scope"
> > > > > right?
> > > > > 
> > > > > Or am I missing something here as to why that wouldn't work and this is
> > > > > the only way to get access to the 'struct device' of this miscdevice?
> > > > 
> > > > Fair point.  I'll speak to Alice.
> > > 
> > > Alice isn't available yet, so I may be talking out of turn at this
> > > point, but I just found this is the Device documentation:
> > > 
> > >   /// A `Device` instance represents a valid `struct device` created by the C portion of the kernel.
> > >   ///
> > >   /// Instances of this type are always reference-counted, that is, a call to `get_device` ensures
> > >   /// that the allocation remains valid at least until the matching call to `put_device`.
> > > 
> > > And:
> > > 
> > >   // SAFETY: Instances of `Device` are always reference-counted.
> > > 
> > > Ready for some analysis from this beginner?
> > > 
> > > Since this impl for Device is AlwaysRefCounted, when any references are
> > > taken i.e. in the Device::as_ref line above, inc_ref() is implicitly
> > > called to increase the refcount.  The same will be true of dec_ref()
> > 
> > No, inc_ref() is not called implicitly in Device::as_ref().
> > 
> > The thing that might "keep" the original `miscdevice::Device` alive is
> > the lifetime, since the returned `device::Device` reference has the
> > same life at the input parameter `miscdevice::Device` reference (i.e.
> > `&self`), so the returned reference cannot outlive `&self`. That means
> > if compilers find `&self` go out of scope while the returned reference
> > be still alive, it will report an error.
> 
> Okay, so is there something I need to do to ensure we increase the
> refcount?  Does inc_ref() need calling manually?
> 

When you convert a `&Device` into a `ARef<Device>`, Device::inc_ref()
will be called. You can do that with:

	ARef::from(Device::as_ref((*self.as_raw()).this_device))

You will also need to change the return type. And when an `ARef<Device>`
goes out of scope, dec_ref() will be called. 


I had an old patch for a bit document on this part:

	https://lore.kernel.org/rust-for-linux/20240710032447.2161189-1-boqun.feng@gmail.com/

maybe I should send a re-spin.

Regards,
Boqun

> -- 
> Lee Jones [李琼斯]
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Lee Jones 1 year ago
On Fri, 06 Dec 2024, Boqun Feng wrote:

> On Fri, Dec 06, 2024 at 08:07:51AM +0000, Lee Jones wrote:
> > On Fri, 06 Dec 2024, Boqun Feng wrote:
> > 
> > > On Fri, Dec 06, 2024 at 07:33:09AM +0000, Lee Jones wrote:
> > > > On Fri, 06 Dec 2024, Lee Jones wrote:
> > > > 
> > > > > On Fri, 06 Dec 2024, Greg KH wrote:
> > > > > 
> > > > > > On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> > > > > > > There are situations where a pointer to a `struct device` will become
> > > > > > > necessary (e.g. for calling into dev_*() functions).  This accessor
> > > > > > > allows callers to pull this out from the `struct miscdevice`.
> > > > > > > 
> > > > > > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > > > > > ---
> > > > > > >  rust/kernel/miscdevice.rs | 9 +++++++++
> > > > > > >  1 file changed, 9 insertions(+)
> > > > > > > 
> > > > > > > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > > > > > > index 7e2a79b3ae26..55340f316006 100644
> > > > > > > --- a/rust/kernel/miscdevice.rs
> > > > > > > +++ b/rust/kernel/miscdevice.rs
> > > > > > > @@ -10,11 +10,13 @@
> > > > > > >  
> > > > > > >  use crate::{
> > > > > > >      bindings,
> > > > > > > +    device::Device,
> > > > > > >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> > > > > > >      prelude::*,
> > > > > > >      str::CStr,
> > > > > > >      types::{ForeignOwnable, Opaque},
> > > > > > >  };
> > > > > > > +
> > > > > > >  use core::{
> > > > > > >      ffi::{c_int, c_long, c_uint, c_ulong},
> > > > > > >      marker::PhantomData,
> > > > > > > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> > > > > > >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> > > > > > >          self.inner.get()
> > > > > > >      }
> > > > > > > +
> > > > > > > +    /// Returns a pointer to the current Device
> > > > > > > +    pub fn device(&self) -> &Device {
> > > > > > > +        // SAFETY: This is only accessible after a successful register() which always
> > > > > > > +        // initialises this_device with a valid device.
> > > > > > > +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> > > > > > 
> > > > > > A "raw" pointer that you can do something with without incrementing the
> > > > > > reference count of it?  Oh wait, no, it's the rust device structure.
> > > > > > If so, why isn't this calling the get_device() interface instead?  That
> > > > > > way it's properly incremented and decremented when it "leaves the scope"
> > > > > > right?
> > > > > > 
> > > > > > Or am I missing something here as to why that wouldn't work and this is
> > > > > > the only way to get access to the 'struct device' of this miscdevice?
> > > > > 
> > > > > Fair point.  I'll speak to Alice.
> > > > 
> > > > Alice isn't available yet, so I may be talking out of turn at this
> > > > point, but I just found this is the Device documentation:
> > > > 
> > > >   /// A `Device` instance represents a valid `struct device` created by the C portion of the kernel.
> > > >   ///
> > > >   /// Instances of this type are always reference-counted, that is, a call to `get_device` ensures
> > > >   /// that the allocation remains valid at least until the matching call to `put_device`.
> > > > 
> > > > And:
> > > > 
> > > >   // SAFETY: Instances of `Device` are always reference-counted.
> > > > 
> > > > Ready for some analysis from this beginner?
> > > > 
> > > > Since this impl for Device is AlwaysRefCounted, when any references are
> > > > taken i.e. in the Device::as_ref line above, inc_ref() is implicitly
> > > > called to increase the refcount.  The same will be true of dec_ref()
> > > 
> > > No, inc_ref() is not called implicitly in Device::as_ref().
> > > 
> > > The thing that might "keep" the original `miscdevice::Device` alive is
> > > the lifetime, since the returned `device::Device` reference has the
> > > same life at the input parameter `miscdevice::Device` reference (i.e.
> > > `&self`), so the returned reference cannot outlive `&self`. That means
> > > if compilers find `&self` go out of scope while the returned reference
> > > be still alive, it will report an error.
> > 
> > Okay, so is there something I need to do to ensure we increase the
> > refcount?  Does inc_ref() need calling manually?
> > 
> 
> When you convert a `&Device` into a `ARef<Device>`, Device::inc_ref()
> will be called. You can do that with:
> 
> 	ARef::from(Device::as_ref((*self.as_raw()).this_device))
> 
> You will also need to change the return type. And when an `ARef<Device>`
> goes out of scope, dec_ref() will be called. 

I have been reliably assured by Alice that we don't need to refcount here.

> I had an old patch for a bit document on this part:
> 
> 	https://lore.kernel.org/rust-for-linux/20240710032447.2161189-1-boqun.feng@gmail.com/
> 
> maybe I should send a re-spin.

Very nice!  Yeah, it would be a shame for all that work to go to waste.

-- 
Lee Jones [李琼斯]
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Greg KH 1 year ago
On Fri, Dec 06, 2024 at 07:33:09AM +0000, Lee Jones wrote:
> On Fri, 06 Dec 2024, Lee Jones wrote:
> 
> > On Fri, 06 Dec 2024, Greg KH wrote:
> > 
> > > On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> > > > There are situations where a pointer to a `struct device` will become
> > > > necessary (e.g. for calling into dev_*() functions).  This accessor
> > > > allows callers to pull this out from the `struct miscdevice`.
> > > > 
> > > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > > ---
> > > >  rust/kernel/miscdevice.rs | 9 +++++++++
> > > >  1 file changed, 9 insertions(+)
> > > > 
> > > > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > > > index 7e2a79b3ae26..55340f316006 100644
> > > > --- a/rust/kernel/miscdevice.rs
> > > > +++ b/rust/kernel/miscdevice.rs
> > > > @@ -10,11 +10,13 @@
> > > >  
> > > >  use crate::{
> > > >      bindings,
> > > > +    device::Device,
> > > >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> > > >      prelude::*,
> > > >      str::CStr,
> > > >      types::{ForeignOwnable, Opaque},
> > > >  };
> > > > +
> > > >  use core::{
> > > >      ffi::{c_int, c_long, c_uint, c_ulong},
> > > >      marker::PhantomData,
> > > > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> > > >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> > > >          self.inner.get()
> > > >      }
> > > > +
> > > > +    /// Returns a pointer to the current Device
> > > > +    pub fn device(&self) -> &Device {
> > > > +        // SAFETY: This is only accessible after a successful register() which always
> > > > +        // initialises this_device with a valid device.
> > > > +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> > > 
> > > A "raw" pointer that you can do something with without incrementing the
> > > reference count of it?  Oh wait, no, it's the rust device structure.
> > > If so, why isn't this calling the get_device() interface instead?  That
> > > way it's properly incremented and decremented when it "leaves the scope"
> > > right?
> > > 
> > > Or am I missing something here as to why that wouldn't work and this is
> > > the only way to get access to the 'struct device' of this miscdevice?
> > 
> > Fair point.  I'll speak to Alice.
> 
> Alice isn't available yet, so I may be talking out of turn at this
> point, but I just found this is the Device documentation:
> 
>   /// A `Device` instance represents a valid `struct device` created by the C portion of the kernel.
>   ///
>   /// Instances of this type are always reference-counted, that is, a call to `get_device` ensures
>   /// that the allocation remains valid at least until the matching call to `put_device`.
> 
> And:
> 
>   // SAFETY: Instances of `Device` are always reference-counted.
> 
> Ready for some analysis from this beginner?
> 
> Since this impl for Device is AlwaysRefCounted, when any references are
> taken i.e. in the Device::as_ref line above, inc_ref() is implicitly
> called to increase the refcount.  The same will be true of dec_ref()
> once it goes out of scope.
> 
>   // SAFETY: Instances of `Device` are always reference-counted.
>   unsafe impl crate::types::AlwaysRefCounted for Device {
>       fn inc_ref(&self) {
>           // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
>           unsafe { bindings::get_device(self.as_raw()) };
>       }
> 
>       unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
>           // SAFETY: The safety requirements guarantee that the refcount is non-zero.
>           unsafe { bindings::put_device(obj.cast().as_ptr()) }
>   }

Ick, really?  So as_ref() implicitly calles inc_ref() and dec_ref()?
Ah, ok, in digging into AlwaysRefCounted I now see that seems to be
true.

So great, this is a reference counted object, so what's preventing it
from now being used in dev_info()?

thanks,

greg k-h
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Alice Ryhl 1 year ago
On Fri, Dec 6, 2024 at 8:46 AM Greg KH <gregkh@linuxfoundation.org> wrote:
>
> On Fri, Dec 06, 2024 at 07:33:09AM +0000, Lee Jones wrote:
> > On Fri, 06 Dec 2024, Lee Jones wrote:
> >
> > > On Fri, 06 Dec 2024, Greg KH wrote:
> > >
> > > > On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> > > > > There are situations where a pointer to a `struct device` will become
> > > > > necessary (e.g. for calling into dev_*() functions).  This accessor
> > > > > allows callers to pull this out from the `struct miscdevice`.
> > > > >
> > > > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > > > ---
> > > > >  rust/kernel/miscdevice.rs | 9 +++++++++
> > > > >  1 file changed, 9 insertions(+)
> > > > >
> > > > > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > > > > index 7e2a79b3ae26..55340f316006 100644
> > > > > --- a/rust/kernel/miscdevice.rs
> > > > > +++ b/rust/kernel/miscdevice.rs
> > > > > @@ -10,11 +10,13 @@
> > > > >
> > > > >  use crate::{
> > > > >      bindings,
> > > > > +    device::Device,
> > > > >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> > > > >      prelude::*,
> > > > >      str::CStr,
> > > > >      types::{ForeignOwnable, Opaque},
> > > > >  };
> > > > > +
> > > > >  use core::{
> > > > >      ffi::{c_int, c_long, c_uint, c_ulong},
> > > > >      marker::PhantomData,
> > > > > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> > > > >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> > > > >          self.inner.get()
> > > > >      }
> > > > > +
> > > > > +    /// Returns a pointer to the current Device
> > > > > +    pub fn device(&self) -> &Device {
> > > > > +        // SAFETY: This is only accessible after a successful register() which always
> > > > > +        // initialises this_device with a valid device.
> > > > > +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> > > >
> > > > A "raw" pointer that you can do something with without incrementing the
> > > > reference count of it?  Oh wait, no, it's the rust device structure.
> > > > If so, why isn't this calling the get_device() interface instead?  That
> > > > way it's properly incremented and decremented when it "leaves the scope"
> > > > right?
> > > >
> > > > Or am I missing something here as to why that wouldn't work and this is
> > > > the only way to get access to the 'struct device' of this miscdevice?
> > >
> > > Fair point.  I'll speak to Alice.
> >
> > Alice isn't available yet, so I may be talking out of turn at this
> > point, but I just found this is the Device documentation:
> >
> >   /// A `Device` instance represents a valid `struct device` created by the C portion of the kernel.
> >   ///
> >   /// Instances of this type are always reference-counted, that is, a call to `get_device` ensures
> >   /// that the allocation remains valid at least until the matching call to `put_device`.
> >
> > And:
> >
> >   // SAFETY: Instances of `Device` are always reference-counted.
> >
> > Ready for some analysis from this beginner?
> >
> > Since this impl for Device is AlwaysRefCounted, when any references are
> > taken i.e. in the Device::as_ref line above, inc_ref() is implicitly
> > called to increase the refcount.  The same will be true of dec_ref()
> > once it goes out of scope.
> >
> >   // SAFETY: Instances of `Device` are always reference-counted.
> >   unsafe impl crate::types::AlwaysRefCounted for Device {
> >       fn inc_ref(&self) {
> >           // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
> >           unsafe { bindings::get_device(self.as_raw()) };
> >       }
> >
> >       unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
> >           // SAFETY: The safety requirements guarantee that the refcount is non-zero.
> >           unsafe { bindings::put_device(obj.cast().as_ptr()) }
> >   }
>
> Ick, really?  So as_ref() implicitly calles inc_ref() and dec_ref()?
> Ah, ok, in digging into AlwaysRefCounted I now see that seems to be
> true.

It doesn't increment the refcount because it uses the reference type
&_ and not the ARef<_> pointer type. References enforce correctness
using the borrow-checker. For example, consider this attempt to UAF:

#[derive(Debug)]
struct Inner {}

struct Outer {
    inner: Inner,
}

impl Outer {
    fn as_ref(&self) -> &Inner {
        &self.inner
    }
}

fn main() {
    let inner;
    {
        let outer = Outer { inner: Inner {} };
        inner = outer.as_ref();
    }
    println!("{:?}", inner);
}

This fails to compile:

error[E0597]: `outer` does not live long enough
  --> src/main.rs:19:17
   |
18 |         let outer = Outer { inner: Inner {} };
   |             ----- binding `outer` declared here
19 |         inner = outer.as_ref();
   |                 ^^^^^ borrowed value does not live long enough
20 |     }
   |     - `outer` dropped here while still borrowed
21 |     println!("{:?}", inner);
   |                      ----- borrow later used here

The same logic applies to the device() accessor. That is, it ensures
that you can only use the pointer to access the `struct device` when
the `struct miscdevice` is still valid, which should be okay.

To grab a refcount, you need the ARef<_> pointer type. Callers can do

let device = ARef::from(miscdevice.device());

and now device is a value of type ARef<Device> which owns a refcount
and drops it when the destructor runs.

Alice
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Lee Jones 1 year ago
On Fri, 06 Dec 2024, Greg KH wrote:

> On Fri, Dec 06, 2024 at 07:33:09AM +0000, Lee Jones wrote:
> > On Fri, 06 Dec 2024, Lee Jones wrote:
> > 
> > > On Fri, 06 Dec 2024, Greg KH wrote:
> > > 
> > > > On Thu, Dec 05, 2024 at 04:25:18PM +0000, Lee Jones wrote:
> > > > > There are situations where a pointer to a `struct device` will become
> > > > > necessary (e.g. for calling into dev_*() functions).  This accessor
> > > > > allows callers to pull this out from the `struct miscdevice`.
> > > > > 
> > > > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > > > ---
> > > > >  rust/kernel/miscdevice.rs | 9 +++++++++
> > > > >  1 file changed, 9 insertions(+)
> > > > > 
> > > > > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > > > > index 7e2a79b3ae26..55340f316006 100644
> > > > > --- a/rust/kernel/miscdevice.rs
> > > > > +++ b/rust/kernel/miscdevice.rs
> > > > > @@ -10,11 +10,13 @@
> > > > >  
> > > > >  use crate::{
> > > > >      bindings,
> > > > > +    device::Device,
> > > > >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> > > > >      prelude::*,
> > > > >      str::CStr,
> > > > >      types::{ForeignOwnable, Opaque},
> > > > >  };
> > > > > +
> > > > >  use core::{
> > > > >      ffi::{c_int, c_long, c_uint, c_ulong},
> > > > >      marker::PhantomData,
> > > > > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> > > > >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> > > > >          self.inner.get()
> > > > >      }
> > > > > +
> > > > > +    /// Returns a pointer to the current Device
> > > > > +    pub fn device(&self) -> &Device {
> > > > > +        // SAFETY: This is only accessible after a successful register() which always
> > > > > +        // initialises this_device with a valid device.
> > > > > +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> > > > 
> > > > A "raw" pointer that you can do something with without incrementing the
> > > > reference count of it?  Oh wait, no, it's the rust device structure.
> > > > If so, why isn't this calling the get_device() interface instead?  That
> > > > way it's properly incremented and decremented when it "leaves the scope"
> > > > right?
> > > > 
> > > > Or am I missing something here as to why that wouldn't work and this is
> > > > the only way to get access to the 'struct device' of this miscdevice?
> > > 
> > > Fair point.  I'll speak to Alice.
> > 
> > Alice isn't available yet, so I may be talking out of turn at this
> > point, but I just found this is the Device documentation:
> > 
> >   /// A `Device` instance represents a valid `struct device` created by the C portion of the kernel.
> >   ///
> >   /// Instances of this type are always reference-counted, that is, a call to `get_device` ensures
> >   /// that the allocation remains valid at least until the matching call to `put_device`.
> > 
> > And:
> > 
> >   // SAFETY: Instances of `Device` are always reference-counted.
> > 
> > Ready for some analysis from this beginner?
> > 
> > Since this impl for Device is AlwaysRefCounted, when any references are
> > taken i.e. in the Device::as_ref line above, inc_ref() is implicitly
> > called to increase the refcount.  The same will be true of dec_ref()
> > once it goes out of scope.
> > 
> >   // SAFETY: Instances of `Device` are always reference-counted.
> >   unsafe impl crate::types::AlwaysRefCounted for Device {
> >       fn inc_ref(&self) {
> >           // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
> >           unsafe { bindings::get_device(self.as_raw()) };
> >       }
> > 
> >       unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
> >           // SAFETY: The safety requirements guarantee that the refcount is non-zero.
> >           unsafe { bindings::put_device(obj.cast().as_ptr()) }
> >   }
> 
> Ick, really?  So as_ref() implicitly calles inc_ref() and dec_ref()?
> Ah, ok, in digging into AlwaysRefCounted I now see that seems to be
> true.
> 
> So great, this is a reference counted object, so what's preventing it
> from now being used in dev_info()?

We're having this conversation in stereo at this point.

TL;DR, we can't call MiscDeviceRegistration::device() after .init YET.

The longer version of this can be seen in the cover-letter thread.

-- 
Lee Jones [李琼斯]
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Fiona Behrens 1 year ago

On 5 Dec 2024, at 17:25, Lee Jones wrote:

> There are situations where a pointer to a `struct device` will become
> necessary (e.g. for calling into dev_*() functions).  This accessor
> allows callers to pull this out from the `struct miscdevice`.
>
> Signed-off-by: Lee Jones <lee@kernel.org>
> ---
>  rust/kernel/miscdevice.rs | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> index 7e2a79b3ae26..55340f316006 100644
> --- a/rust/kernel/miscdevice.rs
> +++ b/rust/kernel/miscdevice.rs
> @@ -10,11 +10,13 @@
>
>  use crate::{
>      bindings,
> +    device::Device,
>      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
>      prelude::*,
>      str::CStr,
>      types::{ForeignOwnable, Opaque},
>  };
> +
>  use core::{
>      ffi::{c_int, c_long, c_uint, c_ulong},
>      marker::PhantomData,
> @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
>      pub fn as_raw(&self) -> *mut bindings::miscdevice {
>          self.inner.get()
>      }
> +
> +    /// Returns a pointer to the current Device

I would not call this pointer but rather reference? Pointer is usually associated with *mut or *const, and this is a reference to the Device abstraction


Thanks,
 - Fiona

> +    pub fn device(&self) -> &Device {
> +        // SAFETY: This is only accessible after a successful register() which always
> +        // initialises this_device with a valid device.
> +        unsafe { Device::as_ref((*self.as_raw()).this_device) }
> +    }
>  }
>
>  #[pinned_drop]
> -- 
> 2.47.0.338.g60cca15819-goog
Re: [PATCH v3 1/5] rust: miscdevice: Provide accessor to pull out miscdevice::this_device
Posted by Lee Jones 1 year ago
On Thu, 05 Dec 2024, Fiona Behrens wrote:

> 
> 
> On 5 Dec 2024, at 17:25, Lee Jones wrote:
> 
> > There are situations where a pointer to a `struct device` will become
> > necessary (e.g. for calling into dev_*() functions).  This accessor
> > allows callers to pull this out from the `struct miscdevice`.
> >
> > Signed-off-by: Lee Jones <lee@kernel.org>
> > ---
> >  rust/kernel/miscdevice.rs | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> >
> > diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
> > index 7e2a79b3ae26..55340f316006 100644
> > --- a/rust/kernel/miscdevice.rs
> > +++ b/rust/kernel/miscdevice.rs
> > @@ -10,11 +10,13 @@
> >
> >  use crate::{
> >      bindings,
> > +    device::Device,
> >      error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR},
> >      prelude::*,
> >      str::CStr,
> >      types::{ForeignOwnable, Opaque},
> >  };
> > +
> >  use core::{
> >      ffi::{c_int, c_long, c_uint, c_ulong},
> >      marker::PhantomData,
> > @@ -84,6 +86,13 @@ pub fn register(opts: MiscDeviceOptions) -> impl PinInit<Self, Error> {
> >      pub fn as_raw(&self) -> *mut bindings::miscdevice {
> >          self.inner.get()
> >      }
> > +
> > +    /// Returns a pointer to the current Device
> 
> I would not call this pointer but rather reference? Pointer is usually associated with *mut or *const, and this is a reference to the Device abstraction

No, no, my Rustacean friend.  That's not the point of the comment at
all.  We can all see that it the return value is literally a reference
to Device (&Device), but the thing it's actually passing back is a
`struct device *`:

  % git --no-pager grep -n this_device -- include/
  include/linux/miscdevice.h:85:	struct device *this_device;

I'll change the comment to be a lot more intentional.

-- 
Lee Jones [李琼斯]