Linux IOMMU Development
 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox