Skip to contentSkip to conversation

rust: add SRCU abstraction

PATCH Superseded Onur Özkan 4 participants 12 messages May 27 – May 28

Subsystems (4)

v5 of 10 Superseded Latest is v10 →

lore
Share & tools
lore

Onur Özkan

author maintainer
#0 lore raw

v5 cover rust: add SRCU abstraction

The immediate motivation is the Tyr reset infrastructure [1] which needs to serialize reset sensitive hardware access against reset and teardown paths. That reset series started to require many independent dependencies so this SRCU support is split out as a standalone Rust API to keep the reset series focused on the reset logic and easier to review, rebase and land.

Changes since v4:

- Exposed srcu_readers_active from C side and wired it to the Rust helpers.
- Used srcu_readers_active() in SRCU drop and logged with pr_warn if there are leaked guards during the drop.

Changes since v3 (which are for Sashiko notes [2]):

- Added rust helpers for srcu_barrier() and synchronize_srcu_expedited() so the abstraction builds with CONFIG_TINY_SRCU, where these are static inline functions.
- Added missing INVARIANT comment in Srcu::new() about why the type invariants hold after successful initialization.

Changes since v2:

- Removed closure-based API.
- Added #[doc(hidden)] on new_srcu macro.
- Added #[must_use..] on srcu::Guard.
- Improved the clean-up path (PinnedDrop implementation) which eventually made read_lock safe with leaked guards.

v2: https://lore.kernel.org/all/[email protected]

Changes since v1:

- Made the owned SRCU read-side guard API unsafe and added a safe closure based helper for callers that do not need to keep the guard. This is to avoid UB on the C side cleanup_srcu_struct where the SRCU struct is freed while there are still active guards, which can happen if the caller leaks the guard e.g., with mem::forget().
- Improved doc comments.

v1: https://lore.kernel.org/all/[email protected]

[1]: https://lore.kernel.org/all/[email protected]
[2]: https://sashiko.dev/#/patchset/[email protected]?part=2

Onur Özkan (4):
rust: helpers: add SRCU helpers
srcu: expose srcu_readers_active()
rust: sync: add SRCU abstraction
MAINTAINERS: add Rust SRCU files to SRCU entry

 MAINTAINERS              |   3 +
 include/linux/srcu.h     |  29 +++++++
 kernel/rcu/srcutiny.c    |   2 +-
 kernel/rcu/srcutree.c    |  25 ------
 rust/helpers/helpers.c   |   1 +
 rust/helpers/srcu.c      |  39 +++++++++
 rust/kernel/sync.rs      |   2 +
 rust/kernel/sync/srcu.rs | 166 +++++++++++++++++++++++++++++++++++++++
 8 files changed, 241 insertions(+), 26 deletions(-)
 create mode 100644 rust/helpers/srcu.c
 create mode 100644 rust/kernel/sync/srcu.rs
Signature · 1 line
2.51.2
author maintainer
#1 lore raw

PATCH v5 1/4 rust: helpers: add SRCU helpers

Add helper wrappers for SRCU functions that are exposed to Rust through generated bindings.

---
 rust/helpers/helpers.c |  1 +
 rust/helpers/srcu.c    | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 rust/helpers/srcu.c
rust/helpers/helpers.c +1 -0
index 625921e27dfb..f3562d3b3888 100644
@@ -88,6 +88,7 @@
 #include "signal.c"
 #include "slab.c"
 #include "spinlock.c"
+#include "srcu.c"
 #include "sync.c"
 #include "task.c"
 #include "time.c"
rust/helpers/srcu.c new file +34 -0
new file mode 100644
index 000000000000..79dd24a104ef
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/srcu.h>
+
+__rust_helper int rust_helper_init_srcu_struct_with_key(struct srcu_struct *ssp,
+							const char *name,
+							struct lock_class_key *key)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	return __init_srcu_struct(ssp, name, key);
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+	return init_srcu_struct(ssp);
+#endif /* CONFIG_DEBUG_LOCK_ALLOC */
+}
+
+__rust_helper int rust_helper_srcu_read_lock(struct srcu_struct *ssp)
+{
+	return srcu_read_lock(ssp);
+}
+
+__rust_helper void rust_helper_srcu_read_unlock(struct srcu_struct *ssp, int idx)
+{
+	srcu_read_unlock(ssp, idx);
+}
+
+__rust_helper void rust_helper_srcu_barrier(struct srcu_struct *ssp)
+{
+	srcu_barrier(ssp);
+}
+
+__rust_helper void rust_helper_synchronize_srcu_expedited(struct srcu_struct *ssp)
+{
+	synchronize_srcu_expedited(ssp);
+}
Signature · 1 line
2.51.2
maintainer
#2 lore raw

Re: [PATCH v5 1/4] rust: helpers: add SRCU helpers

Quoted 32 lines · Onur Özkan

Add helper wrappers for SRCU functions that are exposed to Rust through generated bindings.

---
 rust/helpers/helpers.c |  1 +
 rust/helpers/srcu.c    | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 rust/helpers/srcu.c
rust/helpers/helpers.c +1 -0
index 625921e27dfb..f3562d3b3888 100644
@@ -88,6 +88,7 @@
 #include "signal.c"
 #include "slab.c"
 #include "spinlock.c"
+#include "srcu.c"
 #include "sync.c"
 #include "task.c"
 #include "time.c"
rust/helpers/srcu.c new file +4 -0
new file mode 100644
index 000000000000..79dd24a104ef
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/srcu.h>
+

rust/helpers/srcu.c line 14

Quoted 10 lines
rust/helpers/srcu.c new file +10 -0
+__rust_helper int rust_helper_init_srcu_struct_with_key(struct srcu_struct *ssp,
+							const char *name,
+							struct lock_class_key *key)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	return __init_srcu_struct(ssp, name, key);
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+	return init_srcu_struct(ssp);
+#endif /* CONFIG_DEBUG_LOCK_ALLOC */
+}

Similar to Boqun's feedback on a later patch, could you please make these be two functions under the corresponding legs of the existing CONFIG_DEBUG_LOCK_ALLOC #ifdef in include/linux/srcu.h? You are including that file above, so it should work well.

Actually, you could just name thefunction __init_srcu_struct(), use the existing definition under #ifdef CONFIG_DEBUG_LOCK_ALLOC, and just create the simple wrapper in the other leg of this #ifdef. That would be more aligned with the Linux-kernel coding guidelines and also be less code.

Or is the "rust_helper_" prefix mandatory? If so, you could make rust_helper_init_srcu_struct() be a wrapper for __init_srcu_struct() in this file, then just define __init_srcu_struct() as a wrapper around init_srcu_struct() in the !CONFIG_DEBUG_LOCK_ALLOC leg of the #ifdef in include/linux/srcu.h.

As a historical note, I didn't much like this rule 25 years ago, but tried a new project both ways, and quickly abandoned the one that used #ifdef with abandon. So I quickly came around to the Linux-kernel way of thinking on this particular point, anyway. ;-)

Thanx, Paul

Quoted 22 lines
rust/helpers/srcu.c new file +19 -0
+__rust_helper int rust_helper_srcu_read_lock(struct srcu_struct *ssp)
+{
+	return srcu_read_lock(ssp);
+}
+
+__rust_helper void rust_helper_srcu_read_unlock(struct srcu_struct *ssp, int idx)
+{
+	srcu_read_unlock(ssp, idx);
+}
+
+__rust_helper void rust_helper_srcu_barrier(struct srcu_struct *ssp)
+{
+	srcu_barrier(ssp);
+}
+
+__rust_helper void rust_helper_synchronize_srcu_expedited(struct srcu_struct *ssp)
+{
+	synchronize_srcu_expedited(ssp);
+}
Signature · 1 line
2.51.2
author maintainer
#3 lore raw

Re: [PATCH v5 1/4] rust: helpers: add SRCU helpers

Quoted 49 lines · On Wed, 27 May 2026 16:03:30 -0700 "Paul E. McKenney" <[email protected]>…
Quoted 32 lines · Onur Özkan

Add helper wrappers for SRCU functions that are exposed to Rust through generated bindings.

---
 rust/helpers/helpers.c |  1 +
 rust/helpers/srcu.c    | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 rust/helpers/srcu.c
rust/helpers/helpers.c +1 -0
index 625921e27dfb..f3562d3b3888 100644
@@ -88,6 +88,7 @@
 #include "signal.c"
 #include "slab.c"
 #include "spinlock.c"
+#include "srcu.c"
 #include "sync.c"
 #include "task.c"
 #include "time.c"
rust/helpers/srcu.c new file +4 -0
new file mode 100644
index 000000000000..79dd24a104ef
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/srcu.h>
+

rust/helpers/srcu.c line 14

Quoted 10 lines
rust/helpers/srcu.c new file +10 -0
+__rust_helper int rust_helper_init_srcu_struct_with_key(struct srcu_struct *ssp,
+							const char *name,
+							struct lock_class_key *key)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	return __init_srcu_struct(ssp, name, key);
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+	return init_srcu_struct(ssp);
+#endif /* CONFIG_DEBUG_LOCK_ALLOC */
+}

Similar to Boqun's feedback on a later patch, could you please make these be two functions under the corresponding legs of the existing CONFIG_DEBUG_LOCK_ALLOC #ifdef in include/linux/srcu.h? You are including that file above, so it should work well.

Quoted 6 lines

Actually, you could just name thefunction __init_srcu_struct(), use the existing definition under #ifdef CONFIG_DEBUG_LOCK_ALLOC, and just create the simple wrapper in the other leg of this #ifdef. That would be more aligned with the Linux-kernel coding guidelines and also be less code.

Or is the "rust_helper_" prefix mandatory? If so, you could make

That prefix is indeed mandatory.

Quoted 4 lines

rust_helper_init_srcu_struct() be a wrapper for __init_srcu_struct() in this file, then just define __init_srcu_struct() as a wrapper around init_srcu_struct() in the !CONFIG_DEBUG_LOCK_ALLOC leg of the #ifdef in include/linux/srcu.h.

Sure, sounds good to me.

Thanks,
Onur

Quoted 30 lines

As a historical note, I didn't much like this rule 25 years ago, but tried a new project both ways, and quickly abandoned the one that used #ifdef with abandon. So I quickly came around to the Linux-kernel way of thinking on this particular point, anyway. ;-)

Thanx, Paul

Quoted 22 lines
rust/helpers/srcu.c new file +19 -0
+__rust_helper int rust_helper_srcu_read_lock(struct srcu_struct *ssp)
+{
+	return srcu_read_lock(ssp);
+}
+
+__rust_helper void rust_helper_srcu_read_unlock(struct srcu_struct *ssp, int idx)
+{
+	srcu_read_unlock(ssp, idx);
+}
+
+__rust_helper void rust_helper_srcu_barrier(struct srcu_struct *ssp)
+{
+	srcu_barrier(ssp);
+}
+
+__rust_helper void rust_helper_synchronize_srcu_expedited(struct srcu_struct *ssp)
+{
+	synchronize_srcu_expedited(ssp);
+}
Signature · 1 line
2.51.2
maintainer
#4 lore raw

Re: [PATCH v5 1/4] rust: helpers: add SRCU helpers

In reply to Paul E. McKenney
Quoted 54 lines · Paul E. McKenney
Quoted 32 lines · Onur Özkan

Add helper wrappers for SRCU functions that are exposed to Rust through generated bindings.

---
 rust/helpers/helpers.c |  1 +
 rust/helpers/srcu.c    | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 rust/helpers/srcu.c
rust/helpers/helpers.c +1 -0
index 625921e27dfb..f3562d3b3888 100644
@@ -88,6 +88,7 @@
 #include "signal.c"
 #include "slab.c"
 #include "spinlock.c"
+#include "srcu.c"
 #include "sync.c"
 #include "task.c"
 #include "time.c"
rust/helpers/srcu.c new file +4 -0
new file mode 100644
index 000000000000..79dd24a104ef
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/srcu.h>
+

rust/helpers/srcu.c line 14

Quoted 10 lines
rust/helpers/srcu.c new file +10 -0
+__rust_helper int rust_helper_init_srcu_struct_with_key(struct srcu_struct *ssp,
+							const char *name,
+							struct lock_class_key *key)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	return __init_srcu_struct(ssp, name, key);
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+	return init_srcu_struct(ssp);
+#endif /* CONFIG_DEBUG_LOCK_ALLOC */
+}

Similar to Boqun's feedback on a later patch, could you please make these be two functions under the corresponding legs of the existing CONFIG_DEBUG_LOCK_ALLOC #ifdef in include/linux/srcu.h? You are including that file above, so it should work well.

Actually, you could just name thefunction __init_srcu_struct(), use the existing definition under #ifdef CONFIG_DEBUG_LOCK_ALLOC, and just create the simple wrapper in the other leg of this #ifdef. That would be more aligned with the Linux-kernel coding guidelines and also be less code.

Quoted 5 lines

Or is the "rust_helper_" prefix mandatory? If so, you could make rust_helper_init_srcu_struct() be a wrapper for __init_srcu_struct() in this file, then just define __init_srcu_struct() as a wrapper around init_srcu_struct() in the !CONFIG_DEBUG_LOCK_ALLOC leg of the #ifdef in include/linux/srcu.h.

The rust_helper_ prefix helps avoid duplicate symbol errors.

When you invoke bindings::foo then it will prefer to call the symbol actually called foo(), but if there is no foo symbol, then it will fall back to rust_helper_foo().

This is useful because many symbols are only marked inline under some configurations, and this makes it automatically pick the right one depending on whether the real symbol exists or not.

Alice

maintainer
#5 lore raw

Re: [PATCH v5 1/4] rust: helpers: add SRCU helpers

Quoted 63 lines · Alice Ryhl
Quoted 54 lines · Paul E. McKenney
Quoted 32 lines · Onur Özkan

Add helper wrappers for SRCU functions that are exposed to Rust through generated bindings.

---
 rust/helpers/helpers.c |  1 +
 rust/helpers/srcu.c    | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 rust/helpers/srcu.c
rust/helpers/helpers.c +1 -0
index 625921e27dfb..f3562d3b3888 100644
@@ -88,6 +88,7 @@
 #include "signal.c"
 #include "slab.c"
 #include "spinlock.c"
+#include "srcu.c"
 #include "sync.c"
 #include "task.c"
 #include "time.c"
rust/helpers/srcu.c new file +4 -0
new file mode 100644
index 000000000000..79dd24a104ef
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/srcu.h>
+

rust/helpers/srcu.c line 14

Quoted 10 lines
rust/helpers/srcu.c new file +10 -0
+__rust_helper int rust_helper_init_srcu_struct_with_key(struct srcu_struct *ssp,
+							const char *name,
+							struct lock_class_key *key)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	return __init_srcu_struct(ssp, name, key);
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+	return init_srcu_struct(ssp);
+#endif /* CONFIG_DEBUG_LOCK_ALLOC */
+}

Similar to Boqun's feedback on a later patch, could you please make these be two functions under the corresponding legs of the existing CONFIG_DEBUG_LOCK_ALLOC #ifdef in include/linux/srcu.h? You are including that file above, so it should work well.

Actually, you could just name thefunction __init_srcu_struct(), use the existing definition under #ifdef CONFIG_DEBUG_LOCK_ALLOC, and just create the simple wrapper in the other leg of this #ifdef. That would be more aligned with the Linux-kernel coding guidelines and also be less code.

Quoted 5 lines

Or is the "rust_helper_" prefix mandatory? If so, you could make rust_helper_init_srcu_struct() be a wrapper for __init_srcu_struct() in this file, then just define __init_srcu_struct() as a wrapper around init_srcu_struct() in the !CONFIG_DEBUG_LOCK_ALLOC leg of the #ifdef in include/linux/srcu.h.

The rust_helper_ prefix helps avoid duplicate symbol errors.

Quoted 7 lines

When you invoke bindings::foo then it will prefer to call the symbol actually called foo(), but if there is no foo symbol, then it will fall back to rust_helper_foo().

This is useful because many symbols are only marked inline under some configurations, and this makes it automatically pick the right one depending on whether the real symbol exists or not.

Thank you both for the Rust-bindings tutorial! ;-)

Thanx, Paul

author maintainer
#6 lore raw

PATCH v5 2/4 srcu: expose srcu_readers_active()

In reply to Onur Özkan

Move srcu_readers_active() from kernel/rcu/srcutree.c into include/linux/srcu.h so it can be reused by Rust SRCU helpers.

Provide a CONFIG_TINY_SRCU implementation in the header as well so the helper is available regardless of the selected SRCU backend.

This is needed by rust/helpers/srcu.c which now adds rust_helper_srcu_readers_active() as a wrapper around the SRCU helper for Rust callers.

---
 include/linux/srcu.h  | 29 +++++++++++++++++++++++++++++
 kernel/rcu/srcutiny.c |  2 +-
 kernel/rcu/srcutree.c | 25 -------------------------
 rust/helpers/srcu.c   |  5 +++++
 4 files changed, 35 insertions(+), 26 deletions(-)
include/linux/srcu.h +29 -0
index 81b1938512d5..5ca35efb4536 100644
@@ -92,6 +92,35 @@ void call_srcu(struct srcu_struct *ssp, struct rcu_head *head,
 void cleanup_srcu_struct(struct srcu_struct *ssp);
 void synchronize_srcu(struct srcu_struct *ssp);
 
+/**
+ * srcu_readers_active - returns true if there are readers, and false otherwise
+ * @ssp: which srcu_struct to count active readers (holding srcu_read_lock).
+ *
+ * Note that this is not an atomic primitive, and can therefore suffer
+ * severe errors when invoked on an active srcu_struct. That said, it can be
+ * useful as an error check at cleanup time.
+ */
+static inline bool srcu_readers_active(struct srcu_struct *ssp)
+{
+#ifdef CONFIG_TINY_SRCU
+	return READ_ONCE(ssp->srcu_lock_nesting[0]) || READ_ONCE(ssp->srcu_lock_nesting[1]);
+#else
+	int cpu;
+	unsigned long sum = 0;
+
+	for_each_possible_cpu(cpu) {
+		struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
+
+		sum += atomic_long_read(&sdp->srcu_ctrs[0].srcu_locks);
+		sum += atomic_long_read(&sdp->srcu_ctrs[1].srcu_locks);
+		sum -= atomic_long_read(&sdp->srcu_ctrs[0].srcu_unlocks);
+		sum -= atomic_long_read(&sdp->srcu_ctrs[1].srcu_unlocks);
+	}
+
+	return sum;
+#endif
+}
+
 #define SRCU_GET_STATE_COMPLETED 0x1
 
 /**
kernel/rcu/srcutiny.c +1 -1
index a2e2d516e51b..5dc26af604bf 100644
@@ -85,7 +85,7 @@ EXPORT_SYMBOL_GPL(init_srcu_struct);
  */
 void cleanup_srcu_struct(struct srcu_struct *ssp)
 {
-	WARN_ON(ssp->srcu_lock_nesting[0] || ssp->srcu_lock_nesting[1]);
+	WARN_ON(srcu_readers_active(ssp));
 	irq_work_sync(&ssp->srcu_irq_work);
 	flush_work(&ssp->srcu_work);
 	WARN_ON(ssp->srcu_gp_running);
kernel/rcu/srcutree.c +0 -25
index 0d01cd8c4b4a..b1e97ba2e53f 100644
@@ -598,31 +598,6 @@ static bool srcu_readers_active_idx_check(struct srcu_struct *ssp, int idx)
 	return srcu_readers_lock_idx(ssp, idx, did_gp, unlocks);
 }
 
-/**
- * srcu_readers_active - returns true if there are readers. and false
- *                       otherwise
- * @ssp: which srcu_struct to count active readers (holding srcu_read_lock).
- *
- * Note that this is not an atomic primitive, and can therefore suffer
- * severe errors when invoked on an active srcu_struct.  That said, it
- * can be useful as an error check at cleanup time.
- */
-static bool srcu_readers_active(struct srcu_struct *ssp)
-{
-	int cpu;
-	unsigned long sum = 0;
-
-	for_each_possible_cpu(cpu) {
-		struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
-
-		sum += atomic_long_read(&sdp->srcu_ctrs[0].srcu_locks);
-		sum += atomic_long_read(&sdp->srcu_ctrs[1].srcu_locks);
-		sum -= atomic_long_read(&sdp->srcu_ctrs[0].srcu_unlocks);
-		sum -= atomic_long_read(&sdp->srcu_ctrs[1].srcu_unlocks);
-	}
-	return sum;
-}
-
 /*
  * We use an adaptive strategy for synchronize_srcu() and especially for
  * synchronize_srcu_expedited().  We spin for a fixed time period
rust/helpers/srcu.c +5 -0
index 79dd24a104ef..fa4b5879dda5 100644
@@ -13,6 +13,11 @@ __rust_helper int rust_helper_init_srcu_struct_with_key(struct srcu_struct *ssp,
 #endif /* CONFIG_DEBUG_LOCK_ALLOC */
 }
 
+__rust_helper bool rust_helper_srcu_readers_active(struct srcu_struct *ssp)
+{
+	return srcu_readers_active(ssp);
+}
+
 __rust_helper int rust_helper_srcu_read_lock(struct srcu_struct *ssp)
 {
 	return srcu_read_lock(ssp);
Signature · 1 line
2.51.2
maintainer
#7 lore raw

Re: [PATCH v5 2/4] srcu: expose srcu_readers_active()

Quoted 27 lines · Onur Özkan

Move srcu_readers_active() from kernel/rcu/srcutree.c into include/linux/srcu.h so it can be reused by Rust SRCU helpers.

Provide a CONFIG_TINY_SRCU implementation in the header as well so the helper is available regardless of the selected SRCU backend.

This is needed by rust/helpers/srcu.c which now adds rust_helper_srcu_readers_active() as a wrapper around the SRCU helper for Rust callers.

---
 include/linux/srcu.h  | 29 +++++++++++++++++++++++++++++
 kernel/rcu/srcutiny.c |  2 +-
 kernel/rcu/srcutree.c | 25 -------------------------
 rust/helpers/srcu.c   |  5 +++++
 4 files changed, 35 insertions(+), 26 deletions(-)
include/linux/srcu.h +1 -0
index 81b1938512d5..5ca35efb4536 100644
@@ -92,6 +92,35 @@ void call_srcu(struct srcu_struct *ssp, struct rcu_head *head,
 void cleanup_srcu_struct(struct srcu_struct *ssp);
 void synchronize_srcu(struct srcu_struct *ssp);
 
+/**

include/linux/srcu.h void call_srcu(struct srcu_struct *ssp, struct rcu_head *head, · line 105

Quoted 10 lines
include/linux/srcu.h +10 -0
+ * srcu_readers_active - returns true if there are readers, and false otherwise
+ * @ssp: which srcu_struct to count active readers (holding srcu_read_lock).
+ *
+ * Note that this is not an atomic primitive, and can therefore suffer
+ * severe errors when invoked on an active srcu_struct. That said, it can be
+ * useful as an error check at cleanup time.
+ */
+static inline bool srcu_readers_active(struct srcu_struct *ssp)
+{
+#ifdef CONFIG_TINY_SRCU

Having a "#ifdef" in a function body is generally considered as bad code (I know we have some of these in rust helpers, but helpers are a bit special and maybe we should clean them up). So could you move this function into include/linux/srcutiny.h and include/linux/srcutree.h?

Thanks!

Regards,
Boqun

Quoted 89 lines
include/linux/srcu.h +18 -0
+	return READ_ONCE(ssp->srcu_lock_nesting[0]) || READ_ONCE(ssp->srcu_lock_nesting[1]);
+#else
+	int cpu;
+	unsigned long sum = 0;
+
+	for_each_possible_cpu(cpu) {
+		struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
+
+		sum += atomic_long_read(&sdp->srcu_ctrs[0].srcu_locks);
+		sum += atomic_long_read(&sdp->srcu_ctrs[1].srcu_locks);
+		sum -= atomic_long_read(&sdp->srcu_ctrs[0].srcu_unlocks);
+		sum -= atomic_long_read(&sdp->srcu_ctrs[1].srcu_unlocks);
+	}
+
+	return sum;
+#endif
+}
+
 #define SRCU_GET_STATE_COMPLETED 0x1
 
 /**
kernel/rcu/srcutiny.c +1 -1
index a2e2d516e51b..5dc26af604bf 100644
@@ -85,7 +85,7 @@ EXPORT_SYMBOL_GPL(init_srcu_struct);
  */
 void cleanup_srcu_struct(struct srcu_struct *ssp)
 {
-	WARN_ON(ssp->srcu_lock_nesting[0] || ssp->srcu_lock_nesting[1]);
+	WARN_ON(srcu_readers_active(ssp));
 	irq_work_sync(&ssp->srcu_irq_work);
 	flush_work(&ssp->srcu_work);
 	WARN_ON(ssp->srcu_gp_running);
kernel/rcu/srcutree.c +0 -25
index 0d01cd8c4b4a..b1e97ba2e53f 100644
@@ -598,31 +598,6 @@ static bool srcu_readers_active_idx_check(struct srcu_struct *ssp, int idx)
 	return srcu_readers_lock_idx(ssp, idx, did_gp, unlocks);
 }
 
-/**
- * srcu_readers_active - returns true if there are readers. and false
- *                       otherwise
- * @ssp: which srcu_struct to count active readers (holding srcu_read_lock).
- *
- * Note that this is not an atomic primitive, and can therefore suffer
- * severe errors when invoked on an active srcu_struct.  That said, it
- * can be useful as an error check at cleanup time.
- */
-static bool srcu_readers_active(struct srcu_struct *ssp)
-{
-	int cpu;
-	unsigned long sum = 0;
-
-	for_each_possible_cpu(cpu) {
-		struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
-
-		sum += atomic_long_read(&sdp->srcu_ctrs[0].srcu_locks);
-		sum += atomic_long_read(&sdp->srcu_ctrs[1].srcu_locks);
-		sum -= atomic_long_read(&sdp->srcu_ctrs[0].srcu_unlocks);
-		sum -= atomic_long_read(&sdp->srcu_ctrs[1].srcu_unlocks);
-	}
-	return sum;
-}
-
 /*
  * We use an adaptive strategy for synchronize_srcu() and especially for
  * synchronize_srcu_expedited().  We spin for a fixed time period
rust/helpers/srcu.c +5 -0
index 79dd24a104ef..fa4b5879dda5 100644
@@ -13,6 +13,11 @@ __rust_helper int rust_helper_init_srcu_struct_with_key(struct srcu_struct *ssp,
 #endif /* CONFIG_DEBUG_LOCK_ALLOC */
 }
 
+__rust_helper bool rust_helper_srcu_readers_active(struct srcu_struct *ssp)
+{
+	return srcu_readers_active(ssp);
+}
+
 __rust_helper int rust_helper_srcu_read_lock(struct srcu_struct *ssp)
 {
 	return srcu_read_lock(ssp);
Signature · 1 line
2.51.2
maintainer
#8 lore raw

Re: [PATCH v5 2/4] srcu: expose srcu_readers_active()

Quoted 27 lines · Boqun Feng
Quoted 26 lines · Onur Özkan

Move srcu_readers_active() from kernel/rcu/srcutree.c into include/linux/srcu.h so it can be reused by Rust SRCU helpers.

Provide a CONFIG_TINY_SRCU implementation in the header as well so the helper is available regardless of the selected SRCU backend.

This is needed by rust/helpers/srcu.c which now adds rust_helper_srcu_readers_active() as a wrapper around the SRCU helper for Rust callers.

---
 include/linux/srcu.h  | 29 +++++++++++++++++++++++++++++
 kernel/rcu/srcutiny.c |  2 +-
 kernel/rcu/srcutree.c | 25 -------------------------
 rust/helpers/srcu.c   |  5 +++++
 4 files changed, 35 insertions(+), 26 deletions(-)
include/linux/srcu.h +0 -0
index 81b1938512d5..5ca35efb4536 100644
@@ -92,6 +92,35 @@ void call_srcu(struct srcu_struct *ssp, struct rcu_head *head,
 void cleanup_srcu_struct(struct srcu_struct *ssp);
 void synchronize_srcu(struct srcu_struct *ssp);
 
Quoted 16 lines

include/linux/srcu.h void call_srcu(struct srcu_struct *ssp, struct rcu_head *head, · line 105

Quoted 11 lines
include/linux/srcu.h +11 -0
+/**
+ * srcu_readers_active - returns true if there are readers, and false otherwise
+ * @ssp: which srcu_struct to count active readers (holding srcu_read_lock).
+ *
+ * Note that this is not an atomic primitive, and can therefore suffer
+ * severe errors when invoked on an active srcu_struct. That said, it can be
+ * useful as an error check at cleanup time.
+ */
+static inline bool srcu_readers_active(struct srcu_struct *ssp)
+{
+#ifdef CONFIG_TINY_SRCU

Having a "#ifdef" in a function body is generally considered as bad code (I know we have some of these in rust helpers, but helpers are a bit special and maybe we should clean them up). So could you move this function into include/linux/srcutiny.h and include/linux/srcutree.h?

What Boqun said, please!

Thanx, Paul

Quoted 94 lines

Thanks!

Regards,
Boqun

Quoted 89 lines
include/linux/srcu.h +18 -0
+	return READ_ONCE(ssp->srcu_lock_nesting[0]) || READ_ONCE(ssp->srcu_lock_nesting[1]);
+#else
+	int cpu;
+	unsigned long sum = 0;
+
+	for_each_possible_cpu(cpu) {
+		struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
+
+		sum += atomic_long_read(&sdp->srcu_ctrs[0].srcu_locks);
+		sum += atomic_long_read(&sdp->srcu_ctrs[1].srcu_locks);
+		sum -= atomic_long_read(&sdp->srcu_ctrs[0].srcu_unlocks);
+		sum -= atomic_long_read(&sdp->srcu_ctrs[1].srcu_unlocks);
+	}
+
+	return sum;
+#endif
+}
+
 #define SRCU_GET_STATE_COMPLETED 0x1
 
 /**
kernel/rcu/srcutiny.c +1 -1
index a2e2d516e51b..5dc26af604bf 100644
@@ -85,7 +85,7 @@ EXPORT_SYMBOL_GPL(init_srcu_struct);
  */
 void cleanup_srcu_struct(struct srcu_struct *ssp)
 {
-	WARN_ON(ssp->srcu_lock_nesting[0] || ssp->srcu_lock_nesting[1]);
+	WARN_ON(srcu_readers_active(ssp));
 	irq_work_sync(&ssp->srcu_irq_work);
 	flush_work(&ssp->srcu_work);
 	WARN_ON(ssp->srcu_gp_running);
kernel/rcu/srcutree.c +0 -25
index 0d01cd8c4b4a..b1e97ba2e53f 100644
@@ -598,31 +598,6 @@ static bool srcu_readers_active_idx_check(struct srcu_struct *ssp, int idx)
 	return srcu_readers_lock_idx(ssp, idx, did_gp, unlocks);
 }
 
-/**
- * srcu_readers_active - returns true if there are readers. and false
- *                       otherwise
- * @ssp: which srcu_struct to count active readers (holding srcu_read_lock).
- *
- * Note that this is not an atomic primitive, and can therefore suffer
- * severe errors when invoked on an active srcu_struct.  That said, it
- * can be useful as an error check at cleanup time.
- */
-static bool srcu_readers_active(struct srcu_struct *ssp)
-{
-	int cpu;
-	unsigned long sum = 0;
-
-	for_each_possible_cpu(cpu) {
-		struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
-
-		sum += atomic_long_read(&sdp->srcu_ctrs[0].srcu_locks);
-		sum += atomic_long_read(&sdp->srcu_ctrs[1].srcu_locks);
-		sum -= atomic_long_read(&sdp->srcu_ctrs[0].srcu_unlocks);
-		sum -= atomic_long_read(&sdp->srcu_ctrs[1].srcu_unlocks);
-	}
-	return sum;
-}
-
 /*
  * We use an adaptive strategy for synchronize_srcu() and especially for
  * synchronize_srcu_expedited().  We spin for a fixed time period
rust/helpers/srcu.c +5 -0
index 79dd24a104ef..fa4b5879dda5 100644
@@ -13,6 +13,11 @@ __rust_helper int rust_helper_init_srcu_struct_with_key(struct srcu_struct *ssp,
 #endif /* CONFIG_DEBUG_LOCK_ALLOC */
 }
 
+__rust_helper bool rust_helper_srcu_readers_active(struct srcu_struct *ssp)
+{
+	return srcu_readers_active(ssp);
+}
+
 __rust_helper int rust_helper_srcu_read_lock(struct srcu_struct *ssp)
 {
 	return srcu_read_lock(ssp);
Signature · 1 line
2.51.2
author maintainer
#9 lore raw

PATCH v5 3/4 rust: sync: add SRCU abstraction

In reply to Onur Özkan

Add a Rust abstraction for sleepable RCU (SRCU), backed by C srcu_struct. Provide FFI helpers and a safe wrapper with a guard-based API for read-side critical sections.

Cleanup is handled via PinnedDrop, which explicitly drains pending grace periods and callbacks via synchronize_srcu and srcu_barrier before executing cleanup_srcu_struct to guarantee memory safety e.g. when there are leaked guards (via mem::forget($guard)).

---
 rust/kernel/sync.rs      |   2 +
 rust/kernel/sync/srcu.rs | 166 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 168 insertions(+)
 create mode 100644 rust/kernel/sync/srcu.rs
rust/kernel/sync.rs +2 -0
index 993dbf2caa0e..0d6a5f1300c3 100644
@@ -21,6 +21,7 @@
 pub mod rcu;
 mod refcount;
 mod set_once;
+pub mod srcu;
 
 pub use arc::{Arc, ArcBorrow, UniqueArc};
 pub use completion::Completion;
@@ -31,6 +32,7 @@
 pub use locked_by::LockedBy;
 pub use refcount::Refcount;
 pub use set_once::SetOnce;
+pub use srcu::Srcu;
 
 /// Represents a lockdep class.
 ///
rust/kernel/sync/srcu.rs new file +166 -0

166 lines not on this page · raw message

Signature · 1 line
2.51.2
author maintainer
#10 lore raw

PATCH v5 4/4 MAINTAINERS: add Rust SRCU files to SRCU entry

In reply to Onur Özkan

Include Rust side implementation files to the SRCU maintainer entry.

---
 MAINTAINERS | 3 +++
 1 file changed, 3 insertions(+)
MAINTAINERS +3 -0
index e0b307b2108c..7739a435f258 100644
@@ -24624,6 +24624,7 @@ SLEEPABLE READ-COPY UPDATE (SRCU)
 M:	Lai Jiangshan <[email protected]>
 M:	"Paul E. McKenney" <[email protected]>
 M:	Josh Triplett <[email protected]>
+M:	Onur Özkan <[email protected]> (RUST)
 R:	Steven Rostedt <[email protected]>
 R:	Mathieu Desnoyers <[email protected]>
 L:	[email protected]
@@ -24632,6 +24633,8 @@ W:	http://www.rdrop.com/users/paulmck/RCU/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/rcu/linux.git rcu/dev
 F:	include/linux/srcu*.h
 F:	kernel/rcu/srcu*.c
+F:	rust/helpers/srcu.c
+F:	rust/kernel/sync/srcu.rs
 
 SMACK SECURITY MODULE
 M:	Casey Schaufler <[email protected]>
Signature · 1 line
2.51.2
maintainer Reviewed-by on v5 4/4
#11 lore raw

Re: [PATCH v5 4/4] MAINTAINERS: add Rust SRCU files to SRCU entry

Quoted 4 lines · Onur Özkan

Include Rust side implementation files to the SRCU maintainer entry.

Quoted 28 lines
---
 MAINTAINERS | 3 +++
 1 file changed, 3 insertions(+)
MAINTAINERS +3 -0
index e0b307b2108c..7739a435f258 100644
@@ -24624,6 +24624,7 @@ SLEEPABLE READ-COPY UPDATE (SRCU)
 M:	Lai Jiangshan <[email protected]>
 M:	"Paul E. McKenney" <[email protected]>
 M:	Josh Triplett <[email protected]>
+M:	Onur Özkan <[email protected]> (RUST)
 R:	Steven Rostedt <[email protected]>
 R:	Mathieu Desnoyers <[email protected]>
 L:	[email protected]
@@ -24632,6 +24633,8 @@ W:	http://www.rdrop.com/users/paulmck/RCU/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/rcu/linux.git rcu/dev
 F:	include/linux/srcu*.h
 F:	kernel/rcu/srcu*.c
+F:	rust/helpers/srcu.c
+F:	rust/kernel/sync/srcu.rs
 
 SMACK SECURITY MODULE
 M:	Casey Schaufler <[email protected]>
Signature · 1 line
2.51.2