On Wed, May 27, 2026 at 12:37:14PM -0700, Boqun Feng wrote:
> On Wed, May 27, 2026 at 08:40:43PM +0300, Onur Özkan wrote:
> > 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.
> >
> > Signed-off-by: Onur Özkan <[email protected]>
> > ---
> > 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(-)
> >
> > diff --git a/include/linux/srcu.h b/include/linux/srcu.h
> > index 81b1938512d5..5ca35efb4536 100644
> > --- a/include/linux/srcu.h
> > +++ b/include/linux/srcu.h
> > @@ -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
>
> 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
> Thanks!
>
> Regards,
> Boqun
>
> > + 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
> >
> > /**
> > diff --git a/kernel/rcu/srcutiny.c b/kernel/rcu/srcutiny.c
> > index a2e2d516e51b..5dc26af604bf 100644
> > --- a/kernel/rcu/srcutiny.c
> > +++ b/kernel/rcu/srcutiny.c
> > @@ -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);
> > diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c
> > index 0d01cd8c4b4a..b1e97ba2e53f 100644
> > --- a/kernel/rcu/srcutree.c
> > +++ b/kernel/rcu/srcutree.c
> > @@ -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
> > diff --git a/rust/helpers/srcu.c b/rust/helpers/srcu.c
> > index 79dd24a104ef..fa4b5879dda5 100644
> > --- a/rust/helpers/srcu.c
> > +++ b/rust/helpers/srcu.c
> > @@ -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);
> > --
> > 2.51.2
> >