Skip to content

Commit 9407f5c

Browse files
paulmckrcuFrederic Weisbecker
authored andcommitted
srcu: Unconditionally record srcu_read_lock_lite() in ->srcu_reader_flavor
Currently, srcu_read_lock_lite() uses the SRCU_READ_FLAVOR_LITE bit in ->srcu_reader_flavor to communicate to the grace-period processing in srcu_readers_active_idx_check() that the smp_mb() must be replaced by a synchronize_rcu(). Unfortunately, ->srcu_reader_flavor is not updated unless the kernel is built with CONFIG_PROVE_RCU=y. Therefore in all kernels built with CONFIG_PROVE_RCU=n, srcu_readers_active_idx_check() incorrectly uses smp_mb() instead of synchronize_rcu() for srcu_struct structures whose readers use srcu_read_lock_lite(). This commit therefore causes Tree SRCU srcu_read_lock_lite() to unconditionally update ->srcu_reader_flavor so that srcu_readers_active_idx_check() can make the correct choice. Reported-by: Neeraj Upadhyay <[email protected]> Closes: https://lore.kernel.org/all/[email protected]/ Fixes: c0f08d6 ("srcu: Add srcu_read_lock_lite() and srcu_read_unlock_lite()") Signed-off-by: Paul E. McKenney <[email protected]> Cc: Frederic Weisbecker <[email protected]> Reviewed-by: Neeraj Upadhyay <[email protected]> Signed-off-by: Frederic Weisbecker <[email protected]>
1 parent f8ce622 commit 9407f5c

File tree

4 files changed

+27
-11
lines changed

4 files changed

+27
-11
lines changed

include/linux/srcu.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,6 @@ static inline int srcu_read_lock_held(const struct srcu_struct *ssp)
183183

184184
#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
185185

186-
#if defined(CONFIG_PROVE_RCU) && defined(CONFIG_TREE_SRCU)
187-
void srcu_check_read_flavor(struct srcu_struct *ssp, int read_flavor);
188-
#else
189-
#define srcu_check_read_flavor(ssp, read_flavor) do { } while (0)
190-
#endif
191-
192186

193187
/**
194188
* srcu_dereference_check - fetch SRCU-protected pointer for later dereferencing
@@ -277,7 +271,7 @@ static inline int srcu_read_lock_lite(struct srcu_struct *ssp) __acquires(ssp)
277271
{
278272
int retval;
279273

280-
srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_LITE);
274+
srcu_check_read_flavor_lite(ssp);
281275
retval = __srcu_read_lock_lite(ssp);
282276
rcu_try_lock_acquire(&ssp->dep_map);
283277
return retval;

include/linux/srcutiny.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ static inline void srcu_barrier(struct srcu_struct *ssp)
8181
synchronize_srcu(ssp);
8282
}
8383

84+
#define srcu_check_read_flavor(ssp, read_flavor) do { } while (0)
85+
#define srcu_check_read_flavor_lite(ssp) do { } while (0)
86+
8487
/* Defined here to avoid size increase for non-torture kernels. */
8588
static inline void srcu_torture_stats_print(struct srcu_struct *ssp,
8689
char *tt, char *tf)

include/linux/srcutree.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,4 +248,25 @@ static inline void __srcu_read_unlock_lite(struct srcu_struct *ssp, int idx)
248248
RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_read_unlock_lite().");
249249
}
250250

251+
void __srcu_check_read_flavor(struct srcu_struct *ssp, int read_flavor);
252+
253+
// Record _lite() usage even for CONFIG_PROVE_RCU=n kernels.
254+
static inline void srcu_check_read_flavor_lite(struct srcu_struct *ssp)
255+
{
256+
struct srcu_data *sdp = raw_cpu_ptr(ssp->sda);
257+
258+
if (likely(READ_ONCE(sdp->srcu_reader_flavor) & SRCU_READ_FLAVOR_LITE))
259+
return;
260+
261+
// Note that the cmpxchg() in srcu_check_read_flavor() is fully ordered.
262+
__srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_LITE);
263+
}
264+
265+
// Record non-_lite() usage only for CONFIG_PROVE_RCU=y kernels.
266+
static inline void srcu_check_read_flavor(struct srcu_struct *ssp, int read_flavor)
267+
{
268+
if (IS_ENABLED(CONFIG_PROVE_RCU))
269+
__srcu_check_read_flavor(ssp, read_flavor);
270+
}
271+
251272
#endif

kernel/rcu/srcutree.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -712,11 +712,10 @@ void cleanup_srcu_struct(struct srcu_struct *ssp)
712712
}
713713
EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
714714

715-
#ifdef CONFIG_PROVE_RCU
716715
/*
717716
* Check for consistent reader flavor.
718717
*/
719-
void srcu_check_read_flavor(struct srcu_struct *ssp, int read_flavor)
718+
void __srcu_check_read_flavor(struct srcu_struct *ssp, int read_flavor)
720719
{
721720
int old_read_flavor;
722721
struct srcu_data *sdp;
@@ -734,8 +733,7 @@ void srcu_check_read_flavor(struct srcu_struct *ssp, int read_flavor)
734733
}
735734
WARN_ONCE(old_read_flavor != read_flavor, "CPU %d old state %d new state %d\n", sdp->cpu, old_read_flavor, read_flavor);
736735
}
737-
EXPORT_SYMBOL_GPL(srcu_check_read_flavor);
738-
#endif /* CONFIG_PROVE_RCU */
736+
EXPORT_SYMBOL_GPL(__srcu_check_read_flavor);
739737

740738
/*
741739
* Counts the new reader in the appropriate per-CPU element of the

0 commit comments

Comments
 (0)