Skip to content

Commit 35dc035

Browse files
committed
Merge tag 'rcu.2022.03.13a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu
Pull RCU updates from Paul McKenney: - Fix idle detection (Neeraj Upadhyay) and missing access marking detected by KCSAN. - Reduce coupling between rcu_barrier() and CPU-hotplug operations, so that rcu_barrier() no longer needs to do cpus_read_lock(). This may also someday allow system boot to bring CPUs online concurrently. - Enable more aggressive movement to per-CPU queueing when reacting to excessive lock contention due to workloads placing heavy update-side stress on RCU tasks. - Improvements to RCU priority boosting, including changes from Neeraj Upadhyay, Zqiang, and Alison Chaiken. - Various fixes improving test robustness and debug information. - Add tests for SRCU size transitions, further compress torture.sh build products, and improve debug output. - Miscellaneous fixes. * tag 'rcu.2022.03.13a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: (49 commits) rcu: Replace cpumask_weight with cpumask_empty where appropriate rcu: Remove __read_mostly annotations from rcu_scheduler_active externs rcu: Uninline multi-use function: finish_rcuwait() rcu: Mark writes to the rcu_segcblist structure's ->flags field kasan: Record work creation stack trace with interrupts enabled rcu: Inline __call_rcu() into call_rcu() rcu: Add mutex for rcu boost kthread spawning and affinity setting rcu: Fix description of kvfree_rcu() MAINTAINERS: Add Frederic and Neeraj to their RCU files rcutorture: Provide non-power-of-two Tasks RCU scenarios rcutorture: Test SRCU size transitions torture: Make torture.sh help message match reality rcu-tasks: Set ->percpu_enqueue_shift to zero upon contention rcu-tasks: Use order_base_2() instead of ilog2() rcu: Create and use an rcu_rdp_cpu_online() rcu: Make rcu_barrier() no longer block CPU-hotplug operations rcu: Rework rcu_barrier() and callback-migration logic rcu: Refactor rcu_barrier() empty-list handling rcu: Kill rnp->ofl_seq and use only rcu_state.ofl_lock for exclusion torture: Change KVM environment variable to RCUTORTURE ...
2 parents a04b1bf + d557819 commit 35dc035

31 files changed

+400
-242
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4504,6 +4504,8 @@
45044504
(the least-favored priority). Otherwise, when
45054505
RCU_BOOST is not set, valid values are 0-99 and
45064506
the default is zero (non-realtime operation).
4507+
When RCU_NOCB_CPU is set, also adjust the
4508+
priority of NOCB callback kthreads.
45074509

45084510
rcutree.rcu_nocb_gp_stride= [KNL]
45094511
Set the number of NOCB callback kthreads in

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16324,6 +16324,8 @@ F: tools/testing/selftests/resctrl/
1632416324

1632516325
READ-COPY UPDATE (RCU)
1632616326
M: "Paul E. McKenney" <paulmck@kernel.org>
16327+
M: Frederic Weisbecker <frederic@kernel.org> (kernel/rcu/tree_nocb.h)
16328+
M: Neeraj Upadhyay <quic_neeraju@quicinc.com> (kernel/rcu/tasks.h)
1632716329
M: Josh Triplett <josh@joshtriplett.org>
1632816330
R: Steven Rostedt <rostedt@goodmis.org>
1632916331
R: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>

include/linux/rcupdate.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ static inline int rcu_preempt_depth(void)
8484

8585
/* Internal to kernel */
8686
void rcu_init(void);
87-
extern int rcu_scheduler_active __read_mostly;
87+
extern int rcu_scheduler_active;
8888
void rcu_sched_clock_irq(int user);
8989
void rcu_report_dead(unsigned int cpu);
9090
void rcutree_migrate_callbacks(int cpu);
@@ -924,7 +924,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
924924
*
925925
* kvfree_rcu(ptr);
926926
*
927-
* where @ptr is a pointer to kvfree().
927+
* where @ptr is the pointer to be freed by kvfree().
928928
*
929929
* Please note, head-less way of freeing is permitted to
930930
* use from a context that has to follow might_sleep()

include/linux/rcutree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ static inline void rcu_irq_exit_check_preempt(void) { }
6262
void exit_rcu(void);
6363

6464
void rcu_scheduler_starting(void);
65-
extern int rcu_scheduler_active __read_mostly;
65+
extern int rcu_scheduler_active;
6666
void rcu_end_inkernel_boot(void);
6767
bool rcu_inkernel_boot_has_ended(void);
6868
bool rcu_is_watching(void);

include/linux/rcuwait.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,7 @@ static inline void prepare_to_rcuwait(struct rcuwait *w)
4747
rcu_assign_pointer(w->task, current);
4848
}
4949

50-
static inline void finish_rcuwait(struct rcuwait *w)
51-
{
52-
rcu_assign_pointer(w->task, NULL);
53-
__set_current_state(TASK_RUNNING);
54-
}
50+
extern void finish_rcuwait(struct rcuwait *w);
5551

5652
#define rcuwait_wait_event(w, condition, state) \
5753
({ \

include/trace/events/rcu.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -794,16 +794,15 @@ TRACE_EVENT_RCU(rcu_torture_read,
794794
* Tracepoint for rcu_barrier() execution. The string "s" describes
795795
* the rcu_barrier phase:
796796
* "Begin": rcu_barrier() started.
797+
* "CB": An rcu_barrier_callback() invoked a callback, not the last.
797798
* "EarlyExit": rcu_barrier() piggybacked, thus early exit.
798799
* "Inc1": rcu_barrier() piggyback check counter incremented.
799-
* "OfflineNoCBQ": rcu_barrier() found offline no-CBs CPU with callbacks.
800-
* "OnlineQ": rcu_barrier() found online CPU with callbacks.
801-
* "OnlineNQ": rcu_barrier() found online CPU, no callbacks.
800+
* "Inc2": rcu_barrier() piggyback check counter incremented.
802801
* "IRQ": An rcu_barrier_callback() callback posted on remote CPU.
803802
* "IRQNQ": An rcu_barrier_callback() callback found no callbacks.
804-
* "CB": An rcu_barrier_callback() invoked a callback, not the last.
805803
* "LastCB": An rcu_barrier_callback() invoked the last callback.
806-
* "Inc2": rcu_barrier() piggyback check counter incremented.
804+
* "NQ": rcu_barrier() found a CPU with no callbacks.
805+
* "OnlineQ": rcu_barrier() found online CPU with callbacks.
807806
* The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument
808807
* is the count of remaining callbacks, and "done" is the piggybacking count.
809808
*/

kernel/rcu/rcu_segcblist.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ static inline long rcu_segcblist_n_cbs(struct rcu_segcblist *rsclp)
5656
static inline void rcu_segcblist_set_flags(struct rcu_segcblist *rsclp,
5757
int flags)
5858
{
59-
rsclp->flags |= flags;
59+
WRITE_ONCE(rsclp->flags, rsclp->flags | flags);
6060
}
6161

6262
static inline void rcu_segcblist_clear_flags(struct rcu_segcblist *rsclp,
6363
int flags)
6464
{
65-
rsclp->flags &= ~flags;
65+
WRITE_ONCE(rsclp->flags, rsclp->flags & ~flags);
6666
}
6767

6868
static inline bool rcu_segcblist_test_flags(struct rcu_segcblist *rsclp,

kernel/rcu/rcutorture.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ static atomic_t barrier_cbs_invoked; /* Barrier callbacks invoked. */
284284
static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */
285285
static DECLARE_WAIT_QUEUE_HEAD(barrier_wq);
286286

287-
static bool rcu_fwd_cb_nodelay; /* Short rcu_torture_delay() delays. */
287+
static atomic_t rcu_fwd_cb_nodelay; /* Short rcu_torture_delay() delays. */
288288

289289
/*
290290
* Allocate an element from the rcu_tortures pool.
@@ -387,7 +387,7 @@ rcu_read_delay(struct torture_random_state *rrsp, struct rt_read_seg *rtrsp)
387387
* period, and we want a long delay occasionally to trigger
388388
* force_quiescent_state. */
389389

390-
if (!READ_ONCE(rcu_fwd_cb_nodelay) &&
390+
if (!atomic_read(&rcu_fwd_cb_nodelay) &&
391391
!(torture_random(rrsp) % (nrealreaders * 2000 * longdelay_ms))) {
392392
started = cur_ops->get_gp_seq();
393393
ts = rcu_trace_clock_local();
@@ -674,6 +674,7 @@ static struct rcu_torture_ops srcu_ops = {
674674
.call = srcu_torture_call,
675675
.cb_barrier = srcu_torture_barrier,
676676
.stats = srcu_torture_stats,
677+
.cbflood_max = 50000,
677678
.irq_capable = 1,
678679
.no_pi_lock = IS_ENABLED(CONFIG_TINY_SRCU),
679680
.name = "srcu"
@@ -708,6 +709,7 @@ static struct rcu_torture_ops srcud_ops = {
708709
.call = srcu_torture_call,
709710
.cb_barrier = srcu_torture_barrier,
710711
.stats = srcu_torture_stats,
712+
.cbflood_max = 50000,
711713
.irq_capable = 1,
712714
.no_pi_lock = IS_ENABLED(CONFIG_TINY_SRCU),
713715
.name = "srcud"
@@ -997,7 +999,7 @@ static int rcu_torture_boost(void *arg)
997999
goto checkwait;
9981000

9991001
/* Wait for the next test interval. */
1000-
oldstarttime = boost_starttime;
1002+
oldstarttime = READ_ONCE(boost_starttime);
10011003
while (time_before(jiffies, oldstarttime)) {
10021004
schedule_timeout_interruptible(oldstarttime - jiffies);
10031005
if (stutter_wait("rcu_torture_boost"))
@@ -1041,10 +1043,11 @@ static int rcu_torture_boost(void *arg)
10411043
* interval. Besides, we are running at RT priority,
10421044
* so delays should be relatively rare.
10431045
*/
1044-
while (oldstarttime == boost_starttime && !kthread_should_stop()) {
1046+
while (oldstarttime == READ_ONCE(boost_starttime) && !kthread_should_stop()) {
10451047
if (mutex_trylock(&boost_mutex)) {
10461048
if (oldstarttime == boost_starttime) {
1047-
boost_starttime = jiffies + test_boost_interval * HZ;
1049+
WRITE_ONCE(boost_starttime,
1050+
jiffies + test_boost_interval * HZ);
10481051
n_rcu_torture_boosts++;
10491052
}
10501053
mutex_unlock(&boost_mutex);
@@ -1276,7 +1279,7 @@ rcu_torture_writer(void *arg)
12761279
boot_ended = rcu_inkernel_boot_has_ended();
12771280
stutter_waited = stutter_wait("rcu_torture_writer");
12781281
if (stutter_waited &&
1279-
!READ_ONCE(rcu_fwd_cb_nodelay) &&
1282+
!atomic_read(&rcu_fwd_cb_nodelay) &&
12801283
!cur_ops->slow_gps &&
12811284
!torture_must_stop() &&
12821285
boot_ended)
@@ -2180,7 +2183,6 @@ static void rcu_torture_fwd_cb_hist(struct rcu_fwd *rfp)
21802183
for (i = ARRAY_SIZE(rfp->n_launders_hist) - 1; i > 0; i--)
21812184
if (rfp->n_launders_hist[i].n_launders > 0)
21822185
break;
2183-
mutex_lock(&rcu_fwd_mutex); // Serialize histograms.
21842186
pr_alert("%s: Callback-invocation histogram %d (duration %lu jiffies):",
21852187
__func__, rfp->rcu_fwd_id, jiffies - rfp->rcu_fwd_startat);
21862188
gps_old = rfp->rcu_launder_gp_seq_start;
@@ -2193,7 +2195,6 @@ static void rcu_torture_fwd_cb_hist(struct rcu_fwd *rfp)
21932195
gps_old = gps;
21942196
}
21952197
pr_cont("\n");
2196-
mutex_unlock(&rcu_fwd_mutex);
21972198
}
21982199

21992200
/* Callback function for continuous-flood RCU callbacks. */
@@ -2281,6 +2282,7 @@ static void rcu_torture_fwd_prog_nr(struct rcu_fwd *rfp,
22812282
unsigned long stopat;
22822283
static DEFINE_TORTURE_RANDOM(trs);
22832284

2285+
pr_alert("%s: Starting forward-progress test %d\n", __func__, rfp->rcu_fwd_id);
22842286
if (!cur_ops->sync)
22852287
return; // Cannot do need_resched() forward progress testing without ->sync.
22862288
if (cur_ops->call && cur_ops->cb_barrier) {
@@ -2289,7 +2291,7 @@ static void rcu_torture_fwd_prog_nr(struct rcu_fwd *rfp,
22892291
}
22902292

22912293
/* Tight loop containing cond_resched(). */
2292-
WRITE_ONCE(rcu_fwd_cb_nodelay, true);
2294+
atomic_inc(&rcu_fwd_cb_nodelay);
22932295
cur_ops->sync(); /* Later readers see above write. */
22942296
if (selfpropcb) {
22952297
WRITE_ONCE(fcs.stop, 0);
@@ -2325,6 +2327,7 @@ static void rcu_torture_fwd_prog_nr(struct rcu_fwd *rfp,
23252327
if (selfpropcb) {
23262328
WRITE_ONCE(fcs.stop, 1);
23272329
cur_ops->sync(); /* Wait for running CB to complete. */
2330+
pr_alert("%s: Waiting for CBs: %pS() %d\n", __func__, cur_ops->cb_barrier, rfp->rcu_fwd_id);
23282331
cur_ops->cb_barrier(); /* Wait for queued callbacks. */
23292332
}
23302333

@@ -2333,7 +2336,7 @@ static void rcu_torture_fwd_prog_nr(struct rcu_fwd *rfp,
23332336
destroy_rcu_head_on_stack(&fcs.rh);
23342337
}
23352338
schedule_timeout_uninterruptible(HZ / 10); /* Let kthreads recover. */
2336-
WRITE_ONCE(rcu_fwd_cb_nodelay, false);
2339+
atomic_dec(&rcu_fwd_cb_nodelay);
23372340
}
23382341

23392342
/* Carry out call_rcu() forward-progress testing. */
@@ -2353,13 +2356,14 @@ static void rcu_torture_fwd_prog_cr(struct rcu_fwd *rfp)
23532356
unsigned long stopat;
23542357
unsigned long stoppedat;
23552358

2359+
pr_alert("%s: Starting forward-progress test %d\n", __func__, rfp->rcu_fwd_id);
23562360
if (READ_ONCE(rcu_fwd_emergency_stop))
23572361
return; /* Get out of the way quickly, no GP wait! */
23582362
if (!cur_ops->call)
23592363
return; /* Can't do call_rcu() fwd prog without ->call. */
23602364

23612365
/* Loop continuously posting RCU callbacks. */
2362-
WRITE_ONCE(rcu_fwd_cb_nodelay, true);
2366+
atomic_inc(&rcu_fwd_cb_nodelay);
23632367
cur_ops->sync(); /* Later readers see above write. */
23642368
WRITE_ONCE(rfp->rcu_fwd_startat, jiffies);
23652369
stopat = rfp->rcu_fwd_startat + MAX_FWD_CB_JIFFIES;
@@ -2414,6 +2418,7 @@ static void rcu_torture_fwd_prog_cr(struct rcu_fwd *rfp)
24142418
n_launders_cb_snap = READ_ONCE(rfp->n_launders_cb);
24152419
cver = READ_ONCE(rcu_torture_current_version) - cver;
24162420
gps = rcutorture_seq_diff(cur_ops->get_gp_seq(), gps);
2421+
pr_alert("%s: Waiting for CBs: %pS() %d\n", __func__, cur_ops->cb_barrier, rfp->rcu_fwd_id);
24172422
cur_ops->cb_barrier(); /* Wait for callbacks to be invoked. */
24182423
(void)rcu_torture_fwd_prog_cbfree(rfp);
24192424

@@ -2427,11 +2432,13 @@ static void rcu_torture_fwd_prog_cr(struct rcu_fwd *rfp)
24272432
n_launders, n_launders_sa,
24282433
n_max_gps, n_max_cbs, cver, gps);
24292434
atomic_long_add(n_max_cbs, &rcu_fwd_max_cbs);
2435+
mutex_lock(&rcu_fwd_mutex); // Serialize histograms.
24302436
rcu_torture_fwd_cb_hist(rfp);
2437+
mutex_unlock(&rcu_fwd_mutex);
24312438
}
24322439
schedule_timeout_uninterruptible(HZ); /* Let CBs drain. */
24332440
tick_dep_clear_task(current, TICK_DEP_BIT_RCU);
2434-
WRITE_ONCE(rcu_fwd_cb_nodelay, false);
2441+
atomic_dec(&rcu_fwd_cb_nodelay);
24352442
}
24362443

24372444

@@ -2511,7 +2518,7 @@ static int rcu_torture_fwd_prog(void *args)
25112518
firsttime = false;
25122519
WRITE_ONCE(rcu_fwd_seq, rcu_fwd_seq + 1);
25132520
} else {
2514-
while (READ_ONCE(rcu_fwd_seq) == oldseq)
2521+
while (READ_ONCE(rcu_fwd_seq) == oldseq && !torture_must_stop())
25152522
schedule_timeout_interruptible(1);
25162523
oldseq = READ_ONCE(rcu_fwd_seq);
25172524
}
@@ -2905,8 +2912,10 @@ rcu_torture_cleanup(void)
29052912
int i;
29062913

29072914
if (torture_cleanup_begin()) {
2908-
if (cur_ops->cb_barrier != NULL)
2915+
if (cur_ops->cb_barrier != NULL) {
2916+
pr_info("%s: Invoking %pS().\n", __func__, cur_ops->cb_barrier);
29092917
cur_ops->cb_barrier();
2918+
}
29102919
return;
29112920
}
29122921
if (!cur_ops) {
@@ -2961,8 +2970,10 @@ rcu_torture_cleanup(void)
29612970
* Wait for all RCU callbacks to fire, then do torture-type-specific
29622971
* cleanup operations.
29632972
*/
2964-
if (cur_ops->cb_barrier != NULL)
2973+
if (cur_ops->cb_barrier != NULL) {
2974+
pr_info("%s: Invoking %pS().\n", __func__, cur_ops->cb_barrier);
29652975
cur_ops->cb_barrier();
2976+
}
29662977
if (cur_ops->cleanup != NULL)
29672978
cur_ops->cleanup();
29682979

kernel/rcu/tasks.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ static struct rcu_tasks rt_name = \
123123
.call_func = call, \
124124
.rtpcpu = &rt_name ## __percpu, \
125125
.name = n, \
126-
.percpu_enqueue_shift = ilog2(CONFIG_NR_CPUS) + 1, \
126+
.percpu_enqueue_shift = order_base_2(CONFIG_NR_CPUS), \
127127
.percpu_enqueue_lim = 1, \
128128
.percpu_dequeue_lim = 1, \
129129
.barrier_q_mutex = __MUTEX_INITIALIZER(rt_name.barrier_q_mutex), \
@@ -302,7 +302,7 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
302302
if (unlikely(needadjust)) {
303303
raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
304304
if (rtp->percpu_enqueue_lim != nr_cpu_ids) {
305-
WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids) + 1);
305+
WRITE_ONCE(rtp->percpu_enqueue_shift, 0);
306306
WRITE_ONCE(rtp->percpu_dequeue_lim, nr_cpu_ids);
307307
smp_store_release(&rtp->percpu_enqueue_lim, nr_cpu_ids);
308308
pr_info("Switching %s to per-CPU callback queuing.\n", rtp->name);
@@ -417,7 +417,7 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
417417
if (rcu_task_cb_adjust && ncbs <= rcu_task_collapse_lim) {
418418
raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
419419
if (rtp->percpu_enqueue_lim > 1) {
420-
WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids) + 1);
420+
WRITE_ONCE(rtp->percpu_enqueue_shift, order_base_2(nr_cpu_ids));
421421
smp_store_release(&rtp->percpu_enqueue_lim, 1);
422422
rtp->percpu_dequeue_gpseq = get_state_synchronize_rcu();
423423
pr_info("Starting switch %s to CPU-0 callback queuing.\n", rtp->name);

0 commit comments

Comments
 (0)