Skip to content

Commit bb2cf53

Browse files
nbdd0121Andreas Hindborg
authored andcommitted
LIST: [PATCH v3 1/4] rust: implement kernel::sync::Refcount
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]> Signed-off-by: Gary Guo <[email protected]> Reviewed-by: Fiona Behrens <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8e106d1 commit bb2cf53

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

rust/helpers/refcount.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,21 @@ __rust_helper refcount_t rust_helper_REFCOUNT_INIT(int n)
88
return (refcount_t)REFCOUNT_INIT(n);
99
}
1010

11+
__rust_helper void rust_helper_refcount_set(refcount_t *r, int n)
12+
{
13+
refcount_set(r, n);
14+
}
15+
1116
__rust_helper void rust_helper_refcount_inc(refcount_t *r)
1217
{
1318
refcount_inc(r);
1419
}
1520

21+
__rust_helper void rust_helper_refcount_dec(refcount_t *r)
22+
{
23+
refcount_dec(r);
24+
}
25+
1626
__rust_helper bool rust_helper_refcount_dec_and_test(refcount_t *r)
1727
{
1828
return refcount_dec_and_test(r);

rust/kernel/sync.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ pub mod lock;
1313
mod locked_by;
1414
pub mod poll;
1515
pub mod rcu;
16+
mod refcount;
1617

1718
pub use arc::{Arc, ArcBorrow, UniqueArc};
1819
pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
1920
pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy};
2021
pub use lock::mutex::{new_mutex, Mutex, MutexGuard};
2122
pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard};
2223
pub use locked_by::LockedBy;
24+
pub use refcount::Refcount;
2325

2426
/// Represents a lockdep class. It's a wrapper around C's `lock_class_key`.
2527
#[repr(transparent)]

rust/kernel/sync/refcount.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Atomic reference counting.
4+
//!
5+
//! C header: [`include/linux/refcount.h`](srctree/include/linux/refcount.h)
6+
7+
use crate::types::Opaque;
8+
9+
/// Atomic reference counter.
10+
///
11+
/// This type is conceptually an atomic integer, but provides saturation semantics compared to
12+
/// normal atomic integers. Values in the negative range when viewed as a signed integer are
13+
/// saturation (bad) values. For details about the saturation semantics, please refer to top of
14+
/// [`include/linux/refcount.h`](srctree/include/refcount.h).
15+
///
16+
/// Wraps the kernel's C `refcount_t`.
17+
#[repr(transparent)]
18+
pub struct Refcount(Opaque<bindings::refcount_t>);
19+
20+
impl Refcount {
21+
/// Construct a new [`Refcount`] from an initial value.
22+
#[inline]
23+
pub fn new(value: i32) -> Self {
24+
// SAFETY: There are no safety requirements for this FFI call.
25+
Self(Opaque::new(unsafe { bindings::REFCOUNT_INIT(value) }))
26+
}
27+
28+
#[inline]
29+
fn as_ptr(&self) -> *mut bindings::refcount_t {
30+
self.0.get()
31+
}
32+
33+
/// Set a refcount's value.
34+
#[inline]
35+
pub fn set(&self, value: i32) {
36+
// SAFETY: `self.as_ptr()` is valid.
37+
unsafe { bindings::refcount_set(self.as_ptr(), value) }
38+
}
39+
40+
/// Increment a refcount.
41+
///
42+
/// It will saturate if overflows and `WARN`. It will also `WARN` if the refcount is 0, as this
43+
/// represents a possible use-after-free condition.
44+
///
45+
/// Provides no memory ordering, it is assumed that caller already has a reference on the
46+
/// object.
47+
#[inline]
48+
pub fn inc(&self) {
49+
// SAFETY: self is valid.
50+
unsafe { bindings::refcount_inc(self.as_ptr()) }
51+
}
52+
53+
/// Decrement a refcount.
54+
///
55+
/// It will `WARN` on underflow and fail to decrement when saturated.
56+
///
57+
/// Provides release memory ordering, such that prior loads and stores are done
58+
/// before.
59+
#[inline]
60+
pub fn dec(&self) {
61+
// SAFETY: `self.as_ptr()` is valid.
62+
unsafe { bindings::refcount_dec(self.as_ptr()) }
63+
}
64+
65+
/// Decrement a refcount and test if it is 0.
66+
///
67+
/// It will `WARN` on underflow and fail to decrement when saturated.
68+
///
69+
/// Provides release memory ordering, such that prior loads and stores are done
70+
/// before, and provides an acquire ordering on success such that memory deallocation
71+
/// must come after.
72+
///
73+
/// Returns true if the resulting refcount is 0, false otherwise.
74+
#[inline]
75+
#[must_use = "use `dec` instead you do not need to test if it is 0"]
76+
pub fn dec_and_test(&self) -> bool {
77+
// SAFETY: `self.as_ptr()` is valid.
78+
unsafe { bindings::refcount_dec_and_test(self.as_ptr()) }
79+
}
80+
}
81+
82+
// SAFETY: `refcount_t` is thread-safe.
83+
unsafe impl Send for Refcount {}
84+
85+
// SAFETY: `refcount_t` is thread-safe.
86+
unsafe impl Sync for Refcount {}

0 commit comments

Comments
 (0)