diff options
| -rw-r--r-- | Documentation/RCU/Design/Requirements/Requirements.html | 22 | ||||
| -rw-r--r-- | Documentation/RCU/torture.txt | 15 | ||||
| -rw-r--r-- | include/linux/list.h | 7 | ||||
| -rw-r--r-- | include/linux/rcupdate.h | 1 | ||||
| -rw-r--r-- | include/linux/torture.h | 2 | ||||
| -rw-r--r-- | kernel/cpu.c | 1 | ||||
| -rw-r--r-- | kernel/rcu/rcuperf.c | 7 | ||||
| -rw-r--r-- | kernel/rcu/rcutorture.c | 62 | ||||
| -rw-r--r-- | kernel/rcu/tree.c | 44 | ||||
| -rw-r--r-- | kernel/rcu/tree.h | 1 | ||||
| -rw-r--r-- | kernel/rcu/tree_exp.h | 124 | ||||
| -rw-r--r-- | kernel/rcu/tree_plugin.h | 1 | ||||
| -rw-r--r-- | kernel/rcu/tree_trace.c | 7 | ||||
| -rw-r--r-- | kernel/rcu/update.c | 3 | ||||
| -rw-r--r-- | kernel/sched/core.c | 7 | ||||
| -rw-r--r-- | kernel/torture.c | 27 |
16 files changed, 193 insertions, 138 deletions
diff --git a/Documentation/RCU/Design/Requirements/Requirements.html b/Documentation/RCU/Design/Requirements/Requirements.html index ece410f40436..a4d3838130e4 100644 --- a/Documentation/RCU/Design/Requirements/Requirements.html +++ b/Documentation/RCU/Design/Requirements/Requirements.html | |||
| @@ -2493,6 +2493,28 @@ or some future “lazy” | |||
| 2493 | variant of <tt>call_rcu()</tt> that might one day be created for | 2493 | variant of <tt>call_rcu()</tt> that might one day be created for |
| 2494 | energy-efficiency purposes. | 2494 | energy-efficiency purposes. |
| 2495 | 2495 | ||
| 2496 | <p> | ||
| 2497 | That said, there are limits. | ||
| 2498 | RCU requires that the <tt>rcu_head</tt> structure be aligned to a | ||
| 2499 | two-byte boundary, and passing a misaligned <tt>rcu_head</tt> | ||
| 2500 | structure to one of the <tt>call_rcu()</tt> family of functions | ||
| 2501 | will result in a splat. | ||
| 2502 | It is therefore necessary to exercise caution when packing | ||
| 2503 | structures containing fields of type <tt>rcu_head</tt>. | ||
| 2504 | Why not a four-byte or even eight-byte alignment requirement? | ||
| 2505 | Because the m68k architecture provides only two-byte alignment, | ||
| 2506 | and thus acts as alignment's least common denominator. | ||
| 2507 | |||
| 2508 | <p> | ||
| 2509 | The reason for reserving the bottom bit of pointers to | ||
| 2510 | <tt>rcu_head</tt> structures is to leave the door open to | ||
| 2511 | “lazy” callbacks whose invocations can safely be deferred. | ||
| 2512 | Deferring invocation could potentially have energy-efficiency | ||
| 2513 | benefits, but only if the rate of non-lazy callbacks decreases | ||
| 2514 | significantly for some important workload. | ||
| 2515 | In the meantime, reserving the bottom bit keeps this option open | ||
| 2516 | in case it one day becomes useful. | ||
| 2517 | |||
| 2496 | <h3><a name="Performance, Scalability, Response Time, and Reliability"> | 2518 | <h3><a name="Performance, Scalability, Response Time, and Reliability"> |
| 2497 | Performance, Scalability, Response Time, and Reliability</a></h3> | 2519 | Performance, Scalability, Response Time, and Reliability</a></h3> |
| 2498 | 2520 | ||
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index 118e7c176ce7..278f6a9383b6 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt | |||
| @@ -10,21 +10,6 @@ status messages via printk(), which can be examined via the dmesg | |||
| 10 | command (perhaps grepping for "torture"). The test is started | 10 | command (perhaps grepping for "torture"). The test is started |
| 11 | when the module is loaded, and stops when the module is unloaded. | 11 | when the module is loaded, and stops when the module is unloaded. |
| 12 | 12 | ||
| 13 | CONFIG_RCU_TORTURE_TEST_RUNNABLE | ||
| 14 | |||
| 15 | It is also possible to specify CONFIG_RCU_TORTURE_TEST=y, which will | ||
| 16 | result in the tests being loaded into the base kernel. In this case, | ||
| 17 | the CONFIG_RCU_TORTURE_TEST_RUNNABLE config option is used to specify | ||
| 18 | whether the RCU torture tests are to be started immediately during | ||
| 19 | boot or whether the /proc/sys/kernel/rcutorture_runnable file is used | ||
| 20 | to enable them. This /proc file can be used to repeatedly pause and | ||
| 21 | restart the tests, regardless of the initial state specified by the | ||
| 22 | CONFIG_RCU_TORTURE_TEST_RUNNABLE config option. | ||
| 23 | |||
| 24 | You will normally -not- want to start the RCU torture tests during boot | ||
| 25 | (and thus the default is CONFIG_RCU_TORTURE_TEST_RUNNABLE=n), but doing | ||
| 26 | this can sometimes be useful in finding boot-time bugs. | ||
| 27 | |||
| 28 | 13 | ||
| 29 | MODULE PARAMETERS | 14 | MODULE PARAMETERS |
| 30 | 15 | ||
diff --git a/include/linux/list.h b/include/linux/list.h index 5183138aa932..5809e9a2de5b 100644 --- a/include/linux/list.h +++ b/include/linux/list.h | |||
| @@ -381,8 +381,11 @@ static inline void list_splice_tail_init(struct list_head *list, | |||
| 381 | * | 381 | * |
| 382 | * Note that if the list is empty, it returns NULL. | 382 | * Note that if the list is empty, it returns NULL. |
| 383 | */ | 383 | */ |
| 384 | #define list_first_entry_or_null(ptr, type, member) \ | 384 | #define list_first_entry_or_null(ptr, type, member) ({ \ |
| 385 | (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) | 385 | struct list_head *head__ = (ptr); \ |
| 386 | struct list_head *pos__ = READ_ONCE(head__->next); \ | ||
| 387 | pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ | ||
| 388 | }) | ||
| 386 | 389 | ||
| 387 | /** | 390 | /** |
| 388 | * list_next_entry - get the next element in list | 391 | * list_next_entry - get the next element in list |
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 1aa62e1a761b..321f9ed552a9 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
| @@ -334,6 +334,7 @@ void rcu_sched_qs(void); | |||
| 334 | void rcu_bh_qs(void); | 334 | void rcu_bh_qs(void); |
| 335 | void rcu_check_callbacks(int user); | 335 | void rcu_check_callbacks(int user); |
| 336 | void rcu_report_dead(unsigned int cpu); | 336 | void rcu_report_dead(unsigned int cpu); |
| 337 | void rcu_cpu_starting(unsigned int cpu); | ||
| 337 | 338 | ||
| 338 | #ifndef CONFIG_TINY_RCU | 339 | #ifndef CONFIG_TINY_RCU |
| 339 | void rcu_end_inkernel_boot(void); | 340 | void rcu_end_inkernel_boot(void); |
diff --git a/include/linux/torture.h b/include/linux/torture.h index 6685a73736a2..a45702eb3e7b 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h | |||
| @@ -43,7 +43,7 @@ | |||
| 43 | 43 | ||
| 44 | #define TORTURE_FLAG "-torture:" | 44 | #define TORTURE_FLAG "-torture:" |
| 45 | #define TOROUT_STRING(s) \ | 45 | #define TOROUT_STRING(s) \ |
| 46 | pr_alert("%s" TORTURE_FLAG s "\n", torture_type) | 46 | pr_alert("%s" TORTURE_FLAG " %s\n", torture_type, s) |
| 47 | #define VERBOSE_TOROUT_STRING(s) \ | 47 | #define VERBOSE_TOROUT_STRING(s) \ |
| 48 | do { if (verbose) pr_alert("%s" TORTURE_FLAG " %s\n", torture_type, s); } while (0) | 48 | do { if (verbose) pr_alert("%s" TORTURE_FLAG " %s\n", torture_type, s); } while (0) |
| 49 | #define VERBOSE_TOROUT_ERRSTRING(s) \ | 49 | #define VERBOSE_TOROUT_ERRSTRING(s) \ |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 341bf80f80bd..ff8bc3817dde 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
| @@ -889,6 +889,7 @@ void notify_cpu_starting(unsigned int cpu) | |||
| 889 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); | 889 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); |
| 890 | enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); | 890 | enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); |
| 891 | 891 | ||
| 892 | rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */ | ||
| 892 | while (st->state < target) { | 893 | while (st->state < target) { |
| 893 | struct cpuhp_step *step; | 894 | struct cpuhp_step *step; |
| 894 | 895 | ||
diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c index d38ab08a3fe7..123ccbd22449 100644 --- a/kernel/rcu/rcuperf.c +++ b/kernel/rcu/rcuperf.c | |||
| @@ -52,7 +52,7 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.vnet.ibm.com>"); | |||
| 52 | 52 | ||
| 53 | #define PERF_FLAG "-perf:" | 53 | #define PERF_FLAG "-perf:" |
| 54 | #define PERFOUT_STRING(s) \ | 54 | #define PERFOUT_STRING(s) \ |
| 55 | pr_alert("%s" PERF_FLAG s "\n", perf_type) | 55 | pr_alert("%s" PERF_FLAG " %s\n", perf_type, s) |
| 56 | #define VERBOSE_PERFOUT_STRING(s) \ | 56 | #define VERBOSE_PERFOUT_STRING(s) \ |
| 57 | do { if (verbose) pr_alert("%s" PERF_FLAG " %s\n", perf_type, s); } while (0) | 57 | do { if (verbose) pr_alert("%s" PERF_FLAG " %s\n", perf_type, s); } while (0) |
| 58 | #define VERBOSE_PERFOUT_ERRSTRING(s) \ | 58 | #define VERBOSE_PERFOUT_ERRSTRING(s) \ |
| @@ -400,9 +400,8 @@ rcu_perf_writer(void *arg) | |||
| 400 | sp.sched_priority = 0; | 400 | sp.sched_priority = 0; |
| 401 | sched_setscheduler_nocheck(current, | 401 | sched_setscheduler_nocheck(current, |
| 402 | SCHED_NORMAL, &sp); | 402 | SCHED_NORMAL, &sp); |
| 403 | pr_alert("%s" PERF_FLAG | 403 | pr_alert("%s%s rcu_perf_writer %ld has %d measurements\n", |
| 404 | "rcu_perf_writer %ld has %d measurements\n", | 404 | perf_type, PERF_FLAG, me, MIN_MEAS); |
| 405 | perf_type, me, MIN_MEAS); | ||
| 406 | if (atomic_inc_return(&n_rcu_perf_writer_finished) >= | 405 | if (atomic_inc_return(&n_rcu_perf_writer_finished) >= |
| 407 | nrealwriters) { | 406 | nrealwriters) { |
| 408 | schedule_timeout_interruptible(10); | 407 | schedule_timeout_interruptible(10); |
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 971e2b138063..bf08fee53dc7 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c | |||
| @@ -1238,6 +1238,7 @@ rcu_torture_stats_print(void) | |||
| 1238 | long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 }; | 1238 | long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 }; |
| 1239 | long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 }; | 1239 | long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 }; |
| 1240 | static unsigned long rtcv_snap = ULONG_MAX; | 1240 | static unsigned long rtcv_snap = ULONG_MAX; |
| 1241 | struct task_struct *wtp; | ||
| 1241 | 1242 | ||
| 1242 | for_each_possible_cpu(cpu) { | 1243 | for_each_possible_cpu(cpu) { |
| 1243 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) { | 1244 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) { |
| @@ -1258,8 +1259,9 @@ rcu_torture_stats_print(void) | |||
| 1258 | atomic_read(&n_rcu_torture_alloc), | 1259 | atomic_read(&n_rcu_torture_alloc), |
| 1259 | atomic_read(&n_rcu_torture_alloc_fail), | 1260 | atomic_read(&n_rcu_torture_alloc_fail), |
| 1260 | atomic_read(&n_rcu_torture_free)); | 1261 | atomic_read(&n_rcu_torture_free)); |
| 1261 | pr_cont("rtmbe: %d rtbke: %ld rtbre: %ld ", | 1262 | pr_cont("rtmbe: %d rtbe: %ld rtbke: %ld rtbre: %ld ", |
| 1262 | atomic_read(&n_rcu_torture_mberror), | 1263 | atomic_read(&n_rcu_torture_mberror), |
| 1264 | n_rcu_torture_barrier_error, | ||
| 1263 | n_rcu_torture_boost_ktrerror, | 1265 | n_rcu_torture_boost_ktrerror, |
| 1264 | n_rcu_torture_boost_rterror); | 1266 | n_rcu_torture_boost_rterror); |
| 1265 | pr_cont("rtbf: %ld rtb: %ld nt: %ld ", | 1267 | pr_cont("rtbf: %ld rtb: %ld nt: %ld ", |
| @@ -1312,10 +1314,12 @@ rcu_torture_stats_print(void) | |||
| 1312 | 1314 | ||
| 1313 | rcutorture_get_gp_data(cur_ops->ttype, | 1315 | rcutorture_get_gp_data(cur_ops->ttype, |
| 1314 | &flags, &gpnum, &completed); | 1316 | &flags, &gpnum, &completed); |
| 1315 | pr_alert("??? Writer stall state %s(%d) g%lu c%lu f%#x\n", | 1317 | wtp = READ_ONCE(writer_task); |
| 1318 | pr_alert("??? Writer stall state %s(%d) g%lu c%lu f%#x ->state %#lx\n", | ||
| 1316 | rcu_torture_writer_state_getname(), | 1319 | rcu_torture_writer_state_getname(), |
| 1317 | rcu_torture_writer_state, | 1320 | rcu_torture_writer_state, |
| 1318 | gpnum, completed, flags); | 1321 | gpnum, completed, flags, |
