[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <aF3bWKvj0eCHnATV@pollux>
Date: Fri, 27 Jun 2025 01:44:24 +0200
From: Danilo Krummrich <dakr@...nel.org>
To: Jason Gunthorpe <jgg@...pe.ca>
Cc: Abdiel Janulgue <abdiel.janulgue@...il.com>,
Alexandre Courbot <acourbot@...dia.com>,
Lyude Paul <lyude@...hat.com>, Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>,
Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <benno.lossin@...ton.me>,
Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>, Trevor Gross <tmgross@...ch.edu>,
Valentin Obst <kernel@...entinobst.de>,
open list <linux-kernel@...r.kernel.org>,
Marek Szyprowski <m.szyprowski@...sung.com>,
Robin Murphy <robin.murphy@....com>, airlied@...hat.com,
rust-for-linux@...r.kernel.org,
"open list:DMA MAPPING HELPERS" <iommu@...ts.linux.dev>,
Petr Tesarik <petr@...arici.cz>,
Andrew Morton <akpm@...ux-foundation.org>,
Herbert Xu <herbert@...dor.apana.org.au>,
Sui Jingfeng <sui.jingfeng@...ux.dev>,
Randy Dunlap <rdunlap@...radead.org>,
Michael Kelley <mhklinux@...look.com>
Subject: Re: [PATCH 1/2] rust: add initial scatterlist bindings
On Thu, Jun 26, 2025 at 07:43:55PM -0300, Jason Gunthorpe wrote:
> On Thu, Jun 26, 2025 at 11:31:15PM +0300, Abdiel Janulgue wrote:
> > Just commenting on this bit. From what I've seen, we don't actually leak
> > anything. The cast only creates a reference to the original C `struct
> > sg_table` object which was allocated and owned by whichever kernel subsystem
> > called sg_alloc_table(). Rust doesn't even allow us to take ownership or to
> > dereference the value, so this one is safe. Destructors are not called on
> > those "casted" objects.
>
> This does not seem the right kind of philosophy.
>
> Every pointer out of the kernel APIs has some kind of implicit
> lifetime contract.
Yes, and it also comes with a contract of ownership of the object behind the
pointer.
> Eg if you have
> b = get_b(a);
Given the below I assume you mean taking a reference of an object B that is
embedded in an object A, rather than taking a reference count, which 'get'
implies a bit.
I.e.:
struct A {
b: B,
}
impl A {
fn get_b(&self) -> &B {
&self.b
}
}
> Then the lifetime of b might well be 'alive so long as a is alive'
Yes, and it is a good example of what Abdiel means. In your example a owns b,
which means that the type A is responsible to destroy its instance of B once it
is destroyed itself.
This means that a.get_b() returns a reference b of the type B that is bound to
the lifetime of the object a.
Dropping the reference b does nothing, since it does not have ownership of the
instance of B.
Please find a runnable example in [1] (and please also let me know if I
misunderstood you).
>
> Or if you have some function pointer callback
> void op_foo(a) {}
This is a great example too, since it can have both ownership semantics:
1) The pointer 'a' in the op_foo() callback points to an object that is owed
by some other object somewhere else, but the callback gives you the
guarantee that the pointer 'a' is valid throughout op_foo(). In this case
we can create a reference of the abstracting type in rust. In this case the
lifetime of the reference is limited to the scope of this function.
Dropping the reference does nothing, since we don't own the object behind
the shared reference.
2) The pointer 'a' in the op_foo() callback points to an object that we have
to take (back) ownership of, hence only creating a reference of the
abstracting type would leak the object eventually. Instead, we have to
re-create the actual object instance, which would usually be some Arc<T>,
KBox<T>, etc. In this case, we took (back) ownership of the object and
hence the lifetime depends on what we do with the object subsequently. If
we drop() it, the destructor is called.
> The lifetime of a might well be 'alive only within the function'
>
> AFAICT rust needs to figure out these implicit rules and the compiler
> needs to enforce them.
>
> Eg
>
> a = make_a()
> b = get_b(a)
> destroy_a()
> do_something(b)
>
> Should be something impossible.
Correct, this should give you a compile error. You can also see this case in my
example in [1].
In Rust you can also describe lifetime relationships with explicit lifetime
annotations. For instance, you could have a function signature like this:
fn do_something<'a>(dev: &'a Device<Bound>) -> MyType + 'a
This means that the reference to the bound device has a lifetime of 'a and the
compiler ensures that the new instance of the type MyType returned by the
function can't out-live the reference to the bound device.
[1] https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=eed9d9c3e3ee187a9294961223e6b833
Powered by blists - more mailing lists