Skip to contentSkip to conversation

implement `kernel::sync::Refcount` and convert users

PATCH In review Gary Guo 5 participants 19 messages Jul 23, 2025 – Sep 2, 2025

Subsystems (5)
lore
Share & tools
lore

Gary Guo

author
#0 lore raw

v5 cover implement `kernel::sync::Refcount` and convert users

From: Gary Guo <[email protected]>

Currently there're two refcount usage in rust/, Arc and block::mq. Arc uses refcount_t with FFI calls directly, and block::mq use Rust atomics and custom refcounting.

This series consolidate them to have a single Refcount which wraps refcount_t and have it used by both.

With the removal of Rust AtomicU64 this would also make the code work for 32-bit systems. See [1] as a previous attempt to fix this issue.

Changes in v5:
- Forbid using Refcount::new() with already-saturated initial value. (Refcount::set can still set value to the saturated range, as
users may want to set it to a runtime value that the compiler cannot
easily determine to be non-negative).
- Moved a documentation comment from one commit to another following
Benno's suggestion
- Link to v4: https://lore.kernel.org/rust-for-linux/[email protected]/

Changes in v4:
- Move justification on why &Refcount is okay when used for reference
coutning into the Refcount::dec_and_test documentation comment.
- Split Arc::into_unique_or_drop signature change into another patch.
- Wording/comment changes
- Link to v3: https://lore.kernel.org/rust-for-linux/[email protected]/

Changes in v3:
- Drop dec_not_one and revert to dec_and_test/set as the former
lacks acquire semantics.
- Move a use statement from patch 1 to correct place (patch 3).
- Update maintainer entry to include refcount.rs and add myself as a
reviewer, as suggested by Boqun.
- Link to v2: https://lore.kernel.org/rust-for-linux/[email protected]

Changes in v2:
- Refcount::read method is dropped
- Refcount::dec_not_one method is added and Arc::into_unique_or_drop
is converted to use it.
- Link to v1: https://lore.kernel.org/rust-for-linux/[email protected]

Gary Guo (5):
rust: implement kernel::sync::Refcount
rust: make Arc::into_unique_or_drop associated function
rust: convert Arc to use Refcount
rust: block: convert block::mq to use Refcount
MAINTAINERS: update atomic infrastructure entry to include Rust

 MAINTAINERS                        |   2 +
 rust/helpers/refcount.c            |  10 +++
 rust/kernel/block/mq/operations.rs |   7 +-
 rust/kernel/block/mq/request.rs    |  63 +++++-----------
 rust/kernel/sync.rs                |   2 +
 rust/kernel/sync/arc.rs            |  55 +++++---------
 rust/kernel/sync/refcount.rs       | 112 +++++++++++++++++++++++++++++
 7 files changed, 165 insertions(+), 86 deletions(-)
 create mode 100644 rust/kernel/sync/refcount.rs

base-commit: cc84ef3b88f407e8bd5a5f7b6906d1e69851c856

Signature · 1 line
2.49.0
author
#1 lore raw

PATCH v5 1/5 rust: implement `kernel::sync::Refcount`

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.

---
 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
rust/helpers/refcount.c +10 -0
index d6adbd2e45a18..d175898ad7b81 100644
@@ -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);
rust/kernel/sync.rs +2 -0
index 63c99e015ad6f..43bbc21134c14 100644
@@ -16,6 +16,7 @@
 mod locked_by;
 pub mod poll;
 pub mod rcu;
+mod refcount;
 
 pub use arc::{Arc, ArcBorrow, UniqueArc};
 pub use completion::Completion;
@@ -24,6 +25,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)]
rust/kernel/sync/refcount.rs new file +98 -0

98 lines not on this page · raw message

Signature · 1 line
2.49.0
#2 lore raw

Re: [PATCH v5 1/5] rust: implement `kernel::sync::Refcount`

Hi Gary,

On Thu Jul 24, 2025 at 8:32 AM JST, Gary Guo wrote:
<snip>

rust/kernel/sync/refcount.rs line 27

Quoted 9 lines
rust/kernel/sync/refcount.rs new file +9 -0
+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");

Given that inc will WARN if the refcount is 0, do we want to accept 0 here?

reviewer Reviewed-by on v5 1/5
#3 lore raw

Re: [PATCH v5 1/5] rust: implement `kernel::sync::Refcount`

In reply to Gary Guo
Quoted 10 lines · Gary Guo

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.

Review

Quoted 9 lines
---
 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
(quoted diff) +2 -0
+    #[inline]
+    fn as_ptr(&self) -> *mut bindings::refcount_t {

I think we should make this pub(crate) from the get-go.

Quoted 11 lines
rust/kernel/sync/refcount.rs new file +10 -0
+        self.0.get()
+    }
+
 
+    /// 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.

rust/kernel/sync/refcount.rs line 85

Quoted 10 lines
rust/kernel/sync/refcount.rs new file +10 -0
+    ///
+    /// 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.

Missing <> around link.

---
Cheers,
Benno

maintainer
#4 lore raw

Re: [PATCH v5 1/5] rust: implement `kernel::sync::Refcount`

Quoted 21 lines · On Tue, 12 Aug 2025 10:10:08 +0200 "Benno Lossin" <[email protected]> wrote:
Quoted 10 lines · Gary Guo

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.

Quoted 6 lines
---
 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  
Quoted 4 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+    #[inline]
+    fn as_ptr(&self) -> *mut bindings::refcount_t {  

I think we should make this pub(crate) from the get-go.

I think it's probably fine as is. I think this method won't be useful outside this module unless people add a from_ptr later. But I'm also fine changing this.

Best,
Gary

Quoted 28 lines
Quoted 12 lines
rust/kernel/sync/refcount.rs new file +10 -0
+        self.0.get()
+    }
+  
 
+    /// 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.

rust/kernel/sync/refcount.rs line 85

Quoted 10 lines
rust/kernel/sync/refcount.rs new file +10 -0
+    ///
+    /// 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.  

Missing <> around link.

---
Cheers,
Benno

reviewer
#5 lore raw

Re: [PATCH v5 1/5] rust: implement `kernel::sync::Refcount`

In reply to Gary Guo

rust/kernel/sync/refcount.rs line 42

Quoted 6 lines · Gary Guo
rust/kernel/sync/refcount.rs new file +6 -0
+    /// 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) }
+    }

One more thing, I think this function could use some better docs. When do you want to use it? (How) does it synchronize with other reads/writes?

---
Cheers,
Benno

author
#6 lore raw

PATCH v5 2/5 rust: make `Arc::into_unique_or_drop` associated function

In reply to Gary Guo

From: Gary Guo <[email protected]>

Make Arc::into_unique_or_drop to become a mere associated function instead of a method (i.e. removing the self receiver).

It's a general convention for Rust smart pointers to avoid having methods defined on them, because if the pointee type has a method of the same name, then it is shadowed. This is normally for avoiding semver breakage, which isn't an issue for kernel codebase, but it's still generally a good practice to follow this rule, so that ptr.foo() would always be calling a method on the pointee type.

---
 rust/kernel/sync/arc.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
rust/kernel/sync/arc.rs +6 -6
index 63a66761d0c7d..4ee155b43b2dc 100644
@@ -321,7 +321,7 @@ pub fn ptr_eq(this: &Self, other: &Self) -> bool {
     /// use kernel::sync::{Arc, UniqueArc};
     ///
     /// let arc = Arc::new(42, GFP_KERNEL)?;
-    /// let unique_arc = arc.into_unique_or_drop();
+    /// let unique_arc = Arc::into_unique_or_drop(arc);
     ///
     /// // The above conversion should succeed since refcount of `arc` is 1.
     /// assert!(unique_arc.is_some());
@@ -337,18 +337,18 @@ pub fn ptr_eq(this: &Self, other: &Self) -> bool {
     /// let arc = Arc::new(42, GFP_KERNEL)?;
     /// let another = arc.clone();
     ///
-    /// let unique_arc = arc.into_unique_or_drop();
+    /// let unique_arc = Arc::into_unique_or_drop(arc);
     ///
     /// // The above conversion should fail since refcount of `arc` is >1.
     /// assert!(unique_arc.is_none());
     ///
     /// # Ok::<(), Error>(())
     /// ```
-    pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> {
+    pub fn into_unique_or_drop(this: Self) -> Option<Pin<UniqueArc<T>>> {
         // We will manually manage the refcount in this method, so we disable the destructor.
-        let me = ManuallyDrop::new(self);
+        let this = ManuallyDrop::new(this);
         // SAFETY: We own a refcount, so the pointer is still valid.
-        let refcount = unsafe { me.ptr.as_ref() }.refcount.get();
+        let refcount = unsafe { this.ptr.as_ref() }.refcount.get();
 
         // If the refcount reaches a non-zero value, then we have destroyed this `Arc` and will
         // return without further touching the `Arc`. If the refcount reaches zero, then there are
@@ -365,7 +365,7 @@ pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> {
             // must pin the `UniqueArc` because the values was previously in an `Arc`, and they pin
             // their values.
             Some(Pin::from(UniqueArc {
-                inner: ManuallyDrop::into_inner(me),
+                inner: ManuallyDrop::into_inner(this),
             }))
         } else {
             None
Signature · 1 line
2.49.0
reviewer Reviewed-by on v5 2/5
#7 lore raw

Re: [PATCH v5 2/5] rust: make `Arc::into_unique_or_drop` associated function

Quoted 12 lines · Gary Guo

From: Gary Guo <[email protected]>

Make Arc::into_unique_or_drop to become a mere associated function instead of a method (i.e. removing the self receiver).

It's a general convention for Rust smart pointers to avoid having methods defined on them, because if the pointee type has a method of the same name, then it is shadowed. This is normally for avoiding semver breakage, which isn't an issue for kernel codebase, but it's still generally a good practice to follow this rule, so that ptr.foo() would always be calling a method on the pointee type.

Quoted 2 lines
author
#8 lore raw

PATCH v5 3/5 rust: convert `Arc` to use `Refcount`

In reply to Gary Guo

From: Gary Guo <[email protected]>

With Refcount type created, Arc can use Refcount instead of calling into FFI directly.

---
 rust/kernel/sync/arc.rs | 45 +++++++++++++----------------------------
 1 file changed, 14 insertions(+), 31 deletions(-)
rust/kernel/sync/arc.rs +14 -31
index 4ee155b43b2dc..9298993ea7d8b 100644
@@ -8,7 +8,7 @@
 //! threads.
 //!
 //! It is different from the standard library's [`Arc`] in a few ways:
-//! 1. It is backed by the kernel's `refcount_t` type.
+//! 1. It is backed by the kernel's [`Refcount`] type.
 //! 2. It does not support weak references, which allows it to be half the size.
 //! 3. It saturates the reference count instead of aborting when it goes over a threshold.
 //! 4. It does not provide a `get_mut` method, so the ref counted object is pinned.
@@ -18,11 +18,11 @@
 
 use crate::{
     alloc::{AllocError, Flags, KBox},
-    bindings,
     ffi::c_void,
     init::InPlaceInit,
+    sync::Refcount,
     try_init,
-    types::{ForeignOwnable, Opaque},
+    types::ForeignOwnable,
 };
 use core::{
     alloc::Layout,
@@ -145,7 +145,7 @@ pub struct Arc<T: ?Sized> {
 #[pin_data]
 #[repr(C)]
 struct ArcInner<T: ?Sized> {
-    refcount: Opaque<bindings::refcount_t>,
+    refcount: Refcount,
     data: T,
 }
 
@@ -157,7 +157,7 @@ impl<T: ?Sized> ArcInner<T> {
     /// `ptr` must have been returned by a previous call to [`Arc::into_raw`], and the `Arc` must
     /// not yet have been destroyed.
     unsafe fn container_of(ptr: *const T) -> NonNull<ArcInner<T>> {
-        let refcount_layout = Layout::new::<bindings::refcount_t>();
+        let refcount_layout = Layout::new::<Refcount>();
         // SAFETY: The caller guarantees that the pointer is valid.
         let val_layout = Layout::for_value(unsafe { &*ptr });
         // SAFETY: We're computing the layout of a real struct that existed when compiling this
@@ -229,8 +229,7 @@ impl<T> Arc<T> {
     pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
         // INVARIANT: The refcount is initialised to a non-zero value.
         let value = ArcInner {
-            // SAFETY: There are no safety requirements for this FFI call.
-            refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
+            refcount: Refcount::new(1),
             data: contents,
         };
 
@@ -348,18 +347,13 @@ pub fn into_unique_or_drop(this: Self) -> Option<Pin<UniqueArc<T>>> {
         // We will manually manage the refcount in this method, so we disable the destructor.
         let this = ManuallyDrop::new(this);
         // SAFETY: We own a refcount, so the pointer is still valid.
-        let refcount = unsafe { this.ptr.as_ref() }.refcount.get();
+        let refcount = unsafe { &this.ptr.as_ref().refcount };
 
         // If the refcount reaches a non-zero value, then we have destroyed this `Arc` and will
         // return without further touching the `Arc`. If the refcount reaches zero, then there are
         // no other arcs, and we can create a `UniqueArc`.
-        //
-        // SAFETY: We own a refcount, so the pointer is not dangling.
-        let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };
-        if is_zero {
-            // SAFETY: We have exclusive access to the arc, so we can perform unsynchronized
-            // accesses to the refcount.
-            unsafe { core::ptr::write(refcount, bindings::REFCOUNT_INIT(1)) };
+        if refcount.dec_and_test() {
+            refcount.set(1);
 
             // INVARIANT: We own the only refcount to this arc, so we may create a `UniqueArc`. We
             // must pin the `UniqueArc` because the values was previously in an `Arc`, and they pin
@@ -456,14 +450,10 @@ fn borrow(&self) -> &T {
 
 impl<T: ?Sized> Clone for Arc<T> {
     fn clone(&self) -> Self {
-        // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
-        // safe to dereference it.
-        let refcount = unsafe { self.ptr.as_ref() }.refcount.get();
-
-        // INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero.
+        // INVARIANT: `Refcount` saturates the refcount, so it cannot overflow to zero.
         // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
         // safe to increment the refcount.
-        unsafe { bindings::refcount_inc(refcount) };
+        unsafe { self.ptr.as_ref() }.refcount.inc();
 
         // SAFETY: We just incremented the refcount. This increment is now owned by the new `Arc`.
         unsafe { Self::from_inner(self.ptr) }
@@ -472,16 +462,10 @@ fn clone(&self) -> Self {
 
 impl<T: ?Sized> Drop for Arc<T> {
     fn drop(&mut self) {
-        // SAFETY: By the type invariant, there is necessarily a reference to the object. We cannot
-        // touch `refcount` after it's decremented to a non-zero value because another thread/CPU
-        // may concurrently decrement it to zero and free it. It is ok to have a raw pointer to
-        // freed/invalid memory as long as it is never dereferenced.
-        let refcount = unsafe { self.ptr.as_ref() }.refcount.get();
-
         // INVARIANT: If the refcount reaches zero, there are no other instances of `Arc`, and
         // this instance is being dropped, so the broken invariant is not observable.
-        // SAFETY: Also by the type invariant, we are allowed to decrement the refcount.
-        let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };
+        // SAFETY: By the type invariant, there is necessarily a reference to the object.
+        let is_zero = unsafe { self.ptr.as_ref() }.refcount.dec_and_test();
         if is_zero {
             // The count reached zero, we must free the memory.
             //
@@ -775,8 +759,7 @@ pub fn new_uninit(flags: Flags) -> Result<UniqueArc<MaybeUninit<T>>, AllocError>
         // INVARIANT: The refcount is initialised to a non-zero value.
         let inner = KBox::try_init::<AllocError>(
             try_init!(ArcInner {
-                // SAFETY: There are no safety requirements for this FFI call.
-                refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
+                refcount: Refcount::new(1),
                 data <- pin_init::uninit::<T, AllocError>(),
             }? AllocError),
             flags,
Signature · 1 line
2.49.0
reviewer Reviewed-by on v5 3/5
#10 lore raw

Re: [PATCH v5 3/5] rust: convert `Arc` to use `Refcount`

In reply to Gary Guo
Quoted 6 lines · Gary Guo

From: Gary Guo <[email protected]>

With Refcount type created, Arc can use Refcount instead of calling into FFI directly.

---
Cheers,
Benno

Quoted 3 lines
---
 rust/kernel/sync/arc.rs | 45 +++++++++++++----------------------------
 1 file changed, 14 insertions(+), 31 deletions(-)
author
#11 lore raw

PATCH v5 4/5 rust: block: convert `block::mq` to use `Refcount`

In reply to Gary Guo

From: Gary Guo <[email protected]>

Currently there's a custom reference counting in block::mq, which uses AtomicU64 Rust atomics, and this type doesn't exist on some 32-bit architectures. We cannot just change it to use 32-bit atomics, because doing so will make it vulnerable to refcount overflow. So switch it to use the kernel refcount kernel::sync::Refcount instead.

There is an operation needed by block::mq, atomically decreasing refcount from 2 to 0, which is not available through refcount.h, so I exposed Refcount::as_atomic which allows accessing the refcount directly.

---
 rust/kernel/block/mq/operations.rs |  7 ++--
 rust/kernel/block/mq/request.rs    | 63 ++++++++----------------------
 rust/kernel/sync/refcount.rs       | 14 +++++++
 3 files changed, 34 insertions(+), 50 deletions(-)
rust/kernel/block/mq/operations.rs +4 -3
index c2b98f507bcbd..c0f95a9419c4e 100644
@@ -10,9 +10,10 @@
     block::mq::Request,
     error::{from_result, Result},
     prelude::*,
+    sync::Refcount,
     types::ARef,
 };
-use core::{marker::PhantomData, sync::atomic::AtomicU64, sync::atomic::Ordering};
+use core::marker::PhantomData;
 
 /// Implement this trait to interface blk-mq as block devices.
 ///
@@ -78,7 +79,7 @@ impl<T: Operations> OperationsVTable<T> {
         let request = unsafe { &*(*bd).rq.cast::<Request<T>>() };
 
         // One refcount for the ARef, one for being in flight
-        request.wrapper_ref().refcount().store(2, Ordering::Relaxed);
+        request.wrapper_ref().refcount().set(2);
 
         // SAFETY:
         //  - We own a refcount that we took above. We pass that to `ARef`.
@@ -187,7 +188,7 @@ impl<T: Operations> OperationsVTable<T> {
 
             // SAFETY: The refcount field is allocated but not initialized, so
             // it is valid for writes.
-            unsafe { RequestDataWrapper::refcount_ptr(pdu.as_ptr()).write(AtomicU64::new(0)) };
+            unsafe { RequestDataWrapper::refcount_ptr(pdu.as_ptr()).write(Refcount::new(0)) };
 
             Ok(0)
         })
rust/kernel/block/mq/request.rs +16 -47

120 lines not on this page · raw message

rust/kernel/sync/refcount.rs +14 -0
index 3ff4585326b41..a9b24c6b2f8a7 100644
@@ -4,6 +4,8 @@
 //!
 //! C header: [`include/linux/refcount.h`](srctree/include/linux/refcount.h)
 
+use core::sync::atomic::AtomicI32;
+
 use crate::build_assert;
 use crate::types::Opaque;
 
@@ -34,6 +36,18 @@ fn as_ptr(&self) -> *mut bindings::refcount_t {
         self.0.get()
     }
 
+    /// Get the underlying atomic counter that backs the refcount.
+    ///
+    /// NOTE: This will be changed to LKMM atomic in the future.
+    #[inline]
+    pub fn as_atomic(&self) -> &AtomicI32 {
+        let ptr = self.0.get().cast();
+        // SAFETY: `refcount_t` is a transparent wrapper of `atomic_t`, which is an atomic 32-bit
+        // integer that is layout-wise compatible with `AtomicI32`. All values are valid for
+        // `refcount_t`, despite some of the values being considered saturated and "bad".
+        unsafe { &*ptr }
+    }
+
     /// Set a refcount's value.
     #[inline]
     pub fn set(&self, value: i32) {
Signature · 1 line
2.49.0
#12 lore raw

Re: [PATCH v5 4/5] rust: block: convert `block::mq` to use `Refcount`

Quoted 48 lines · Gary Guo

From: Gary Guo <[email protected]>

Currently there's a custom reference counting in block::mq, which uses AtomicU64 Rust atomics, and this type doesn't exist on some 32-bit architectures. We cannot just change it to use 32-bit atomics, because doing so will make it vulnerable to refcount overflow. So switch it to use the kernel refcount kernel::sync::Refcount instead.

There is an operation needed by block::mq, atomically decreasing refcount from 2 to 0, which is not available through refcount.h, so I exposed Refcount::as_atomic which allows accessing the refcount directly.

---
 rust/kernel/block/mq/operations.rs |  7 ++--
 rust/kernel/block/mq/request.rs    | 63 ++++++++----------------------
 rust/kernel/sync/refcount.rs       | 14 +++++++
 3 files changed, 34 insertions(+), 50 deletions(-)
rust/kernel/block/mq/operations.rs +3 -2
index c2b98f507bcbd..c0f95a9419c4e 100644
@@ -10,9 +10,10 @@
     block::mq::Request,
     error::{from_result, Result},
     prelude::*,
+    sync::Refcount,
     types::ARef,
 };
-use core::{marker::PhantomData, sync::atomic::AtomicU64, sync::atomic::Ordering};
+use core::marker::PhantomData;
 
 /// Implement this trait to interface blk-mq as block devices.
 ///
@@ -78,7 +79,7 @@ impl<T: Operations> OperationsVTable<T> {
         let request = unsafe { &*(*bd).rq.cast::<Request<T>>() };
 
         // One refcount for the ARef, one for being in flight
-        request.wrapper_ref().refcount().store(2, Ordering::Relaxed);
+        request.wrapper_ref().refcount().set(2);
 
         // SAFETY:
         //  - We own a refcount that we took above. We pass that to `ARef`.

rust/kernel/block/mq/operations.rs impl<T: Operations> OperationsVTable<T> { · line 191

Quoted 5 lines
rust/kernel/block/mq/operations.rs +1 -1
@@ -187,7 +188,7 @@ impl<T: Operations> OperationsVTable<T> {
 
             // SAFETY: The refcount field is allocated but not initialized, so
             // it is valid for writes.
-            unsafe { RequestDataWrapper::refcount_ptr(pdu.as_ptr()).write(AtomicU64::new(0)) };
+            unsafe { RequestDataWrapper::refcount_ptr(pdu.as_ptr()).write(Refcount::new(0)) };

Ah, so that's why 0 is allowed as a valid value for Refcount::new. Seeing the use that is made of atomics here, I wonder if Refcount is a good choice, or if we could adapt the code to use them as expected. I am not familiar enough with this part of the code to give informed advice unfortunately.

But at the very least, I think the constructor should not be made unsafe due to account for one particular user. How about doing a Refcount::new(1) immediately followed by a set(0) so other users are not tricked into creating an invalid Refcount?

#13 lore raw

Re: [PATCH v5 4/5] rust: block: convert `block::mq` to use `Refcount`

Quoted 61 lines · Alexandre Courbot
Quoted 48 lines · Gary Guo

From: Gary Guo <[email protected]>

Currently there's a custom reference counting in block::mq, which uses AtomicU64 Rust atomics, and this type doesn't exist on some 32-bit architectures. We cannot just change it to use 32-bit atomics, because doing so will make it vulnerable to refcount overflow. So switch it to use the kernel refcount kernel::sync::Refcount instead.

There is an operation needed by block::mq, atomically decreasing refcount from 2 to 0, which is not available through refcount.h, so I exposed Refcount::as_atomic which allows accessing the refcount directly.

---
 rust/kernel/block/mq/operations.rs |  7 ++--
 rust/kernel/block/mq/request.rs    | 63 ++++++++----------------------
 rust/kernel/sync/refcount.rs       | 14 +++++++
 3 files changed, 34 insertions(+), 50 deletions(-)
rust/kernel/block/mq/operations.rs +3 -2
index c2b98f507bcbd..c0f95a9419c4e 100644
@@ -10,9 +10,10 @@
     block::mq::Request,
     error::{from_result, Result},
     prelude::*,
+    sync::Refcount,
     types::ARef,
 };
-use core::{marker::PhantomData, sync::atomic::AtomicU64, sync::atomic::Ordering};
+use core::marker::PhantomData;
 
 /// Implement this trait to interface blk-mq as block devices.
 ///
@@ -78,7 +79,7 @@ impl<T: Operations> OperationsVTable<T> {
         let request = unsafe { &*(*bd).rq.cast::<Request<T>>() };
 
         // One refcount for the ARef, one for being in flight
-        request.wrapper_ref().refcount().store(2, Ordering::Relaxed);
+        request.wrapper_ref().refcount().set(2);
 
         // SAFETY:
         //  - We own a refcount that we took above. We pass that to `ARef`.

rust/kernel/block/mq/operations.rs impl<T: Operations> OperationsVTable<T> { · line 191

Quoted 5 lines
rust/kernel/block/mq/operations.rs +1 -1
@@ -187,7 +188,7 @@ impl<T: Operations> OperationsVTable<T> {
 
             // SAFETY: The refcount field is allocated but not initialized, so
             // it is valid for writes.
-            unsafe { RequestDataWrapper::refcount_ptr(pdu.as_ptr()).write(AtomicU64::new(0)) };
+            unsafe { RequestDataWrapper::refcount_ptr(pdu.as_ptr()).write(Refcount::new(0)) };

Ah, so that's why 0 is allowed as a valid value for Refcount::new. Seeing the use that is made of atomics here, I wonder if Refcount is a good choice, or if we could adapt the code to use them as expected. I am not familiar enough with this part of the code to give informed advice unfortunately.

Quoted 2 lines

But at the very least, I think the constructor should not be made unsafe due to account for one particular user. How about doing a

Hmm.. a refcount being 0 is not unsafe I would say, it means no one references the object (usually in a particular type of referencing). In general, one should use Arc and be done with that, but if you were to have different types of referencing to a same object, then one of the refcounts may end up being 0.

Quoted 2 lines

Refcount::new(1) immediately followed by a set(0) so other users are not tricked into creating an invalid Refcount?

This I will call bad code, as it would introduce further confusion because the new(1) is pretty pointless imo.

Regards,
Boqun

Quoted 2 lines
reviewer Reviewed-by on v5 4/5
#14 lore raw

Re: [PATCH v5 4/5] rust: block: convert `block::mq` to use `Refcount`

In reply to Gary Guo
Quoted 8 lines · Gary Guo

From: Gary Guo <[email protected]>

Currently there's a custom reference counting in block::mq, which uses AtomicU64 Rust atomics, and this type doesn't exist on some 32-bit architectures. We cannot just change it to use 32-bit atomics, because doing so will make it vulnerable to refcount overflow. So switch it to use the kernel refcount kernel::sync::Refcount instead.

Quoted 8 lines

There is an operation needed by block::mq, atomically decreasing refcount from 2 to 0, which is not available through refcount.h, so I exposed Refcount::as_atomic which allows accessing the refcount directly.

Quoted 20 lines
---
 rust/kernel/block/mq/operations.rs |  7 ++--
 rust/kernel/block/mq/request.rs    | 63 ++++++++----------------------
 rust/kernel/sync/refcount.rs       | 14 +++++++
 3 files changed, 34 insertions(+), 50 deletions(-)
rust/kernel/sync/refcount.rs +2 -0
index 3ff4585326b41..a9b24c6b2f8a7 100644
@@ -4,6 +4,8 @@
 //!
 //! C header: [`include/linux/refcount.h`](srctree/include/linux/refcount.h)
 
+use core::sync::atomic::AtomicI32;
+
 use crate::build_assert;
 use crate::types::Opaque;
 

rust/kernel/sync/refcount.rs fn as_ptr(&self) -> *mut bindings::refcount_t { · line 41

Quoted 6 lines
rust/kernel/sync/refcount.rs +3 -0
@@ -34,6 +36,18 @@ fn as_ptr(&self) -> *mut bindings::refcount_t {
         self.0.get()
     }
 
+    /// Get the underlying atomic counter that backs the refcount.
+    ///
+    /// NOTE: This will be changed to LKMM atomic in the future.

Can we discourage using this function a bit more in the docs? At least point people to try other ways before reaching for this, since it allows overflowing & doesn't warn on saturate etc.

---
Cheers,
Benno

Quoted 12 lines
rust/kernel/sync/refcount.rs +9 -0
+    #[inline]
+    pub fn as_atomic(&self) -> &AtomicI32 {
+        let ptr = self.0.get().cast();
+        // SAFETY: `refcount_t` is a transparent wrapper of `atomic_t`, which is an atomic 32-bit
+        // integer that is layout-wise compatible with `AtomicI32`. All values are valid for
+        // `refcount_t`, despite some of the values being considered saturated and "bad".
+        unsafe { &*ptr }
+    }
+
     /// Set a refcount's value.
     #[inline]
     pub fn set(&self, value: i32) {
maintainer
#15 lore raw

Re: [PATCH v5 4/5] rust: block: convert `block::mq` to use `Refcount`

Quoted 43 lines · On Tue, 12 Aug 2025 10:17:44 +0200 "Benno Lossin" <[email protected]> wrote:
Quoted 8 lines · Gary Guo

From: Gary Guo <[email protected]>

Currently there's a custom reference counting in block::mq, which uses AtomicU64 Rust atomics, and this type doesn't exist on some 32-bit architectures. We cannot just change it to use 32-bit atomics, because doing so will make it vulnerable to refcount overflow. So switch it to use the kernel refcount kernel::sync::Refcount instead.

Quoted 8 lines

There is an operation needed by block::mq, atomically decreasing refcount from 2 to 0, which is not available through refcount.h, so I exposed Refcount::as_atomic which allows accessing the refcount directly.

Quoted 23 lines
---
 rust/kernel/block/mq/operations.rs |  7 ++--
 rust/kernel/block/mq/request.rs    | 63 ++++++++----------------------
 rust/kernel/sync/refcount.rs       | 14 +++++++
 3 files changed, 34 insertions(+), 50 deletions(-)  
rust/kernel/sync/refcount.rs +2 -0
index 3ff4585326b41..a9b24c6b2f8a7 100644
@@ -4,6 +4,8 @@
 //!
 //! C header: [`include/linux/refcount.h`](srctree/include/linux/refcount.h)
 
+use core::sync::atomic::AtomicI32;
+
 use crate::build_assert;
 use crate::types::Opaque;
 
@@ -34,6 +36,18 @@ fn as_ptr(&self) -> *mut bindings::refcount_t {
         self.0.get()
     }
 
Quoted 7 lines

rust/kernel/sync/refcount.rs fn as_ptr(&self) -> *mut bindings::refcount_t { · line 41

Quoted 3 lines
rust/kernel/sync/refcount.rs +3 -0
+    /// Get the underlying atomic counter that backs the refcount.
+    ///
+    /// NOTE: This will be changed to LKMM atomic in the future.  

Can we discourage using this function a bit more in the docs? At least point people to try other ways before reaching for this, since it allows overflowing & doesn't warn on saturate etc.

Would this additional doc comment be good enough for you?

/// NOTE: usage of this function is discouraged unless there is no way /// to achieve the desired result using APIs in refcount.h. If an API /// in refcount.h does not currently contain a binding, please /// consider adding a binding for it instead.

Best,
Gary

Quoted 18 lines

---
Cheers,
Benno

Quoted 12 lines
rust/kernel/sync/refcount.rs +9 -0
+    #[inline]
+    pub fn as_atomic(&self) -> &AtomicI32 {
+        let ptr = self.0.get().cast();
+        // SAFETY: `refcount_t` is a transparent wrapper of `atomic_t`, which is an atomic 32-bit
+        // integer that is layout-wise compatible with `AtomicI32`. All values are valid for
+        // `refcount_t`, despite some of the values being considered saturated and "bad".
+        unsafe { &*ptr }
+    }
+
     /// Set a refcount's value.
     #[inline]
     pub fn set(&self, value: i32) {  
reviewer
#16 lore raw

Re: [PATCH v5 4/5] rust: block: convert `block::mq` to use `Refcount`

Quoted 15 lines · Gary Guo
Quoted 5 lines · On Tue, 12 Aug 2025 10:17:44 +0200 "Benno Lossin" <[email protected]> wrote:
Quoted 4 lines · Gary Guo
rust/kernel/sync/refcount.rs +0 -0
@@ -34,6 +36,18 @@ fn as_ptr(&self) -> *mut bindings::refcount_t {
         self.0.get()
     }
 
Quoted 7 lines

rust/kernel/sync/refcount.rs fn as_ptr(&self) -> *mut bindings::refcount_t { · line 41

Quoted 3 lines
rust/kernel/sync/refcount.rs +3 -0
+    /// Get the underlying atomic counter that backs the refcount.
+    ///
+    /// NOTE: This will be changed to LKMM atomic in the future.  

Can we discourage using this function a bit more in the docs? At least point people to try other ways before reaching for this, since it allows overflowing & doesn't warn on saturate etc.

Quoted 6 lines

Would this additional doc comment be good enough for you?

/// NOTE: usage of this function is discouraged unless there is no way /// to achieve the desired result using APIs in refcount.h. If an API /// in refcount.h does not currently contain a binding, please /// consider adding a binding for it instead.

I'd like to stress that the atomic doesn't have the same protections as the refcount type, how about:

    /// NOTE: usage of this function is discouraged as it can circumvent the protections offered by
    /// `refcount.h`. If there is no way to achieve the result using APIs in `refcount.h`, then this
    /// function can be used. Otherwise consider adding a binding for the required API.

---
Cheers,
Benno

#17 lore raw

Re: [PATCH v5 4/5] rust: block: convert `block::mq` to use `Refcount`

Quoted 23 lines · Benno Lossin
Quoted 15 lines · Gary Guo
Quoted 5 lines · On Tue, 12 Aug 2025 10:17:44 +0200 "Benno Lossin" <[email protected]> wrote:
Quoted 4 lines · Gary Guo
rust/kernel/sync/refcount.rs +0 -0
@@ -34,6 +36,18 @@ fn as_ptr(&self) -> *mut bindings::refcount_t {
         self.0.get()
     }
 
Quoted 7 lines

rust/kernel/sync/refcount.rs fn as_ptr(&self) -> *mut bindings::refcount_t { · line 41

Quoted 3 lines
rust/kernel/sync/refcount.rs +3 -0
+    /// Get the underlying atomic counter that backs the refcount.
+    ///
+    /// NOTE: This will be changed to LKMM atomic in the future.  

Can we discourage using this function a bit more in the docs? At least point people to try other ways before reaching for this, since it allows overflowing & doesn't warn on saturate etc.

Quoted 6 lines

Would this additional doc comment be good enough for you?

/// NOTE: usage of this function is discouraged unless there is no way /// to achieve the desired result using APIs in refcount.h. If an API /// in refcount.h does not currently contain a binding, please /// consider adding a binding for it instead.

Quoted 7 lines

I'd like to stress that the atomic doesn't have the same protections as the refcount type, how about:

    /// NOTE: usage of this function is discouraged as it can circumvent the protections offered by
    /// `refcount.h`. If there is no way to achieve the result using APIs in `refcount.h`, then this
    /// function can be used. Otherwise consider adding a binding for the required API.

Looks good to me. I will apply this and some adjustment against my atomic patchset, and queue this whole series for v6.18, thanks!

Regards,
Boqun

Quoted 3 lines

---
Cheers,
Benno

author
#18 lore raw

PATCH v5 5/5 MAINTAINERS: update atomic infrastructure entry to include Rust

In reply to Gary Guo

From: Gary Guo <[email protected]>

I would like to help review atomic related patches, especially Rust related ones, hence add myself as an reviewer.

---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)
MAINTAINERS +2 -0
index dd810da5261b5..322d040cd98f3 100644
@@ -3895,12 +3895,14 @@ M:	Will Deacon <[email protected]>
 M:	Peter Zijlstra <[email protected]>
 R:	Boqun Feng <[email protected]>
 R:	Mark Rutland <[email protected]>
+R:	Gary Guo <[email protected]>
 L:	[email protected]
 S:	Maintained
 F:	Documentation/atomic_*.txt
 F:	arch/*/include/asm/atomic*.h
 F:	include/*/atomic*.h
 F:	include/linux/refcount.h
+F:	rust/kernel/sync/refcount.rs
 F:	scripts/atomic/
 
 ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
Signature · 1 line
2.49.0