implement `kernel::sync::Refcount` and convert users
Subsystems (5)
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
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
@@ -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
@@ -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
Alexandre Courbot
reviewerRe: [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?
Re: [PATCH v5 1/5] rust: implement `kernel::sync::Refcount`
In reply to Gary GuoQuoted 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 inArc, 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]>
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
Gary Guo
maintainerRe: [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 inArc, 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]>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
Benno Lossin
reviewerRe: [PATCH v5 1/5] rust: implement `kernel::sync::Refcount`
In reply to Gary Guorust/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
PATCH v5 2/5 rust: make `Arc::into_unique_or_drop` associated function
In reply to Gary GuoFrom: 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
@@ -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
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_dropto become a mere associated function instead of a method (i.e. removing theselfreceiver).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
Reviewed-by Benno Lossin <[email protected]>Signed-off-by Gary Guo <[email protected]>
PATCH v5 3/5 rust: convert `Arc` to use `Refcount`
In reply to Gary GuoFrom: 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
@@ -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
Re: [PATCH v5 3/5] rust: convert `Arc` to use `Refcount`
Quoted 6 lines · Gary Guo
From: Gary Guo <[email protected]>
With
Refcounttype created,Arccan useRefcountinstead of calling into FFI directly.Signed-off-by Gary Guo <[email protected]>
FWIW,
Re: [PATCH v5 3/5] rust: convert `Arc` to use `Refcount`
In reply to Gary GuoQuoted 6 lines · Gary Guo
From: Gary Guo <[email protected]>
With
Refcounttype created,Arccan useRefcountinstead of calling into FFI directly.Signed-off-by Gary Guo <[email protected]>
---
Cheers,
Benno
Quoted 3 lines
--- rust/kernel/sync/arc.rs | 45 +++++++++++++---------------------------- 1 file changed, 14 insertions(+), 31 deletions(-)
PATCH v5 4/5 rust: block: convert `block::mq` to use `Refcount`
In reply to Gary GuoFrom: 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
@@ -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
@@ -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
Alexandre Courbot
reviewerRe: [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 usesAtomicU64Rust 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 refcountkernel::sync::Refcountinstead.There is an operation needed by
block::mq, atomically decreasing refcount from 2 to 0, which is not available throughrefcount.h, so I exposedRefcount::as_atomicwhich allows accessing the refcount directly.Tested-by David Gow <[email protected]>Acked-by Andreas Hindborg <[email protected]>Signed-off-by Gary Guo <[email protected]>--- 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@@ -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?
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 usesAtomicU64Rust 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 refcountkernel::sync::Refcountinstead.There is an operation needed by
block::mq, atomically decreasing refcount from 2 to 0, which is not available throughrefcount.h, so I exposedRefcount::as_atomicwhich allows accessing the refcount directly.Tested-by David Gow <[email protected]>Acked-by Andreas Hindborg <[email protected]>Signed-off-by Gary Guo <[email protected]>--- 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@@ -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
0is allowed as a valid value forRefcount::new. Seeing the use that is made of atomics here, I wonder ifRefcountis 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 aset(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
Re: [PATCH v5 4/5] rust: block: convert `block::mq` to use `Refcount`
In reply to Gary GuoQuoted 8 lines · Gary Guo
From: Gary Guo <[email protected]>
Currently there's a custom reference counting in
block::mq, which usesAtomicU64Rust 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 refcountkernel::sync::Refcountinstead.
Quoted 8 lines
There is an operation needed by
block::mq, atomically decreasing refcount from 2 to 0, which is not available throughrefcount.h, so I exposedRefcount::as_atomicwhich allows accessing the refcount directly.Tested-by David Gow <[email protected]>Acked-by Andreas Hindborg <[email protected]>Signed-off-by Gary Guo <[email protected]>
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@@ -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 ) {
Gary Guo
maintainerRe: [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 usesAtomicU64Rust 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 refcountkernel::sync::Refcountinstead.Quoted 8 lines
There is an operation needed by
block::mq, atomically decreasing refcount from 2 to 0, which is not available throughrefcount.h, so I exposedRefcount::as_atomicwhich allows accessing the refcount directly.Tested-by David Gow <[email protected]>Acked-by Andreas Hindborg <[email protected]>Signed-off-by Gary Guo <[email protected]>Reviewed-by Benno Lossin <[email protected]>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@@ -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,
BennoQuoted 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 ) {
Benno Lossin
reviewerRe: [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 /// inrefcount.hdoes 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
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 /// inrefcount.hdoes 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
PATCH v5 5/5 MAINTAINERS: update atomic infrastructure entry to include Rust
In reply to Gary GuoFrom: 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
@@ -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