Re: [PATCH 10/14] rust: implement `kernel::sync::Refcount`
Elle Rhumsaa <[email protected]> Sat, 6 Sep 2025 04:25:21 +0000
| Newsgroups | dev.linux.lists.lkmm,org.kernel.vger.linux-kernel,org.kernel.vger.rust-for-linux |
|---|---|
| Message-ID | <aLu3saVN2506n7NZ@archiso> |
On Thu, Sep 04, 2025 at 09:41:37PM -0700, Boqun Feng wrote: > From: Gary Guo <[email protected]> > > This is a wrapping layer of `include/linux/refcount.h`. Currently the > kernel refcount has already been used in `Arc`, however it calls into > FFI directly. > > Reviewed-by: Alice Ryhl <[email protected]> > Reviewed-by: Boqun Feng <[email protected]> > Reviewed-by: Fiona Behrens <[email protected]> > Signed-off-by: Gary Guo <[email protected]> > Reviewed-by: Benno Lossin <[email protected]> > [boqun: Add the missing <> for the link in comment] > Signed-off-by: Boqun Feng <[email protected]> > Link: https://lore.kernel.org/r/[email protected] > --- > rust/helpers/refcount.c | 10 ++++ > rust/kernel/sync.rs | 2 + > rust/kernel/sync/refcount.rs | 98 ++++++++++++++++++++++++++++++++++++ > 3 files changed, 110 insertions(+) > create mode 100644 rust/kernel/sync/refcount.rs > > diff --git a/rust/helpers/refcount.c b/rust/helpers/refcount.c > index d6adbd2e45a1..d175898ad7b8 100644 > --- a/rust/helpers/refcount.c > +++ b/rust/helpers/refcount.c > @@ -7,11 +7,21 @@ refcount_t rust_helper_REFCOUNT_INIT(int n) > return (refcount_t)REFCOUNT_INIT(n); > } > > +void rust_helper_refcount_set(refcount_t *r, int n) > +{ > + refcount_set(r, n); > +} > + > void rust_helper_refcount_inc(refcount_t *r) > { > refcount_inc(r); > } > > +void rust_helper_refcount_dec(refcount_t *r) > +{ > + refcount_dec(r); > +} > + > bool rust_helper_refcount_dec_and_test(refcount_t *r) > { > return refcount_dec_and_test(r); > diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs > index bf8943c88a89..cf5b638a097d 100644 > --- a/rust/kernel/sync.rs > +++ b/rust/kernel/sync.rs > @@ -19,6 +19,7 @@ > mod locked_by; > pub mod poll; > pub mod rcu; > +mod refcount; > > pub use arc::{Arc, ArcBorrow, UniqueArc}; > pub use completion::Completion; > @@ -27,6 +28,7 @@ > pub use lock::mutex::{new_mutex, Mutex, MutexGuard}; > pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard}; > pub use locked_by::LockedBy; > +pub use refcount::Refcount; > > /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. > #[repr(transparent)] > diff --git a/rust/kernel/sync/refcount.rs b/rust/kernel/sync/refcount.rs > new file mode 100644 > index 000000000000..cc1a80ae7ae9 > --- /dev/null > +++ b/rust/kernel/sync/refcount.rs > @@ -0,0 +1,98 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! Atomic reference counting. > +//! > +//! C header: [`include/linux/refcount.h`](srctree/include/linux/refcount.h) > + > +use crate::build_assert; > +use crate::types::Opaque; > + > +/// Atomic reference counter. > +/// > +/// This type is conceptually an atomic integer, but provides saturation semantics compared to > +/// normal atomic integers. Values in the negative range when viewed as a signed integer are > +/// saturation (bad) values. For details about the saturation semantics, please refer to top of > +/// [`include/linux/refcount.h`](srctree/include/linux/refcount.h). > +/// > +/// Wraps the kernel's C `refcount_t`. > +#[repr(transparent)] > +pub struct Refcount(Opaque<bindings::refcount_t>); > + > +impl Refcount { > + /// Construct a new [`Refcount`] from an initial value. > + /// > + /// The initial value should be non-saturated. > + #[inline] > + pub fn new(value: i32) -> Self { > + build_assert!(value >= 0, "initial value saturated"); > + // SAFETY: There are no safety requirements for this FFI call. > + Self(Opaque::new(unsafe { bindings::REFCOUNT_INIT(value) })) > + } > + > + #[inline] > + fn as_ptr(&self) -> *mut bindings::refcount_t { > + self.0.get() > + } > + > + /// Set a refcount's value. > + #[inline] > + pub fn set(&self, value: i32) { > + // SAFETY: `self.as_ptr()` is valid. > + unsafe { bindings::refcount_set(self.as_ptr(), value) } > + } > + > + /// Increment a refcount. > + /// > + /// It will saturate if overflows and `WARN`. It will also `WARN` if the refcount is 0, as this > + /// represents a possible use-after-free condition. > + /// > + /// Provides no memory ordering, it is assumed that caller already has a reference on the > + /// object. > + #[inline] > + pub fn inc(&self) { > + // SAFETY: self is valid. > + unsafe { bindings::refcount_inc(self.as_ptr()) } > + } > + > + /// Decrement a refcount. > + /// > + /// It will `WARN` on underflow and fail to decrement when saturated. > + /// > + /// Provides release memory ordering, such that prior loads and stores are done > + /// before. > + #[inline] > + pub fn dec(&self) { > + // SAFETY: `self.as_ptr()` is valid. > + unsafe { bindings::refcount_dec(self.as_ptr()) } > + } > + > + /// Decrement a refcount and test if it is 0. > + /// > + /// It will `WARN` on underflow and fail to decrement when saturated. > + /// > + /// Provides release memory ordering, such that prior loads and stores are done > + /// before, and provides an acquire ordering on success such that memory deallocation > + /// must come after. > + /// > + /// Returns true if the resulting refcount is 0, false otherwise. > + /// > + /// # Notes > + /// > + /// A common pattern of using `Refcount` is to free memory when the reference count reaches > + /// zero. This means that the reference to `Refcount` could become invalid after calling this > + /// function. This is fine as long as the reference to `Refcount` is no longer used when this > + /// function returns `false`. It is not necessary to use raw pointers in this scenario, see > + /// <https://github.com/rust-lang/rust/issues/55005>. > + #[inline] > + #[must_use = "use `dec` instead if you do not need to test if it is 0"] > + pub fn dec_and_test(&self) -> bool { > + // SAFETY: `self.as_ptr()` is valid. > + unsafe { bindings::refcount_dec_and_test(self.as_ptr()) } > + } > +} > + > +// SAFETY: `refcount_t` is thread-safe. > +unsafe impl Send for Refcount {} > + > +// SAFETY: `refcount_t` is thread-safe. > +unsafe impl Sync for Refcount {} > -- > 2.51.0 > > Reviewed-by: Elle Rhumsaa <[email protected]>