Commit d6dd50e0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull RCU updates from Ingo Molnar:
 "The main changes in this cycle were:

   - changes related to No-CBs CPUs and NO_HZ_FULL

   - RCU-tasks implementation

   - torture-test updates

   - miscellaneous fixes

   - locktorture updates

   - RCU documentation updates"

* 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (81 commits)
  workqueue: Use cond_resched_rcu_qs macro
  workqueue: Add quiescent state between work items
  locktorture: Cleanup header usage
  locktorture: Cannot hold read and write lock
  locktorture: Fix __acquire annotation for spinlock irq
  locktorture: Support rwlocks
  rcu: Eliminate deadlock between CPU hotplug and expedited grace periods
  locktorture: Document boot/module parameters
  rcutorture: Rename rcutorture_runnable parameter
  locktorture: Add test scenario for rwsem_lock
  locktorture: Add test scenario for mutex_lock
  locktorture: Make torture scripting account for new _runnable name
  locktorture: Introduce torture context
  locktorture: Support rwsems
  locktorture: Add infrastructure for torturing read locks
  torture: Address race in module cleanup
  locktorture: Make statistics generic
  locktorture: Teach about lock debugging
  locktorture: Support mutexes
  locktorture: Add documentation
  ...
parents 5ff0b9e1 fd19bda4
...@@ -56,8 +56,20 @@ RCU_STALL_RAT_DELAY ...@@ -56,8 +56,20 @@ RCU_STALL_RAT_DELAY
two jiffies. (This is a cpp macro, not a kernel configuration two jiffies. (This is a cpp macro, not a kernel configuration
parameter.) parameter.)
When a CPU detects that it is stalling, it will print a message similar rcupdate.rcu_task_stall_timeout
to the following:
This boot/sysfs parameter controls the RCU-tasks stall warning
interval. A value of zero or less suppresses RCU-tasks stall
warnings. A positive value sets the stall-warning interval
in jiffies. An RCU-tasks stall warning starts wtih the line:
INFO: rcu_tasks detected stalls on tasks:
And continues with the output of sched_show_task() for each
task stalling the current RCU-tasks grace period.
For non-RCU-tasks flavors of RCU, when a CPU detects that it is stalling,
it will print a message similar to the following:
INFO: rcu_sched_state detected stall on CPU 5 (t=2500 jiffies) INFO: rcu_sched_state detected stall on CPU 5 (t=2500 jiffies)
...@@ -174,8 +186,12 @@ o A CPU looping with preemption disabled. This condition can ...@@ -174,8 +186,12 @@ o A CPU looping with preemption disabled. This condition can
o A CPU looping with bottom halves disabled. This condition can o A CPU looping with bottom halves disabled. This condition can
result in RCU-sched and RCU-bh stalls. result in RCU-sched and RCU-bh stalls.
o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the kernel o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the
without invoking schedule(). kernel without invoking schedule(). Note that cond_resched()
does not necessarily prevent RCU CPU stall warnings. Therefore,
if the looping in the kernel is really expected and desirable
behavior, you might need to replace some of the cond_resched()
calls with calls to cond_resched_rcu_qs().
o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might
happen to preempt a low-priority task in the middle of an RCU happen to preempt a low-priority task in the middle of an RCU
...@@ -208,11 +224,10 @@ o A hardware failure. This is quite unlikely, but has occurred ...@@ -208,11 +224,10 @@ o A hardware failure. This is quite unlikely, but has occurred
This resulted in a series of RCU CPU stall warnings, eventually This resulted in a series of RCU CPU stall warnings, eventually
leading the realization that the CPU had failed. leading the realization that the CPU had failed.
The RCU, RCU-sched, and RCU-bh implementations have CPU stall warning. The RCU, RCU-sched, RCU-bh, and RCU-tasks implementations have CPU stall
SRCU does not have its own CPU stall warnings, but its calls to warning. Note that SRCU does -not- have CPU stall warnings. Please note
synchronize_sched() will result in RCU-sched detecting RCU-sched-related that RCU only detects CPU stalls when there is a grace period in progress.
CPU stalls. Please note that RCU only detects CPU stalls when there is No grace period, no CPU stall warnings.
a grace period in progress. No grace period, no CPU stall warnings.
To diagnose the cause of the stall, inspect the stack traces. To diagnose the cause of the stall, inspect the stack traces.
The offending function will usually be near the top of the stack. The offending function will usually be near the top of the stack.
......
...@@ -1723,6 +1723,49 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -1723,6 +1723,49 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
lockd.nlm_udpport=M [NFS] Assign UDP port. lockd.nlm_udpport=M [NFS] Assign UDP port.
Format: <integer> Format: <integer>
locktorture.nreaders_stress= [KNL]
Set the number of locking read-acquisition kthreads.
Defaults to being automatically set based on the
number of online CPUs.
locktorture.nwriters_stress= [KNL]
Set the number of locking write-acquisition kthreads.
locktorture.onoff_holdoff= [KNL]
Set time (s) after boot for CPU-hotplug testing.
locktorture.onoff_interval= [KNL]
Set time (s) between CPU-hotplug operations, or
zero to disable CPU-hotplug testing.
locktorture.shuffle_interval= [KNL]
Set task-shuffle interval (jiffies). Shuffling
tasks allows some CPUs to go into dyntick-idle
mode during the locktorture test.
locktorture.shutdown_secs= [KNL]
Set time (s) after boot system shutdown. This
is useful for hands-off automated testing.
locktorture.stat_interval= [KNL]
Time (s) between statistics printk()s.
locktorture.stutter= [KNL]
Time (s) to stutter testing, for example,
specifying five seconds causes the test to run for
five seconds, wait for five seconds, and so on.
This tests the locking primitive's ability to
transition abruptly to and from idle.
locktorture.torture_runnable= [BOOT]
Start locktorture running at boot time.
locktorture.torture_type= [KNL]
Specify the locking implementation to test.
locktorture.verbose= [KNL]
Enable additional printk() statements.
logibm.irq= [HW,MOUSE] Logitech Bus Mouse Driver logibm.irq= [HW,MOUSE] Logitech Bus Mouse Driver
Format: <irq> Format: <irq>
...@@ -2900,6 +2943,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -2900,6 +2943,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Lazy RCU callbacks are those which RCU can Lazy RCU callbacks are those which RCU can
prove do nothing more than free memory. prove do nothing more than free memory.
rcutorture.cbflood_inter_holdoff= [KNL]
Set holdoff time (jiffies) between successive
callback-flood tests.
rcutorture.cbflood_intra_holdoff= [KNL]
Set holdoff time (jiffies) between successive
bursts of callbacks within a given callback-flood
test.
rcutorture.cbflood_n_burst= [KNL]
Set the number of bursts making up a given
callback-flood test. Set this to zero to
disable callback-flood testing.
rcutorture.cbflood_n_per_burst= [KNL]
Set the number of callbacks to be registered
in a given burst of a callback-flood test.
rcutorture.fqs_duration= [KNL] rcutorture.fqs_duration= [KNL]
Set duration of force_quiescent_state bursts. Set duration of force_quiescent_state bursts.
...@@ -2939,7 +3000,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -2939,7 +3000,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Set time (s) between CPU-hotplug operations, or Set time (s) between CPU-hotplug operations, or
zero to disable CPU-hotplug testing. zero to disable CPU-hotplug testing.
rcutorture.rcutorture_runnable= [BOOT] rcutorture.torture_runnable= [BOOT]
Start rcutorture running at boot time. Start rcutorture running at boot time.
rcutorture.shuffle_interval= [KNL] rcutorture.shuffle_interval= [KNL]
...@@ -3001,6 +3062,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -3001,6 +3062,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
rcupdate.rcu_cpu_stall_timeout= [KNL] rcupdate.rcu_cpu_stall_timeout= [KNL]
Set timeout for RCU CPU stall warning messages. Set timeout for RCU CPU stall warning messages.
rcupdate.rcu_task_stall_timeout= [KNL]
Set timeout in jiffies for RCU task stall warning
messages. Disable with a value less than or equal
to zero.
rdinit= [KNL] rdinit= [KNL]
Format: <full_path> Format: <full_path>
Run specified binary instead of /init from the ramdisk, Run specified binary instead of /init from the ramdisk,
......
Kernel Lock Torture Test Operation
CONFIG_LOCK_TORTURE_TEST
The CONFIG LOCK_TORTURE_TEST config option provides a kernel module
that runs torture tests on core kernel locking primitives. The kernel
module, 'locktorture', may be built after the fact on the running
kernel to be tested, if desired. The tests periodically output status
messages via printk(), which can be examined via the dmesg (perhaps
grepping for "torture"). The test is started when the module is loaded,
and stops when the module is unloaded. This program is based on how RCU
is tortured, via rcutorture.
This torture test consists of creating a number of kernel threads which
acquire the lock and hold it for specific amount of time, thus simulating
different critical region behaviors. The amount of contention on the lock
can be simulated by either enlarging this critical region hold time and/or
creating more kthreads.
MODULE PARAMETERS
This module has the following parameters:
** Locktorture-specific **
nwriters_stress Number of kernel threads that will stress exclusive lock
ownership (writers). The default value is twice the number
of online CPUs.
nreaders_stress Number of kernel threads that will stress shared lock
ownership (readers). The default is the same amount of writer
locks. If the user did not specify nwriters_stress, then
both readers and writers be the amount of online CPUs.
torture_type Type of lock to torture. By default, only spinlocks will
be tortured. This module can torture the following locks,
with string values as follows:
o "lock_busted": Simulates a buggy lock implementation.
o "spin_lock": spin_lock() and spin_unlock() pairs.
o "spin_lock_irq": spin_lock_irq() and spin_unlock_irq()
pairs.
o "rw_lock": read/write lock() and unlock() rwlock pairs.
o "rw_lock_irq": read/write lock_irq() and unlock_irq()
rwlock pairs.
o "mutex_lock": mutex_lock() and mutex_unlock() pairs.
o "rwsem_lock": read/write down() and up() semaphore pairs.
torture_runnable Start locktorture at boot time in the case where the
module is built into the kernel, otherwise wait for
torture_runnable to be set via sysfs before starting.
By default it will begin once the module is loaded.
** Torture-framework (RCU + locking) **
shutdown_secs The number of seconds to run the test before terminating
the test and powering off the system. The default is
zero, which disables test termination and system shutdown.
This capability is useful for automated testing.
onoff_interval The number of seconds between each attempt to execute a
randomly selected CPU-hotplug operation. Defaults
to zero, which disables CPU hotplugging. In
CONFIG_HOTPLUG_CPU=n kernels, locktorture will silently
refuse to do any CPU-hotplug operations regardless of
what value is specified for onoff_interval.
onoff_holdoff The number of seconds to wait until starting CPU-hotplug
operations. This would normally only be used when
locktorture was built into the kernel and started
automatically at boot time, in which case it is useful
in order to avoid confusing boot-time code with CPUs
coming and going. This parameter is only useful if
CONFIG_HOTPLUG_CPU is enabled.
stat_interval Number of seconds between statistics-related printk()s.
By default, locktorture will report stats every 60 seconds.
Setting the interval to zero causes the statistics to
be printed -only- when the module is unloaded, and this
is the default.
stutter The length of time to run the test before pausing for this
same period of time. Defaults to "stutter=5", so as
to run and pause for (roughly) five-second intervals.
Specifying "stutter=0" causes the test to run continuously
without pausing, which is the old default behavior.
shuffle_interval The number of seconds to keep the test threads affinitied
to a particular subset of the CPUs, defaults to 3 seconds.
Used in conjunction with test_no_idle_hz.
verbose Enable verbose debugging printing, via printk(). Enabled
by default. This extra information is mostly related to
high-level errors and reports from the main 'torture'
framework.
STATISTICS
Statistics are printed in the following format:
spin_lock-torture: Writes: Total: 93746064 Max/Min: 0/0 Fail: 0
(A) (B) (C) (D) (E)
(A): Lock type that is being tortured -- torture_type parameter.
(B): Number of writer lock acquisitions. If dealing with a read/write primitive
a second "Reads" statistics line is printed.
(C): Number of times the lock was acquired.
(D): Min and max number of times threads failed to acquire the lock.
(E): true/false values if there were errors acquiring the lock. This should
-only- be positive if there is a bug in the locking primitive's
implementation. Otherwise a lock should never fail (i.e., spin_lock()).
Of course, the same applies for (C), above. A dummy example of this is
the "lock_busted" type.
USAGE
The following script may be used to torture locks:
#!/bin/sh
modprobe locktorture
sleep 3600
rmmod locktorture
dmesg | grep torture:
The output can be manually inspected for the error flag of "!!!".
One could of course create a more elaborate script that automatically
checked for such errors. The "rmmod" command forces a "SUCCESS",
"FAILURE", or "RCU_HOTPLUG" indication to be printk()ed. The first
two are self-explanatory, while the last indicates that while there
were no locking failures, CPU-hotplug problems were detected.
Also see: Documentation/RCU/torture.txt
...@@ -574,30 +574,14 @@ However, stores are not speculated. This means that ordering -is- provided ...@@ -574,30 +574,14 @@ However, stores are not speculated. This means that ordering -is- provided
in the following example: in the following example:
q = ACCESS_ONCE(a); q = ACCESS_ONCE(a);
if (ACCESS_ONCE(q)) {
ACCESS_ONCE(b) = p;
}
Please note that ACCESS_ONCE() is not optional! Without the ACCESS_ONCE(),
the compiler is within its rights to transform this example:
q = a;
if (q) { if (q) {
b = p; /* BUG: Compiler can reorder!!! */ ACCESS_ONCE(b) = p;
do_something();
} else {
b = p; /* BUG: Compiler can reorder!!! */
do_something_else();
} }
into this, which of course defeats the ordering: Please note that ACCESS_ONCE() is not optional! Without the
ACCESS_ONCE(), might combine the load from 'a' with other loads from
b = p; 'a', and the store to 'b' with other stores to 'b', with possible highly
q = a; counterintuitive effects on ordering.
if (q)
do_something();
else
do_something_else();
Worse yet, if the compiler is able to prove (say) that the value of Worse yet, if the compiler is able to prove (say) that the value of
variable 'a' is always non-zero, it would be well within its rights variable 'a' is always non-zero, it would be well within its rights
...@@ -605,11 +589,12 @@ to optimize the original example by eliminating the "if" statement ...@@ -605,11 +589,12 @@ to optimize the original example by eliminating the "if" statement
as follows: as follows:
q = a; q = a;
b = p; /* BUG: Compiler can reorder!!! */ b = p; /* BUG: Compiler and CPU can both reorder!!! */
do_something();
The solution is again ACCESS_ONCE() and barrier(), which preserves the So don't leave out the ACCESS_ONCE().
ordering between the load from variable 'a' and the store to variable 'b':
It is tempting to try to enforce ordering on identical stores on both
branches of the "if" statement as follows:
q = ACCESS_ONCE(a); q = ACCESS_ONCE(a);
if (q) { if (q) {
...@@ -622,18 +607,11 @@ ordering between the load from variable 'a' and the store to variable 'b': ...@@ -622,18 +607,11 @@ ordering between the load from variable 'a' and the store to variable 'b':
do_something_else(); do_something_else();
} }
The initial ACCESS_ONCE() is required to prevent the compiler from Unfortunately, current compilers will transform this as follows at high
proving the value of 'a', and the pair of barrier() invocations are optimization levels:
required to prevent the compiler from pulling the two identical stores
to 'b' out from the legs of the "if" statement.
It is important to note that control dependencies absolutely require a
a conditional. For example, the following "optimized" version of
the above example breaks ordering, which is why the barrier() invocations
are absolutely required if you have identical stores in both legs of
the "if" statement:
q = ACCESS_ONCE(a); q = ACCESS_ONCE(a);
barrier();
ACCESS_ONCE(b) = p; /* BUG: No ordering vs. load from a!!! */ ACCESS_ONCE(b) = p; /* BUG: No ordering vs. load from a!!! */
if (q) { if (q) {
/* ACCESS_ONCE(b) = p; -- moved up, BUG!!! */ /* ACCESS_ONCE(b) = p; -- moved up, BUG!!! */
...@@ -643,21 +621,36 @@ the "if" statement: ...@@ -643,21 +621,36 @@ the "if" statement:
do_something_else(); do_something_else();
} }
It is of course legal for the prior load to be part of the conditional, Now there is no conditional between the load from 'a' and the store to
for example, as follows: 'b', which means that the CPU is within its rights to reorder them:
The conditional is absolutely required, and must be present in the
assembly code even after all compiler optimizations have been applied.
Therefore, if you need ordering in this example, you need explicit
memory barriers, for example, smp_store_release():
if (ACCESS_ONCE(a) > 0) { q = ACCESS_ONCE(a);
barrier(); if (q) {
ACCESS_ONCE(b) = q / 2; smp_store_release(&b, p);
do_something(); do_something();
} else { } else {
barrier(); smp_store_release(&b, p);
ACCESS_ONCE(b) = q / 3;
do_something_else(); do_something_else();
} }
This will again ensure that the load from variable 'a' is ordered before the In contrast, without explicit memory barriers, two-legged-if control
stores to variable 'b'. ordering is guaranteed only when the stores differ, for example:
q = ACCESS_ONCE(a);
if (q) {
ACCESS_ONCE(b) = p;
do_something();
} else {
ACCESS_ONCE(b) = r;
do_something_else();
}
The initial ACCESS_ONCE() is still required to prevent the compiler from
proving the value of 'a'.
In addition, you need to be careful what you do with the local variable 'q', In addition, you need to be careful what you do with the local variable 'q',
otherwise the compiler might be able to guess the value and again remove otherwise the compiler might be able to guess the value and again remove
...@@ -665,12 +658,10 @@ the needed conditional. For example: ...@@ -665,12 +658,10 @@ the needed conditional. For example:
q = ACCESS_ONCE(a); q = ACCESS_ONCE(a);
if (q % MAX) { if (q % MAX) {
barrier();
ACCESS_ONCE(b) = p; ACCESS_ONCE(b) = p;
do_something(); do_something();
} else { } else {
barrier(); ACCESS_ONCE(b) = r;
ACCESS_ONCE(b) = p;
do_something_else(); do_something_else();
} }
...@@ -682,9 +673,12 @@ transform the above code into the following: ...@@ -682,9 +673,12 @@ transform the above code into the following:
ACCESS_ONCE(b) = p; ACCESS_ONCE(b) = p;
do_something_else(); do_something_else();
This transformation loses the ordering between the load from variable 'a' Given this transformation, the CPU is not required to respect the ordering
and the store to variable 'b'. If you are relying on this ordering, you between the load from variable 'a' and the store to variable 'b'. It is
should do something like the following: tempting to add a barrier(), but this does not help. The conditional
is gone, and the barrier won't bring it back. Therefore, if you are
relying on this ordering, you should make sure that MAX is greater than
one, perhaps as follows:
q = ACCESS_ONCE(a); q = ACCESS_ONCE(a);
BUILD_BUG_ON(MAX <= 1); /* Order load from a with store to b. */ BUILD_BUG_ON(MAX <= 1); /* Order load from a with store to b. */
...@@ -692,35 +686,45 @@ should do something like the following: ...@@ -692,35 +686,45 @@ should do something like the following:
ACCESS_ONCE(b) = p; ACCESS_ONCE(b) = p;
do_something(); do_something();
} else { } else {
ACCESS_ONCE(b) = p; ACCESS_ONCE(b) = r;
do_something_else(); do_something_else();
} }
Please note once again that the stores to 'b' differ. If they were
identical, as noted earlier, the compiler could pull this store outside
of the 'if' statement.
Finally, control dependencies do -not- provide transitivity. This is Finally, control dependencies do -not- provide transitivity. This is
demonstrated by two related examples: demonstrated by two related examples, with the initial values of
x and y both being zero:
CPU 0 CPU 1 CPU 0 CPU 1
===================== ===================== ===================== =====================
r1 = ACCESS_ONCE(x); r2 = ACCESS_ONCE(y); r1 = ACCESS_ONCE(x); r2 = ACCESS_ONCE(y);
if (r1 >= 0) if (r2 >= 0) if (r1 > 0) if (r2 > 0)
ACCESS_ONCE(y) = 1; ACCESS_ONCE(x) = 1; ACCESS_ONCE(y) = 1; ACCESS_ONCE(x) = 1;
assert(!(r1 == 1 && r2 == 1)); assert(!(r1 == 1 && r2 == 1));
The above two-CPU example will never trigger the assert(). However, The above two-CPU example will never trigger the assert(). However,
if control dependencies guaranteed transitivity (which they do not), if control dependencies guaranteed transitivity (which they do not),
then adding the following two CPUs would guarantee a related assertion: then adding the following CPU would guarantee a related assertion:
CPU 2 CPU 3 CPU 2
===================== ===================== =====================
ACCESS_ONCE(x) = 2; ACCESS_ONCE(y) = 2; ACCESS_ONCE(x) = 2;
assert(!(r1 == 2 && r2 == 1 && x == 2)); /* FAILS!!! */
assert(!(r1 == 2 && r2 == 2 && x == 1 && y == 1)); /* FAILS!!! */ But because control dependencies do -not- provide transitivity, the above
assertion can fail after the combined three-CPU example completes. If you
need the three-CPU example to provide ordering, you will need smp_mb()
between the loads and stores in the CPU 0 and CPU 1 code fragments,
that is, just before or just after the "if" statements.
But because control dependencies do -not- provide transitivity, the These two examples are the LB and WWC litmus tests from this paper:
above assertion can fail after the combined four-CPU example completes. http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf and this
If you need the four-CPU example to provide ordering, you will need site: https://www.cl.cam.ac.uk/~pes20/ppcmem/index.html.
smp_mb() between the loads and stores in the CPU 0 and CPU 1 code fragments.
In summary: In summary:
......
...@@ -367,7 +367,7 @@ static struct fdtable *close_files(struct files_struct * files) ...@@ -367,7 +367,7 @@ static struct fdtable *close_files(struct files_struct * files)
struct file * file = xchg(&fdt->fd[i], NULL); struct file * file = xchg(&fdt->fd[i], NULL);
if (file) { if (file) {
filp_close(file, files); filp_close(file, files);
cond_resched(); cond_resched_rcu_qs();
} }
} }
i++; i++;
......
...@@ -213,6 +213,7 @@ extern struct bus_type cpu_subsys; ...@@ -213,6 +213,7 @@ extern struct bus_type cpu_subsys;
extern void cpu_hotplug_begin(void); extern void cpu_hotplug_begin(void);
extern void cpu_hotplug_done(void); extern void cpu_hotplug_done(void);
extern void get_online_cpus(void); extern void get_online_cpus(void);
extern bool try_get_online_cpus(void);
extern void put_online_cpus(void); extern void put_online_cpus(void);
extern void cpu_hotplug_disable(void); extern void cpu_hotplug_disable(void);
extern void cpu_hotplug_enable(void); extern void cpu_hotplug_enable(void);
...@@ -230,6 +231,7 @@ int cpu_down(unsigned int cpu); ...@@ -230,6 +231,7 @@ int cpu_down(unsigned int cpu);
static inline void cpu_hotplug_begin(void) {} static inline void cpu_hotplug_begin(void) {}
static inline void cpu_hotplug_done(void) {} static inline void cpu_hotplug_done(void) {}
#define get_online_cpus() do { } while (0) #define get_online_cpus() do { } while (0)
#define try_get_online_cpus() true
#define put_online_cpus() do { } while (0) #define put_online_cpus() do { } while (0)
#define cpu_hotplug_disable() do { } while (0) #define cpu_hotplug_disable() do { } while (0)
#define cpu_hotplug_enable() do { } while (0) #define cpu_hotplug_enable() do { } while (0)
......
...@@ -111,12 +111,21 @@ extern struct group_info init_groups; ...@@ -111,12 +111,21 @@ extern struct group_info init_groups;
#ifdef CONFIG_PREEMPT_RCU #ifdef CONFIG_PREEMPT_RCU
#define INIT_TASK_RCU_PREEMPT(tsk) \ #define INIT_TASK_RCU_PREEMPT(tsk) \
.rcu_read_lock_nesting = 0, \ .rcu_read_lock_nesting = 0, \
.rcu_read_unlock_special = 0, \ .rcu_read_unlock_special.s = 0, \
.rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), \ .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), \
INIT_TASK_RCU_TREE_PREEMPT() INIT_TASK_RCU_TREE_PREEMPT()
#else #else
#define INIT_TASK_RCU_PREEMPT(tsk) #define INIT_TASK_RCU_PREEMPT(tsk)
#endif #endif
#ifdef CONFIG_TASKS_RCU
#define INIT_TASK_RCU_TASKS(tsk) \
.rcu_tasks_holdout = false, \
.rcu_tasks_holdout_list = \
LIST_HEAD_INIT(tsk.rcu_tasks_holdout_list), \
.rcu_tasks_idle_cpu = -1,
#else
#define INIT_TASK_RCU_TASKS(tsk)
#endif
extern struct cred init_cred; extern struct cred init_cred;
...@@ -224,6 +233,7 @@ extern struct task_group root_task_group; ...@@ -224,6 +233,7 @@ extern struct task_group root_task_group;
INIT_FTRACE_GRAPH \ INIT_FTRACE_GRAPH \
INIT_TRACE_RECURSION \ INIT_TRACE_RECURSION \
INIT_TASK_RCU_PREEMPT(tsk) \ INIT_TASK_RCU_PREEMPT(tsk) \
INIT_TASK_RCU_TASKS(tsk) \
INIT_CPUSET_SEQ(tsk) \ INIT_CPUSET_SEQ(tsk) \
INIT_RT_MUTEXES(tsk) \ INIT_RT_MUTEXES(tsk) \
INIT_VTIME(tsk) \ INIT_VTIME(tsk) \
......
...@@ -510,6 +510,7 @@ static inline void print_irqtrace_events(struct task_struct *curr) ...@@ -510,6 +510,7 @@ static inline void print_irqtrace_events(struct task_struct *curr)
#define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_) #define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_)
#define lock_map_acquire_read(l) lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_) #define lock_map_acquire_read(l) lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_)
#define lock_map_acquire_tryread(l) lock_acquire_shared_recursive(l, 0, 1, NULL, _THIS_IP_)
#define lock_map_release(l) lock_release(l, 1, _THIS_IP_) #define lock_map_release(l) lock_release(l, 1, _THIS_IP_)
#ifdef CONFIG_PROVE_LOCKING #ifdef CONFIG_PROVE_LOCKING
......
...@@ -47,14 +47,12 @@ ...@@ -47,14 +47,12 @@
#include <asm/barrier.h> #include <asm/barrier.h>
extern int rcu_expedited; /* for sysctl */ extern int rcu_expedited; /* for sysctl */
#ifdef CONFIG_RCU_TORTURE_TEST
extern int rcutorture_runnable; /* for sysctl */
#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
enum rcutorture_type { enum rcutorture_type {
RCU_FLAVOR, RCU_FLAVOR,
RCU_BH_FLAVOR, RCU_BH_FLAVOR,
RCU_SCHED_FLAVOR, RCU_SCHED_FLAVOR,
RCU_TASKS_FLAVOR,
SRCU_FLAVOR, SRCU_FLAVOR,
INVALID_RCU_FLAVOR INVALID_RCU_FLAVOR
}; };
...@@ -197,6 +195,28 @@ void call_rcu_sched(struct rcu_head *head, ...@@ -197,6 +195,28 @@ void call_rcu_sched(struct rcu_head *head,
void synchronize_sched(void); void synchronize_sched(void);
/**
* call_rcu_tasks() - Queue an RCU for invocation task-based grace period
* @head: structure to be used for queueing the RCU updates.
* @func: actual callback function to be invoked after the grace period
*
* The callback function will be invoked some time after a full grace
* period elapses, in other words after all currently executing RCU
* read-side critical sections have completed. call_rcu_tasks() assumes
* that the read-side critical sections end at a voluntary context
* switch (not a preemption!), entry into idle, or transition to usermode
* execution. As such, there are no read-side primitives analogous to
* rcu_read_lock() and rcu_read_unlock() because this primitive is intended
* to determine that all tasks have passed through a safe state, not so
* much for data-strcuture synchronization.
*
* See the description of call_rcu() for more detailed information on
* memory ordering guarantees.
*/
void call_rcu_tasks(struct rcu_head *head, void (*func)(struct rcu_head *head));
void synchronize_rcu_tasks(void);
void rcu_barrier_tasks(void);
#ifdef CONFIG_PREEMPT_RCU #ifdef CONFIG_PREEMPT_RCU
void __rcu_read_lock(void); void __rcu_read_lock(void);
...@@ -238,8 +258,8 @@ static inline int rcu_preempt_depth(void) ...@@ -238,8 +258,8 @@ static inline int rcu_preempt_depth(void)
/* Internal to kernel */ /* Internal to kernel */
void rcu_init(void); void rcu_init(void);
void rcu_sched_qs(int cpu); void rcu_sched_qs(void);
void rcu_bh_qs(int cpu); void rcu_bh_qs(void);
void rcu_check_callbacks(int cpu, int user); void rcu_check_callbacks(int cpu, int user);
struct notifier_block; struct notifier_block;
void rcu_idle_enter(void); void rcu_idle_enter(void);
...@@ -269,6 +289,14 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev, ...@@ -269,6 +289,14 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev,
struct task_struct *next) { } struct task_struct *next) { }
#endif /* CONFIG_RCU_USER_QS */ #endif /* CONFIG_RCU_USER_QS */
#ifdef CONFIG_RCU_NOCB_CPU
void rcu_init_nohz(void);
#else /* #ifdef CONFIG_RCU_NOCB_CPU */
static inline void rcu_init_nohz(void)
{
}
#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
/** /**
* RCU_NONIDLE - Indicate idle-loop code that needs RCU readers * RCU_NONIDLE - Indicate idle-loop code that needs RCU readers
* @a: Code that RCU needs to pay attention to. * @a: Code that RCU needs to pay attention to.
...@@ -294,6 +322,36 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev, ...@@ -294,6 +322,36 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev,
rcu_irq_exit(); \ rcu_irq_exit(); \
} while (0) } while (0)
/*
* Note a voluntary context switch for RCU-tasks benefit. This is a
* macro rather than an inline function to avoid #include hell.
*/
#ifdef CONFIG_TASKS_RCU
#define TASKS_RCU(x) x
extern struct srcu_struct tasks_rcu_exit_srcu;
#define rcu_note_voluntary_context_switch(t) \
do { \
if (ACCESS_ONCE((t)->rcu_tasks_holdout)) \
ACCESS_ONCE((t)->rcu_tasks_holdout) = false; \
} while (0)
#else /* #ifdef CONFIG_TASKS_RCU */
#define TASKS_RCU(x) do { } while (0)
#define rcu_note_voluntary_context_switch(t) do { } while (0)
#endif /* #else #ifdef CONFIG_TASKS_RCU */
/**
* cond_resched_rcu_qs - Report potential quiescent states to RCU
*
* This macro resembles cond_resched(), except that it is defined to
* report potential quiescent states to RCU-tasks even if the cond_resched()
* machinery were to be shut off, as some advocate for PREEMPT kernels.
*/
#define cond_resched_rcu_qs() \
do { \
rcu_note_voluntary_context_switch(current); \
cond_resched(); \
} while (0)
#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP)
bool __rcu_is_watching(void); bool __rcu_is_watching(void);
#endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) */ #endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) */
...@@ -349,7 +407,7 @@ bool rcu_lockdep_current_cpu_online(void); ...@@ -349,7 +407,7 @@ bool rcu_lockdep_current_cpu_online(void);
#else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */ #else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
static inline bool rcu_lockdep_current_cpu_online(void) static inline bool rcu_lockdep_current_cpu_online(void)
{ {
return 1; return true;
} }
#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */ #endif /* #else #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
...@@ -371,41 +429,7 @@ extern struct lockdep_map rcu_sched_lock_map; ...@@ -371,41 +429,7 @@ extern struct lockdep_map rcu_sched_lock_map;
extern struct lockdep_map rcu_callback_map; extern struct lockdep_map rcu_callback_map;
int debug_lockdep_rcu_enabled(void); int debug_lockdep_rcu_enabled(void);
/** int rcu_read_lock_held(void);
* rcu_read_lock_held() - might we be in RCU read-side critical section?
*
* If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an RCU
* read-side critical section. In absence of CONFIG_DEBUG_LOCK_ALLOC,
* this assumes we are in an RCU read-side critical section unless it can
* prove otherwise. This is useful for debug checks in functions that
* require that they be called within an RCU read-side critical section.
*
* Checks debug_lockdep_rcu_enabled() to prevent false positives during boot
* and while lockdep is disabled.
*
* Note that rcu_read_lock() and the matching rcu_read_unlock() must
* occur in the same context, for example, it is illegal to invoke
* rcu_read_unlock() in process context if the matching rcu_read_lock()
* was invoked from within an irq handler.
*
* Note that rcu_read_lock() is disallowed if the CPU is either idle or
* offline from an RCU perspective, so check for those as well.
*/
static inline int rcu_read_lock_held(void)
{
if (!debug_lockdep_rcu_enabled())
return 1;
if (!rcu_is_watching())
return 0;
if (!rcu_lockdep_current_cpu_online())
return 0;
return lock_is_held(&rcu_lock_map);
}
/*
* rcu_read_lock_bh_held() is defined out of line to avoid #include-file
* hell.
*/
int rcu_read_lock_bh_held(void); int rcu_read_lock_bh_held(void);
/** /**
......
...@@ -80,7 +80,7 @@ static inline void kfree_call_rcu(struct rcu_head *head, ...@@ -80,7 +80,7 @@ static inline void kfree_call_rcu(struct rcu_head *head,
static inline void rcu_note_context_switch(int cpu) static inline void rcu_note_context_switch(int cpu)
{ {
rcu_sched_qs(cpu); rcu_sched_qs();
} }
/* /*
......
...@@ -1213,6 +1213,13 @@ struct sched_dl_entity { ...@@ -1213,6 +1213,13 @@ struct sched_dl_entity {
struct hrtimer dl_timer; struct hrtimer dl_timer;
}; };
union rcu_special {
struct {
bool blocked;
bool need_qs;
} b;
short s;
};
struct rcu_node; struct rcu_node;
enum perf_event_task_context { enum perf_event_task_context {
...@@ -1265,12 +1272,18 @@ struct task_struct { ...@@ -1265,12 +1272,18 @@ struct task_struct {
#ifdef CONFIG_PREEMPT_RCU #ifdef CONFIG_PREEMPT_RCU
int rcu_read_lock_nesting; int rcu_read_lock_nesting;
char rcu_read_unlock_special; union rcu_special rcu_read_unlock_special;
struct list_head rcu_node_entry; struct list_head rcu_node_entry;
#endif /* #ifdef CONFIG_PREEMPT_RCU */ #endif /* #ifdef CONFIG_PREEMPT_RCU */
#ifdef CONFIG_TREE_PREEMPT_RCU #ifdef CONFIG_TREE_PREEMPT_RCU
struct rcu_node *rcu_blocked_node; struct rcu_node *rcu_blocked_node;
#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
#ifdef CONFIG_TASKS_RCU
unsigned long rcu_tasks_nvcsw;
bool rcu_tasks_holdout;
struct list_head rcu_tasks_holdout_list;
int rcu_tasks_idle_cpu;
#endif /* #ifdef CONFIG_TASKS_RCU */
#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
struct sched_info sched_info; struct sched_info sched_info;
...@@ -2014,29 +2027,21 @@ extern void task_clear_jobctl_trapping(struct task_struct *task); ...@@ -2014,29 +2027,21 @@ extern void task_clear_jobctl_trapping(struct task_struct *task);
extern void task_clear_jobctl_pending(struct task_struct *task, extern void task_clear_jobctl_pending(struct task_struct *task,
unsigned int mask); unsigned int mask);
#ifdef CONFIG_PREEMPT_RCU
#define RCU_READ_UNLOCK_BLOCKED (1 << 0) /* blocked while in RCU read-side. */
#define RCU_READ_UNLOCK_NEED_QS (1 << 1) /* RCU core needs CPU response. */
static inline void rcu_copy_process(struct task_struct *p) static inline void rcu_copy_process(struct task_struct *p)
{ {
#ifdef CONFIG_PREEMPT_RCU
p->rcu_read_lock_nesting = 0; p->rcu_read_lock_nesting = 0;
p->rcu_read_unlock_special = 0; p->rcu_read_unlock_special.s = 0;
#ifdef CONFIG_TREE_PREEMPT_RCU
p->rcu_blocked_node = NULL; p->rcu_blocked_node = NULL;
#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
INIT_LIST_HEAD(&p->rcu_node_entry); INIT_LIST_HEAD(&p->rcu_node_entry);
#endif /* #ifdef CONFIG_PREEMPT_RCU */
#ifdef CONFIG_TASKS_RCU
p->rcu_tasks_holdout = false;
INIT_LIST_HEAD(&p->rcu_tasks_holdout_list);
p->rcu_tasks_idle_cpu = -1;
#endif /* #ifdef CONFIG_TASKS_RCU */
} }
#else
static inline void rcu_copy_process(struct task_struct *p)
{
}
#endif
static inline void tsk_restore_flags(struct task_struct *task, static inline void tsk_restore_flags(struct task_struct *task,
unsigned long orig_flags, unsigned long flags) unsigned long orig_flags, unsigned long flags)
{ {
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
/* Definitions for online/offline exerciser. */ /* Definitions for online/offline exerciser. */
int torture_onoff_init(long ooholdoff, long oointerval); int torture_onoff_init(long ooholdoff, long oointerval);
char *torture_onoff_stats(char *page); void torture_onoff_stats(void);
bool torture_onoff_failures(void); bool torture_onoff_failures(void);
/* Low-rider random number generator. */ /* Low-rider random number generator. */
...@@ -77,7 +77,8 @@ int torture_stutter_init(int s); ...@@ -77,7 +77,8 @@ int torture_stutter_init(int s);
/* Initialization and cleanup. */ /* Initialization and cleanup. */
bool torture_init_begin(char *ttype, bool v, int *runnable); bool torture_init_begin(char *ttype, bool v, int *runnable);
void torture_init_end(void); void torture_init_end(void);
bool torture_cleanup(void); bool torture_cleanup_begin(void);
void torture_cleanup_end(void);
bool torture_must_stop(void); bool torture_must_stop(void);
bool torture_must_stop_irq(void); bool torture_must_stop_irq(void);
void torture_kthread_stopping(char *title); void torture_kthread_stopping(char *title);
......
...@@ -180,9 +180,12 @@ TRACE_EVENT(rcu_grace_period_init, ...@@ -180,9 +180,12 @@ TRACE_EVENT(rcu_grace_period_init,
* argument is a string as follows: * argument is a string as follows:
* *
* "WakeEmpty": Wake rcuo kthread, first CB to empty list. * "WakeEmpty": Wake rcuo kthread, first CB to empty list.
* "WakeEmptyIsDeferred": Wake rcuo kthread later, first CB to empty list.
* "WakeOvf": Wake rcuo kthread, CB list is huge. * "WakeOvf": Wake rcuo kthread, CB list is huge.
* "WakeOvfIsDeferred": Wake rcuo kthread later, CB list is huge.
* "WakeNot": Don't wake rcuo kthread. * "WakeNot": Don't wake rcuo kthread.
* "WakeNotPoll": Don't wake rcuo kthread because it is polling. * "WakeNotPoll": Don't wake rcuo kthread because it is polling.
* "DeferredWake": Carried out the "IsDeferred" wakeup.
* "Poll": Start of new polling cycle for rcu_nocb_poll. * "Poll": Start of new polling cycle for rcu_nocb_poll.
* "Sleep": Sleep waiting for CBs for !rcu_nocb_poll. * "Sleep": Sleep waiting for CBs for !rcu_nocb_poll.
* "WokeEmpty": rcuo kthread woke to find empty list. * "WokeEmpty": rcuo kthread woke to find empty list.
......
...@@ -507,6 +507,16 @@ config PREEMPT_RCU ...@@ -507,6 +507,16 @@ config PREEMPT_RCU
This option enables preemptible-RCU code that is common between This option enables preemptible-RCU code that is common between
TREE_PREEMPT_RCU and, in the old days, TINY_PREEMPT_RCU. TREE_PREEMPT_RCU and, in the old days, TINY_PREEMPT_RCU.
config TASKS_RCU
bool "Task_based RCU implementation using voluntary context switch"
default n
help
This option enables a task-based RCU implementation that uses
only voluntary context switch (not preemption!), idle, and
user-mode execution as quiescent states.
If unsure, say N.
config RCU_STALL_COMMON config RCU_STALL_COMMON
def_bool ( TREE_RCU || TREE_PREEMPT_RCU || RCU_TRACE ) def_bool ( TREE_RCU || TREE_PREEMPT_RCU || RCU_TRACE )
help help
...@@ -737,7 +747,7 @@ choice ...@@ -737,7 +747,7 @@ choice
config RCU_NOCB_CPU_NONE config RCU_NOCB_CPU_NONE
bool "No build_forced no-CBs CPUs" bool "No build_forced no-CBs CPUs"
depends on RCU_NOCB_CPU && !NO_HZ_FULL_ALL depends on RCU_NOCB_CPU
help help
This option does not force any of the CPUs to be no-CBs CPUs. This option does not force any of the CPUs to be no-CBs CPUs.
Only CPUs designated by the rcu_nocbs= boot parameter will be Only CPUs designated by the rcu_nocbs= boot parameter will be
...@@ -751,7 +761,7 @@ config RCU_NOCB_CPU_NONE ...@@ -751,7 +761,7 @@ config RCU_NOCB_CPU_NONE
config RCU_NOCB_CPU_ZERO config RCU_NOCB_CPU_ZERO
bool "CPU 0 is a build_forced no-CBs CPU" bool "CPU 0 is a build_forced no-CBs CPU"
depends on RCU_NOCB_CPU && !NO_HZ_FULL_ALL depends on RCU_NOCB_CPU
help help
This option forces CPU 0 to be a no-CBs CPU, so that its RCU This option forces CPU 0 to be a no-CBs CPU, so that its RCU
callbacks are invoked by a per-CPU kthread whose name begins callbacks are invoked by a per-CPU kthread whose name begins
......
...@@ -583,6 +583,7 @@ asmlinkage __visible void __init start_kernel(void) ...@@ -583,6 +583,7 @@ asmlinkage __visible void __init start_kernel(void)
early_irq_init(); early_irq_init();
init_IRQ(); init_IRQ();
tick_init(); tick_init();
rcu_init_nohz();
init_timers(); init_timers();
hrtimers_init(); hrtimers_init();
softirq_init(); softirq_init();
......
...@@ -79,6 +79,8 @@ static struct { ...@@ -79,6 +79,8 @@ static struct {
/* Lockdep annotations for get/put_online_cpus() and cpu_hotplug_begin/end() */ /* Lockdep annotations for get/put_online_cpus() and cpu_hotplug_begin/end() */
#define cpuhp_lock_acquire_read() lock_map_acquire_read(&cpu_hotplug.dep_map) #define cpuhp_lock_acquire_read() lock_map_acquire_read(&cpu_hotplug.dep_map)
#define cpuhp_lock_acquire_tryread() \
lock_map_acquire_tryread(&cpu_hotplug.dep_map)
#define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map) #define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map)
#define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map) #define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map)
...@@ -91,10 +93,22 @@ void get_online_cpus(void) ...@@ -91,10 +93,22 @@ void get_online_cpus(void)
mutex_lock(&cpu_hotplug.lock); mutex_lock(&cpu_hotplug.lock);
cpu_hotplug.refcount++; cpu_hotplug.refcount++;
mutex_unlock(&cpu_hotplug.lock); mutex_unlock(&cpu_hotplug.lock);
} }
EXPORT_SYMBOL_GPL(get_online_cpus); EXPORT_SYMBOL_GPL(get_online_cpus);
bool try_get_online_cpus(void)
{
if (cpu_hotplug.active_writer == current)
return true;
if (!mutex_trylock(&cpu_hotplug.lock))
return false;
cpuhp_lock_acquire_tryread();
cpu_hotplug.refcount++;
mutex_unlock(&cpu_hotplug.lock);
return true;
}
EXPORT_SYMBOL_GPL(try_get_online_cpus);
void put_online_cpus(void) void put_online_cpus(void)
{ {
if (cpu_hotplug.active_writer == current) if (cpu_hotplug.active_writer == current)
......
...@@ -667,6 +667,7 @@ void do_exit(long code) ...@@ -667,6 +667,7 @@ void do_exit(long code)
{ {
struct task_struct *tsk = current; struct task_struct *tsk = current;
int group_dead; int group_dead;
TASKS_RCU(int tasks_rcu_i);
profile_task_exit(tsk); profile_task_exit(tsk);
...@@ -775,6 +776,7 @@ void do_exit(long code) ...@@ -775,6 +776,7 @@ void do_exit(long code)
*/ */
flush_ptrace_hw_breakpoint(tsk); flush_ptrace_hw_breakpoint(tsk);
TASKS_RCU(tasks_rcu_i = __srcu_read_lock(&tasks_rcu_exit_srcu));
exit_notify(tsk, group_dead); exit_notify(tsk, group_dead);
proc_exit_connector(tsk); proc_exit_connector(tsk);
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
...@@ -814,6 +816,7 @@ void do_exit(long code) ...@@ -814,6 +816,7 @@ void do_exit(long code)
if (tsk->nr_dirtied) if (tsk->nr_dirtied)
__this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied); __this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied);
exit_rcu(); exit_rcu();
TASKS_RCU(__srcu_read_unlock(&tasks_rcu_exit_srcu, tasks_rcu_i));
/* /*
* The setting of TASK_RUNNING by try_to_wake_up() may be delayed * The setting of TASK_RUNNING by try_to_wake_up() may be delayed
......
This diff is collapsed.
This diff is collapsed.
...@@ -51,7 +51,7 @@ static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; ...@@ -51,7 +51,7 @@ static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
#include "tiny_plugin.h" #include "tiny_plugin.h"
/* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */ /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcu/tree.c. */
static void rcu_idle_enter_common(long long newval) static void rcu_idle_enter_common(long long newval)
{ {
if (newval) { if (newval) {
...@@ -62,7 +62,7 @@ static void rcu_idle_enter_common(long long newval) ...@@ -62,7 +62,7 @@ static void rcu_idle_enter_common(long long newval)
} }
RCU_TRACE(trace_rcu_dyntick(TPS("Start"), RCU_TRACE(trace_rcu_dyntick(TPS("Start"),
rcu_dynticks_nesting, newval)); rcu_dynticks_nesting, newval));
if (!is_idle_task(current)) { if (IS_ENABLED(CONFIG_RCU_TRACE) && !is_idle_task(current)) {
struct task_struct *idle __maybe_unused = idle_task(smp_processor_id()); struct task_struct *idle __maybe_unused = idle_task(smp_processor_id());
RCU_TRACE(trace_rcu_dyntick(TPS("Entry error: not idle task"), RCU_TRACE(trace_rcu_dyntick(TPS("Entry error: not idle task"),
...@@ -72,7 +72,7 @@ static void rcu_idle_enter_common(long long newval) ...@@ -72,7 +72,7 @@ static void rcu_idle_enter_common(long long newval)
current->pid, current->comm, current->pid, current->comm,
idle->pid, idle->comm); /* must be idle task! */ idle->pid, idle->comm); /* must be idle task! */
} }
rcu_sched_qs(0); /* implies rcu_bh_qsctr_inc(0) */ rcu_sched_qs(); /* implies rcu_bh_inc() */
barrier(); barrier();
rcu_dynticks_nesting = newval; rcu_dynticks_nesting = newval;
} }
...@@ -114,7 +114,7 @@ void rcu_irq_exit(void) ...@@ -114,7 +114,7 @@ void rcu_irq_exit(void)
} }
EXPORT_SYMBOL_GPL(rcu_irq_exit); EXPORT_SYMBOL_GPL(rcu_irq_exit);
/* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcutree.c. */ /* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcu/tree.c. */
static void rcu_idle_exit_common(long long oldval) static void rcu_idle_exit_common(long long oldval)
{ {
if (oldval) { if (oldval) {
...@@ -123,7 +123,7 @@ static void rcu_idle_exit_common(long long oldval) ...@@ -123,7 +123,7 @@ static void rcu_idle_exit_common(long long oldval)
return; return;
} }
RCU_TRACE(trace_rcu_dyntick(TPS("End"), oldval, rcu_dynticks_nesting)); RCU_TRACE(trace_rcu_dyntick(TPS("End"), oldval, rcu_dynticks_nesting));
if (!is_idle_task(current)) { if (IS_ENABLED(CONFIG_RCU_TRACE) && !is_idle_task(current)) {
struct task_struct *idle __maybe_unused = idle_task(smp_processor_id()); struct task_struct *idle __maybe_unused = idle_task(smp_processor_id());
RCU_TRACE(trace_rcu_dyntick(TPS("Exit error: not idle task"), RCU_TRACE(trace_rcu_dyntick(TPS("Exit error: not idle task"),
...@@ -217,7 +217,7 @@ static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) ...@@ -217,7 +217,7 @@ static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
* are at it, given that any rcu quiescent state is also an rcu_bh * are at it, given that any rcu quiescent state is also an rcu_bh
* quiescent state. Use "+" instead of "||" to defeat short circuiting. * quiescent state. Use "+" instead of "||" to defeat short circuiting.
*/ */
void rcu_sched_qs(int cpu) void rcu_sched_qs(void)
{ {
unsigned long flags; unsigned long flags;
...@@ -231,7 +231,7 @@ void rcu_sched_qs(int cpu) ...@@ -231,7 +231,7 @@ void rcu_sched_qs(int cpu)
/* /*
* Record an rcu_bh quiescent state. * Record an rcu_bh quiescent state.
*/ */
void rcu_bh_qs(int cpu) void rcu_bh_qs(void)
{ {
unsigned long flags; unsigned long flags;
...@@ -251,9 +251,11 @@ void rcu_check_callbacks(int cpu, int user) ...@@ -251,9 +251,11 @@ void rcu_check_callbacks(int cpu, int user)
{ {
RCU_TRACE(check_cpu_stalls()); RCU_TRACE(check_cpu_stalls());
if (user || rcu_is_cpu_rrupt_from_idle()) if (user || rcu_is_cpu_rrupt_from_idle())
rcu_sched_qs(cpu); rcu_sched_qs();
else if (!in_softirq()) else if (!in_softirq())
rcu_bh_qs(cpu); rcu_bh_qs();
if (user)
rcu_note_voluntary_context_switch(current);
} }
/* /*
......
This diff is collapsed.
...@@ -350,7 +350,7 @@ struct rcu_data { ...@@ -350,7 +350,7 @@ struct rcu_data {
int nocb_p_count_lazy; /* (approximate). */ int nocb_p_count_lazy; /* (approximate). */
wait_queue_head_t nocb_wq; /* For nocb kthreads to sleep on. */ wait_queue_head_t nocb_wq; /* For nocb kthreads to sleep on. */
struct task_struct *nocb_kthread; struct task_struct *nocb_kthread;
bool nocb_defer_wakeup; /* Defer wakeup of nocb_kthread. */ int nocb_defer_wakeup; /* Defer wakeup of nocb_kthread. */
/* The following fields are used by the leader, hence own cacheline. */ /* The following fields are used by the leader, hence own cacheline. */
struct rcu_head *nocb_gp_head ____cacheline_internodealigned_in_smp; struct rcu_head *nocb_gp_head ____cacheline_internodealigned_in_smp;
...@@ -383,6 +383,11 @@ struct rcu_data { ...@@ -383,6 +383,11 @@ struct rcu_data {
#define RCU_FORCE_QS 3 /* Need to force quiescent state. */ #define RCU_FORCE_QS 3 /* Need to force quiescent state. */
#define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK #define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK
/* Values for nocb_defer_wakeup field in struct rcu_data. */
#define RCU_NOGP_WAKE_NOT 0
#define RCU_NOGP_WAKE 1
#define RCU_NOGP_WAKE_FORCE 2
#define RCU_JIFFIES_TILL_FORCE_QS (1 + (HZ > 250) + (HZ > 500)) #define RCU_JIFFIES_TILL_FORCE_QS (1 + (HZ > 250) + (HZ > 500))
/* For jiffies_till_first_fqs and */ /* For jiffies_till_first_fqs and */
/* and jiffies_till_next_fqs. */ /* and jiffies_till_next_fqs. */
...@@ -572,6 +577,7 @@ static void rcu_preempt_do_callbacks(void); ...@@ -572,6 +577,7 @@ static void rcu_preempt_do_callbacks(void);
static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp, static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
struct rcu_node *rnp); struct rcu_node *rnp);
#endif /* #ifdef CONFIG_RCU_BOOST */ #endif /* #ifdef CONFIG_RCU_BOOST */
static void __init rcu_spawn_boost_kthreads(void);
static void rcu_prepare_kthreads(int cpu); static void rcu_prepare_kthreads(int cpu);
static void rcu_cleanup_after_idle(int cpu); static void rcu_cleanup_after_idle(int cpu);
static void rcu_prepare_for_idle(int cpu); static void rcu_prepare_for_idle(int cpu);
...@@ -589,10 +595,14 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, ...@@ -589,10 +595,14 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
static bool rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, static bool rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
struct rcu_data *rdp, struct rcu_data *rdp,
unsigned long flags); unsigned long flags);
static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp); static int rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp);
static void do_nocb_deferred_wakeup(struct rcu_data *rdp); static void do_nocb_deferred_wakeup(struct rcu_data *rdp);
static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp); static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp);
static void rcu_spawn_nocb_kthreads(struct rcu_state *rsp); static void rcu_spawn_all_nocb_kthreads(int cpu);
static void __init rcu_spawn_nocb_kthreads(void);
#ifdef CONFIG_RCU_NOCB_CPU
static void __init rcu_organize_nocb_kthreads(struct rcu_state *rsp);
#endif /* #ifdef CONFIG_RCU_NOCB_CPU */
static void __maybe_unused rcu_kick_nohz_cpu(int cpu); static void __maybe_unused rcu_kick_nohz_cpu(int cpu);
static bool init_nocb_callback_list(struct rcu_data *rdp); static bool init_nocb_callback_list(struct rcu_data *rdp);
static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq); static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq);
...@@ -605,6 +615,8 @@ static void rcu_sysidle_report_gp(struct rcu_state *rsp, int isidle, ...@@ -605,6 +615,8 @@ static void rcu_sysidle_report_gp(struct rcu_state *rsp, int isidle,
static void rcu_bind_gp_kthread(void); static void rcu_bind_gp_kthread(void);
static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp); static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp);
static bool rcu_nohz_full_cpu(struct rcu_state *rsp); static bool rcu_nohz_full_cpu(struct rcu_state *rsp);
static void rcu_dynticks_task_enter(void);
static void rcu_dynticks_task_exit(void);
#endif /* #ifndef RCU_TREE_NONCORE */ #endif /* #ifndef RCU_TREE_NONCORE */
......
This diff is collapsed.
This diff is collapsed.
...@@ -278,7 +278,7 @@ asmlinkage __visible void __do_softirq(void) ...@@ -278,7 +278,7 @@ asmlinkage __visible void __do_softirq(void)
pending >>= softirq_bit; pending >>= softirq_bit;
} }
rcu_bh_qs(smp_processor_id()); rcu_bh_qs();
local_irq_disable(); local_irq_disable();
pending = local_softirq_pending(); pending = local_softirq_pending();
......
...@@ -1055,15 +1055,6 @@ static struct ctl_table kern_table[] = { ...@@ -1055,15 +1055,6 @@ static struct ctl_table kern_table[] = {
.child = key_sysctls, .child = key_sysctls,
}, },
#endif #endif
#ifdef CONFIG_RCU_TORTURE_TEST
{
.procname = "rcutorture_runnable",
.data = &rcutorture_runnable,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
#endif
#ifdef CONFIG_PERF_EVENTS #ifdef CONFIG_PERF_EVENTS
/* /*
* User-space scripts rely on the existence of this file * User-space scripts rely on the existence of this file
......
...@@ -211,18 +211,16 @@ EXPORT_SYMBOL_GPL(torture_onoff_cleanup); ...@@ -211,18 +211,16 @@ EXPORT_SYMBOL_GPL(torture_onoff_cleanup);
/* /*
* Print online/offline testing statistics. * Print online/offline testing statistics.
*/ */
char *torture_onoff_stats(char *page) void torture_onoff_stats(void)
{ {
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
page += sprintf(page, pr_cont("onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
"onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
n_online_successes, n_online_attempts, n_online_successes, n_online_attempts,
n_offline_successes, n_offline_attempts, n_offline_successes, n_offline_attempts,
min_online, max_online, min_online, max_online,
min_offline, max_offline, min_offline, max_offline,
sum_online, sum_offline, HZ); sum_online, sum_offline, HZ);
#endif /* #ifdef CONFIG_HOTPLUG_CPU */ #endif /* #ifdef CONFIG_HOTPLUG_CPU */
return page;
} }
EXPORT_SYMBOL_GPL(torture_onoff_stats); EXPORT_SYMBOL_GPL(torture_onoff_stats);
...@@ -635,8 +633,13 @@ EXPORT_SYMBOL_GPL(torture_init_end); ...@@ -635,8 +633,13 @@ EXPORT_SYMBOL_GPL(torture_init_end);
* *
* This must be called before the caller starts shutting down its own * This must be called before the caller starts shutting down its own
* kthreads. * kthreads.
*
* Both torture_cleanup_begin() and torture_cleanup_end() must be paired,
* in order to correctly perform the cleanup. They are separated because
* threads can still need to reference the torture_type type, thus nullify
* only after completing all other relevant calls.
*/ */
bool torture_cleanup(void) bool torture_cleanup_begin(void)
{ {
mutex_lock(&fullstop_mutex); mutex_lock(&fullstop_mutex);
if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) { if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
...@@ -651,12 +654,17 @@ bool torture_cleanup(void) ...@@ -651,12 +654,17 @@ bool torture_cleanup(void)
torture_shuffle_cleanup(); torture_shuffle_cleanup();
torture_stutter_cleanup(); torture_stutter_cleanup();
torture_onoff_cleanup(); torture_onoff_cleanup();
return false;
}
EXPORT_SYMBOL_GPL(torture_cleanup_begin);
void torture_cleanup_end(void)
{
mutex_lock(&fullstop_mutex); mutex_lock(&fullstop_mutex);
torture_type = NULL; torture_type = NULL;
mutex_unlock(&fullstop_mutex); mutex_unlock(&fullstop_mutex);
return false;
} }
EXPORT_SYMBOL_GPL(torture_cleanup); EXPORT_SYMBOL_GPL(torture_cleanup_end);
/* /*
* Is it time for the current torture test to stop? * Is it time for the current torture test to stop?
......
...@@ -2043,9 +2043,10 @@ __acquires(&pool->lock) ...@@ -2043,9 +2043,10 @@ __acquires(&pool->lock)
* kernels, where a requeueing work item waiting for something to * kernels, where a requeueing work item waiting for something to
* happen could deadlock with stop_machine as such work item could * happen could deadlock with stop_machine as such work item could
* indefinitely requeue itself while all other CPUs are trapped in * indefinitely requeue itself while all other CPUs are trapped in
* stop_machine. * stop_machine. At the same time, report a quiescent RCU state so
* the same condition doesn't freeze RCU.
*/ */
cond_resched(); cond_resched_rcu_qs();
spin_lock_irq(&pool->lock); spin_lock_irq(&pool->lock);
......
...@@ -789,7 +789,7 @@ static int do_mlockall(int flags) ...@@ -789,7 +789,7 @@ static int do_mlockall(int flags)
/* Ignore errors */ /* Ignore errors */
mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags); mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
cond_resched(); cond_resched_rcu_qs();
} }
out: out:
return 0; return 0;
......
#!/bin/sh #!/bin/bash
# Usage: sh config2frag.sh < .config > configfrag # Usage: config2frag.sh < .config > configfrag
# #
# Converts the "# CONFIG_XXX is not set" to "CONFIG_XXX=n" so that the # Converts the "# CONFIG_XXX is not set" to "CONFIG_XXX=n" so that the
# resulting file becomes a legitimate Kconfig fragment. # resulting file becomes a legitimate Kconfig fragment.
......
#!/bin/sh #!/bin/bash
# Usage: sh configcheck.sh .config .config-template # Usage: configcheck.sh .config .config-template
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
......
#!/bin/sh #!/bin/bash
# #
# sh configinit.sh config-spec-file [ build output dir ] # Usage: configinit.sh config-spec-file [ build output dir ]
# #
# Create a .config file from the spec file. Run from the kernel source tree. # Create a .config file from the spec file. Run from the kernel source tree.
# Exits with 0 if all went well, with 1 if all went well but the config # Exits with 0 if all went well, with 1 if all went well but the config
......
...@@ -64,6 +64,26 @@ configfrag_boot_params () { ...@@ -64,6 +64,26 @@ configfrag_boot_params () {
fi fi
} }
# configfrag_boot_cpus bootparam-string config-fragment-file config-cpus
#
# Decreases number of CPUs based on any maxcpus= boot parameters specified.
configfrag_boot_cpus () {
local bootargs="`configfrag_boot_params "$1" "$2"`"
local maxcpus
if echo "${bootargs}" | grep -q 'maxcpus=[0-9]'
then
maxcpus="`echo "${bootargs}" | sed -e 's/^.*maxcpus=\([0-9]*\).*$/\1/'`"
if test "$3" -gt "$maxcpus"
then
echo $maxcpus
else
echo $3
fi
else
echo $3
fi
}
# configfrag_hotplug_cpu config-fragment-file # configfrag_hotplug_cpu config-fragment-file
# #
# Returns 1 if the config fragment specifies hotplug CPU. # Returns 1 if the config fragment specifies hotplug CPU.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# #
# Build a kvm-ready Linux kernel from the tree in the current directory. # Build a kvm-ready Linux kernel from the tree in the current directory.
# #
# Usage: sh kvm-build.sh config-template build-dir more-configs # Usage: kvm-build.sh config-template build-dir more-configs
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# #
# Analyze a given results directory for locktorture progress. # Analyze a given results directory for locktorture progress.
# #
# Usage: sh kvm-recheck-lock.sh resdir # Usage: kvm-recheck-lock.sh resdir
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# #
# Analyze a given results directory for rcutorture progress. # Analyze a given results directory for rcutorture progress.
# #
# Usage: sh kvm-recheck-rcu.sh resdir # Usage: kvm-recheck-rcu.sh resdir
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# check the build and console output for errors. Given a directory # check the build and console output for errors. Given a directory
# containing results directories, this recursively checks them all. # containing results directories, this recursively checks them all.
# #
# Usage: sh kvm-recheck.sh resdir ... # Usage: kvm-recheck.sh resdir ...
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# Execute this in the source tree. Do not run it as a background task # Execute this in the source tree. Do not run it as a background task
# because qemu does not seem to like that much. # because qemu does not seem to like that much.
# #
# Usage: sh kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args # Usage: kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args
# #
# qemu-args defaults to "-nographic", along with arguments specifying the # qemu-args defaults to "-nographic", along with arguments specifying the
# number of CPUs and other options generated from # number of CPUs and other options generated from
...@@ -140,6 +140,7 @@ fi ...@@ -140,6 +140,7 @@ fi
# Generate -smp qemu argument. # Generate -smp qemu argument.
qemu_args="-nographic $qemu_args" qemu_args="-nographic $qemu_args"
cpu_count=`configNR_CPUS.sh $config_template` cpu_count=`configNR_CPUS.sh $config_template`
cpu_count=`configfrag_boot_cpus "$boot_args" "$config_template" "$cpu_count"`
vcpus=`identify_qemu_vcpus` vcpus=`identify_qemu_vcpus`
if test $cpu_count -gt $vcpus if test $cpu_count -gt $vcpus
then then
...@@ -214,7 +215,7 @@ then ...@@ -214,7 +215,7 @@ then
fi fi
if test $kruntime -ge $((seconds + grace)) if test $kruntime -ge $((seconds + grace))
then then
echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1 echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
kill -KILL $qemu_pid kill -KILL $qemu_pid
break break
fi fi
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
# Edit the definitions below to set the locations of the various directories, # Edit the definitions below to set the locations of the various directories,
# as well as the test duration. # as well as the test duration.
# #
# Usage: sh kvm.sh [ options ] # Usage: kvm.sh [ options ]
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
...@@ -188,7 +188,9 @@ for CF in $configs ...@@ -188,7 +188,9 @@ for CF in $configs
do do
if test -f "$CONFIGFRAG/$kversion/$CF" if test -f "$CONFIGFRAG/$kversion/$CF"
then then
echo $CF `configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF` >> $T/cfgcpu cpu_count=`configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF`
cpu_count=`configfrag_boot_cpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$kversion/$CF" "$cpu_count"`
echo $CF $cpu_count >> $T/cfgcpu
else else
echo "The --configs file $CF does not exist, terminating." echo "The --configs file $CF does not exist, terminating."
exit 1 exit 1
......
#!/bin/sh #!/bin/bash
# #
# Check the build output from an rcutorture run for goodness. # Check the build output from an rcutorture run for goodness.
# The "file" is a pathname on the local system, and "title" is # The "file" is a pathname on the local system, and "title" is
...@@ -6,8 +6,7 @@ ...@@ -6,8 +6,7 @@
# #
# The file must contain kernel build output. # The file must contain kernel build output.
# #
# Usage: # Usage: parse-build.sh file title
# sh parse-build.sh file title
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
......
#!/bin/sh #!/bin/bash
# #
# Check the console output from an rcutorture run for oopses. # Check the console output from an rcutorture run for oopses.
# The "file" is a pathname on the local system, and "title" is # The "file" is a pathname on the local system, and "title" is
# a text string for error-message purposes. # a text string for error-message purposes.
# #
# Usage: # Usage: parse-console.sh file title
# sh parse-console.sh file title
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
...@@ -33,6 +32,10 @@ title="$2" ...@@ -33,6 +32,10 @@ title="$2"
. functions.sh . functions.sh
if grep -Pq '\x00' < $file
then
print_warning Console output contains nul bytes, old qemu still running?
fi
egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T
if test -s $T if test -s $T
then then
......
#!/bin/sh #!/bin/bash
# #
# Check the console output from a torture run for goodness. # Check the console output from a torture run for goodness.
# The "file" is a pathname on the local system, and "title" is # The "file" is a pathname on the local system, and "title" is
...@@ -7,8 +7,7 @@ ...@@ -7,8 +7,7 @@
# The file must contain torture output, but can be interspersed # The file must contain torture output, but can be interspersed
# with other dmesg text, as in console-log output. # with other dmesg text, as in console-log output.
# #
# Usage: # Usage: parse-torture.sh file title
# sh parse-torture.sh file title
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
......
LOCK01 LOCK01
LOCK02
LOCK03
LOCK04
\ No newline at end of file
CONFIG_SMP=y
CONFIG_NR_CPUS=4
CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=4
CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=4
CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
...@@ -38,6 +38,6 @@ per_version_boot_params () { ...@@ -38,6 +38,6 @@ per_version_boot_params () {
echo $1 `locktorture_param_onoff "$1" "$2"` \ echo $1 `locktorture_param_onoff "$1" "$2"` \
locktorture.stat_interval=15 \ locktorture.stat_interval=15 \
locktorture.shutdown_secs=$3 \ locktorture.shutdown_secs=$3 \
locktorture.locktorture_runnable=1 \ locktorture.torture_runnable=1 \
locktorture.verbose=1 locktorture.verbose=1
} }
...@@ -11,3 +11,6 @@ SRCU-N ...@@ -11,3 +11,6 @@ SRCU-N
SRCU-P SRCU-P
TINY01 TINY01
TINY02 TINY02
TASKS01
TASKS02
TASKS03
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_RCU=y
CONFIG_TASKS_RCU=y
CONFIG_SMP=n
CONFIG_PREEMPT_NONE=y
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_TASKS_RCU=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_HOTPLUG_CPU=n
CONFIG_SUSPEND=n
CONFIG_HIBERNATION=n
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
CONFIG_TASKS_RCU=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=n
CONFIG_NO_HZ_FULL=y
CONFIG_NO_HZ_FULL_ALL=y
CONFIG_SMP=y CONFIG_SMP=y
CONFIG_NR_CPUS=8
CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y CONFIG_PREEMPT=y
...@@ -10,8 +9,7 @@ CONFIG_NO_HZ_FULL=n ...@@ -10,8 +9,7 @@ CONFIG_NO_HZ_FULL=n
CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_FAST_NO_HZ=y
CONFIG_RCU_TRACE=y CONFIG_RCU_TRACE=y
CONFIG_HOTPLUG_CPU=y CONFIG_HOTPLUG_CPU=y
CONFIG_RCU_FANOUT=8 CONFIG_MAXSMP=y
CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU=y
CONFIG_RCU_NOCB_CPU_ZERO=y CONFIG_RCU_NOCB_CPU_ZERO=y
CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_DEBUG_LOCK_ALLOC=n
......
rcutorture.torture_type=rcu_bh rcutorture.torture_type=rcu_bh maxcpus=8
CONFIG_SMP=y CONFIG_SMP=y
CONFIG_NR_CPUS=16 CONFIG_NR_CPUS=16
CONFIG_CPUMASK_OFFSTACK=y
CONFIG_PREEMPT_NONE=y CONFIG_PREEMPT_NONE=y
CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n CONFIG_PREEMPT=n
...@@ -7,7 +8,7 @@ CONFIG_PREEMPT=n ...@@ -7,7 +8,7 @@ CONFIG_PREEMPT=n
CONFIG_HZ_PERIODIC=n CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=n CONFIG_NO_HZ_IDLE=n
CONFIG_NO_HZ_FULL=y CONFIG_NO_HZ_FULL=y
CONFIG_NO_HZ_FULL_ALL=y CONFIG_NO_HZ_FULL_ALL=n
CONFIG_NO_HZ_FULL_SYSIDLE=y CONFIG_NO_HZ_FULL_SYSIDLE=y
CONFIG_RCU_FAST_NO_HZ=n CONFIG_RCU_FAST_NO_HZ=n
CONFIG_RCU_TRACE=y CONFIG_RCU_TRACE=y
......
...@@ -51,7 +51,7 @@ per_version_boot_params () { ...@@ -51,7 +51,7 @@ per_version_boot_params () {
`rcutorture_param_n_barrier_cbs "$1"` \ `rcutorture_param_n_barrier_cbs "$1"` \
rcutorture.stat_interval=15 \ rcutorture.stat_interval=15 \
rcutorture.shutdown_secs=$3 \ rcutorture.shutdown_secs=$3 \
rcutorture.rcutorture_runnable=1 \ rcutorture.torture_runnable=1 \
rcutorture.test_no_idle_hz=1 \ rcutorture.test_no_idle_hz=1 \
rcutorture.verbose=1 rcutorture.verbose=1
} }
...@@ -6,6 +6,7 @@ this case. There are probably much better ways of doing this. ...@@ -6,6 +6,7 @@ this case. There are probably much better ways of doing this.
That said, here are the commands: That said, here are the commands:
------------------------------------------------------------------------ ------------------------------------------------------------------------
cd tools/testing/selftests/rcutorture
zcat /initrd.img > /tmp/initrd.img.zcat zcat /initrd.img > /tmp/initrd.img.zcat
mkdir initrd mkdir initrd
cd initrd cd initrd
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment