All of lore.kernel.org
 help / color / mirror / Atom feed
From: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
To: Qingsong Chen <changxian.cqs@antgroup.com>, linux-kernel@vger.kernel.org
Cc: 田洪亮 <tate.thl@antgroup.com>, "Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Wedson Almeida Filho" <wedsonaf@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>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Asahi Lina" <lina@asahilina.net>,
	"Niklas Mohrin" <dev@niklasmohrin.de>,
	rust-for-linux@vger.kernel.org
Subject: Re: [PATCH 1/2] rust: kernel: add scatterlist wrapper
Date: Tue, 30 May 2023 17:15:17 -0300	[thread overview]
Message-ID: <33ef6ea0-712b-25b6-6be9-c407ecbdb68f@gmail.com> (raw)
In-Reply-To: <20230530064821.1222290-2-changxian.cqs@antgroup.com>

On 5/30/23 03:48, Qingsong Chen wrote:
> Add abstractions for single `struct scatterlist` and chainable
> `struct sg_table`.
> 
> Signed-off-by: Qingsong Chen <changxian.cqs@antgroup.com>
> ---
>   rust/bindings/bindings_helper.h |   1 +
>   rust/helpers.c                  |  14 +
>   rust/kernel/lib.rs              |   1 +
>   rust/kernel/scatterlist.rs      | 478 ++++++++++++++++++++++++++++++++

I think that 478 line changes are a bit too much for a commit, I'd
suggest to split this patch into smaller parts for easier reviews,
like one for ScatterList, another for SgTable, one for iterator
implementations, etc.

>   4 files changed, 494 insertions(+)
>   create mode 100644 rust/kernel/scatterlist.rs
> 
> [...]
> +
> +/// A [`ScatterList`] table of fixed `N` entries.
> +///
> +/// According to the SG table design (form kernel ), the `page_link` field may contain
> +/// a pointer to the next sg table list, so this struct should be pinned. If the table
> +/// is chainable, the last entry will be reserved for chainning. The recommended way to

This comment has some orthographic, coherence (like "SG table",
"sg table") and grammatical, though, it's correct on its meaning.

> +/// create such instances is with the [`pin_init`].
This ([`pin_init`]) might point to nothing in `rustdoc`, though I'd
recommend to test it with `make rustdoc` and opening it in a browser
nonetheless.

> +///
> +/// # Examples
> +///
> +/// The following is examples of creating [`SgTable<N>`] instances> +///
> [...]> +
> +impl<'a, const N: usize> SgTable<'a, N> {
> [...]

This `impl` block has the same definition as the one above it. And
thus, wouldn't be worth to have the iter functions inside the same
block?

> +}
> +
> +/// Wrap the kernel's `struct scatterlist`.
> +///
> +/// According to the SG table design (from kernel), the `page_link` field may contain
> +/// a pointer to the next sg table list, so this struct should be pinned.
> +///
> +/// # Invirants
> +///
> +/// All instances are valid, either created by the `new` constructor (see [`pin_init`]),
> +/// or transmuted from raw pointers by the `as_ref` or `as_mut` function (usually used
> +/// to get an entry of [`SgTable`]).
> +///
> +/// # Examples
> +///
> +/// The following is examples of creating [`ScatterList`] instances.

Same as `SgTable` above.

> +///
> +/// ```rust
> +/// use core::pin::pin;
> +/// # use kernel::error::Result;
> +/// # use kernel::scatterlist::ScatterList;
> +///
> +/// // Prepare memory buffer.
> +/// let buf: Pin<&mut [u8]> = pin!([0u8; 512]);
> +///
> +/// // Allocates an instance on stack.
> +/// kernel::stack_pin_init!(let foo = ScatterList::new(&buf));
> +/// let foo: Pin<&mut ScatterList<'_>> = foo;
> +/// assert_eq!(foo.length(), 512);
> +/// assert_eq!(foo.count(), 1);
> +///
> +/// // Alloccate an instance by Box::pin_init.
> +/// let bar: Result<Pin<Box<ScatterList<'_>>>> = Box::pin_init(ScatterList::new(&buf));
> +/// assert_eq!(bar.as_ref().unwrap().length(), 512);
> +/// assert_eq!(bar.as_ref().unwrap().count(), 1);
> +/// ```
> +#[pin_data]
> +pub struct ScatterList<'a> {
> +    #[pin]
> +    opaque: Opaque<bindings::scatterlist>,
> +    _p: PhantomData<&'a mut bindings::scatterlist>,
> +}
> +
> +impl<'a> ScatterList<'a> {
> +    /// Construct a new initializer.
> +    pub fn new(buf: &'a Pin<&mut [u8]>) -> impl PinInit<ScatterList<'a>> {
> +        // SAFETY: `slot` is valid while the closure is called, the memory buffer is
> +        // pinned and valid.
> +        unsafe {
> +            init::pin_init_from_closure(move |slot: *mut Self| {
> +                (*slot).set_buf(buf);
> +                (*slot).mark_end();
> +                Ok(())
> +            })
> +        }
> +    }
> +
> +    /// Obtain [`Pin<&ScatterList>`] from raw pointer.

I'd rather say "Obtain a pinned reference to a scatter list from a raw
pointer.

> +    pub fn as_ref(entry: *mut bindings::scatterlist) -> Option<Pin<&'a Self>> {
> +        match entry.is_null() {
> +            true => None,
> +            // SAFETY: `entry` is non-null and valid.
> +            false => Some(Pin::new(unsafe { &*(entry as *const ScatterList<'_>) })),
> +        }

Another approach could be `NonNull::new` with `Option::map`, though if
you don't use it, no problem.

> +    }
> +
> +    /// Obtain [`Pin<&mut ScatterList>`] from raw pointer.

Same as `ScatterList::as_mut`.

> +    pub fn as_mut(entry: *mut bindings::scatterlist) -> Option<Pin<&'a mut Self>> {
> +        match entry.is_null() {
> +            true => None,
> +            // SAFETY: `entry` is non-null and valid.
> +            false => Some(Pin::new(unsafe { &mut *(entry as *mut ScatterList<'_>) })),
> +        }
> +    }
> +}
> +
> +impl ScatterList<'_> {
> [...]
> +
> +    /// Return the mapped DMA length.
> +    ///
> +    /// # Safety
> +    ///
> +    /// It is only valid after this scatterlist has been mapped to some bus address
> +    /// and then called `set_dma` method to setup it.
> +    #[cfg(CONFIG_NEED_SG_DMA_LENGTH)]
> +    pub fn dma_length(&self) -> usize {
> +        // SAFETY: By the type invariant, we know that `self.opaque` is valid.
> +        unsafe { (*self.opaque.get()).dma_length as _ }
> +    }
> +
> +    /// Return the mapped DMA length.
> +    ///
> +    /// # Safety
> +    ///
> +    /// It is only valid after this scatterlist has been mapped to some bus address
> +    /// and then called `set_dma` method to setup it.
> +    #[cfg(not(CONFIG_NEED_SG_DMA_LENGTH))]
> +    pub fn dma_length(&self) -> usize {
> +        // SAFETY: By the type invariant, we know that `self.opaque` is valid.
> +        unsafe { (*self.opaque.get()).length as _ }
> +    }
> +
> +    /// Setup the DMA address and length.
> +    #[cfg(CONFIG_NEED_SG_DMA_LENGTH)]
> +    pub fn set_dma(&mut self, addr: usize, len: usize) {
> +        // SAFETY: By the type invariant, we know that `self.opaque` is valid.
> +        unsafe {
> +            (*self.opaque.get()).dma_address = addr as _;
> +            (*self.opaque.get()).dma_length = len as _;
> +        }
> +        self.dma_mark_bus_address();
> +    }
> +
> +    /// Setup the DMA address and length.
> +    #[cfg(not(CONFIG_NEED_SG_DMA_LENGTH))]
> +    pub fn set_dma(&mut self, addr: usize, len: usize) {
> +        // SAFETY: By the type invariant, we know that `self.opaque` is valid.
> +        unsafe {
> +            (*self.opaque.get()).dma_address = addr as _;
> +            (*self.opaque.get()).length = len as _;
> +        }
> +        self.dma_mark_bus_address();
> +    }

Please avoid boilerplate by putting those `cfgs` inside the function.
For example you can turn this...

     /// Setup the DMA address and length.
     #[cfg(CONFIG_NEED_SG_DMA_LENGTH)]
     pub fn set_dma(&mut self, addr: usize, len: usize) {
         // SAFETY: By the type invariant, we know that `self.opaque` is valid.
         unsafe {
             (*self.opaque.get()).dma_address = addr as _;
             (*self.opaque.get()).dma_length = len as _;
         }
         self.dma_mark_bus_address();
     }

     /// Setup the DMA address and length.
     #[cfg(CONFIG_NEED_SG_DMA_LENGTH)]
     pub fn set_dma(&mut self, addr: usize, len: usize) {
         // SAFETY: By the type invariant, we know that `self.opaque` is valid.
         unsafe {
             (*self.opaque.get()).dma_address = addr as _;
             (*self.opaque.get()).length = len as _;
         }
         self.dma_mark_bus_address();
     }

...into this...

     /// Setup the DMA address and length.
     pub fn set_dma(&mut self, addr: usize, len: usize) {
         // SAFETY: By the type invariant, we know that `self.opaque` is valid.
         #[cfg(CONFIG_NEED_SG_DMA_LENGTH)]
         unsafe {
             (*self.opaque.get()).dma_address = addr as _;
             (*self.opaque.get()).dma_length = len as _;
         }
         #[cfg(not(CONFIG_NEED_SG_DMA_LENGTH))]
         unsafe {
             (*self.opaque.get()).dma_address = addr as _;
             (*self.opaque.get()).length = len as _;
         }
         self.dma_mark_bus_address();
     }

> [...]
> +}
> [...]

  reply	other threads:[~2023-05-30 20:15 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-30  6:48 [PATCH 0/2] Rust scatterlist abstractions Qingsong Chen
2023-05-30  6:48 ` [PATCH 1/2] rust: kernel: add scatterlist wrapper Qingsong Chen
2023-05-30 20:15   ` Martin Rodriguez Reboredo [this message]
2023-05-30  6:48 ` [PATCH 2/2] samples: rust: add `SgTable` and `ScatterList` selftests Qingsong Chen
2023-05-30  7:31   ` Greg KH
2023-05-30 18:33     ` Boqun Feng
2023-05-31  5:30       ` Qingsong Chen
2023-05-31 10:17         ` Miguel Ojeda
2023-05-30 14:21   ` Miguel Ojeda

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=33ef6ea0-712b-25b6-6be9-c407ecbdb68f@gmail.com \
    --to=yakoyoku@gmail.com \
    --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=changxian.cqs@antgroup.com \
    --cc=dev@niklasmohrin.de \
    --cc=gary@garyguo.net \
    --cc=lina@asahilina.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tate.thl@antgroup.com \
    --cc=wedsonaf@gmail.com \
    /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.