All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alexandre Courbot" <acourbot@nvidia.com>
To: "Lyude Paul" <lyude@redhat.com>,
	"Abdiel Janulgue" <abdiel.janulgue@gmail.com>,
	"Jason Gunthorpe" <jgg@ziepe.ca>
Cc: dakr@kernel.org, "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>,
	"Benno Lossin" <benno.lossin@proton.me>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Valentin Obst" <kernel@valentinobst.de>,
	"open list" <linux-kernel@vger.kernel.org>,
	"Marek Szyprowski" <m.szyprowski@samsung.com>,
	"Robin Murphy" <robin.murphy@arm.com>,
	airlied@redhat.com, rust-for-linux@vger.kernel.org,
	"open list:DMA MAPPING HELPERS" <iommu@lists.linux.dev>,
	"Petr Tesarik" <petr@tesarici.cz>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Herbert Xu" <herbert@gondor.apana.org.au>,
	"Sui Jingfeng" <sui.jingfeng@linux.dev>,
	"Randy Dunlap" <rdunlap@infradead.org>,
	"Michael Kelley" <mhklinux@outlook.com>
Subject: Re: [PATCH 1/2] rust: add initial scatterlist bindings
Date: Wed, 18 Jun 2025 10:03:46 +0900	[thread overview]
Message-ID: <DAP96FEJ0XWT.PWYMIE8IJAVQ@nvidia.com> (raw)
In-Reply-To: <f787046921fd608c385dc5c559883c5d70839507.camel@redhat.com>

Hi Lyude, sorry for taking so long to come back to this!

On Tue Jun 10, 2025 at 2:44 AM JST, Lyude Paul wrote:
> On Thu, 2025-06-05 at 22:56 +0900, Alexandre Courbot wrote:
>> On Thu Jun 5, 2025 at 10:30 PM JST, Abdiel Janulgue wrote:
>> > 
>> > 
>> > On 05/06/2025 08:51, Alexandre Courbot wrote:
>> > > Maybe I need more context to understand your problem, but the point of
>> > > this design is precisely that it doesn't make any assumption about the
>> > > memory layout - all `P` needs to do is provide the pages describing the
>> > > memory backing.
>> > > 
>> > > Assuming that `_owner` here is the owner of the memory, couldn't you
>> > > flip your data layout and pass `_owner` (or rather a newtype wrapping
>> > > it) to `SGTable`, thus removing the need for a custom type?
>> > 
>> > I think what Lyude has in mind here (Lyude, correct me if I'm wrong) is 
>> > for cases where we need to have a rust SGTable instances for those 
>> > struct sg_table that we didn't allocate ourselves for instance in the 
>> > gem shmem bindings. So memory layout needs to match for
>> > #[repr(transparent)] to work
>> 
>> Thanks, I think I am starting to understand and this is a problem
>> indeed. I should probably take a look at the DRM code to get my answers,
>> but IIUC in `OwnedSGTable`, `sg_table` is already provided by the C side
>> and is backed by `_owner`?
>
> Correct. You generally create a gem shmem object, and then you can call a
> function to ask gem to create an sg_table and hand it back to you. I should
> note my priorities have shifted a bit from trying to get shmem bindings
> upstream, but currently it's still the best example I have of this usecase.
>
> So, for gem shmem this means we can operate with an SGTable in two ways:
>
>  * gem_shmem_object.sg_table() -> Result<&kernel::scatterlist::SGTable>
>  * gem_shmem_object.owned_sg_table() ->
>    Result<kernel::drm::gem::shmem::OwnedSGTable<T: DriverObject>
>
> I'm going to call the first return type SGTable and the second one
> OwnedSGTable, just so I can type a bit less.
>
> The first, sg_table(), quite literally just calls drm_gem_shmem_get_pages_sgt
> which attempts to allocate the table and return a pointer to it on success. We
> then cast that to &SGTable and return it to the user. This can be good for

Mmm but if you cast the returned C pointer into a `&SGTable`, then who
owns (and is responsible for freeing) the `SGTable` it refers to? If the
pointer is just turned into a reference then this might leak the `struct
sg_table`.

> usecases where we might only want to look up the SGTable once or twice, and
> only need it for the duration of the & reference for the gem object. This also
> skips needing to take a reference on the gem object as a result, so it's a bit
> cheaper.
>
> The second, owned_sg_table(), just calls .sg_table(), and then takes a
> reference to the gem object on success and returns both as an OwnedSGTable.
> This is for situations where we might be using the SGTable rather frequently,
> e.g. beyond the lifetime of the & reference to the gem object, and we want to
> avoid having to handle a fallible operation for initializing the sg_table each
> time we use it. OwnedSGTable then just implements Deref<SGTable>, which lets
> us use it pretty much identically to a raw SGTable.
>
> With all of this being said though, I think this means we really have two
> classes of operations around sg_table:
>
>    1. Operations that are reasonable to make available on anything that
>       provide a pointer to an sg_table, embedded or not. (iterating through
>       pages immutably, checking the size of the table, etc.).
>    2. Operations that are context-specific. For example: manually assigning
>       pages would be context-specific since it relies on the context that
>       we're the ones creating and allocating the table from scratch.
>
> My reason for leaning towards having SGTable be a barebones wrapper that other
> types can embed or point to is because I think that for any interface that
> handles sg_table creation for the user, the most common class 2 behavior
> across these interfaces is what the SGTable's lifetime is actually tied to and
> where it comes from. For all of these interfaces, `P` (like in your example)
> would be nearly identical implementations that just read from the embedded
> sg_table anyhow. And we'd also have to have separate SGTable implementors for
> each interface even if the majority of them don't introduce much/any
> specialized behavior. It's probably worth noting as well: if getting the
> SGTable from gem shmem wasn't fallible then I likely wouldn't have even added
> the OwnedSGTable type and simply stuck with an & reference to SGTable instead.

I guess what this highlights is that we need one additional layer
between the `SGTable` and the (now optional) `SGTablePages` trait.

The only way I can think of to satisfy your use-case is to have an
unsafe constructor for `SGTable` that takes an already-existing `struct
sg_table` and fully manages it. IMHO it should still store a second
parameter, which ensures that the backing memory of the passed `struct
sg_table` is still there and doesn't move. In your first case, this
second parameter could be a reference to `gem_shmem_object`; in the
second case, an `ARef`. It is the responsibility of the caller to ensure
that the second parameter is indeed tied to the lifetime of the pages
described by the `struct sg_table`.

Then on top of that, we would have a safe constructor for anything that
implements `SGTablePages`, so we can cover common use-cases like `VVec`
at ease. This trait would become a helper instead of being the only way
to create a `SGTable`.

WDYT? I don't think we can provide something that is safe to use without
also storing a "guarantor" for the backing memory of the `struct
sg_table`. And IIUC the casting of the C pointer into a Rust reference
means that there is no owner to eventually free the `struct sg_table` so
it cannot be done anyway - but please correct me if I misunderstood.

>
> I think that this design also doesn't prevent us from abstracting more complex
> behavior through traits anyway. If we had a DeviceSGTable and CpuSGTable, both
> can easily embed a basic SGTable and then implement additional behavior like
> mutable iteration through pages either through a trait that each type
> implements or just through implementing such methods on the types themselves.
> And behavior in type 1 can just be exposed simply through implementing
> Deref<SGTable> again.
>
> Hopefully that makes sense? Let me know if I made any mistakes or need to
> clarify anything though :)

It makes a lot of sense and I clearly overlooked this case, so thank
you. I might still be missing a few details of your explanation, so
would appreciate if we can keep iterating until we reach something that
fully covers what you described. :)

  reply	other threads:[~2025-06-18  1:03 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-28 22:14 [PATCH 0/2] rust: add initial scatterlist abstraction Abdiel Janulgue
2025-05-28 22:14 ` [PATCH 1/2] rust: add initial scatterlist bindings Abdiel Janulgue
2025-05-29  0:45   ` Jason Gunthorpe
2025-05-29 14:14     ` Petr Tesařík
2025-05-29 14:36       ` Jason Gunthorpe
2025-05-30 14:02     ` Alexandre Courbot
2025-05-30 14:14       ` Jason Gunthorpe
2025-05-30 14:44         ` Alexandre Courbot
2025-05-30 14:50           ` Jason Gunthorpe
2025-05-30 15:18             ` Danilo Krummrich
2025-05-31 12:54             ` Alexandre Courbot
2025-06-02 11:40               ` Jason Gunthorpe
2025-06-02 12:25                 ` Abdiel Janulgue
2025-06-02 12:41                 ` Alexandre Courbot
2025-06-04 18:21       ` Lyude Paul
2025-06-05  5:51         ` Alexandre Courbot
2025-06-05 13:30           ` Abdiel Janulgue
2025-06-05 13:56             ` Alexandre Courbot
2025-06-09 17:44               ` Lyude Paul
2025-06-18  1:03                 ` Alexandre Courbot [this message]
2025-06-26 20:31                   ` Abdiel Janulgue
2025-06-26 22:43                     ` Jason Gunthorpe
2025-06-26 23:44                       ` Danilo Krummrich
2025-06-28 11:07                     ` Alexandre Courbot
2025-06-05 13:22       ` Abdiel Janulgue
2025-06-28 11:18         ` Alexandre Courbot
2025-06-30  7:11           ` Abdiel Janulgue
2025-06-05 15:35       ` Boqun Feng
2025-06-05 16:02         ` Jason Gunthorpe
2025-06-05 16:18           ` Boqun Feng
2025-05-30 11:04   ` Alexandre Courbot
2025-05-28 22:14 ` [PATCH 2/2] samples: rust: add sample code for " Abdiel Janulgue

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=DAP96FEJ0XWT.PWYMIE8IJAVQ@nvidia.com \
    --to=acourbot@nvidia.com \
    --cc=a.hindborg@kernel.org \
    --cc=abdiel.janulgue@gmail.com \
    --cc=airlied@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=dakr@kernel.org \
    --cc=gary@garyguo.net \
    --cc=herbert@gondor.apana.org.au \
    --cc=iommu@lists.linux.dev \
    --cc=jgg@ziepe.ca \
    --cc=kernel@valentinobst.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lyude@redhat.com \
    --cc=m.szyprowski@samsung.com \
    --cc=mhklinux@outlook.com \
    --cc=ojeda@kernel.org \
    --cc=petr@tesarici.cz \
    --cc=rdunlap@infradead.org \
    --cc=robin.murphy@arm.com \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=sui.jingfeng@linux.dev \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.