Skip to content

Commit 2848320

Browse files
committed
Merge tag 'rcu.2026.03.31a' of git://git.kernel.org/pub/scm/linux/kernel/git/rcu/linux
Pull RCU updates from Joel Fernandes: "NOCB CPU management: - Consolidate rcu_nocb_cpu_offload() and rcu_nocb_cpu_deoffload() to reduce code duplication - Extract nocb_bypass_needs_flush() helper to reduce duplication in NOCB bypass path rcutorture/torture infrastructure: - Add NOCB01 config for RCU_LAZY torture testing - Add NOCB02 config for NOCB poll mode testing - Add TRIVIAL-PREEMPT config for textbook-style preemptible RCU torture - Test call_srcu() with preemption both disabled and enabled - Remove kvm-check-branches.sh in favor of kvm-series.sh - Make hangs more visible in torture.sh output - Add informative message for tests without a recheck file - Fix numeric test comparison in srcu_lockdep.sh - Use torture_shutdown_init() in refscale and rcuscale instead of open-coded shutdown functions - Fix modulo-zero error in torture_hrtimeout_ns(). SRCU: - Fix SRCU read flavor macro comments - Fix s/they disables/they disable/ typo in srcu_read_unlock_fast() RCU Tasks: - Document that RCU Tasks Trace grace periods now imply RCU grace periods - Remove unnecessary smp_store_release() in cblist_init_generic()" * tag 'rcu.2026.03.31a' of git://git.kernel.org/pub/scm/linux/kernel/git/rcu/linux: rcutorture: Test call_srcu() with preemption disabled and not rcu: Add BOOTPARAM_RCU_STALL_PANIC Kconfig option torture: Avoid modulo-zero error in torture_hrtimeout_ns() rcu/nocb: Extract nocb_bypass_needs_flush() to reduce duplication rcu/nocb: Consolidate rcu_nocb_cpu_offload/deoffload functions rcu-tasks: Remove unnecessary smp_store_release() in cblist_init_generic() rcutorture: Add NOCB02 config for nocb poll mode testing rcutorture: Add NOCB01 config for RCU_LAZY torture testing rcu-tasks: Document that RCU Tasks Trace grace periods now imply RCU grace periods srcu: Fix s/they disables/they disable/ typo in srcu_read_unlock_fast() srcu: Fix SRCU read flavor macro comments rcuscale: Ditch rcu_scale_shutdown in favor of torture_shutdown_init() refscale: Ditch ref_scale_shutdown in favor of torture_shutdown_init() rcutorture: Fix numeric "test" comparison in srcu_lockdep.sh torture: Print informative message for test without recheck file torture: Make hangs more visible in torture.sh output kvm-check-branches.sh: Remove in favor of kvm-series.sh rcutorture: Add a textbook-style trivial preemptible RCU
2 parents 599bbba + 95c7d02 commit 2848320

26 files changed

Lines changed: 301 additions & 267 deletions

File tree

Documentation/RCU/Design/Requirements/Requirements.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2787,6 +2787,13 @@ which avoids the read-side memory barriers, at least for architectures
27872787
that apply noinstr to kernel entry/exit code (or that build with
27882788
``CONFIG_TASKS_TRACE_RCU_NO_MB=y``.
27892789

2790+
Now that the implementation is based on SRCU-fast, a call
2791+
to synchronize_rcu_tasks_trace() implies at least one call to
2792+
synchronize_rcu(), that is, every Tasks Trace RCU grace period contains
2793+
at least one plain vanilla RCU grace period. Should there ever
2794+
be a synchronize_rcu_tasks_trace_expedited(), this guarantee would
2795+
*not* necessarily apply to this hypothetical API member.
2796+
27902797
The tasks-trace-RCU API is also reasonably compact,
27912798
consisting of rcu_read_lock_trace(), rcu_read_unlock_trace(),
27922799
rcu_read_lock_trace_held(), call_rcu_tasks_trace(),

include/linux/rcupdate.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,9 @@ static inline void exit_tasks_rcu_finish(void) { }
208208
/**
209209
* rcu_trace_implies_rcu_gp - does an RCU Tasks Trace grace period imply an RCU grace period?
210210
*
211-
* As an accident of implementation, an RCU Tasks Trace grace period also
212-
* acts as an RCU grace period. However, this could change at any time.
213-
* Code relying on this accident must call this function to verify that
214-
* this accident is still happening.
215-
*
216-
* You have been warned!
211+
* Now that RCU Tasks Trace is implemented in terms of SRCU-fast, a
212+
* call to synchronize_rcu_tasks_trace() is guaranteed to imply at least
213+
* one call to synchronize_rcu().
217214
*/
218215
static inline bool rcu_trace_implies_rcu_gp(void) { return true; }
219216

include/linux/sched.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,10 @@ struct task_struct {
949949
struct srcu_ctr __percpu *trc_reader_scp;
950950
#endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
951951

952+
#ifdef CONFIG_TRIVIAL_PREEMPT_RCU
953+
int rcu_trivial_preempt_nesting;
954+
#endif /* #ifdef CONFIG_TRIVIAL_PREEMPT_RCU */
955+
952956
struct sched_info sched_info;
953957

954958
struct list_head tasks;

include/linux/srcu.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ int init_srcu_struct_fast_updown(struct srcu_struct *ssp);
6969
#define SRCU_READ_FLAVOR_NORMAL 0x1 // srcu_read_lock().
7070
#define SRCU_READ_FLAVOR_NMI 0x2 // srcu_read_lock_nmisafe().
7171
// 0x4 // SRCU-lite is no longer with us.
72-
#define SRCU_READ_FLAVOR_FAST 0x4 // srcu_read_lock_fast().
73-
#define SRCU_READ_FLAVOR_FAST_UPDOWN 0x8 // srcu_read_lock_fast().
72+
#define SRCU_READ_FLAVOR_FAST 0x4 // srcu_read_lock_fast(), also NMI-safe.
73+
#define SRCU_READ_FLAVOR_FAST_UPDOWN 0x8 // srcu_read_lock_fast_updown().
7474
#define SRCU_READ_FLAVOR_ALL (SRCU_READ_FLAVOR_NORMAL | SRCU_READ_FLAVOR_NMI | \
7575
SRCU_READ_FLAVOR_FAST | SRCU_READ_FLAVOR_FAST_UPDOWN)
7676
// All of the above.

include/linux/srcutree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ static inline struct srcu_ctr __percpu *__srcu_ctr_to_ptr(struct srcu_struct *ss
260260
* srcu_read_unlock_fast().
261261
*
262262
* Note that both this_cpu_inc() and atomic_long_inc() are RCU read-side
263-
* critical sections either because they disables interrupts, because
263+
* critical sections either because they disable interrupts, because
264264
* they are a single instruction, or because they are read-modify-write
265265
* atomic operations, depending on the whims of the architecture.
266266
* This matters because the SRCU-fast grace-period mechanism uses either

kernel/rcu/Kconfig.debug

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,15 @@ config RCU_DYNTICKS_TORTURE
228228

229229
This has no value for production and is only for testing.
230230

231+
config TRIVIAL_PREEMPT_RCU
232+
bool "Textbook trivial preemptible RCU in rcutorture"
233+
depends on RCU_EXPERT && RCU_TORTURE_TEST
234+
default n
235+
help
236+
This option enables a textbook preemptible RCU that is
237+
implemented in rcutorture. Its sole purpose is to validate
238+
code used in books, papers, and presentations.
239+
240+
This has no value for production and is only for testing.
241+
231242
endmenu # "RCU Debugging"

kernel/rcu/rcu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,4 +691,8 @@ int rcu_stall_notifier_call_chain(unsigned long val, void *v);
691691
static inline int rcu_stall_notifier_call_chain(unsigned long val, void *v) { return NOTIFY_DONE; }
692692
#endif // #else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
693693

694+
#ifdef CONFIG_TRIVIAL_PREEMPT_RCU
695+
void synchronize_rcu_trivial_preempt(void);
696+
#endif // #ifdef CONFIG_TRIVIAL_PREEMPT_RCU
697+
694698
#endif /* __LINUX_RCU_H */

kernel/rcu/rcuscale.c

Lines changed: 21 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,15 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com>");
7979
* test-end checks, and the pair of calls through pointers.
8080
*/
8181

82-
#ifdef MODULE
83-
# define RCUSCALE_SHUTDOWN 0
84-
#else
85-
# define RCUSCALE_SHUTDOWN 1
86-
#endif
87-
8882
torture_param(bool, gp_async, false, "Use asynchronous GP wait primitives");
8983
torture_param(int, gp_async_max, 1000, "Max # outstanding waits per writer");
9084
torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
9185
torture_param(int, holdoff, 10, "Holdoff time before test start (s)");
9286
torture_param(int, minruntime, 0, "Minimum run time (s)");
9387
torture_param(int, nreaders, -1, "Number of RCU reader threads");
9488
torture_param(int, nwriters, -1, "Number of RCU updater threads");
95-
torture_param(bool, shutdown, RCUSCALE_SHUTDOWN,
96-
"Shutdown at end of scalability tests.");
89+
torture_param(int, shutdown_secs, !IS_MODULE(CONFIG_RCU_SCALE_TEST) * 300,
90+
"Shutdown at end of scalability tests or at specified timeout (s).");
9791
torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
9892
torture_param(int, writer_holdoff, 0, "Holdoff (us) between GPs, zero to disable");
9993
torture_param(int, writer_holdoff_jiffies, 0, "Holdoff (jiffies) between GPs, zero to disable");
@@ -123,7 +117,6 @@ static int nrealreaders;
123117
static int nrealwriters;
124118
static struct task_struct **writer_tasks;
125119
static struct task_struct **reader_tasks;
126-
static struct task_struct *shutdown_task;
127120

128121
static u64 **writer_durations;
129122
static bool *writer_done;
@@ -132,7 +125,6 @@ static int *writer_n_durations;
132125
static atomic_t n_rcu_scale_reader_started;
133126
static atomic_t n_rcu_scale_writer_started;
134127
static atomic_t n_rcu_scale_writer_finished;
135-
static wait_queue_head_t shutdown_wq;
136128
static u64 t_rcu_scale_writer_started;
137129
static u64 t_rcu_scale_writer_finished;
138130
static unsigned long b_rcu_gp_test_started;
@@ -519,6 +511,8 @@ static void rcu_scale_async_cb(struct rcu_head *rhp)
519511
rcu_scale_free(wmbp);
520512
}
521513

514+
static void rcu_scale_cleanup(void);
515+
522516
/*
523517
* RCU scale writer kthread. Repeatedly does a grace period.
524518
*/
@@ -622,9 +616,11 @@ rcu_scale_writer(void *arg)
622616
b_rcu_gp_test_finished =
623617
cur_ops->get_gp_seq();
624618
}
625-
if (shutdown) {
619+
if (shutdown_secs) {
620+
writer_tasks[me] = NULL;
626621
smp_mb(); /* Assign before wake. */
627-
wake_up(&shutdown_wq);
622+
rcu_scale_cleanup();
623+
kernel_power_off();
628624
}
629625
}
630626
}
@@ -668,8 +664,8 @@ static void
668664
rcu_scale_print_module_parms(struct rcu_scale_ops *cur_ops, const char *tag)
669665
{
670666
pr_alert("%s" SCALE_FLAG
671-
"--- %s: gp_async=%d gp_async_max=%d gp_exp=%d holdoff=%d minruntime=%d nreaders=%d nwriters=%d writer_holdoff=%d writer_holdoff_jiffies=%d verbose=%d shutdown=%d\n",
672-
scale_type, tag, gp_async, gp_async_max, gp_exp, holdoff, minruntime, nrealreaders, nrealwriters, writer_holdoff, writer_holdoff_jiffies, verbose, shutdown);
667+
"--- %s: gp_async=%d gp_async_max=%d gp_exp=%d holdoff=%d minruntime=%d nreaders=%d nwriters=%d writer_holdoff=%d writer_holdoff_jiffies=%d verbose=%d shutdown_secs=%d\n",
668+
scale_type, tag, gp_async, gp_async_max, gp_exp, holdoff, minruntime, nrealreaders, nrealwriters, writer_holdoff, writer_holdoff_jiffies, verbose, shutdown_secs);
673669
}
674670

675671
/*
@@ -722,6 +718,8 @@ static void kfree_call_rcu(struct rcu_head *rh)
722718
kfree(obj);
723719
}
724720

721+
static void kfree_scale_cleanup(void);
722+
725723
static int
726724
kfree_scale_thread(void *arg)
727725
{
@@ -791,9 +789,11 @@ kfree_scale_thread(void *arg)
791789
rcuscale_seq_diff(b_rcu_gp_test_finished, b_rcu_gp_test_started),
792790
PAGES_TO_MB(mem_begin - mem_during));
793791

794-
if (shutdown) {
792+
if (shutdown_secs) {
793+
kfree_reader_tasks[me] = NULL;
795794
smp_mb(); /* Assign before wake. */
796-
wake_up(&shutdown_wq);
795+
kfree_scale_cleanup();
796+
kernel_power_off();
797797
}
798798
}
799799

@@ -820,22 +820,6 @@ kfree_scale_cleanup(void)
820820
torture_cleanup_end();
821821
}
822822

823-
/*
824-
* shutdown kthread. Just waits to be awakened, then shuts down system.
825-
*/
826-
static int
827-
kfree_scale_shutdown(void *arg)
828-
{
829-
wait_event_idle(shutdown_wq,
830-
atomic_read(&n_kfree_scale_thread_ended) >= kfree_nrealthreads);
831-
832-
smp_mb(); /* Wake before output. */
833-
834-
kfree_scale_cleanup();
835-
kernel_power_off();
836-
return -EINVAL;
837-
}
838-
839823
// Used if doing RCU-kfree'ing via call_rcu().
840824
static unsigned long jiffies_at_lazy_cb;
841825
static struct rcu_head lazy_test1_rh;
@@ -895,13 +879,10 @@ kfree_scale_init(void)
895879

896880
kfree_nrealthreads = compute_real(kfree_nthreads);
897881
/* Start up the kthreads. */
898-
if (shutdown) {
899-
init_waitqueue_head(&shutdown_wq);
900-
firsterr = torture_create_kthread(kfree_scale_shutdown, NULL,
901-
shutdown_task);
882+
if (shutdown_secs) {
883+
firsterr = torture_shutdown_init(shutdown_secs, kfree_scale_cleanup);
902884
if (torture_init_error(firsterr))
903885
goto unwind;
904-
schedule_timeout_uninterruptible(1);
905886
}
906887

907888
pr_alert("kfree object size=%zu, kfree_by_call_rcu=%d\n",
@@ -1058,20 +1039,6 @@ rcu_scale_cleanup(void)
10581039
torture_cleanup_end();
10591040
}
10601041

1061-
/*
1062-
* RCU scalability shutdown kthread. Just waits to be awakened, then shuts
1063-
* down system.
1064-
*/
1065-
static int
1066-
rcu_scale_shutdown(void *arg)
1067-
{
1068-
wait_event_idle(shutdown_wq, atomic_read(&n_rcu_scale_writer_finished) >= nrealwriters);
1069-
smp_mb(); /* Wake before output. */
1070-
rcu_scale_cleanup();
1071-
kernel_power_off();
1072-
return -EINVAL;
1073-
}
1074-
10751042
static int __init
10761043
rcu_scale_init(void)
10771044
{
@@ -1121,13 +1088,10 @@ rcu_scale_init(void)
11211088

11221089
/* Start up the kthreads. */
11231090

1124-
if (shutdown) {
1125-
init_waitqueue_head(&shutdown_wq);
1126-
firsterr = torture_create_kthread(rcu_scale_shutdown, NULL,
1127-
shutdown_task);
1091+
if (shutdown_secs) {
1092+
firsterr = torture_shutdown_init(shutdown_secs, rcu_scale_cleanup);
11281093
if (torture_init_error(firsterr))
11291094
goto unwind;
1130-
schedule_timeout_uninterruptible(1);
11311095
}
11321096
reader_tasks = kzalloc_objs(reader_tasks[0], nrealreaders);
11331097
if (reader_tasks == NULL) {
@@ -1201,7 +1165,7 @@ rcu_scale_init(void)
12011165
unwind:
12021166
torture_init_end();
12031167
rcu_scale_cleanup();
1204-
if (shutdown) {
1168+
if (shutdown_secs) {
12051169
WARN_ON(!IS_MODULE(CONFIG_RCU_SCALE_TEST));
12061170
kernel_power_off();
12071171
}

kernel/rcu/rcutorture.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,14 @@ static unsigned long srcu_torture_completed(void)
842842

843843
static void srcu_torture_deferred_free(struct rcu_torture *rp)
844844
{
845+
unsigned long flags;
846+
bool lockit = jiffies & 0x1;
847+
848+
if (lockit)
849+
raw_spin_lock_irqsave(&current->pi_lock, flags);
845850
call_srcu(srcu_ctlp, &rp->rtort_rcu, rcu_torture_cb);
851+
if (lockit)
852+
raw_spin_unlock_irqrestore(&current->pi_lock, flags);
846853
}
847854

848855
static void srcu_torture_synchronize(void)
@@ -1061,6 +1068,61 @@ static struct rcu_torture_ops trivial_ops = {
10611068
.name = "trivial"
10621069
};
10631070

1071+
#ifdef CONFIG_TRIVIAL_PREEMPT_RCU
1072+
1073+
/*
1074+
* Definitions for trivial CONFIG_PREEMPT=y torture testing. This
1075+
* implementation does not work well with large numbers of tasks or with
1076+
* long-term preemption. Either or both get you RCU CPU stall warnings.
1077+
*/
1078+
1079+
static void rcu_sync_torture_init_trivial_preempt(void)
1080+
{
1081+
rcu_sync_torture_init();
1082+
if (WARN_ONCE(onoff_interval || shuffle_interval, "%s: Non-zero onoff_interval (%d) or shuffle_interval (%d) breaks trivial RCU, resetting to zero", __func__, onoff_interval, shuffle_interval)) {
1083+
onoff_interval = 0;
1084+
shuffle_interval = 0;
1085+
}
1086+
}
1087+
1088+
static int rcu_torture_read_lock_trivial_preempt(void)
1089+
{
1090+
struct task_struct *t = current;
1091+
1092+
WRITE_ONCE(t->rcu_trivial_preempt_nesting, t->rcu_trivial_preempt_nesting + 1);
1093+
smp_mb();
1094+
return 0;
1095+
}
1096+
1097+
static void rcu_torture_read_unlock_trivial_preempt(int idx)
1098+
{
1099+
struct task_struct *t = current;
1100+
1101+
smp_store_release(&t->rcu_trivial_preempt_nesting, t->rcu_trivial_preempt_nesting - 1);
1102+
}
1103+
1104+
static struct rcu_torture_ops trivial_preempt_ops = {
1105+
.ttype = RCU_TRIVIAL_FLAVOR,
1106+
.init = rcu_sync_torture_init_trivial_preempt,
1107+
.readlock = rcu_torture_read_lock_trivial_preempt,
1108+
.read_delay = rcu_read_delay, // just reuse rcu's version.
1109+
.readunlock = rcu_torture_read_unlock_trivial_preempt,
1110+
.readlock_held = torture_readlock_not_held,
1111+
.get_gp_seq = rcu_no_completed,
1112+
.sync = synchronize_rcu_trivial_preempt,
1113+
.exp_sync = synchronize_rcu_trivial_preempt,
1114+
.irq_capable = 0, // In theory it should be, but let's keep it trivial.
1115+
.name = "trivial-preempt"
1116+
};
1117+
1118+
#define TRIVIAL_PREEMPT_OPS &trivial_preempt_ops,
1119+
1120+
#else // #ifdef CONFIG_TRIVIAL_PREEMPT_RCU
1121+
1122+
#define TRIVIAL_PREEMPT_OPS
1123+
1124+
#endif // #else // #ifdef CONFIG_TRIVIAL_PREEMPT_RCU
1125+
10641126
#ifdef CONFIG_TASKS_RCU
10651127

10661128
/*
@@ -4449,7 +4511,7 @@ rcu_torture_init(void)
44494511
static struct rcu_torture_ops *torture_ops[] = {
44504512
&rcu_ops, &rcu_busted_ops, &srcu_ops, &srcud_ops, &busted_srcud_ops,
44514513
TASKS_OPS TASKS_RUDE_OPS TASKS_TRACING_OPS
4452-
&trivial_ops,
4514+
&trivial_ops, TRIVIAL_PREEMPT_OPS
44534515
};
44544516

44554517
if (!torture_init_begin(torture_type, verbose))

0 commit comments

Comments
 (0)