From: "Benno Lossin" <lossin@kernel.org>
To: "Elijah Wright" <git@elijahs.space>,
"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>,
"Danilo Krummrich" <dakr@kernel.org>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] rust: slab: add basic slab module
Date: Thu, 25 Sep 2025 10:01:43 +0200 [thread overview]
Message-ID: <DD1Q2D6DJXZQ.34HUUS27GNI2Y@kernel.org> (raw)
In-Reply-To: <20250924193643.4001-1-git@elijahs.space>
On Wed Sep 24, 2025 at 9:36 PM CEST, Elijah Wright wrote:
> this patch adds a basic slab module for kmem_cache, primarily wrapping
> kmem_cache_create, kmem_cache_alloc, kmem_cache_free, and kmem_cache_destroy.
IIRC, Alice had an idea for how to use our allocator API to create
idiomatic kmem_cache abstractions. So we might want to explore that too?
> Signed-off-by: Elijah Wright <git@elijahs.space>
> ---
> rust/helpers/slab.c | 10 ++++++
> rust/kernel/lib.rs | 1 +
> rust/kernel/slab.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 96 insertions(+)
> create mode 100644 rust/kernel/slab.rs
>
> diff --git a/rust/helpers/slab.c b/rust/helpers/slab.c
> index a842bfbddcba..799de7bc1405 100644
> --- a/rust/helpers/slab.c
> +++ b/rust/helpers/slab.c
> @@ -13,3 +13,13 @@ rust_helper_kvrealloc(const void *p, size_t size, gfp_t flags)
> {
> return kvrealloc(p, size, flags);
> }
> +
> +struct kmem_cache * rust_helper_kmem_cache_create(const char *name, unsigned int size, unsigned int align, gfp_t flags, void (*ctor)(void *))
> +{
> + return kmem_cache_create(name, size, align, flags, NULL);
> +}
> +
> +void * rust_helper_kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
> +{
> + return kmem_cache_alloc(cachep, flags);
> +}
> \ No newline at end of file
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index fef97f2a5098..bd76eadbe297 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -116,6 +116,7 @@
> pub mod security;
> pub mod seq_file;
> pub mod sizes;
> +pub mod slab;
> mod static_assert;
> #[doc(hidden)]
> pub mod std_vendor;
> diff --git a/rust/kernel/slab.rs b/rust/kernel/slab.rs
> new file mode 100644
> index 000000000000..8b418f9db7cb
> --- /dev/null
> +++ b/rust/kernel/slab.rs
> @@ -0,0 +1,85 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Slab bindings.
> +//!
> +//! C header: [`include/linux/slab.h`](srctree/include/linux/slab.h)
> +
> +use core::{marker::PhantomData, mem, ptr::NonNull};
> +
> +use crate::{
> + alloc::Flags,
> + bindings,
> + error::{code::ENOMEM, Result},
> + str::CStr,
> +};
> +
> +/// A wrapper for kmem_cache that allocates objects of type `T`.
> +#[repr(transparent)]
> +pub struct Slab<T> {
> + cache: NonNull<bindings::kmem_cache>,
You need an invariant for this pointer to point at a valid
kmem_cache for values of layout `T`.
> + _p: PhantomData<T>,
> +}
> +
> +impl<T> Slab<T> {
> + /// Creates a cache for objects of type `T`.
> + pub fn try_new(name: &CStr, flags: Flags) -> Result<Self> {
> + let size = mem::size_of::<T>();
> + let align = mem::align_of::<T>();
> + debug_assert!(size <= usize::MAX);
> + debug_assert!(align <= usize::MAX);
These are always true? Did you mean to use `u32::MAX`?
> +
> + // SAFETY: `flags` is a valid impl, `name` is a valid C string, and
> + // other arguments are plain values.
But you also care about them being correct for the invariant I mentioned
above.
> + let cache = unsafe {
> + bindings::kmem_cache_create(
> + name.as_char_ptr(),
> + size as u32,
> + align as u32,
What do you do if they don't fit in u32? This will just produce wrong
code? I think you should return `EINVAL`. (maybe use `TryFrom` & then
convert the error)
> + flags.as_raw(),
> + None,
> + )
> + };
> +
> + NonNull::new(cache)
> + .map(|c| Slab {
> + cache: c,
> + _p: PhantomData,
> + })
> + .ok_or(ENOMEM)
> + }
> +
> + /// Allocates one object from the cache with the given gfp flags.
> + #[inline]
> + pub fn alloc(&self, flags: Flags) -> Result<NonNull<T>> {
> + // SAFETY: `self.cache` is a valid pointer obtained from
> + // `kmem_cache_create` and still alive because `self` is borrowed.
> + let ptr = unsafe { bindings::kmem_cache_alloc(self.cache.as_ptr(), flags.as_raw()) };
> + NonNull::new(ptr.cast()).ok_or(ENOMEM)
> + }
I don't like that this API makes the user handle `NonNull` directly...
> +
> + /// Frees an object previously returned by `alloc()`.
> + ///
> + /// # Safety
> + /// The caller must guarantee that `obj` was allocated from this cache and
> + /// is no longer accessed afterwards.
> + #[inline]
> + pub unsafe fn free(&self, obj: NonNull<T>) {
> + // SAFETY: By the safety contract the pointer is valid and unique at
> + // this point.
> + unsafe { bindings::kmem_cache_free(self.cache.as_ptr(), obj.cast().as_ptr()) };
> + }
This similarly looks bad, we should have some kind of `KmemCacheBox` or
use the approach that Alice had in mind.
---
Cheers,
Benno
> +
> + /// Returns the raw mutable pointer to the cache
> + #[inline]
> + pub fn as_ptr(&self) -> *mut bindings::kmem_cache {
> + self.cache.as_ptr()
> + }
> +}
> +
> +impl<T> Drop for Slab<T> {
> + fn drop(&mut self) {
> + // SAFETY: `self.cache` is valid and we are the final owner because
> + // of ownership rules.
> + unsafe { bindings::kmem_cache_destroy(self.cache.as_ptr()) };
> + }
> +}
next prev parent reply other threads:[~2025-09-25 8:01 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-24 19:36 [PATCH] rust: slab: add basic slab module Elijah Wright
2025-09-25 2:17 ` John Hubbard
2025-09-25 8:01 ` Benno Lossin [this message]
2025-09-25 9:54 ` Danilo Krummrich
2025-09-25 17:20 ` Elijah
2025-09-25 17:43 ` Danilo Krummrich
2025-09-25 18:02 ` Liam R. Howlett
2025-09-25 18:08 ` Danilo Krummrich
2025-09-25 18:11 ` Boqun Feng
2025-09-25 18:05 ` Elijah
2025-09-25 18:15 ` Danilo Krummrich
2025-09-25 18:17 ` Danilo Krummrich
[not found] ` <74b3ef24-a307-4d3c-891a-8c5283448b20@elijahs.space>
2025-09-25 18:52 ` Elijah
2025-09-25 17:54 ` Alice Ryhl
2025-09-26 15:00 ` Vlastimil Babka
2025-09-26 15:33 ` Danilo Krummrich
2025-09-26 15:55 ` Danilo Krummrich
2025-09-26 16:32 ` Vlastimil Babka
2025-09-26 16:58 ` Danilo Krummrich
2025-09-26 17:11 ` Vlastimil Babka
2025-09-26 19:01 ` Danilo Krummrich
2025-09-28 14:47 ` Danilo Krummrich
2025-09-29 7:14 ` Vlastimil Babka
2025-09-29 14:11 ` Elijah
2025-09-29 20:32 ` Danilo Krummrich
2025-10-01 4:44 ` [PATCH v2] " Elijah Wright
2025-11-06 7:53 ` Alice Ryhl
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=DD1Q2D6DJXZQ.34HUUS27GNI2Y@kernel.org \
--to=lossin@kernel.org \
--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=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=git@elijahs.space \
--cc=linux-kernel@vger.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 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.