From: Oliver Mangold <oliver.mangold@pm.me>
To: Benno Lossin <lossin@kernel.org>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Asahi Lina" <lina+kernel@asahilina.net>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v11 4/4] rust: Add `OwnableRefCounted`
Date: Tue, 08 Jul 2025 09:36:38 +0000 [thread overview]
Message-ID: <aGzmoMWvy1v7ayyn@mango> (raw)
In-Reply-To: <DB5PX74OB3DX.1UNT8MIBWNC2G@kernel.org>
On 250707 1133, Benno Lossin wrote:
> On Mon Jul 7, 2025 at 10:07 AM CEST, Oliver Mangold wrote:
> > On 250702 1524, Benno Lossin wrote:
> >> On Wed Jun 18, 2025 at 2:27 PM CEST, Oliver Mangold wrote:
> >> > @@ -132,3 +134,124 @@ fn drop(&mut self) {
> >> > unsafe { T::release(self.ptr) };
> >> > }
> >> > }
> >> > +
> >> > +/// A trait for objects that can be wrapped in either one of the reference types [`Owned`] and
> >> > +/// [`ARef`].
> >> > +///
> >> > +/// # Safety
> >> > +///
> >> > +/// Implementers must ensure that:
> >> > +///
> >> > +/// - [`try_from_shared()`](OwnableRefCounted::into_shared) only returns an [`Owned<Self>`] if
> >> > +/// exactly one [`ARef<Self>`] exists.
> >>
> >> This shouldn't be required?
> >
> > Ehm, why not? `Owned<T>` is supposed to be unique.
>
> It's not needed as a safety requirement for implementing the trait. If
> the implementation only contains sound code, then `Owned::from_raw`
> should already ensure that `Owned<Self>` is only created if there is
> exactly one reference to it.
Okay, got it now. I guess you are right, it is not strictly needed. If the
requirement should be removed, not sure, though. Isn't it error-prone if it
explicitly stated here (again) that it is required?
> >> > +/// - [`into_shared()`](OwnableRefCounted::into_shared) set the reference count to the value which
> >> > +/// the returned [`ARef<Self>`] expects for an object with a single reference in existence. This
> >> > +/// implies that if [`into_shared()`](OwnableRefCounted::into_shared) is left on the default
> >> > +/// implementation, which just rewraps the underlying object, the reference count needs not to be
> >> > +/// modified when converting an [`Owned<Self>`] to an [`ARef<Self>`].
> >>
> >> This also seems pretty weird...
> >>
> >> I feel like `OwnableRefCounted` is essentially just a compatibility
> >> condition between `Ownable` and `RefCounted`. It ensures that the
> >> ownership declared in `Ownable` corresponds to exactly one refcount
> >> declared in `RefCounted`.
> >>
> >> That being said, I think a `RefCounted` *always* canonically is
> >> `Ownable` by the following impl:
> >>
> >> unsafe impl<T: RefCounted> Ownable for T {
> >> unsafe fn release(this: NonNull<Self>) {
> >> T::dec_ref(this)
> >> }
> >> }
> >>
> >> So I don't think that we need this trait at all?
> >
> > No. For an `ARef<T>` to be converted to an `Owned<T>` it requires a
> > `try_from_shared()` implementation. It is not even a given that the
> > function can implemented, if all the kernel exposes are some kind of
> > `inc_ref()` and `dec_ref()`.
>
> I don't understand this paragraph.
What I mean is, to convert from an `ARef` to an `Owned`, it is necessary to
check that there is only one reference. The API of the underlying object
might not provide that.
About the above documentation, it is a bit convoluted, because I had the
case of `mq::Request` in mind, where the refcount needs to be changed
during conversion.
> > Also there are more complicated cases like with `Mq::Request`, where the
> > existence of an `Owned<T>` cannot be represented by the same refcount value
> > as the existence of exactly one `ARef<T>`.
>
> Ah right, I forgot about this. What was the refcount characteristics of
> this again?
>
> * 1 = in flight, owned by C
> * 2 = in flight, owned by Rust
> * >2 = in flight, owned by Rust + additional references used by Rust
> code
>
> Correct? Maybe @Andreas can check.
>
> >> > +///
> >> > +/// # Examples
> >>
> >> If we're having an example here, then we should also have on on `Owned`.
> >
> > Yes, maybe. I mostly felt the need to create one for `OwnableRefCounted`
> > because it is a more complex idea than `Ownable`.
> >
> > If I remember correctly, I didn't create one for `Owned`, as it should
> > probably more or less the same as for `ARef` and the one there has even
> > more problems of the kind you are pointing out. So maybe it would be best
> > to wait until someone fixes that and have the fixed version copied over to
> > `Owned` in the process?
>
> Wait which problems on `ARef` do you mean? I disagree that `Owned` and
> `ARef` have the same example. `Owned` should expose operations that
> `ARef` can't otherwise there would be no value in using `Owned`.
I mean it uses a `struct Empty {}`, which doesn't do any refcounting and
the safety requirements of `ARef::from_raw()` are also not fulfilled.
The point of `Owned` is not that it provides more operations than `ARef`
but rather that it provides less. The reference cannot be cloned. Actually
it is not supposed to provide much features at all, except for freeing the
underlying object when it is dropped.
It is supposed to just be a safe wrapper around a `*T`, marking that the
reference is Owned/Unique. Safe functions defined elsewhere can then take a
`Owned<T>` or `&mut Owned<T>` which provides the assurance of
ownership/uniqueness.
> >> > +///
> >> > +/// A minimal example implementation of [`OwnableRefCounted`], [`Ownable`] and its usage with
> >> > +/// [`ARef`] and [`Owned`] looks like this:
> >> > +///
> >> > +/// ```
> >> > +/// # #![expect(clippy::disallowed_names)]
> >> > +/// use core::cell::Cell;
> >> > +/// use core::ptr::NonNull;
> >> > +/// use kernel::alloc::{flags, kbox::KBox, AllocError};
> >> > +/// use kernel::types::{
> >> > +/// ARef, RefCounted, Owned, Ownable, OwnableRefCounted,
> >> > +/// };
> >> > +///
> >> > +/// struct Foo {
> >> > +/// refcount: Cell<usize>,
> >> > +/// }
> >> > +///
> >> > +/// impl Foo {
> >> > +/// fn new() -> Result<Owned<Self>, AllocError> {
> >> > +/// // Use a `KBox` to handle the actual allocation.
> >> > +/// let result = KBox::new(
> >> > +/// Foo {
> >> > +/// refcount: Cell::new(1),
> >> > +/// },
> >> > +/// flags::GFP_KERNEL,
> >> > +/// )?;
> >> > +/// let result = NonNull::new(KBox::into_raw(result))
> >> > +/// .expect("Raw pointer to newly allocation KBox is null, this should never happen.");
> >>
> >> I'm not really convinced that an example using `KBox` is a good one...
> >> Maybe we should just have a local invisible `bindings` module that
> >> exposes a `-> *mut foo`. (internally it can just create a KBox`)
> >
> > The example would become quite a bit more complicated then, no?
>
> Just hide those parts behind `#` lines in the example.
I don't know about this method. Can you give an example on how that works?
> ---
> Cheers,
> Benno
next prev parent reply other threads:[~2025-07-08 9:36 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <OYpTDi4YYXiWvLG3nO_8_WKsgOl9KOpun9l3a34m0jza6nmEWDCLTldSwCfZ2PRRprjXqGmrgSL2JN8rPOQH8Q==@protonmail.internalid>
2025-06-18 12:27 ` [PATCH v11 0/4] New trait OwnableRefCounted for ARef<->Owned conversion Oliver Mangold
2025-06-18 12:27 ` [PATCH v11 1/4] rust: types: Add Ownable/Owned types Oliver Mangold
2025-07-02 11:03 ` Benno Lossin
2025-07-07 6:58 ` Oliver Mangold
2025-07-07 9:23 ` Benno Lossin
2025-07-08 9:56 ` Oliver Mangold
2025-07-08 10:16 ` Miguel Ojeda
2025-07-08 13:06 ` Benno Lossin
2025-07-08 18:30 ` Andreas Hindborg
2025-07-08 19:18 ` Benno Lossin
2025-07-09 8:53 ` Andreas Hindborg
2025-07-09 9:11 ` Benno Lossin
2025-07-08 13:22 ` Andreas Hindborg
2025-07-08 14:53 ` Benno Lossin
2025-07-08 15:00 ` Benno Lossin
2025-07-07 12:26 ` Miguel Ojeda
2025-08-18 12:46 ` Andreas Hindborg
2025-08-18 13:04 ` Oliver Mangold
2025-08-18 22:27 ` Benno Lossin
2025-08-19 6:04 ` Oliver Mangold
2025-08-19 8:26 ` Benno Lossin
2025-08-19 8:45 ` Oliver Mangold
2025-08-19 9:00 ` Andreas Hindborg
2025-08-19 17:15 ` Benno Lossin
2025-08-20 10:48 ` Andreas Hindborg
2025-08-19 8:53 ` Andreas Hindborg
2025-08-19 17:13 ` Benno Lossin
2025-08-19 18:28 ` Andreas Hindborg
2025-08-20 6:02 ` Oliver Mangold
2025-08-20 7:41 ` Benno Lossin
2025-08-20 7:43 ` Oliver Mangold
2025-08-20 10:51 ` Andreas Hindborg
2025-06-18 12:27 ` [PATCH v11 2/4] rust: Split `AlwaysRefCounted` into two traits Oliver Mangold
2025-06-19 3:15 ` kernel test robot
2025-07-02 11:23 ` Benno Lossin
2025-07-07 7:42 ` Oliver Mangold
2025-07-07 9:27 ` Benno Lossin
2025-06-18 12:27 ` [PATCH v11 3/4] rust: Add missing SAFETY documentation for `ARef` example Oliver Mangold
2025-06-18 12:27 ` [PATCH v11 4/4] rust: Add `OwnableRefCounted` Oliver Mangold
2025-07-02 13:24 ` Benno Lossin
2025-07-07 8:07 ` Oliver Mangold
2025-07-07 9:33 ` Benno Lossin
2025-07-07 11:12 ` Andreas Hindborg
2025-07-07 11:47 ` Benno Lossin
2025-07-07 13:21 ` Andreas Hindborg
2025-07-07 15:39 ` Benno Lossin
2025-07-08 13:15 ` Andreas Hindborg
2025-07-08 14:50 ` Benno Lossin
2025-07-08 15:35 ` Andreas Hindborg
2025-07-08 9:36 ` Oliver Mangold [this message]
2025-07-08 13:42 ` Benno Lossin
2025-08-05 17:23 ` [PATCH v11 0/4] New trait OwnableRefCounted for ARef<->Owned conversion Danilo Krummrich
2025-08-06 5:56 ` Oliver Mangold
2025-08-15 10:12 ` Andreas Hindborg
2025-08-18 5:59 ` Oliver Mangold
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=aGzmoMWvy1v7ayyn@mango \
--to=oliver.mangold@pm.me \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=gary@garyguo.net \
--cc=lina+kernel@asahilina.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/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).