From 6e67669678d2d51b2bcf0411aeb629b4353a9880 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 5 Dec 2013 14:56:54 -0800 Subject: [PATCH 01/77] documentation: Document call_rcu() safety mechanisms and limitations The call_rcu() family of primitives will take action to accelerate grace periods when the number of callbacks pending on a given CPU becomes excessive. Although this safety mechanism can be useful, it is no substitute for users of call_rcu() having rate-limit controls in place. This commit adds this nuance to the documentation. Reported-by: "Michael S. Tsirkin" Reported-by: Gleb Natapov Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- Documentation/RCU/checklist.txt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index 91266193b8f4..9d10d1db16a5 100644 --- a/Documentation/RCU/checklist.txt +++ b/Documentation/RCU/checklist.txt @@ -256,10 +256,10 @@ over a rather long period of time, but improvements are always welcome! variations on this theme. b. Limiting update rate. For example, if updates occur only - once per hour, then no explicit rate limiting is required, - unless your system is already badly broken. The dcache - subsystem takes this approach -- updates are guarded - by a global lock, limiting their rate. + once per hour, then no explicit rate limiting is + required, unless your system is already badly broken. + Older versions of the dcache subsystem take this approach, + guarding updates with a global lock, limiting their rate. c. Trusted update -- if updates can only be done manually by superuser or some other trusted user, then it might not @@ -268,7 +268,8 @@ over a rather long period of time, but improvements are always welcome! the machine. d. Use call_rcu_bh() rather than call_rcu(), in order to take - advantage of call_rcu_bh()'s faster grace periods. + advantage of call_rcu_bh()'s faster grace periods. (This + is only a partial solution, though.) e. Periodically invoke synchronize_rcu(), permitting a limited number of updates per grace period. @@ -276,6 +277,13 @@ over a rather long period of time, but improvements are always welcome! The same cautions apply to call_rcu_bh(), call_rcu_sched(), call_srcu(), and kfree_rcu(). + Note that although these primitives do take action to avoid memory + exhaustion when any given CPU has too many callbacks, a determined + user could still exhaust memory. This is especially the case + if a system with a large number of CPUs has been configured to + offload all of its RCU callbacks onto a single CPU, or if the + system has relatively little free memory. + 9. All RCU list-traversal primitives, which include rcu_dereference(), list_for_each_entry_rcu(), and list_for_each_safe_rcu(), must be either within an RCU read-side From 449f7413c876a229fd95362cc12bc7ade18d0661 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 2 Jan 2014 15:03:50 -0800 Subject: [PATCH 02/77] Documentation/memory-barriers.txt: ACCESS_ONCE() provides cache coherence The ACCESS_ONCE() primitive provides cache coherence, but the documentation does not clearly state this. This commit therefore upgrades the documentation. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- Documentation/memory-barriers.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 102dc19c4119..f9ff060d8320 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1249,6 +1249,23 @@ The ACCESS_ONCE() function can prevent any number of optimizations that, while perfectly safe in single-threaded code, can be fatal in concurrent code. Here are some examples of these sorts of optimizations: + (*) The compiler is within its rights to reorder loads and stores + to the same variable, and in some cases, the CPU is within its + rights to reorder loads to the same variable. This means that + the following code: + + a[0] = x; + a[1] = x; + + Might result in an older value of x stored in a[1] than in a[0]. + Prevent both the compiler and the CPU from doing this as follows: + + a[0] = ACCESS_ONCE(x); + a[1] = ACCESS_ONCE(x); + + In short, ACCESS_ONCE() provides cache coherence for accesses from + multiple CPUs to a single variable. + (*) The compiler is within its rights to merge successive loads from the same variable. Such merging can cause the compiler to "optimize" the following code: From 586dd56a4c17611e3927c9ff02ab8d0a6a545b38 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 11 Feb 2014 12:28:06 -0800 Subject: [PATCH 03/77] Documentation/memory-barriers.txt: Conditional must use prior load A control dependency consists of a load, a conditional that depends on that load, and a store. This commit emphasizes this point in the summary. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- Documentation/memory-barriers.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index f9ff060d8320..6b25efd45583 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -724,7 +724,8 @@ In summary: later loads, smp_mb(). (*) Control dependencies require at least one run-time conditional - between the prior load and the subsequent store. If the compiler + between the prior load and the subsequent store, and this + conditional must involve the prior load. If the compiler is able to optimize the conditional away, it will have also optimized away the ordering. Careful use of ACCESS_ONCE() can help to preserve the needed conditional. From bbf393b0d5350d68dbcf1f231b8af07b1b31121d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 12 Feb 2014 11:12:37 -0800 Subject: [PATCH 04/77] Documentation/kernel-per-CPU-kthreads.txt: Workqueue affinity This commit documents the ability to apply CPU affinity to WQ_SYSFS workqueues, thus offloading them from the desired worker CPUs. Signed-off-by: Paul E. McKenney Reviewed-by: Tejun Heo Acked-by: Frederic Weisbecker Reviewed-by: Lai Jiangshan Reviewed-by: Josh Triplett --- Documentation/kernel-per-CPU-kthreads.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Documentation/kernel-per-CPU-kthreads.txt b/Documentation/kernel-per-CPU-kthreads.txt index 827104fb9364..f3cd299fcc41 100644 --- a/Documentation/kernel-per-CPU-kthreads.txt +++ b/Documentation/kernel-per-CPU-kthreads.txt @@ -162,7 +162,18 @@ Purpose: Execute workqueue requests To reduce its OS jitter, do any of the following: 1. Run your workload at a real-time priority, which will allow preempting the kworker daemons. -2. Do any of the following needed to avoid jitter that your +2. A given workqueue can be made visible in the sysfs filesystem + by passing the WQ_SYSFS to that workqueue's alloc_workqueue(). + Such a workqueue can be confined to a given subset of the + CPUs using the /sys/devices/virtual/workqueue/*/cpumask sysfs + files. The set of WQ_SYSFS workqueues can be displayed using + "ls sys/devices/virtual/workqueue". That said, the workqueues + maintainer would like to caution people against indiscriminately + sprinkling WQ_SYSFS across all the workqueues. The reason for + caution is that it is easy to add WQ_SYSFS, but because sysfs is + part of the formal user/kernel API, it can be nearly impossible + to remove it, even if its addition was a mistake. +3. Do any of the following needed to avoid jitter that your application cannot tolerate: a. Build your kernel with CONFIG_SLUB=y rather than CONFIG_SLAB=y, thus avoiding the slab allocator's periodic From 9b2b3bf53124dca4ac815bd2fca53a31e5e262bd Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 12 Feb 2014 20:19:47 -0800 Subject: [PATCH 05/77] Documentation/memory-barriers.txt: Need barriers() for some control dependencies Current compilers can "speculate" stores in the case where both legs of the "if" statement start with identical stores. Because the stores are identical, the compiler knows that the store will unconditionally execute regardless of the "if" condition, and so the compiler is within its rights to hoist the store to precede the condition. Such hoisting destroys the control-dependency ordering. This ordering can be restored by placing a barrier() at the beginning of each leg of the "if" statement. This commit adds this requirement to the control-dependencies section. Signed-off-by: Paul E. McKenney --- Documentation/memory-barriers.txt | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 6b25efd45583..9dde54c55b24 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -608,26 +608,30 @@ as follows: b = p; /* BUG: Compiler can reorder!!! */ do_something(); -The solution is again ACCESS_ONCE(), which preserves the ordering between -the load from variable 'a' and the store to variable 'b': +The solution is again ACCESS_ONCE() and barrier(), which preserves the +ordering between the load from variable 'a' and the store to variable 'b': q = ACCESS_ONCE(a); if (q) { + barrier(); ACCESS_ONCE(b) = p; do_something(); } else { + barrier(); ACCESS_ONCE(b) = p; do_something_else(); } -You could also use barrier() to prevent the compiler from moving -the stores to variable 'b', but barrier() would not prevent the -compiler from proving to itself that a==1 always, so ACCESS_ONCE() -is also needed. +The initial ACCESS_ONCE() is required to prevent the compiler from +proving the value of 'a', and the pair of barrier() invocations are +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: +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); ACCESS_ONCE(b) = p; /* BUG: No ordering vs. load from a!!! */ @@ -643,9 +647,11 @@ It is of course legal for the prior load to be part of the conditional, for example, as follows: if (ACCESS_ONCE(a) > 0) { + barrier(); ACCESS_ONCE(b) = q / 2; do_something(); } else { + barrier(); ACCESS_ONCE(b) = q / 3; do_something_else(); } @@ -659,9 +665,11 @@ the needed conditional. For example: q = ACCESS_ONCE(a); if (q % MAX) { + barrier(); ACCESS_ONCE(b) = p; do_something(); } else { + barrier(); ACCESS_ONCE(b) = p; do_something_else(); } @@ -723,6 +731,10 @@ In summary: use smb_rmb(), smp_wmb(), or, in the case of prior stores and later loads, smp_mb(). + (*) If both legs of the "if" statement begin with identical stores + to the same variable, a barrier() statement is required at the + beginning of each leg of the "if" statement. + (*) Control dependencies require at least one run-time conditional between the prior load and the subsequent store, and this conditional must involve the prior load. If the compiler From e4696a1d3b1125d427de685531a44258ea6263df Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 15 Feb 2014 08:52:32 -0800 Subject: [PATCH 06/77] documentation: Fix some inconsistencies in RTFP.txt Some of the early history leaves out some citations and vice versa. This commit fixes these up. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- Documentation/RCU/RTFP.txt | 149 +++++++++++++++++++++++++++++++------ 1 file changed, 125 insertions(+), 24 deletions(-) diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt index 273e654d7d08..2f0fcb2112d2 100644 --- a/Documentation/RCU/RTFP.txt +++ b/Documentation/RCU/RTFP.txt @@ -31,6 +31,14 @@ has lapsed, so this approach may be used in non-GPL software, if desired. (In contrast, implementation of RCU is permitted only in software licensed under either GPL or LGPL. Sorry!!!) +In 1987, Rashid et al. described lazy TLB-flush [RichardRashid87a]. +At first glance, this has nothing to do with RCU, but nevertheless +this paper helped inspire the update-side batching used in the later +RCU implementation in DYNIX/ptx. In 1988, Barbara Liskov published +a description of Argus that noted that use of out-of-date values can +be tolerated in some situations. Thus, this paper provides some early +theoretical justification for use of stale data. + In 1990, Pugh [Pugh90] noted that explicitly tracking which threads were reading a given data structure permitted deferred free to operate in the presence of non-terminating threads. However, this explicit @@ -41,11 +49,11 @@ providing a fine-grained locking design, however, it would be interesting to see how much of the performance advantage reported in 1990 remains today. -At about this same time, Adams [Adams91] described ``chaotic relaxation'', -where the normal barriers between successive iterations of convergent -numerical algorithms are relaxed, so that iteration $n$ might use -data from iteration $n-1$ or even $n-2$. This introduces error, -which typically slows convergence and thus increases the number of +At about this same time, Andrews [Andrews91textbook] described ``chaotic +relaxation'', where the normal barriers between successive iterations +of convergent numerical algorithms are relaxed, so that iteration $n$ +might use data from iteration $n-1$ or even $n-2$. This introduces +error, which typically slows convergence and thus increases the number of iterations required. However, this increase is sometimes more than made up for by a reduction in the number of expensive barrier operations, which are otherwise required to synchronize the threads at the end @@ -55,7 +63,8 @@ is thus inapplicable to most data structures in operating-system kernels. In 1992, Henry (now Alexia) Massalin completed a dissertation advising parallel programmers to defer processing when feasible to simplify -synchronization. RCU makes extremely heavy use of this advice. +synchronization [HMassalinPhD]. RCU makes extremely heavy use of +this advice. In 1993, Jacobson [Jacobson93] verbally described what is perhaps the simplest deferred-free technique: simply waiting a fixed amount of time @@ -90,27 +99,29 @@ mechanism, which is quite similar to RCU [Gamsa99]. These operating systems made pervasive use of RCU in place of "existence locks", which greatly simplifies locking hierarchies and helps avoid deadlocks. -2001 saw the first RCU presentation involving Linux [McKenney01a] -at OLS. The resulting abundance of RCU patches was presented the -following year [McKenney02a], and use of RCU in dcache was first -described that same year [Linder02a]. +The year 2000 saw an email exchange that would likely have +led to yet another independent invention of something like RCU +[RustyRussell2000a,RustyRussell2000b]. Instead, 2001 saw the first +RCU presentation involving Linux [McKenney01a] at OLS. The resulting +abundance of RCU patches was presented the following year [McKenney02a], +and use of RCU in dcache was first described that same year [Linder02a]. Also in 2002, Michael [Michael02b,Michael02a] presented "hazard-pointer" techniques that defer the destruction of data structures to simplify non-blocking synchronization (wait-free synchronization, lock-free synchronization, and obstruction-free synchronization are all examples of -non-blocking synchronization). In particular, this technique eliminates -locking, reduces contention, reduces memory latency for readers, and -parallelizes pipeline stalls and memory latency for writers. However, -these techniques still impose significant read-side overhead in the -form of memory barriers. Researchers at Sun worked along similar lines -in the same timeframe [HerlihyLM02]. These techniques can be thought -of as inside-out reference counts, where the count is represented by the -number of hazard pointers referencing a given data structure rather than -the more conventional counter field within the data structure itself. -The key advantage of inside-out reference counts is that they can be -stored in immortal variables, thus allowing races between access and -deletion to be avoided. +non-blocking synchronization). The corresponding journal article appeared +in 2004 [MagedMichael04a]. This technique eliminates locking, reduces +contention, reduces memory latency for readers, and parallelizes pipeline +stalls and memory latency for writers. However, these techniques still +impose significant read-side overhead in the form of memory barriers. +Researchers at Sun worked along similar lines in the same timeframe +[HerlihyLM02]. These techniques can be thought of as inside-out reference +counts, where the count is represented by the number of hazard pointers +referencing a given data structure rather than the more conventional +counter field within the data structure itself. The key advantage +of inside-out reference counts is that they can be stored in immortal +variables, thus allowing races between access and deletion to be avoided. By the same token, RCU can be thought of as a "bulk reference count", where some form of reference counter covers all reference by a given CPU @@ -123,8 +134,10 @@ can be thought of in other terms as well. In 2003, the K42 group described how RCU could be used to create hot-pluggable implementations of operating-system functions [Appavoo03a]. -Later that year saw a paper describing an RCU implementation of System -V IPC [Arcangeli03], and an introduction to RCU in Linux Journal +Later that year saw a paper describing an RCU implementation +of System V IPC [Arcangeli03] (following up on a suggestion by +Hugh Dickins [Dickins02a] and an implementation by Mingming Cao +[MingmingCao2002IPCRCU]), and an introduction to RCU in Linux Journal [McKenney03a]. 2004 has seen a Linux-Journal article on use of RCU in dcache @@ -383,6 +396,21 @@ for Programming Languages and Operating Systems}" } } +@phdthesis{HMassalinPhD +,author="H. Massalin" +,title="Synthesis: An Efficient Implementation of Fundamental Operating +System Services" +,school="Columbia University" +,address="New York, NY" +,year="1992" +,annotation={ + Mondo optimizing compiler. + Wait-free stuff. + Good advice: defer work to avoid synchronization. See page 90 + (PDF page 106), Section 5.4, fourth bullet point. +} +} + @unpublished{Jacobson93 ,author="Van Jacobson" ,title="Avoid Read-Side Locking Via Delayed Free" @@ -671,6 +699,20 @@ Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni" [Viewed October 18, 2004]" } +@conference{Michael02b +,author="Maged M. Michael" +,title="High Performance Dynamic Lock-Free Hash Tables and List-Based Sets" +,Year="2002" +,Month="August" +,booktitle="{Proceedings of the 14\textsuperscript{th} Annual ACM +Symposium on Parallel +Algorithms and Architecture}" +,pages="73-82" +,annotation={ +Like the title says... +} +} + @Conference{Linder02a ,Author="Hanna Linder and Dipankar Sarma and Maneesh Soni" ,Title="Scalability of the Directory Entry Cache" @@ -727,6 +769,24 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell" } } +@conference{Michael02a +,author="Maged M. Michael" +,title="Safe Memory Reclamation for Dynamic Lock-Free Objects Using Atomic +Reads and Writes" +,Year="2002" +,Month="August" +,booktitle="{Proceedings of the 21\textsuperscript{st} Annual ACM +Symposium on Principles of Distributed Computing}" +,pages="21-30" +,annotation={ + Each thread keeps an array of pointers to items that it is + currently referencing. Sort of an inside-out garbage collection + mechanism, but one that requires the accessing code to explicitly + state its needs. Also requires read-side memory barriers on + most architectures. +} +} + @unpublished{Dickins02a ,author="Hugh Dickins" ,title="Use RCU for System-V IPC" @@ -735,6 +795,17 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell" ,note="private communication" } +@InProceedings{HerlihyLM02 +,author={Maurice Herlihy and Victor Luchangco and Mark Moir} +,title="The Repeat Offender Problem: A Mechanism for Supporting Dynamic-Sized, +Lock-Free Data Structures" +,booktitle={Proceedings of 16\textsuperscript{th} International +Symposium on Distributed Computing} +,year=2002 +,month="October" +,pages="339-353" +} + @unpublished{Sarma02b ,Author="Dipankar Sarma" ,Title="Some dcache\_rcu benchmark numbers" @@ -749,6 +820,19 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell" } } +@unpublished{MingmingCao2002IPCRCU +,Author="Mingming Cao" +,Title="[PATCH]updated ipc lock patch" +,month="October" +,year="2002" +,note="Available: +\url{https://lkml.org/lkml/2002/10/24/262} +[Viewed February 15, 2014]" +,annotation={ + Mingming Cao's patch to introduce RCU to SysV IPC. +} +} + @unpublished{LinusTorvalds2003a ,Author="Linus Torvalds" ,Title="Re: {[PATCH]} small fixes in brlock.h" @@ -982,6 +1066,23 @@ Realtime Applications" } } +@article{MagedMichael04a +,author="Maged M. Michael" +,title="Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects" +,Year="2004" +,Month="June" +,journal="IEEE Transactions on Parallel and Distributed Systems" +,volume="15" +,number="6" +,pages="491-504" +,url="Available: +\url{http://www.research.ibm.com/people/m/michael/ieeetpds-2004.pdf} +[Viewed March 1, 2005]" +,annotation={ + New canonical hazard-pointer citation. +} +} + @phdthesis{PaulEdwardMcKenneyPhD ,author="Paul E. McKenney" ,title="Exploiting Deferred Destruction: From 3660c2813fb6d0ba48ee44bcbf9feddf7218c11d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 3 Dec 2013 09:24:02 -0800 Subject: [PATCH 07/77] rcu: Add ACCESS_ONCE() to ->n_force_qs_lh accesses The ->n_force_qs_lh field is accessed without the benefit of any synchronization, so this commit adds the needed ACCESS_ONCE() wrappers. Yes, increments to ->n_force_qs_lh can be lost, but contention should be low and the field is strictly statistical in nature, so this is not a problem. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/tree.c | 4 ++-- kernel/rcu/tree_trace.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index b3d116cd072d..e64157798624 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2304,7 +2304,7 @@ static void force_quiescent_state(struct rcu_state *rsp) if (rnp_old != NULL) raw_spin_unlock(&rnp_old->fqslock); if (ret) { - rsp->n_force_qs_lh++; + ACCESS_ONCE(rsp->n_force_qs_lh)++; return; } rnp_old = rnp; @@ -2316,7 +2316,7 @@ static void force_quiescent_state(struct rcu_state *rsp) smp_mb__after_unlock_lock(); raw_spin_unlock(&rnp_old->fqslock); if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) { - rsp->n_force_qs_lh++; + ACCESS_ONCE(rsp->n_force_qs_lh)++; raw_spin_unlock_irqrestore(&rnp_old->lock, flags); return; /* Someone beat us to it. */ } diff --git a/kernel/rcu/tree_trace.c b/kernel/rcu/tree_trace.c index 4def475336d4..d1f1e64a6d72 100644 --- a/kernel/rcu/tree_trace.c +++ b/kernel/rcu/tree_trace.c @@ -273,7 +273,7 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) seq_printf(m, "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld/%ld\n", rsp->n_force_qs, rsp->n_force_qs_ngp, rsp->n_force_qs - rsp->n_force_qs_ngp, - rsp->n_force_qs_lh, rsp->qlen_lazy, rsp->qlen); + ACCESS_ONCE(rsp->n_force_qs_lh), rsp->qlen_lazy, rsp->qlen); for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < rcu_num_nodes; rnp++) { if (rnp->level != level) { seq_puts(m, "\n"); From 87de1cfdc55b16b794e245b07322340725149d62 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 3 Dec 2013 10:02:52 -0800 Subject: [PATCH 08/77] rcu: Stop tracking FSF's postal address All of the RCU source files have the usual GPL header, which contains a long-obsolete postal address for FSF. To avoid the need to track the FSF office's movements, this commit substitutes the URL where GPL may be found. Reported-by: Greg KH Reported-by: Steven Rostedt Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/rcupdate.h | 4 ++-- include/linux/rcutiny.h | 4 ++-- include/linux/rcutree.h | 4 ++-- include/linux/srcu.h | 4 ++-- kernel/rcu/rcu.h | 4 ++-- kernel/rcu/srcu.c | 4 ++-- kernel/rcu/tiny.c | 4 ++-- kernel/rcu/tiny_plugin.h | 4 ++-- kernel/rcu/torture.c | 4 ++-- kernel/rcu/tree.c | 4 ++-- kernel/rcu/tree.h | 4 ++-- kernel/rcu/tree_plugin.h | 4 ++-- kernel/rcu/tree_trace.c | 4 ++-- kernel/rcu/update.c | 4 ++-- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 72bf3a01a4ee..b200756ea4c0 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2001 * diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 6f01771b571c..c364e9148de2 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2008 * diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 72137ee8c603..08b084068967 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2008 * diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 9b058eecd403..a2783cb5d275 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright (C) IBM Corporation, 2006 * Copyright (C) Fujitsu, 2012 diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index 79c3877e9c5b..1bd787fddcb2 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2011 * diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index 3318d8284384..5db7e9272d37 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright (C) IBM Corporation, 2006 * Copyright (C) Fujitsu, 2012 diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 1254f312d024..53b95bbf4abb 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2008 * diff --git a/kernel/rcu/tiny_plugin.h b/kernel/rcu/tiny_plugin.h index 280d06cae352..431528520562 100644 --- a/kernel/rcu/tiny_plugin.h +++ b/kernel/rcu/tiny_plugin.h @@ -14,8 +14,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright (c) 2010 Linaro * diff --git a/kernel/rcu/torture.c b/kernel/rcu/torture.c index 732f8ae3086a..ab7dd192a50b 100644 --- a/kernel/rcu/torture.c +++ b/kernel/rcu/torture.c @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright (C) IBM Corporation, 2005, 2006 * diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index e64157798624..321feef0f5c0 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2008 * diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 8c19873f1ac9..75dc3c39a02a 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -13,8 +13,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2008 * diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 6e2ef4b2b920..f9b9cdd36c8d 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -14,8 +14,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright Red Hat, 2009 * Copyright IBM Corporation, 2009 diff --git a/kernel/rcu/tree_trace.c b/kernel/rcu/tree_trace.c index d1f1e64a6d72..5cdc62e1beeb 100644 --- a/kernel/rcu/tree_trace.c +++ b/kernel/rcu/tree_trace.c @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2008 * diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index c54609faf233..fd0d5b5b8e7c 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -12,8 +12,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. * * Copyright IBM Corporation, 2001 * From cb1e78cfa267453bb19e7edafd214c03834b664c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 4 Dec 2013 18:42:03 -0800 Subject: [PATCH 09/77] rcu: Remove ACCESS_ONCE() from jiffies Because jiffies is one of a very few variables marked "volatile", there is no need to use ACCESS_ONCE() when accessing it. This commit therefore removes the redundant ACCESS_ONCE() wrappers. Reported by: Eric Dumazet Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/torture.c | 4 ++-- kernel/rcu/tree.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/rcu/torture.c b/kernel/rcu/torture.c index ab7dd192a50b..022c5312b725 100644 --- a/kernel/rcu/torture.c +++ b/kernel/rcu/torture.c @@ -1352,7 +1352,7 @@ rcu_torture_shutdown(void *arg) unsigned long jiffies_snap; VERBOSE_PRINTK_STRING("rcu_torture_shutdown task started"); - jiffies_snap = ACCESS_ONCE(jiffies); + jiffies_snap = jiffies; while (ULONG_CMP_LT(jiffies_snap, shutdown_time) && !kthread_should_stop()) { delta = shutdown_time - jiffies_snap; @@ -1361,7 +1361,7 @@ rcu_torture_shutdown(void *arg) "rcu_torture_shutdown task: %lu jiffies remaining\n", torture_type, delta); schedule_timeout_interruptible(delta); - jiffies_snap = ACCESS_ONCE(jiffies); + jiffies_snap = jiffies; } if (kthread_should_stop()) { VERBOSE_PRINTK_STRING("rcu_torture_shutdown task stopping"); diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 321feef0f5c0..73c3cd2b87ac 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -837,7 +837,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, * to the next. Only do this for the primary flavor of RCU. */ if (rdp->rsp == rcu_state && - ULONG_CMP_GE(ACCESS_ONCE(jiffies), rdp->rsp->jiffies_resched)) { + ULONG_CMP_GE(jiffies, rdp->rsp->jiffies_resched)) { rdp->rsp->jiffies_resched += 5; resched_cpu(rdp->cpu); } @@ -847,7 +847,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp, static void record_gp_stall_check_time(struct rcu_state *rsp) { - unsigned long j = ACCESS_ONCE(jiffies); + unsigned long j = jiffies; unsigned long j1; rsp->gp_start = j; @@ -1005,7 +1005,7 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) if (rcu_cpu_stall_suppress || !rcu_gp_in_progress(rsp)) return; - j = ACCESS_ONCE(jiffies); + j = jiffies; /* * Lots of memory barriers to reject false positives. From 41f4abd92a34f9c5110bbb870c04f8854604e28d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 5 Dec 2013 15:10:23 -0800 Subject: [PATCH 10/77] rcu: Glue ASCII strings together Split strings make it difficult to find the code that resulted in a given console message, so this commit glues split strings back together despite the resulting long lines. Signed-off-by: Joe Perches Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/rcupdate.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index b200756ea4c0..d946d3660633 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -479,11 +479,9 @@ static inline void rcu_preempt_sleep_check(void) do { \ rcu_preempt_sleep_check(); \ rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map), \ - "Illegal context switch in RCU-bh" \ - " read-side critical section"); \ + "Illegal context switch in RCU-bh read-side critical section"); \ rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map), \ - "Illegal context switch in RCU-sched"\ - " read-side critical section"); \ + "Illegal context switch in RCU-sched read-side critical section"); \ } while (0) #else /* #ifdef CONFIG_PROVE_RCU */ @@ -518,16 +516,14 @@ static inline void rcu_preempt_sleep_check(void) #define __rcu_dereference_check(p, c, space) \ ({ \ typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \ - rcu_lockdep_assert(c, "suspicious rcu_dereference_check()" \ - " usage"); \ + rcu_lockdep_assert(c, "suspicious rcu_dereference_check() usage"); \ rcu_dereference_sparse(p, space); \ smp_read_barrier_depends(); \ ((typeof(*p) __force __kernel *)(_________p1)); \ }) #define __rcu_dereference_protected(p, c, space) \ ({ \ - rcu_lockdep_assert(c, "suspicious rcu_dereference_protected()" \ - " usage"); \ + rcu_lockdep_assert(c, "suspicious rcu_dereference_protected() usage"); \ rcu_dereference_sparse(p, space); \ ((typeof(*p) __force __kernel *)(p)); \ }) @@ -542,8 +538,7 @@ static inline void rcu_preempt_sleep_check(void) ({ \ typeof(p) _________p1 = ACCESS_ONCE(p); \ rcu_lockdep_assert(c, \ - "suspicious rcu_dereference_index_check()" \ - " usage"); \ + "suspicious rcu_dereference_index_check() usage"); \ smp_read_barrier_depends(); \ (_________p1); \ }) From 0adab9b9aa18d7e90337d43567f1eec3d5401b81 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 5 Dec 2013 16:19:15 -0800 Subject: [PATCH 11/77] rcu: Indentation and spacing fixes. This commit outdents expression-statement macros, thus repairing a few line-length complaints. Also fix some spacing errors called out by checkpatch.pl. Signed-off-by: Joe Perches Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/rculist.h | 17 ++++++------ include/linux/rcupdate.h | 58 ++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/include/linux/rculist.h b/include/linux/rculist.h index dbaf99084112..8183b46fbaa2 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -247,9 +247,10 @@ static inline void list_splice_init_rcu(struct list_head *list, * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). */ #define list_entry_rcu(ptr, type, member) \ - ({typeof (*ptr) __rcu *__ptr = (typeof (*ptr) __rcu __force *)ptr; \ - container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \ - }) +({ \ + typeof(*ptr) __rcu *__ptr = (typeof(*ptr) __rcu __force *)ptr; \ + container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \ +}) /** * Where are list_empty_rcu() and list_first_entry_rcu()? @@ -285,11 +286,11 @@ static inline void list_splice_init_rcu(struct list_head *list, * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). */ #define list_first_or_null_rcu(ptr, type, member) \ - ({struct list_head *__ptr = (ptr); \ - struct list_head *__next = ACCESS_ONCE(__ptr->next); \ - likely(__ptr != __next) ? \ - list_entry_rcu(__next, type, member) : NULL; \ - }) +({ \ + struct list_head *__ptr = (ptr); \ + struct list_head *__next = ACCESS_ONCE(__ptr->next); \ + likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \ +}) /** * list_for_each_entry_rcu - iterate over rcu list of given type diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index d946d3660633..278a9da69ec4 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -508,40 +508,40 @@ static inline void rcu_preempt_sleep_check(void) #endif /* #else #ifdef __CHECKER__ */ #define __rcu_access_pointer(p, space) \ - ({ \ - typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \ - rcu_dereference_sparse(p, space); \ - ((typeof(*p) __force __kernel *)(_________p1)); \ - }) +({ \ + typeof(*p) *_________p1 = (typeof(*p) *__force)ACCESS_ONCE(p); \ + rcu_dereference_sparse(p, space); \ + ((typeof(*p) __force __kernel *)(_________p1)); \ +}) #define __rcu_dereference_check(p, c, space) \ - ({ \ - typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \ - rcu_lockdep_assert(c, "suspicious rcu_dereference_check() usage"); \ - rcu_dereference_sparse(p, space); \ - smp_read_barrier_depends(); \ - ((typeof(*p) __force __kernel *)(_________p1)); \ - }) +({ \ + typeof(*p) *_________p1 = (typeof(*p) *__force)ACCESS_ONCE(p); \ + rcu_lockdep_assert(c, "suspicious rcu_dereference_check() usage"); \ + rcu_dereference_sparse(p, space); \ + smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ + ((typeof(*p) __force __kernel *)(_________p1)); \ +}) #define __rcu_dereference_protected(p, c, space) \ - ({ \ - rcu_lockdep_assert(c, "suspicious rcu_dereference_protected() usage"); \ - rcu_dereference_sparse(p, space); \ - ((typeof(*p) __force __kernel *)(p)); \ - }) +({ \ + rcu_lockdep_assert(c, "suspicious rcu_dereference_protected() usage"); \ + rcu_dereference_sparse(p, space); \ + ((typeof(*p) __force __kernel *)(p)); \ +}) #define __rcu_access_index(p, space) \ - ({ \ - typeof(p) _________p1 = ACCESS_ONCE(p); \ - rcu_dereference_sparse(p, space); \ - (_________p1); \ - }) +({ \ + typeof(p) _________p1 = ACCESS_ONCE(p); \ + rcu_dereference_sparse(p, space); \ + (_________p1); \ +}) #define __rcu_dereference_index_check(p, c) \ - ({ \ - typeof(p) _________p1 = ACCESS_ONCE(p); \ - rcu_lockdep_assert(c, \ - "suspicious rcu_dereference_index_check() usage"); \ - smp_read_barrier_depends(); \ - (_________p1); \ - }) +({ \ + typeof(p) _________p1 = ACCESS_ONCE(p); \ + rcu_lockdep_assert(c, \ + "suspicious rcu_dereference_index_check() usage"); \ + smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ + (_________p1); \ +}) /** * RCU_INITIALIZER() - statically initialize an RCU-protected global variable From 88c1863066ccfa456797e12c5d8b4631aa1ad0d0 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 16 Dec 2013 13:24:32 -0800 Subject: [PATCH 12/77] rcu: Define rcu_assign_pointer() in terms of smp_store_release() The new smp_store_release() function provides better guarantees than did rcu_assign_pointer(), and potentially less overhead on some architectures. The guarantee that smp_store_release() provides that rcu_assign_pointer() does that is obscure, but its lack could cause considerable confusion. This guarantee is illustrated by the following code fragment: struct foo { int a; int b; int c; struct foo *next; }; struct foo foo1; struct foo foo2; struct foo __rcu *foop; ... foo2.a = 1; foo2.b = 2; BUG_ON(foo2.c); rcu_assign_pointer(foop, &foo); ... fp = rcu_dereference(foop); fp.c = 3; The current rcu_assign_pointer() semantics permit the BUG_ON() to trigger because rcu_assign_pointer()'s smp_wmb() is not guaranteed to order prior reads against later writes. This commit therefore upgrades rcu_assign_pointer() from smp_wmb() to smp_store_release() to avoid this counter-intuitive outcome. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/rcupdate.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 278a9da69ec4..32decf1a9c6c 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef CONFIG_RCU_TORTURE_TEST extern int rcutorture_runnable; /* for sysctl */ @@ -580,12 +581,7 @@ static inline void rcu_preempt_sleep_check(void) * please be careful when making changes to rcu_assign_pointer() and the * other macros that it invokes. */ -#define rcu_assign_pointer(p, v) \ - do { \ - smp_wmb(); \ - ACCESS_ONCE(p) = RCU_INITIALIZER(v); \ - } while (0) - +#define rcu_assign_pointer(p, v) smp_store_release(&p, RCU_INITIALIZER(v)) /** * rcu_access_pointer() - fetch RCU pointer with no dereferencing From 52e2bb958ac4f9b3c4bdd78606d279852fd72922 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sun, 9 Feb 2014 14:35:11 +0100 Subject: [PATCH 13/77] rcu: Disambiguate CONFIG_RCU_NOCB_CPUs This commit fixes a grammar issue in the rcu_nohz_full_cpu() comment header, so that it is clear that the plural is CPUs not Kconfig options. Signed-off-by: Paul Bolle Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/tree_plugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index f9b9cdd36c8d..fffe4178a23d 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -2893,7 +2893,7 @@ static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp) * CPU unless the grace period has extended for too long. * * This code relies on the fact that all NO_HZ_FULL CPUs are also - * CONFIG_RCU_NOCB_CPUs. + * CONFIG_RCU_NOCB_CPU CPUs. */ static bool rcu_nohz_full_cpu(struct rcu_state *rsp) { From ae1670339c95c3ff96ab10582506cf827c5fecc8 Mon Sep 17 00:00:00 2001 From: Shaibal Dutta Date: Fri, 31 Jan 2014 11:53:06 -0800 Subject: [PATCH 14/77] rcu: Move SRCU grace period work to power efficient workqueue For better use of CPU idle time, allow the scheduler to select the CPU on which the SRCU grace period work would be scheduled. This improves idle residency time and conserves power. This functionality is enabled when CONFIG_WQ_POWER_EFFICIENT is selected. Cc: Lai Jiangshan Cc: "Paul E. McKenney" Cc: Dipankar Sarma Signed-off-by: Shaibal Dutta [zoran.markovic@linaro.org: Rebased to latest kernel version. Added commit message. Fixed code alignment.] Signed-off-by: Zoran Markovic Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/srcu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index 5db7e9272d37..2359779e1daa 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c @@ -398,7 +398,7 @@ void call_srcu(struct srcu_struct *sp, struct rcu_head *head, rcu_batch_queue(&sp->batch_queue, head); if (!sp->running) { sp->running = true; - schedule_delayed_work(&sp->work, 0); + queue_delayed_work(system_power_efficient_wq, &sp->work, 0); } spin_unlock_irqrestore(&sp->queue_lock, flags); } @@ -674,7 +674,8 @@ static void srcu_reschedule(struct srcu_struct *sp) } if (pending) - schedule_delayed_work(&sp->work, SRCU_INTERVAL); + queue_delayed_work(system_power_efficient_wq, + &sp->work, SRCU_INTERVAL); } /* From add1f0995454374d90c9d6b2c420d2fba3d0a4e3 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 12 Feb 2014 12:51:09 -0800 Subject: [PATCH 15/77] fs: Substitute rcu_access_pointer() for rcu_dereference_raw() (Trivial patch.) If the code is looking at the RCU-protected pointer itself, but not dereferencing it, the rcu_dereference() functions can be downgraded to rcu_access_pointer(). This commit makes this downgrade in __alloc_fd(), which simply compares the RCU-protected pointer against NULL with no dereferencing. Signed-off-by: Paul E. McKenney Cc: Alexander Viro Cc: linux-fsdevel@vger.kernel.org Reviewed-by: Josh Triplett --- fs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/file.c b/fs/file.c index db25c2bdfe46..18f7d27855c4 100644 --- a/fs/file.c +++ b/fs/file.c @@ -497,7 +497,7 @@ repeat: error = fd; #if 1 /* Sanity check */ - if (rcu_dereference_raw(fdt->fd[fd]) != NULL) { + if (rcu_access_pointer(fdt->fd[fd]) != NULL) { printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd); rcu_assign_pointer(fdt->fd[fd], NULL); } From 2f33b512a5460578f6cf11d7b7867bed53157c7c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 17 Nov 2013 18:25:48 -0800 Subject: [PATCH 16/77] rcu: Optimize rcu_is_nocb_cpu() for RCU_NOCB_CPU_ALL If CONFIG_RCU_NOCB_CPU_ALL=y, then rcu_is_nocb_cpu() will always return true, however, the current version nevertheless checks rcu_nocb_mask. This commit therefore creates a static inline implementation of rcu_is_nocb_cpu() that unconditionally returns true when CONFIG_RCU_NOCB_CPU_ALL=y. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/rcupdate.h | 6 ++++-- kernel/rcu/tree_plugin.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 72bf3a01a4ee..281c90f8989e 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -1015,11 +1015,13 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) #define kfree_rcu(ptr, rcu_head) \ __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head)) -#ifdef CONFIG_RCU_NOCB_CPU +#if defined(CONFIG_RCU_NOCB_CPU_ALL) +static inline bool rcu_is_nocb_cpu(int cpu) { return true; } +#elif defined(CONFIG_RCU_NOCB_CPU) bool rcu_is_nocb_cpu(int cpu); #else static inline bool rcu_is_nocb_cpu(int cpu) { return false; } -#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */ +#endif /* Only for use by adaptive-ticks code. */ diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 6e2ef4b2b920..39a50b918bff 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -2101,6 +2101,7 @@ static void rcu_init_one_nocb(struct rcu_node *rnp) init_waitqueue_head(&rnp->nocb_gp_wq[1]); } +#ifndef CONFIG_RCU_NOCB_CPU_ALL /* Is the specified CPU a no-CPUs CPU? */ bool rcu_is_nocb_cpu(int cpu) { @@ -2108,6 +2109,7 @@ bool rcu_is_nocb_cpu(int cpu) return cpumask_test_cpu(cpu, rcu_nocb_mask); return false; } +#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ /* * Enqueue the specified string of rcu_head structures onto the specified From ffa83fb565fbc397cbafb4b71fd1cce276d4c3b6 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 17 Nov 2013 19:27:16 -0800 Subject: [PATCH 17/77] rcu: Optimize rcu_needs_cpu() for RCU_NOCB_CPU_ALL If CONFIG_RCU_NOCB_CPU_ALL=y, then rcu_needs_cpu() will always return false, however, the current version nevertheless checks for RCU callbacks. This commit therefore creates a static inline implementation of rcu_needs_cpu() that unconditionally returns false when CONFIG_RCU_NOCB_CPU_ALL=y. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/rcupdate.h | 8 ++++++++ include/linux/rcutiny.h | 6 ------ include/linux/rcutree.h | 2 ++ kernel/rcu/tree.c | 2 +- kernel/rcu/tree_plugin.h | 4 ++++ 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 281c90f8989e..5f7d5f410d50 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -1015,6 +1015,14 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) #define kfree_rcu(ptr, rcu_head) \ __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head)) +#if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL) +static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies) +{ + *delta_jiffies = ULONG_MAX; + return 0; +} +#endif /* #if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL) */ + #if defined(CONFIG_RCU_NOCB_CPU_ALL) static inline bool rcu_is_nocb_cpu(int cpu) { return true; } #elif defined(CONFIG_RCU_NOCB_CPU) diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 6f01771b571c..9524903487d0 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -68,12 +68,6 @@ static inline void kfree_call_rcu(struct rcu_head *head, call_rcu(head, func); } -static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies) -{ - *delta_jiffies = ULONG_MAX; - return 0; -} - static inline void rcu_note_context_switch(int cpu) { rcu_sched_qs(cpu); diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 72137ee8c603..81198c84e268 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -31,7 +31,9 @@ #define __LINUX_RCUTREE_H void rcu_note_context_switch(int cpu); +#ifndef CONFIG_RCU_NOCB_CPU_ALL int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies); +#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ void rcu_cpu_stall_reset(void); /* diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index b3d116cd072d..c2c8234a0291 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2880,7 +2880,7 @@ static int rcu_pending(int cpu) * non-NULL, store an indication of whether all callbacks are lazy. * (If there are no callbacks, all of them are deemed to be lazy.) */ -static int rcu_cpu_has_callbacks(int cpu, bool *all_lazy) +static int __maybe_unused rcu_cpu_has_callbacks(int cpu, bool *all_lazy) { bool al = true; bool hc = false; diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 39a50b918bff..820b06aefbee 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1586,11 +1586,13 @@ static void rcu_prepare_kthreads(int cpu) * Because we not have RCU_FAST_NO_HZ, just check whether this CPU needs * any flavor of RCU. */ +#ifndef CONFIG_RCU_NOCB_CPU_ALL int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies) { *delta_jiffies = ULONG_MAX; return rcu_cpu_has_callbacks(cpu, NULL); } +#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ /* * Because we do not have RCU_FAST_NO_HZ, don't bother cleaning up @@ -1696,6 +1698,7 @@ static bool rcu_try_advance_all_cbs(void) * * The caller must have disabled interrupts. */ +#ifndef CONFIG_RCU_NOCB_CPU_ALL int rcu_needs_cpu(int cpu, unsigned long *dj) { struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu); @@ -1726,6 +1729,7 @@ int rcu_needs_cpu(int cpu, unsigned long *dj) } return 0; } +#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ /* * Prepare a CPU for idle from an RCU perspective. The first major task From f1f399d1281ea339a08469f7e58193624992f620 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 17 Nov 2013 21:08:07 -0800 Subject: [PATCH 18/77] rcu: Optimize RCU_FAST_NO_HZ for RCU_NOCB_CPU_ALL If CONFIG_RCU_NOCB_CPU_ALL=y, then no CPU will ever have RCU callbacks because these callbacks will instead be handled by the rcuo kthreads. However, the current version of RCU_FAST_NO_HZ nevertheless checks for RCU callbacks. This commit therefore creates static inline implementations of rcu_prepare_for_idle() and rcu_cleanup_after_idle() that are no-ops when CONFIG_RCU_NOCB_CPU_ALL=y. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/tree_plugin.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 820b06aefbee..41afc3fbfb6c 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1658,7 +1658,7 @@ extern int tick_nohz_active; * only if it has been awhile since the last time we did so. Afterwards, * if there are any callbacks ready for immediate invocation, return true. */ -static bool rcu_try_advance_all_cbs(void) +static bool __maybe_unused rcu_try_advance_all_cbs(void) { bool cbs_ready = false; struct rcu_data *rdp; @@ -1743,6 +1743,7 @@ int rcu_needs_cpu(int cpu, unsigned long *dj) */ static void rcu_prepare_for_idle(int cpu) { +#ifndef CONFIG_RCU_NOCB_CPU_ALL struct rcu_data *rdp; struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu); struct rcu_node *rnp; @@ -1794,6 +1795,7 @@ static void rcu_prepare_for_idle(int cpu) rcu_accelerate_cbs(rsp, rnp, rdp); raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ } +#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ } /* @@ -1803,11 +1805,12 @@ static void rcu_prepare_for_idle(int cpu) */ static void rcu_cleanup_after_idle(int cpu) { - +#ifndef CONFIG_RCU_NOCB_CPU_ALL if (rcu_is_nocb_cpu(cpu)) return; if (rcu_try_advance_all_cbs()) invoke_rcu_core(); +#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */ } /* From c7e8240db112a128ca09cfc9ee0db1bafd7229ec Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 18 Dec 2013 16:56:22 -0800 Subject: [PATCH 19/77] rcutorture: Print grace-period performance statistics Sometime problems can manifest themselves as unusually slow grace periods. This commit therefore prints the number of rcutorture updates during the test and the number per second. These statistics are harvested from the config.out and qemu-cmd files, and are silently omitted if these files are not available, as would be the case if there was a build failure or a boot-time hang. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- .../selftests/rcutorture/bin/kvm-recheck.sh | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh index baef09f3469b..e3b1af3677e3 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh @@ -31,7 +31,24 @@ do for i in $dirs do configfile=`echo $i | sed -e 's/^.*\///'` - echo $configfile + ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'` + if test -z "$ngps" + then + echo $configfile + else + title="$configfile ------- $ngps grace periods" + dur=`sed -e 's/^.* rcutorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null` + if test -z "$dur" + then + : + else + ngpsps=$((ngps / dur)) + ngpsps=`awk -v ngps=$ngps -v dur=$dur ' + BEGIN { print ngps / dur }' < /dev/null` + title="$title ($ngpsps per second)" + fi + echo $title + fi configcheck.sh $i/.config $i/ConfigFragment parse-build.sh $i/Make.out $configfile parse-rcutorture.sh $i/console.log $configfile From 1219c8636cc51eaed1529c9d5ed4184f726c8f24 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 19 Dec 2013 10:52:55 -0800 Subject: [PATCH 20/77] rcutorture: Print script and arguments to standard output Although the script name and arguments are logged in the results directory, it is more convenient to see it in the output. This commit therefore adds the output of this information. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm-recheck.sh | 7 +++++++ tools/testing/selftests/rcutorture/bin/kvm.sh | 1 + 2 files changed, 8 insertions(+) diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh index e3b1af3677e3..eb2850935c26 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh @@ -27,9 +27,16 @@ PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH for rd in "$@" do + firsttime=1 dirs=`find $rd -name Make.defconfig.out -print | sort | sed -e 's,/[^/]*$,,' | sort -u` for i in $dirs do + if test $firsttime + then + firsttime=0 + resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'` + head -1 $resdir/log + fi configfile=`echo $i | sed -e 's/^.*\///'` ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'` if test -z "$ngps" diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 1b7923bf6a70..f60f98415f13 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -169,6 +169,7 @@ else fi mkdir $resdir/$ds touch $resdir/$ds/log +echo $scriptname $args echo $scriptname $args >> $resdir/$ds/log pwd > $resdir/$ds/testid.txt From 4a261dbceaaece2018ef03b16d5092c09147df28 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 13 Jan 2014 22:57:48 -0800 Subject: [PATCH 21/77] rcutorture: Move common boot flags to kvm-test-1-rcu.sh Currently, most boot flags are calculated in kvm-test-1-rcu.sh, except that rcutorture.test_no_idle_hz and rcutorture.verbose are set up by kvm.sh. This commit promotes one-stop shopping by consolidating the determination of boot flags into kvm-test-1-rcu.sh. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh | 8 ++++---- tools/testing/selftests/rcutorture/bin/kvm.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh index 151b23788935..2cb7facbc86d 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh @@ -6,15 +6,15 @@ # Execute this in the source tree. Do not run it as a background task # because qemu does not seem to like that much. # -# Usage: sh kvm-test-1-rcu.sh config builddir resdir minutes qemu-args bootargs +# Usage: sh kvm-test-1-rcu.sh config builddir resdir minutes qemu-args boot_args # # qemu-args defaults to "" -- you will want "-nographic" if running headless. -# bootargs defaults to "root=/dev/sda noapic selinux=0 console=ttyS0" +# boot_args defaults to "root=/dev/sda noapic selinux=0 console=ttyS0" # "initcall_debug debug rcutorture.stat_interval=15" # "rcutorture.shutdown_secs=$((minutes * 60))" # "rcutorture.rcutorture_runnable=1" # -# Anything you specify for either qemu-args or bootargs is appended to +# Anything you specify for either qemu-args or boot_args is appended to # the default values. The "-smp" value is deduced from the contents of # the config fragment. # @@ -138,7 +138,7 @@ boot_args="`rcutorture_param_onoff "$boot_args" $builddir/.config`" # Generate rcu_barrier() boot parameter boot_args="`rcutorture_param_n_barrier_cbs "$boot_args"`" # Pull in standard rcutorture boot arguments -boot_args="$boot_args rcutorture.stat_interval=15 rcutorture.shutdown_secs=$seconds rcutorture.rcutorture_runnable=1" +boot_args="$boot_args rcutorture.stat_interval=15 rcutorture.shutdown_secs=$seconds rcutorture.rcutorture_runnable=1 rcutorture.test_no_idle_hz=1 rcutorture.verbose=1" echo $QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd if test -n "$RCU_BUILDONLY" diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index f60f98415f13..979881baa80f 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -203,7 +203,7 @@ do fi mkdir "${rd}" echo Results directory: $rd - kvm-test-1-rcu.sh $CONFIGFRAG/$kversion/$CF $builddir $rd $dur "-nographic $RCU_QEMU_ARG" "rcutorture.test_no_idle_hz=1 rcutorture.verbose=1 $RCU_BOOTARGS" + kvm-test-1-rcu.sh $CONFIGFRAG/$kversion/$CF $builddir $rd $dur "-nographic $RCU_QEMU_ARG" "$RCU_BOOTARGS" done # Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier From bad804406ad627591477a87778e0698116f8e7f5 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 13 Jan 2014 23:16:55 -0800 Subject: [PATCH 22/77] rcutorture: Allow kvm-test-1-rcu.sh to pause after build Parallel rcutorture runs is valuable on large systems, but it is not a good idea to do (say) five builds in parallel if each build believes it has the whole system at its disposal, especially if the system is shared. It is also bad to restrict the build to (say) a single CPU just because the corresponding rcutorture run uses only a single CPU. This commit therefore adds a kvm-test-1-rcu.sh ability to pause after the build completes, which will allow kvm.sh to do a number of builds serially (with each build thus having the full system at its disposal), then allow the rcutorture runs to proceed in parallel. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- .../selftests/rcutorture/bin/kvm-test-1-rcu.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh index 2cb7facbc86d..c3a396518113 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh @@ -96,11 +96,23 @@ then cp $builddir/.config $resdir cp $builddir/arch/x86/boot/bzImage $resdir parse-build.sh $resdir/Make.out $title + if test -f $builddir.wait + then + mv $builddir.wait $builddir.ready + fi else cp $builddir/Make*.out $resdir echo Build failed, not running KVM, see $resdir. + if test -f $builddir.wait + then + mv $builddir.wait $builddir.ready + fi exit 1 fi +while test -f $builddir.ready +do + sleep 1 +done minutes=$4 seconds=$(($minutes * 60)) qemu_args=$5 From 16d301cbddeb4fb79126fdcda1509207ac6034ba Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 14 Jan 2014 21:28:57 -0800 Subject: [PATCH 23/77] rcutorture: Move common qemu flags to kvm-test-1.sh Currently, most qemu flags are calculated in kvm-test-1-rcu.sh, except that -nographics is set up by kvm.sh. This commit promotes one-stop shopping by consolidating the determination of qemu flags into kvm-test-1-rcu.sh. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh | 1 + tools/testing/selftests/rcutorture/bin/kvm.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh index c3a396518113..a06a0a6ce5ac 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh @@ -126,6 +126,7 @@ echo ' ---' `date`: Starting kernel QEMU="`identify_qemu $builddir/vmlinux.o`" # Generate -smp qemu argument. +qemu_args="-nographic $qemu_args" cpu_count=`configNR_CPUS.sh $config_template` vcpus=`identify_qemu_vcpus` if test $cpu_count -gt $vcpus diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 979881baa80f..f2113493bbfc 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -203,7 +203,7 @@ do fi mkdir "${rd}" echo Results directory: $rd - kvm-test-1-rcu.sh $CONFIGFRAG/$kversion/$CF $builddir $rd $dur "-nographic $RCU_QEMU_ARG" "$RCU_BOOTARGS" + kvm-test-1-rcu.sh $CONFIGFRAG/$kversion/$CF $builddir $rd $dur "$RCU_QEMU_ARG" "$RCU_BOOTARGS" done # Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier From 061862386e8062046cc980e1be1fc4779159411e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 14 Jan 2014 22:26:09 -0800 Subject: [PATCH 24/77] rcutorture: Reduce SRCU-N number of CPUs Both SRCU-P and SRCU-N specify eight CPUs, which results in four iterations for a parallel run on 32 CPUs. This commit reduces SRCU-N to four CPUs (but leaving SRCU-P at eight) to speed up parallel runs, while maintaining essentially the same test coverage. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/configs/SRCU-N | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N b/tools/testing/selftests/rcutorture/configs/SRCU-N index 10a0e27f4c75..b4c6340d920a 100644 --- a/tools/testing/selftests/rcutorture/configs/SRCU-N +++ b/tools/testing/selftests/rcutorture/configs/SRCU-N @@ -1,6 +1,6 @@ CONFIG_RCU_TRACE=n CONFIG_SMP=y -CONFIG_NR_CPUS=8 +CONFIG_NR_CPUS=4 CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=y CONFIG_PREEMPT_VOLUNTARY=n From 43e38ab3d518352932951bacb99705a3bee9477c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 15 Jan 2014 15:48:41 -0800 Subject: [PATCH 25/77] rcutorture: Enable concurrent rcutorture runs The rcutorture tests run by default range from using one CPU to using sixteen of them. Therefore, rcutorture testing could be sped up significantly simply by running the kernels in parallel. Building them in parallel is not all that helpful: "make -j" is usually a better bet. So this commit takes a new "--cpus" argument that specifies how many CPUs rcutorture is permitted to use for its parallel runs. The default of zero does sequential runs as before. The bin-packing is minimal, and will be grossly suboptimal for some configurations. However, powers of two work reasonably well. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- .../selftests/rcutorture/bin/functions.sh | 1 + .../selftests/rcutorture/bin/kvm-recheck.sh | 4 +- .../rcutorture/bin/kvm-test-1-rcu.sh | 2 +- tools/testing/selftests/rcutorture/bin/kvm.sh | 125 +++++++++++++++--- 4 files changed, 108 insertions(+), 24 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh index 587561d7c035..9b17e810ddc3 100644 --- a/tools/testing/selftests/rcutorture/bin/functions.sh +++ b/tools/testing/selftests/rcutorture/bin/functions.sh @@ -96,6 +96,7 @@ identify_qemu () { echo qemu-system-ppc64 else echo Cannot figure out what qemu command to use! 1>&2 + echo file $1 output: $u # Usually this will be one of /usr/bin/qemu-system-* # Use RCU_QEMU_CMD environment variable or appropriate # argument to top-level script. diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh index eb2850935c26..89b5dbac5327 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh @@ -31,9 +31,9 @@ do dirs=`find $rd -name Make.defconfig.out -print | sort | sed -e 's,/[^/]*$,,' | sort -u` for i in $dirs do - if test $firsttime + if test -n "$firsttime" then - firsttime=0 + firsttime="" resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'` head -1 $resdir/log fi diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh index a06a0a6ce5ac..1b9555b2b0d7 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh @@ -123,7 +123,7 @@ kstarttime=`awk 'BEGIN { print systime() }' < /dev/null` echo ' ---' `date`: Starting kernel # Determine the appropriate flavor of qemu command. -QEMU="`identify_qemu $builddir/vmlinux.o`" +QEMU="`identify_qemu $builddir/vmlinux`" # Generate -smp qemu argument. qemu_args="-nographic $qemu_args" diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index f2113493bbfc..f74f00628afe 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -30,6 +30,10 @@ scriptname=$0 args="$*" +T=/tmp/kvm.sh.$$ +trap 'rm -rf $T' 0 +mkdir $T + dur=30 KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM PATH=${KVM}/bin:$PATH; export PATH @@ -38,6 +42,7 @@ RCU_INITRD="$KVM/initrd"; export RCU_INITRD RCU_KMAKE_ARG=""; export RCU_KMAKE_ARG resdir="" configs="" +cpus=0 ds=`date +%Y.%m.%d-%H:%M:%S` kversion="" @@ -49,6 +54,7 @@ usage () { echo " --builddir absolute-pathname" echo " --buildonly" echo " --configs \"config-file list\"" + echo " --cpus N" echo " --datestamp string" echo " --duration minutes" echo " --interactive" @@ -85,6 +91,11 @@ do configs="$2" shift ;; + --cpus) + checkarg --cpus "(number)" "$#" "$2" '^[0-9]*$' '^--' + cpus=$2 + shift + ;; --datestamp) checkarg --datestamp "(relative pathname)" "$#" "$2" '^[^/]*$' '^--' ds=$2 @@ -168,6 +179,7 @@ else fi fi mkdir $resdir/$ds +echo Results directory: $resdir/$ds touch $resdir/$ds/log echo $scriptname $args echo $scriptname $args >> $resdir/$ds/log @@ -178,33 +190,104 @@ then git status >> $resdir/$ds/testid.txt git rev-parse HEAD >> $resdir/$ds/testid.txt fi -builddir=$KVM/b1 -if ! test -e $builddir -then - mkdir $builddir || : -fi +touch $T/cfgcpu for CF in $configs do - # Running TREE01 multiple times creates TREE01, TREE01.2, TREE01.3, ... - rd=$resdir/$ds/$CF - if test -d "${rd}" + if test -f "$CONFIGFRAG/$kversion/$CF" then - n="`ls -d "${rd}"* | grep '\.[0-9]\+$' | - sed -e 's/^.*\.\([0-9]\+\)/\1/' | - sort -k1n | tail -1`" - if test -z "$n" - then - rd="${rd}.2" - else - n="`expr $n + 1`" - rd="${rd}.${n}" - fi + echo $CF `configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF` >> $T/cfgcpu + else + echo "The --configs file $CF does not exist, terminating." + exit 1 fi - mkdir "${rd}" - echo Results directory: $rd - kvm-test-1-rcu.sh $CONFIGFRAG/$kversion/$CF $builddir $rd $dur "$RCU_QEMU_ARG" "$RCU_BOOTARGS" done +sort -k2nr $T/cfgcpu > $T/cfgcpu.sort + +awk < $T/cfgcpu.sort \ + -v CONFIGDIR="$CONFIGFRAG/$kversion/" \ + -v KVM="$KVM" \ + -v ncpus=$cpus \ + -v rd=$resdir/$ds/ \ + -v dur=$dur \ + -v RCU_QEMU_ARG=$RCU_QEMU_ARG \ + -v RCU_BOOTARGS=$RCU_BOOTARGS \ +'BEGIN { + i = 0; +} + +{ + cf[i] = $1; + cpus[i] = $2; + i++; +} + +function dump(first, pastlast) +{ + print "echo ----start batch----" + jn=1 + for (j = first; j < pastlast; j++) { + builddir=KVM "/b" jn + print "echo ", cf[j], cpus[j] ": Starting build." + print "rm -f " builddir ".*" + print "touch " builddir ".wait" + print "mkdir " builddir " || :" + if (cfrep[cf[j]] == "") { + cfr[j] = cf[j]; + cfrep[cf[j]] = 1; + } else { + cfrep[cf[j]]++; + cfr[j] = cf[j] "." cfrep[cf[j]]; + } + print "mkdir " rd cfr[j] " || :"; + print "kvm-test-1-rcu.sh " CONFIGDIR cf[j], builddir, rd cfr[j], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " builddir ".out 2>&1 &" + print "echo ", cf[j], cpus[j] ": Waiting for build to complete." + print "while test -f " builddir ".wait" + print "do" + print "\tsleep 1" + print "done" + print "echo ", cf[j], cpus[j] ": Build complete." + jn++; + } + k = first + for (j = 1; j < jn; j++) { + builddir=KVM "/b" j + print "rm -f " builddir ".ready" + print "echo ----", cf[k], cpus[k] ": Starting kernel" + k++; + } + print "wait" + print "echo ---- All kernel runs complete" + k = first + for (j = 1; j < jn; j++) { + builddir=KVM "/b" j + print "echo ----", cf[k], cpus[k] ": Build/run results:" + print "cat " builddir ".out" + k++; + } +} + +END { + njobs = i; + nc = ncpus; + first = 0; + for (i = 0; i < njobs; i++) { + if (ncpus == 0) { + dump(i, i + 1); + first = i; + } else if (nc < cpus[i] && i != 0) { + dump(first, i); + first = i; + nc = ncpus; + } + nc -= cpus[i]; + } + if (ncpus != 0) + dump(first, i); +}' > $T/script + +sh $T/script + # Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier echo " --- `date` Test summary:" From db007ab5ce155c90d89220495ee17213f66b7241 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 16 Jan 2014 20:37:50 -0800 Subject: [PATCH 26/77] rcutorture: Fix results-directory error message The message complains about a build directory when it should instead be complaining about the results directory, so this commit fixes it. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh index 1b9555b2b0d7..41ea7810354f 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh @@ -57,7 +57,7 @@ fi resdir=${3} if test -z "$resdir" -o ! -d "$resdir" -o ! -w "$resdir" then - echo "kvm-test-1-rcu.sh :$resdir: Not a writable directory, cannot build into it" + echo "kvm-test-1-rcu.sh :$resdir: Not a writable directory, cannot store results into it" exit 1 fi cp $config_template $resdir/ConfigFragment From a7582815b98c843e6468cad82d01a6c084ed4072 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 17 Jan 2014 03:10:16 -0800 Subject: [PATCH 27/77] rcutorture: Add dryrun capability Actual rcutorture tests take considerable time and machine resources, so it is inconvenient to actually do an rcutorture run when optimizing the bin-packing algorithm. This commit therefore adds a --dryrun argument, which defaults to doing a run, but for which "sched" says to simply print the run schedule and "script" dumps the script without running it. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index f74f00628afe..9fab7c8e76f0 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -35,6 +35,7 @@ trap 'rm -rf $T' 0 mkdir $T dur=30 +dryrun="" KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM PATH=${KVM}/bin:$PATH; export PATH builddir="${KVM}/b1" @@ -56,6 +57,7 @@ usage () { echo " --configs \"config-file list\"" echo " --cpus N" echo " --datestamp string" + echo " --dryrun sched|script" echo " --duration minutes" echo " --interactive" echo " --kmake-arg kernel-make-arguments" @@ -101,6 +103,11 @@ do ds=$2 shift ;; + --dryrun) + checkarg --dryrun "sched|script" $# "$2" 'sched\|script' '^--' + dryrun=$2 + shift + ;; --duration) checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error' dur=$2 @@ -179,9 +186,12 @@ else fi fi mkdir $resdir/$ds -echo Results directory: $resdir/$ds +if test "$dryrun" = "" +then + echo Results directory: $resdir/$ds + echo $scriptname $args +fi touch $resdir/$ds/log -echo $scriptname $args echo $scriptname $args >> $resdir/$ds/log pwd > $resdir/$ds/testid.txt @@ -231,7 +241,7 @@ function dump(first, pastlast) print "echo ", cf[j], cpus[j] ": Starting build." print "rm -f " builddir ".*" print "touch " builddir ".wait" - print "mkdir " builddir " || :" + print "mkdir " builddir " > /dev/null 2>&1 || :" if (cfrep[cf[j]] == "") { cfr[j] = cf[j]; cfrep[cf[j]] = 1; @@ -286,7 +296,28 @@ END { dump(first, i); }' > $T/script -sh $T/script +if test "$dryrun" = script +then + echo CONFIGFRAG="$CONFIGFRAG; export CONFIGFRAG" + echo KVM="$KVM; export KVM" + echo KVPATH="$KVPATH; export KVPATH" + echo PATH="$PATH; export PATH" + echo RCU_BUILDONLY="$RCU_BUILDONLY; export RCU_BUILDONLY" + echo RCU_INITRD="$RCU_INITRD; export RCU_INITRD" + echo RCU_KMAKE_ARG="$RCU_KMAKE_ARG; export RCU_KMAKE_ARG" + echo RCU_QEMU_CMD="$RCU_QEMU_CMD; export RCU_QEMU_CMD" + echo RCU_QEMU_INTERACTIVE="$RCU_QEMU_INTERACTIVE; export RCU_QEMU_INTERACTIVE" + echo RCU_QEMU_MAC="$RCU_QEMU_MAC; export RCU_QEMU_MAC" + cat $T/script + exit 0 +elif test "$dryrun" = sched +then + egrep 'start batch|Starting build\.' $T/script | + sed -e 's/:.*$//' -e 's/^echo //' + exit 0 +else + sh $T/script +fi # Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier From 0ae3f73af5ba8025abcb328913643b291698af35 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 17 Jan 2014 03:29:12 -0800 Subject: [PATCH 28/77] rcutorture: Handle multiple runs of the same test This commit fixes handling numbering of multiple runs of the same test so as to disambiguate output. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 9fab7c8e76f0..ad3779cefdb8 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -238,42 +238,39 @@ function dump(first, pastlast) jn=1 for (j = first; j < pastlast; j++) { builddir=KVM "/b" jn - print "echo ", cf[j], cpus[j] ": Starting build." - print "rm -f " builddir ".*" - print "touch " builddir ".wait" - print "mkdir " builddir " > /dev/null 2>&1 || :" + cpusr[jn] = cpus[j]; if (cfrep[cf[j]] == "") { - cfr[j] = cf[j]; + cfr[jn] = cf[j]; cfrep[cf[j]] = 1; } else { cfrep[cf[j]]++; - cfr[j] = cf[j] "." cfrep[cf[j]]; + cfr[jn] = cf[j] "." cfrep[cf[j]]; } - print "mkdir " rd cfr[j] " || :"; - print "kvm-test-1-rcu.sh " CONFIGDIR cf[j], builddir, rd cfr[j], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " builddir ".out 2>&1 &" - print "echo ", cf[j], cpus[j] ": Waiting for build to complete." + print "echo ", cfr[jn], cpusr[jn] ": Starting build."; + print "rm -f " builddir ".*"; + print "touch " builddir ".wait"; + print "mkdir " builddir " > /dev/null 2>&1 || :"; + print "mkdir " rd cfr[jn] " || :"; + print "kvm-test-1-rcu.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " builddir ".out 2>&1 &" + print "echo ", cfr[jn], cpusr[jn] ": Waiting for build to complete." print "while test -f " builddir ".wait" print "do" print "\tsleep 1" print "done" - print "echo ", cf[j], cpus[j] ": Build complete." + print "echo ", cfr[jn], cpusr[jn] ": Build complete." jn++; } - k = first for (j = 1; j < jn; j++) { builddir=KVM "/b" j print "rm -f " builddir ".ready" - print "echo ----", cf[k], cpus[k] ": Starting kernel" - k++; + print "echo ----", cfr[j], cpusr[j] ": Starting kernel" } print "wait" print "echo ---- All kernel runs complete" - k = first for (j = 1; j < jn; j++) { builddir=KVM "/b" j - print "echo ----", cf[k], cpus[k] ": Build/run results:" + print "echo ----", cfr[j], cpusr[j] ": Build/run results:" print "cat " builddir ".out" - k++; } } From 53954671033dc878acbeef1ecf9ac653c7b1a58f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 17 Jan 2014 14:18:05 -0800 Subject: [PATCH 29/77] rcutorture: Do better bin packing Running the standard set of rcutorture tests on 24 CPUs results in the following sub-optimal schedule: ----start batch---- TREE07 16 ----start batch---- TREE08 16 SRCU-P 8 ----start batch---- TREE01 8 TREE02 8 TREE03 8 ----start batch---- TREE04 8 TREE05 8 TREE06 8 ----start batch---- SRCU-N 4 TINY01 1 TINY02 1 TREE09 1 If one of the eight-CPU runs were to be moved into the first batch, the test suite would complete in four batches rather than five. This commit therefore uses a greedy algorithm to re-order the test entries so that the sequential batching will produce an optimal schedule in this case: ----start batch---- TREE07 16 SRCU-P 8 ----start batch---- TREE08 16 TREE01 8 ----start batch---- TREE02 8 TREE03 8 TREE04 8 ----start batch---- TREE05 8 TREE06 8 SRCU-N 4 TINY01 1 TINY02 1 TREE09 1 Please note that this is still not an optimal bin-packing algorithm, however, it does produce optimal solutions for most common scenarios. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index ad3779cefdb8..18649b87ea6c 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -214,7 +214,42 @@ do done sort -k2nr $T/cfgcpu > $T/cfgcpu.sort -awk < $T/cfgcpu.sort \ +awk < $T/cfgcpu.sort > $T/cfgcpu.pack -v ncpus=$cpus ' +BEGIN { + njobs = 0; +} + +{ + cf[njobs] = $1; + cpus[njobs] = $2; + njobs++; +} + +END { + alldone = 0; + batch = 0; + nc = -1; + while (nc != ncpus) { + batch++; + nc = ncpus; + for (i = 0; i < njobs; i++) { + if (done[i]) + continue; + if (nc >= cpus[i] || nc == ncpus) { + done[i] = batch; + nc -= cpus[i]; + if (nc <= 0) + break; + } + } + } + for (b = 1; b <= batch; b++) + for (i = 0; i < njobs; i++) + if (done[i] == b) + print cf[i], cpus[i]; +}' + +awk < $T/cfgcpu.pack \ -v CONFIGDIR="$CONFIGFRAG/$kversion/" \ -v KVM="$KVM" \ -v ncpus=$cpus \ From 78ad0693233080169e5a01811bd3fcb3966f2d3f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 17 Jan 2014 21:56:57 -0800 Subject: [PATCH 30/77] rcutorture: Add comments, especially on bin packing. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 18649b87ea6c..7ef3b245c778 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -188,6 +188,7 @@ fi mkdir $resdir/$ds if test "$dryrun" = "" then + # Be noisy only if running the script. echo Results directory: $resdir/$ds echo $scriptname $args fi @@ -201,6 +202,7 @@ then git rev-parse HEAD >> $resdir/$ds/testid.txt fi +# Create a file of test-name/#cpus pairs, sorted by decreasing #cpus. touch $T/cfgcpu for CF in $configs do @@ -214,12 +216,14 @@ do done sort -k2nr $T/cfgcpu > $T/cfgcpu.sort +# Use a greedy bin-packing algorithm, sorting the list accordingly. awk < $T/cfgcpu.sort > $T/cfgcpu.pack -v ncpus=$cpus ' BEGIN { njobs = 0; } { + # Read file of tests and corresponding required numbers of CPUs. cf[njobs] = $1; cpus[njobs] = $2; njobs++; @@ -229,26 +233,40 @@ END { alldone = 0; batch = 0; nc = -1; + + # Each pass through the following loop creates on test batch + # that can be executed concurrently given ncpus. Note that a + # given test that requires more than the available CPUs will run in + # their own batch. Such tests just have to make do with what + # is available. while (nc != ncpus) { batch++; nc = ncpus; + + # Each pass through the following loop considers one + # test for inclusion in the current batch. for (i = 0; i < njobs; i++) { if (done[i]) - continue; + continue; # Already part of a batch. if (nc >= cpus[i] || nc == ncpus) { + + # This test fits into the current batch. done[i] = batch; nc -= cpus[i]; if (nc <= 0) - break; + break; # Too-big test in its own batch. } } } + + # Dump out the tests in batch order. for (b = 1; b <= batch; b++) for (i = 0; i < njobs; i++) if (done[i] == b) print cf[i], cpus[i]; }' +# Generate a script to execute the tests in appropriate batches. awk < $T/cfgcpu.pack \ -v CONFIGDIR="$CONFIGFRAG/$kversion/" \ -v KVM="$KVM" \ @@ -267,6 +285,7 @@ awk < $T/cfgcpu.pack \ i++; } +# Dump out the scripting required to run one test batch. function dump(first, pastlast) { print "echo ----start batch----" @@ -313,23 +332,31 @@ END { njobs = i; nc = ncpus; first = 0; + + # Each pass through the following loop considers one test. for (i = 0; i < njobs; i++) { if (ncpus == 0) { + # Sequential test specified, each test its own batch. dump(i, i + 1); first = i; } else if (nc < cpus[i] && i != 0) { + # Out of CPUs, dump out a batch. dump(first, i); first = i; nc = ncpus; } + # Account for the CPUs needed by the current test. nc -= cpus[i]; } + # Dump the last batch. if (ncpus != 0) dump(first, i); }' > $T/script if test "$dryrun" = script then + # Dump out the script, but define the environment variables that + # it needs to run standalone. echo CONFIGFRAG="$CONFIGFRAG; export CONFIGFRAG" echo KVM="$KVM; export KVM" echo KVPATH="$KVPATH; export KVPATH" @@ -344,10 +371,12 @@ then exit 0 elif test "$dryrun" = sched then + # Extract the test run schedule from the script. egrep 'start batch|Starting build\.' $T/script | sed -e 's/:.*$//' -e 's/^echo //' exit 0 else + # Not a dryru, so run the script. sh $T/script fi From df1cc81ba7ce80a681aa7f42cad0b9d93f677a6a Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 17 Jan 2014 22:08:09 -0800 Subject: [PATCH 31/77] rcutorture: Flag tests requiring more CPUs than are available This commit adds a "(!)" flag after the number of CPUs required by a given test if that test requires more than the available number of CPUs. Note that these flags appear only when the number of CPUs is specified using the --cpus argument. In the absence of a --cpus argument, no tests are flagged. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 7ef3b245c778..c099f8695112 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -300,30 +300,34 @@ function dump(first, pastlast) cfrep[cf[j]]++; cfr[jn] = cf[j] "." cfrep[cf[j]]; } - print "echo ", cfr[jn], cpusr[jn] ": Starting build."; + if (cpusr[jn] > ncpus && ncpus != 0) + ovf = "(!)"; + else + ovf = ""; + print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build."; print "rm -f " builddir ".*"; print "touch " builddir ".wait"; print "mkdir " builddir " > /dev/null 2>&1 || :"; print "mkdir " rd cfr[jn] " || :"; print "kvm-test-1-rcu.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " builddir ".out 2>&1 &" - print "echo ", cfr[jn], cpusr[jn] ": Waiting for build to complete." + print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete." print "while test -f " builddir ".wait" print "do" print "\tsleep 1" print "done" - print "echo ", cfr[jn], cpusr[jn] ": Build complete." + print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete." jn++; } for (j = 1; j < jn; j++) { builddir=KVM "/b" j print "rm -f " builddir ".ready" - print "echo ----", cfr[j], cpusr[j] ": Starting kernel" + print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel" } print "wait" print "echo ---- All kernel runs complete" for (j = 1; j < jn; j++) { builddir=KVM "/b" j - print "echo ----", cfr[j], cpusr[j] ": Build/run results:" + print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:" print "cat " builddir ".out" } } From ec256c0f687f40a42472da798e30a1b9ec04cafe Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 17 Jan 2014 22:12:07 -0800 Subject: [PATCH 32/77] rcutorture: Print results directory when dumping results Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index c099f8695112..cde25d8546da 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -386,5 +386,8 @@ fi # Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier +echo +echo echo " --- `date` Test summary:" +echo Results directory: $resdir/$ds kvm-recheck.sh $resdir/$ds From 806274c018e9858320a27b785df761f45c33a56c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 17 Feb 2014 13:13:05 -0800 Subject: [PATCH 33/77] rcutorture: Fix checkpatch complaint This commit does a code-style cleanup so that the first curly brace of an initializer does not appear at the beginning of a line. Signed-off-by: Paul E. McKenney --- kernel/rcu/torture.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/rcu/torture.c b/kernel/rcu/torture.c index 732f8ae3086a..dad67238d086 100644 --- a/kernel/rcu/torture.c +++ b/kernel/rcu/torture.c @@ -170,10 +170,10 @@ static struct rcu_torture __rcu *rcu_torture_current; static unsigned long rcu_torture_current_version; static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN]; static DEFINE_SPINLOCK(rcu_torture_lock); -static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) = - { 0 }; -static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) = - { 0 }; +static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], + rcu_torture_count) = { 0 }; +static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], + rcu_torture_batch) = { 0 }; static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1]; static atomic_t n_rcu_torture_alloc; static atomic_t n_rcu_torture_alloc_fail; From 51b1130eb5823ddb90a9ad07d243031d8cb7ecf2 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 27 Jan 2014 11:49:39 -0800 Subject: [PATCH 34/77] rcutorture: Abstract rcu_torture_random() Because rcu_torture_random() will be used by the locking equivalent to rcutorture, pull it out into its own module. This new module cannot be separately configured, instead, use the Kconfig "select" statement from the Kconfig options of tests depending on it. Suggested-by: Rusty Russell Signed-off-by: Paul E. McKenney --- include/linux/torture.h | 47 +++++++++++++++++ kernel/Makefile | 1 + kernel/rcu/Makefile | 2 +- kernel/rcu/{torture.c => rcutorture.c} | 67 ++++++++---------------- kernel/torture.c | 71 ++++++++++++++++++++++++++ lib/Kconfig.debug | 5 ++ 6 files changed, 147 insertions(+), 46 deletions(-) create mode 100644 include/linux/torture.h rename kernel/rcu/{torture.c => rcutorture.c} (97%) create mode 100644 kernel/torture.c diff --git a/include/linux/torture.h b/include/linux/torture.h new file mode 100644 index 000000000000..979e3e6b378a --- /dev/null +++ b/include/linux/torture.h @@ -0,0 +1,47 @@ +/* + * Common functions for in-kernel torture tests. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright IBM Corporation, 2014 + * + * Author: Paul E. McKenney + */ + +#ifndef __LINUX_TORTURE_H +#define __LINUX_TORTURE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct torture_random_state { + unsigned long trs_state; + long trs_count; +}; + +#define DEFINE_TORTURE_RANDOM(name) struct torture_random_state name = { 0, 0 } + +unsigned long torture_random(struct torture_random_state *trsp); + +#endif /* __LINUX_TORTURE_H */ diff --git a/kernel/Makefile b/kernel/Makefile index bc010ee272b6..5c0e7666811d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_PADATA) += padata.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o +obj-$(CONFIG_TORTURE_TEST) += torture.o $(obj)/configs.o: $(obj)/config_data.h diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile index 01e9ec37a3e3..807ccfbf69b3 100644 --- a/kernel/rcu/Makefile +++ b/kernel/rcu/Makefile @@ -1,5 +1,5 @@ obj-y += update.o srcu.o -obj-$(CONFIG_RCU_TORTURE_TEST) += torture.o +obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_TREE_RCU) += tree.o obj-$(CONFIG_TREE_PREEMPT_RCU) += tree.o obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o diff --git a/kernel/rcu/torture.c b/kernel/rcu/rcutorture.c similarity index 97% rename from kernel/rcu/torture.c rename to kernel/rcu/rcutorture.c index dad67238d086..94b1cd8b214c 100644 --- a/kernel/rcu/torture.c +++ b/kernel/rcu/rcutorture.c @@ -48,6 +48,7 @@ #include #include #include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Paul E. McKenney and Josh Triplett "); @@ -320,32 +321,6 @@ rcu_torture_free(struct rcu_torture *p) spin_unlock_bh(&rcu_torture_lock); } -struct rcu_random_state { - unsigned long rrs_state; - long rrs_count; -}; - -#define RCU_RANDOM_MULT 39916801 /* prime */ -#define RCU_RANDOM_ADD 479001701 /* prime */ -#define RCU_RANDOM_REFRESH 10000 - -#define DEFINE_RCU_RANDOM(name) struct rcu_random_state name = { 0, 0 } - -/* - * Crude but fast random-number generator. Uses a linear congruential - * generator, with occasional help from cpu_clock(). - */ -static unsigned long -rcu_random(struct rcu_random_state *rrsp) -{ - if (--rrsp->rrs_count < 0) { - rrsp->rrs_state += (unsigned long)local_clock(); - rrsp->rrs_count = RCU_RANDOM_REFRESH; - } - rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD; - return swahw32(rrsp->rrs_state); -} - static void rcu_stutter_wait(const char *title) { @@ -365,7 +340,7 @@ rcu_stutter_wait(const char *title) struct rcu_torture_ops { void (*init)(void); int (*readlock)(void); - void (*read_delay)(struct rcu_random_state *rrsp); + void (*read_delay)(struct torture_random_state *rrsp); void (*readunlock)(int idx); int (*completed)(void); void (*deferred_free)(struct rcu_torture *p); @@ -392,7 +367,7 @@ static int rcu_torture_read_lock(void) __acquires(RCU) return 0; } -static void rcu_read_delay(struct rcu_random_state *rrsp) +static void rcu_read_delay(struct torture_random_state *rrsp) { const unsigned long shortdelay_us = 200; const unsigned long longdelay_ms = 50; @@ -401,12 +376,13 @@ static void rcu_read_delay(struct rcu_random_state *rrsp) * period, and we want a long delay occasionally to trigger * force_quiescent_state. */ - if (!(rcu_random(rrsp) % (nrealreaders * 2000 * longdelay_ms))) + if (!(torture_random(rrsp) % (nrealreaders * 2000 * longdelay_ms))) mdelay(longdelay_ms); - if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us))) + if (!(torture_random(rrsp) % (nrealreaders * 2 * shortdelay_us))) udelay(shortdelay_us); #ifdef CONFIG_PREEMPT - if (!preempt_count() && !(rcu_random(rrsp) % (nrealreaders * 20000))) + if (!preempt_count() && + !(torture_random(rrsp) % (nrealreaders * 20000))) preempt_schedule(); /* No QS if preempt_disable() in effect */ #endif } @@ -530,7 +506,7 @@ static int srcu_torture_read_lock(void) __acquires(&srcu_ctl) return srcu_read_lock(&srcu_ctl); } -static void srcu_read_delay(struct rcu_random_state *rrsp) +static void srcu_read_delay(struct torture_random_state *rrsp) { long delay; const long uspertick = 1000000 / HZ; @@ -538,7 +514,8 @@ static void srcu_read_delay(struct rcu_random_state *rrsp) /* We want there to be long-running readers, but not all the time. */ - delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick); + delay = torture_random(rrsp) % + (nrealreaders * 2 * longdelay * uspertick); if (!delay) schedule_timeout_interruptible(longdelay); else @@ -802,7 +779,7 @@ rcu_torture_writer(void *arg) struct rcu_torture *rp; struct rcu_torture *rp1; struct rcu_torture *old_rp; - static DEFINE_RCU_RANDOM(rand); + static DEFINE_TORTURE_RANDOM(rand); VERBOSE_PRINTK_STRING("rcu_torture_writer task started"); set_user_nice(current, 19); @@ -813,7 +790,7 @@ rcu_torture_writer(void *arg) if (rp == NULL) continue; rp->rtort_pipe_count = 0; - udelay(rcu_random(&rand) & 0x3ff); + udelay(torture_random(&rand) & 0x3ff); old_rp = rcu_dereference_check(rcu_torture_current, current == writer_task); rp->rtort_mbtest = 1; @@ -826,7 +803,7 @@ rcu_torture_writer(void *arg) atomic_inc(&rcu_torture_wcount[i]); old_rp->rtort_pipe_count++; if (gp_normal == gp_exp) - exp = !!(rcu_random(&rand) & 0x80); + exp = !!(torture_random(&rand) & 0x80); else exp = gp_exp; if (!exp) { @@ -868,19 +845,19 @@ rcu_torture_writer(void *arg) static int rcu_torture_fakewriter(void *arg) { - DEFINE_RCU_RANDOM(rand); + DEFINE_TORTURE_RANDOM(rand); VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started"); set_user_nice(current, 19); do { - schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); - udelay(rcu_random(&rand) & 0x3ff); + schedule_timeout_uninterruptible(1 + torture_random(&rand)%10); + udelay(torture_random(&rand) & 0x3ff); if (cur_ops->cb_barrier != NULL && - rcu_random(&rand) % (nfakewriters * 8) == 0) { + torture_random(&rand) % (nfakewriters * 8) == 0) { cur_ops->cb_barrier(); } else if (gp_normal == gp_exp) { - if (rcu_random(&rand) & 0x80) + if (torture_random(&rand) & 0x80) cur_ops->sync(); else cur_ops->exp_sync(); @@ -921,7 +898,7 @@ static void rcu_torture_timer(unsigned long unused) int idx; int completed; int completed_end; - static DEFINE_RCU_RANDOM(rand); + static DEFINE_TORTURE_RANDOM(rand); static DEFINE_SPINLOCK(rand_lock); struct rcu_torture *p; int pipe_count; @@ -980,7 +957,7 @@ rcu_torture_reader(void *arg) int completed; int completed_end; int idx; - DEFINE_RCU_RANDOM(rand); + DEFINE_TORTURE_RANDOM(rand); struct rcu_torture *p; int pipe_count; struct timer_list t; @@ -1389,7 +1366,7 @@ rcu_torture_onoff(void *arg) int cpu; unsigned long delta; int maxcpu = -1; - DEFINE_RCU_RANDOM(rand); + DEFINE_TORTURE_RANDOM(rand); int ret; unsigned long starttime; @@ -1403,7 +1380,7 @@ rcu_torture_onoff(void *arg) VERBOSE_PRINTK_STRING("rcu_torture_onoff end holdoff"); } while (!kthread_should_stop()) { - cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1); + cpu = (torture_random(&rand) >> 4) % (maxcpu + 1); if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) { if (verbose) pr_alert("%s" TORTURE_FLAG diff --git a/kernel/torture.c b/kernel/torture.c new file mode 100644 index 000000000000..c82c70f7828e --- /dev/null +++ b/kernel/torture.c @@ -0,0 +1,71 @@ +/* + * Common functions for in-kernel torture tests. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright (C) IBM Corporation, 2014 + * + * Author: Paul E. McKenney + * Based on kernel/rcu/torture.c. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Paul E. McKenney "); + +#define TORTURE_RANDOM_MULT 39916801 /* prime */ +#define TORTURE_RANDOM_ADD 479001701 /* prime */ +#define TORTURE_RANDOM_REFRESH 10000 + +/* + * Crude but fast random-number generator. Uses a linear congruential + * generator, with occasional help from cpu_clock(). + */ +unsigned long +torture_random(struct torture_random_state *trsp) +{ + if (--trsp->trs_count < 0) { + trsp->trs_state += (unsigned long)local_clock(); + trsp->trs_count = TORTURE_RANDOM_REFRESH; + } + trsp->trs_state = trsp->trs_state * TORTURE_RANDOM_MULT + + TORTURE_RANDOM_ADD; + return swahw32(trsp->trs_state); +} +EXPORT_SYMBOL_GPL(torture_random); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index a48abeac753f..2bfb4e5cdf8c 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1141,9 +1141,14 @@ config SPARSE_RCU_POINTER Say N if you are unsure. +config TORTURE_TEST + tristate + default n + config RCU_TORTURE_TEST tristate "torture tests for RCU" depends on DEBUG_KERNEL + select TORTURE_TEST default n help This option provides a kernel module that runs torture tests From daeda23de108fab1202b6843e5adb59de0a261f9 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 27 Jan 2014 12:31:20 -0800 Subject: [PATCH 35/77] rcutorture: Don't create results directory for dryruns This commit prevents the results directory from being created for dryruns. However, a script generated from a dryrun will create the results directory should it be run. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett > $resdir/$ds/log -pwd > $resdir/$ds/testid.txt -if test -d .git -then - git status >> $resdir/$ds/testid.txt - git rev-parse HEAD >> $resdir/$ds/testid.txt + touch $resdir/$ds/log + echo $scriptname $args >> $resdir/$ds/log + + pwd > $resdir/$ds/testid.txt + if test -d .git + then + git status >> $resdir/$ds/testid.txt + git rev-parse HEAD >> $resdir/$ds/testid.txt + fi fi # Create a file of test-name/#cpus pairs, sorted by decreasing #cpus. @@ -371,6 +369,8 @@ then echo RCU_QEMU_CMD="$RCU_QEMU_CMD; export RCU_QEMU_CMD" echo RCU_QEMU_INTERACTIVE="$RCU_QEMU_INTERACTIVE; export RCU_QEMU_INTERACTIVE" echo RCU_QEMU_MAC="$RCU_QEMU_MAC; export RCU_QEMU_MAC" + echo "mkdir -p "$resdir" || :" + echo "mkdir $resdir/$ds" cat $T/script exit 0 elif test "$dryrun" = sched From 9e2502254132261e0ea8010692fd447b1cedf627 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 27 Jan 2014 16:27:00 -0800 Subject: [PATCH 36/77] rcutorture: Abstract torture_param() Create a torture_param() macro and apply it to rcutorture in order to save a few lines of code. This same macro may be applied to other torture frameworks. Signed-off-by: Paul E. McKenney --- include/linux/torture.h | 9 +++- kernel/rcu/rcutorture.c | 103 +++++++++++++--------------------------- 2 files changed, 41 insertions(+), 71 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 979e3e6b378a..5aae880b6b4e 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -35,13 +35,18 @@ #include #include +/* Definitions for a non-string torture-test module parameter. */ +#define torture_param(type, name, init, msg) \ + static type name = init; \ + module_param(name, type, 0444); \ + MODULE_PARM_DESC(name, msg); + +/* Low-rider random number generator. */ struct torture_random_state { unsigned long trs_state; long trs_count; }; - #define DEFINE_TORTURE_RANDOM(name) struct torture_random_state name = { 0, 0 } - unsigned long torture_random(struct torture_random_state *trsp); #endif /* __LINUX_TORTURE_H */ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 94b1cd8b214c..930791e0698d 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -59,78 +59,43 @@ MODULE_ALIAS("rcutorture"); #endif #define MODULE_PARAM_PREFIX "rcutorture." -static int fqs_duration; -module_param(fqs_duration, int, 0444); -MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us), 0 to disable"); -static int fqs_holdoff; -module_param(fqs_holdoff, int, 0444); -MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); -static int fqs_stutter = 3; -module_param(fqs_stutter, int, 0444); -MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); -static bool gp_exp; -module_param(gp_exp, bool, 0444); -MODULE_PARM_DESC(gp_exp, "Use expedited GP wait primitives"); -static bool gp_normal; -module_param(gp_normal, bool, 0444); -MODULE_PARM_DESC(gp_normal, "Use normal (non-expedited) GP wait primitives"); -static int irqreader = 1; -module_param(irqreader, int, 0444); -MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers"); -static int n_barrier_cbs; -module_param(n_barrier_cbs, int, 0444); -MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing"); -static int nfakewriters = 4; -module_param(nfakewriters, int, 0444); -MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads"); -static int nreaders = -1; -module_param(nreaders, int, 0444); -MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); -static int object_debug; -module_param(object_debug, int, 0444); -MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing"); -static int onoff_holdoff; -module_param(onoff_holdoff, int, 0444); -MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)"); -static int onoff_interval; -module_param(onoff_interval, int, 0444); -MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); -static int shuffle_interval = 3; -module_param(shuffle_interval, int, 0444); -MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); -static int shutdown_secs; -module_param(shutdown_secs, int, 0444); -MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), <= zero to disable."); -static int stall_cpu; -module_param(stall_cpu, int, 0444); -MODULE_PARM_DESC(stall_cpu, "Stall duration (s), zero to disable."); -static int stall_cpu_holdoff = 10; -module_param(stall_cpu_holdoff, int, 0444); -MODULE_PARM_DESC(stall_cpu_holdoff, "Time to wait before starting stall (s)."); -static int stat_interval = 60; -module_param(stat_interval, int, 0644); -MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s"); -static int stutter = 5; -module_param(stutter, int, 0444); -MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test"); -static int test_boost = 1; -module_param(test_boost, int, 0444); -MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes."); -static int test_boost_duration = 4; -module_param(test_boost_duration, int, 0444); -MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds."); -static int test_boost_interval = 7; -module_param(test_boost_interval, int, 0444); -MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds."); -static bool test_no_idle_hz = true; -module_param(test_no_idle_hz, bool, 0444); -MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); +torture_param(int, fqs_duration, 0, + "Duration of fqs bursts (us), 0 to disable"); +torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)"); +torture_param(int, fqs_stutter, 3, "Wait time between fqs bursts (s)"); +torture_param(bool, gp_exp, false, "Use expedited GP wait primitives"); +torture_param(bool, gp_normal, false, + "Use normal (non-expedited) GP wait primitives"); +torture_param(int, irqreader, 1, "Allow RCU readers from irq handlers"); +torture_param(int, n_barrier_cbs, 0, + "# of callbacks/kthreads for barrier testing"); +torture_param(int, nfakewriters, 4, "Number of RCU fake writer threads"); +torture_param(int, nreaders, -1, "Number of RCU reader threads"); +torture_param(int, object_debug, 0, + "Enable debug-object double call_rcu() testing"); +torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)"); +torture_param(int, onoff_interval, 0, + "Time between CPU hotplugs (s), 0=disable"); +torture_param(int, shuffle_interval, 3, "Number of seconds between shuffles"); +torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable."); +torture_param(int, stall_cpu, 0, "Stall duration (s), zero to disable."); +torture_param(int, stall_cpu_holdoff, 10, + "Time to wait before starting stall (s)."); +torture_param(int, stat_interval, 60, + "Number of seconds between stats printk()s"); +torture_param(int, stutter, 5, "Number of seconds to run/halt test"); +torture_param(int, test_boost, 1, "Test RCU prio boost: 0=no, 1=maybe, 2=yes."); +torture_param(int, test_boost_duration, 4, + "Duration of each boost test, seconds."); +torture_param(int, test_boost_interval, 7, + "Interval between boost tests, seconds."); +torture_param(bool, test_no_idle_hz, true, + "Test support for tickless idle CPUs"); +torture_param(bool, verbose, false, "Enable verbose debugging printk()s"); + static char *torture_type = "rcu"; module_param(torture_type, charp, 0444); MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)"); -static bool verbose; -module_param(verbose, bool, 0444); -MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s"); #define TORTURE_FLAG "-torture:" #define PRINTK_STRING(s) \ From 5ccf60f23d33afd53568cff4f3f421f2ca624401 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 29 Jan 2014 07:25:25 -0800 Subject: [PATCH 37/77] rcutorture: Rename PRINTK to TOROUT Since it doesn't do printk()s anymore anyway, this commit renames these macros from PRINTK to TOROUT (short for torture output). Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/rcutorture.c | 134 ++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 930791e0698d..34a75b1170e8 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -98,11 +98,11 @@ module_param(torture_type, charp, 0444); MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)"); #define TORTURE_FLAG "-torture:" -#define PRINTK_STRING(s) \ +#define TOROUT_STRING(s) \ do { pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0) -#define VERBOSE_PRINTK_STRING(s) \ +#define VERBOSE_TOROUT_STRING(s) \ do { if (verbose) pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0) -#define VERBOSE_PRINTK_ERRSTRING(s) \ +#define VERBOSE_TOROUT_ERRSTRING(s) \ do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0) static int nrealreaders; @@ -619,12 +619,12 @@ static int rcu_torture_boost(void *arg) struct rcu_boost_inflight rbi = { .inflight = 0 }; struct sched_param sp; - VERBOSE_PRINTK_STRING("rcu_torture_boost started"); + VERBOSE_TOROUT_STRING("rcu_torture_boost started"); /* Set real-time priority. */ sp.sched_priority = 1; if (sched_setscheduler(current, SCHED_FIFO, &sp) < 0) { - VERBOSE_PRINTK_STRING("rcu_torture_boost RT prio failed!"); + VERBOSE_TOROUT_STRING("rcu_torture_boost RT prio failed!"); n_rcu_torture_boost_rterror++; } @@ -652,7 +652,7 @@ static int rcu_torture_boost(void *arg) call_rcu(&rbi.rcu, rcu_torture_boost_cb); if (jiffies - call_rcu_time > test_boost_duration * HZ - HZ / 2) { - VERBOSE_PRINTK_STRING("rcu_torture_boost boosting failed"); + VERBOSE_TOROUT_STRING("rcu_torture_boost boosting failed"); n_rcu_torture_boost_failure++; } call_rcu_time = jiffies; @@ -688,7 +688,7 @@ checkwait: rcu_stutter_wait("rcu_torture_boost"); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); /* Clean up and exit. */ - VERBOSE_PRINTK_STRING("rcu_torture_boost task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_boost task stopping"); rcutorture_shutdown_absorb("rcu_torture_boost"); while (!kthread_should_stop() || rbi.inflight) schedule_timeout_uninterruptible(1); @@ -708,7 +708,7 @@ rcu_torture_fqs(void *arg) unsigned long fqs_resume_time; int fqs_burst_remaining; - VERBOSE_PRINTK_STRING("rcu_torture_fqs task started"); + VERBOSE_TOROUT_STRING("rcu_torture_fqs task started"); do { fqs_resume_time = jiffies + fqs_stutter * HZ; while (ULONG_CMP_LT(jiffies, fqs_resume_time) && @@ -724,7 +724,7 @@ rcu_torture_fqs(void *arg) } rcu_stutter_wait("rcu_torture_fqs"); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); - VERBOSE_PRINTK_STRING("rcu_torture_fqs task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_fqs task stopping"); rcutorture_shutdown_absorb("rcu_torture_fqs"); while (!kthread_should_stop()) schedule_timeout_uninterruptible(1); @@ -746,7 +746,7 @@ rcu_torture_writer(void *arg) struct rcu_torture *old_rp; static DEFINE_TORTURE_RANDOM(rand); - VERBOSE_PRINTK_STRING("rcu_torture_writer task started"); + VERBOSE_TOROUT_STRING("rcu_torture_writer task started"); set_user_nice(current, 19); do { @@ -796,7 +796,7 @@ rcu_torture_writer(void *arg) rcutorture_record_progress(++rcu_torture_current_version); rcu_stutter_wait("rcu_torture_writer"); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); - VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_writer task stopping"); rcutorture_shutdown_absorb("rcu_torture_writer"); while (!kthread_should_stop()) schedule_timeout_uninterruptible(1); @@ -812,7 +812,7 @@ rcu_torture_fakewriter(void *arg) { DEFINE_TORTURE_RANDOM(rand); - VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started"); + VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task started"); set_user_nice(current, 19); do { @@ -834,7 +834,7 @@ rcu_torture_fakewriter(void *arg) rcu_stutter_wait("rcu_torture_fakewriter"); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); - VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task stopping"); rcutorture_shutdown_absorb("rcu_torture_fakewriter"); while (!kthread_should_stop()) schedule_timeout_uninterruptible(1); @@ -928,7 +928,7 @@ rcu_torture_reader(void *arg) struct timer_list t; unsigned long long ts; - VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); + VERBOSE_TOROUT_STRING("rcu_torture_reader task started"); set_user_nice(current, 19); if (irqreader && cur_ops->irq_capable) setup_timer_on_stack(&t, rcu_torture_timer, 0); @@ -978,7 +978,7 @@ rcu_torture_reader(void *arg) schedule(); rcu_stutter_wait("rcu_torture_reader"); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); - VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_reader task stopping"); rcutorture_shutdown_absorb("rcu_torture_reader"); if (irqreader && cur_ops->irq_capable) del_timer_sync(&t); @@ -1099,13 +1099,13 @@ rcu_torture_stats_print(void) static int rcu_torture_stats(void *arg) { - VERBOSE_PRINTK_STRING("rcu_torture_stats task started"); + VERBOSE_TOROUT_STRING("rcu_torture_stats task started"); do { schedule_timeout_interruptible(stat_interval * HZ); rcu_torture_stats_print(); rcutorture_shutdown_absorb("rcu_torture_stats"); } while (!kthread_should_stop()); - VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_stats task stopping"); return 0; } @@ -1183,13 +1183,13 @@ static void rcu_torture_shuffle_tasks(void) static int rcu_torture_shuffle(void *arg) { - VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started"); + VERBOSE_TOROUT_STRING("rcu_torture_shuffle task started"); do { schedule_timeout_interruptible(shuffle_interval * HZ); rcu_torture_shuffle_tasks(); rcutorture_shutdown_absorb("rcu_torture_shuffle"); } while (!kthread_should_stop()); - VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_shuffle task stopping"); return 0; } @@ -1199,7 +1199,7 @@ rcu_torture_shuffle(void *arg) static int rcu_torture_stutter(void *arg) { - VERBOSE_PRINTK_STRING("rcu_torture_stutter task started"); + VERBOSE_TOROUT_STRING("rcu_torture_stutter task started"); do { schedule_timeout_interruptible(stutter * HZ); stutter_pause_test = 1; @@ -1208,7 +1208,7 @@ rcu_torture_stutter(void *arg) stutter_pause_test = 0; rcutorture_shutdown_absorb("rcu_torture_stutter"); } while (!kthread_should_stop()); - VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_stutter task stopping"); return 0; } @@ -1246,7 +1246,7 @@ static void rcutorture_booster_cleanup(int cpu) if (boost_tasks[cpu] == NULL) return; mutex_lock(&boost_mutex); - VERBOSE_PRINTK_STRING("Stopping rcu_torture_boost task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_boost task"); t = boost_tasks[cpu]; boost_tasks[cpu] = NULL; mutex_unlock(&boost_mutex); @@ -1265,13 +1265,13 @@ static int rcutorture_booster_init(int cpu) /* Don't allow time recalculation while creating a new task. */ mutex_lock(&boost_mutex); - VERBOSE_PRINTK_STRING("Creating rcu_torture_boost task"); + VERBOSE_TOROUT_STRING("Creating rcu_torture_boost task"); boost_tasks[cpu] = kthread_create_on_node(rcu_torture_boost, NULL, cpu_to_node(cpu), "rcu_torture_boost"); if (IS_ERR(boost_tasks[cpu])) { retval = PTR_ERR(boost_tasks[cpu]); - VERBOSE_PRINTK_STRING("rcu_torture_boost task create failed"); + VERBOSE_TOROUT_STRING("rcu_torture_boost task create failed"); n_rcu_torture_boost_ktrerror++; boost_tasks[cpu] = NULL; mutex_unlock(&boost_mutex); @@ -1293,7 +1293,7 @@ rcu_torture_shutdown(void *arg) long delta; unsigned long jiffies_snap; - VERBOSE_PRINTK_STRING("rcu_torture_shutdown task started"); + VERBOSE_TOROUT_STRING("rcu_torture_shutdown task started"); jiffies_snap = ACCESS_ONCE(jiffies); while (ULONG_CMP_LT(jiffies_snap, shutdown_time) && !kthread_should_stop()) { @@ -1306,13 +1306,13 @@ rcu_torture_shutdown(void *arg) jiffies_snap = ACCESS_ONCE(jiffies); } if (kthread_should_stop()) { - VERBOSE_PRINTK_STRING("rcu_torture_shutdown task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_shutdown task stopping"); return 0; } /* OK, shut down the system. */ - VERBOSE_PRINTK_STRING("rcu_torture_shutdown task shutting down system"); + VERBOSE_TOROUT_STRING("rcu_torture_shutdown task shutting down system"); shutdown_task = NULL; /* Avoid self-kill deadlock. */ rcu_torture_cleanup(); /* Get the success/failure message. */ kernel_power_off(); /* Shut down the system. */ @@ -1335,14 +1335,14 @@ rcu_torture_onoff(void *arg) int ret; unsigned long starttime; - VERBOSE_PRINTK_STRING("rcu_torture_onoff task started"); + VERBOSE_TOROUT_STRING("rcu_torture_onoff task started"); for_each_online_cpu(cpu) maxcpu = cpu; WARN_ON(maxcpu < 0); if (onoff_holdoff > 0) { - VERBOSE_PRINTK_STRING("rcu_torture_onoff begin holdoff"); + VERBOSE_TOROUT_STRING("rcu_torture_onoff begin holdoff"); schedule_timeout_interruptible(onoff_holdoff * HZ); - VERBOSE_PRINTK_STRING("rcu_torture_onoff end holdoff"); + VERBOSE_TOROUT_STRING("rcu_torture_onoff end holdoff"); } while (!kthread_should_stop()) { cpu = (torture_random(&rand) >> 4) % (maxcpu + 1); @@ -1409,7 +1409,7 @@ rcu_torture_onoff(void *arg) } schedule_timeout_interruptible(onoff_interval * HZ); } - VERBOSE_PRINTK_STRING("rcu_torture_onoff task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_onoff task stopping"); return 0; } @@ -1433,7 +1433,7 @@ static void rcu_torture_onoff_cleanup(void) { if (onoff_task == NULL) return; - VERBOSE_PRINTK_STRING("Stopping rcu_torture_onoff task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_onoff task"); kthread_stop(onoff_task); onoff_task = NULL; } @@ -1460,11 +1460,11 @@ static int rcu_torture_stall(void *args) { unsigned long stop_at; - VERBOSE_PRINTK_STRING("rcu_torture_stall task started"); + VERBOSE_TOROUT_STRING("rcu_torture_stall task started"); if (stall_cpu_holdoff > 0) { - VERBOSE_PRINTK_STRING("rcu_torture_stall begin holdoff"); + VERBOSE_TOROUT_STRING("rcu_torture_stall begin holdoff"); schedule_timeout_interruptible(stall_cpu_holdoff * HZ); - VERBOSE_PRINTK_STRING("rcu_torture_stall end holdoff"); + VERBOSE_TOROUT_STRING("rcu_torture_stall end holdoff"); } if (!kthread_should_stop()) { stop_at = get_seconds() + stall_cpu; @@ -1505,7 +1505,7 @@ static void rcu_torture_stall_cleanup(void) { if (stall_task == NULL) return; - VERBOSE_PRINTK_STRING("Stopping rcu_torture_stall_task."); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_stall_task."); kthread_stop(stall_task); stall_task = NULL; } @@ -1525,7 +1525,7 @@ static int rcu_torture_barrier_cbs(void *arg) struct rcu_head rcu; init_rcu_head_on_stack(&rcu); - VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task started"); + VERBOSE_TOROUT_STRING("rcu_torture_barrier_cbs task started"); set_user_nice(current, 19); do { wait_event(barrier_cbs_wq[myid], @@ -1541,7 +1541,7 @@ static int rcu_torture_barrier_cbs(void *arg) if (atomic_dec_and_test(&barrier_cbs_count)) wake_up(&barrier_wq); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); - VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_barrier_cbs task stopping"); rcutorture_shutdown_absorb("rcu_torture_barrier_cbs"); while (!kthread_should_stop()) schedule_timeout_interruptible(1); @@ -1555,7 +1555,7 @@ static int rcu_torture_barrier(void *arg) { int i; - VERBOSE_PRINTK_STRING("rcu_torture_barrier task starting"); + VERBOSE_TOROUT_STRING("rcu_torture_barrier task starting"); do { atomic_set(&barrier_cbs_invoked, 0); atomic_set(&barrier_cbs_count, n_barrier_cbs); @@ -1578,7 +1578,7 @@ static int rcu_torture_barrier(void *arg) n_barrier_successes++; schedule_timeout_interruptible(HZ / 10); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); - VERBOSE_PRINTK_STRING("rcu_torture_barrier task stopping"); + VERBOSE_TOROUT_STRING("rcu_torture_barrier task stopping"); rcutorture_shutdown_absorb("rcu_torture_barrier"); while (!kthread_should_stop()) schedule_timeout_interruptible(1); @@ -1619,7 +1619,7 @@ static int rcu_torture_barrier_init(void) "rcu_torture_barrier_cbs"); if (IS_ERR(barrier_cbs_tasks[i])) { ret = PTR_ERR(barrier_cbs_tasks[i]); - VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier_cbs"); + VERBOSE_TOROUT_ERRSTRING("Failed to create rcu_torture_barrier_cbs"); barrier_cbs_tasks[i] = NULL; return ret; } @@ -1628,7 +1628,7 @@ static int rcu_torture_barrier_init(void) "rcu_torture_barrier"); if (IS_ERR(barrier_task)) { ret = PTR_ERR(barrier_task); - VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier"); + VERBOSE_TOROUT_ERRSTRING("Failed to create rcu_torture_barrier"); barrier_task = NULL; } return 0; @@ -1640,14 +1640,14 @@ static void rcu_torture_barrier_cleanup(void) int i; if (barrier_task != NULL) { - VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_barrier task"); kthread_stop(barrier_task); barrier_task = NULL; } if (barrier_cbs_tasks != NULL) { for (i = 0; i < n_barrier_cbs; i++) { if (barrier_cbs_tasks[i] != NULL) { - VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier_cbs task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_barrier_cbs task"); kthread_stop(barrier_cbs_tasks[i]); barrier_cbs_tasks[i] = NULL; } @@ -1706,19 +1706,19 @@ rcu_torture_cleanup(void) rcu_torture_barrier_cleanup(); rcu_torture_stall_cleanup(); if (stutter_task) { - VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_stutter task"); kthread_stop(stutter_task); } stutter_task = NULL; if (shuffler_task) { - VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_shuffle task"); kthread_stop(shuffler_task); free_cpumask_var(shuffle_tmp_mask); } shuffler_task = NULL; if (writer_task) { - VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_writer task"); kthread_stop(writer_task); } writer_task = NULL; @@ -1726,7 +1726,7 @@ rcu_torture_cleanup(void) if (reader_tasks) { for (i = 0; i < nrealreaders; i++) { if (reader_tasks[i]) { - VERBOSE_PRINTK_STRING( + VERBOSE_TOROUT_STRING( "Stopping rcu_torture_reader task"); kthread_stop(reader_tasks[i]); } @@ -1740,7 +1740,7 @@ rcu_torture_cleanup(void) if (fakewriter_tasks) { for (i = 0; i < nfakewriters; i++) { if (fakewriter_tasks[i]) { - VERBOSE_PRINTK_STRING( + VERBOSE_TOROUT_STRING( "Stopping rcu_torture_fakewriter task"); kthread_stop(fakewriter_tasks[i]); } @@ -1751,13 +1751,13 @@ rcu_torture_cleanup(void) } if (stats_task) { - VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_stats task"); kthread_stop(stats_task); } stats_task = NULL; if (fqs_task) { - VERBOSE_PRINTK_STRING("Stopping rcu_torture_fqs task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_fqs task"); kthread_stop(fqs_task); } fqs_task = NULL; @@ -1768,7 +1768,7 @@ rcu_torture_cleanup(void) rcutorture_booster_cleanup(i); } if (shutdown_task != NULL) { - VERBOSE_PRINTK_STRING("Stopping rcu_torture_shutdown task"); + VERBOSE_TOROUT_STRING("Stopping rcu_torture_shutdown task"); kthread_stop(shutdown_task); } shutdown_task = NULL; @@ -1924,12 +1924,12 @@ rcu_torture_init(void) /* Start up the kthreads. */ - VERBOSE_PRINTK_STRING("Creating rcu_torture_writer task"); + VERBOSE_TOROUT_STRING("Creating rcu_torture_writer task"); writer_task = kthread_create(rcu_torture_writer, NULL, "rcu_torture_writer"); if (IS_ERR(writer_task)) { firsterr = PTR_ERR(writer_task); - VERBOSE_PRINTK_ERRSTRING("Failed to create writer"); + VERBOSE_TOROUT_ERRSTRING("Failed to create writer"); writer_task = NULL; goto unwind; } @@ -1937,17 +1937,17 @@ rcu_torture_init(void) fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]), GFP_KERNEL); if (fakewriter_tasks == NULL) { - VERBOSE_PRINTK_ERRSTRING("out of memory"); + VERBOSE_TOROUT_ERRSTRING("out of memory"); firsterr = -ENOMEM; goto unwind; } for (i = 0; i < nfakewriters; i++) { - VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task"); + VERBOSE_TOROUT_STRING("Creating rcu_torture_fakewriter task"); fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL, "rcu_torture_fakewriter"); if (IS_ERR(fakewriter_tasks[i])) { firsterr = PTR_ERR(fakewriter_tasks[i]); - VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter"); + VERBOSE_TOROUT_ERRSTRING("Failed to create fakewriter"); fakewriter_tasks[i] = NULL; goto unwind; } @@ -1955,28 +1955,28 @@ rcu_torture_init(void) reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]), GFP_KERNEL); if (reader_tasks == NULL) { - VERBOSE_PRINTK_ERRSTRING("out of memory"); + VERBOSE_TOROUT_ERRSTRING("out of memory"); firsterr = -ENOMEM; goto unwind; } for (i = 0; i < nrealreaders; i++) { - VERBOSE_PRINTK_STRING("Creating rcu_torture_reader task"); + VERBOSE_TOROUT_STRING("Creating rcu_torture_reader task"); reader_tasks[i] = kthread_run(rcu_torture_reader, NULL, "rcu_torture_reader"); if (IS_ERR(reader_tasks[i])) { firsterr = PTR_ERR(reader_tasks[i]); - VERBOSE_PRINTK_ERRSTRING("Failed to create reader"); + VERBOSE_TOROUT_ERRSTRING("Failed to create reader"); reader_tasks[i] = NULL; goto unwind; } } if (stat_interval > 0) { - VERBOSE_PRINTK_STRING("Creating rcu_torture_stats task"); + VERBOSE_TOROUT_STRING("Creating rcu_torture_stats task"); stats_task = kthread_run(rcu_torture_stats, NULL, "rcu_torture_stats"); if (IS_ERR(stats_task)) { firsterr = PTR_ERR(stats_task); - VERBOSE_PRINTK_ERRSTRING("Failed to create stats"); + VERBOSE_TOROUT_ERRSTRING("Failed to create stats"); stats_task = NULL; goto unwind; } @@ -1986,7 +1986,7 @@ rcu_torture_init(void) if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) { firsterr = -ENOMEM; - VERBOSE_PRINTK_ERRSTRING("Failed to alloc mask"); + VERBOSE_TOROUT_ERRSTRING("Failed to alloc mask"); goto unwind; } @@ -1996,7 +1996,7 @@ rcu_torture_init(void) if (IS_ERR(shuffler_task)) { free_cpumask_var(shuffle_tmp_mask); firsterr = PTR_ERR(shuffler_task); - VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler"); + VERBOSE_TOROUT_ERRSTRING("Failed to create shuffler"); shuffler_task = NULL; goto unwind; } @@ -2009,7 +2009,7 @@ rcu_torture_init(void) "rcu_torture_stutter"); if (IS_ERR(stutter_task)) { firsterr = PTR_ERR(stutter_task); - VERBOSE_PRINTK_ERRSTRING("Failed to create stutter"); + VERBOSE_TOROUT_ERRSTRING("Failed to create stutter"); stutter_task = NULL; goto unwind; } @@ -2022,7 +2022,7 @@ rcu_torture_init(void) "rcu_torture_fqs"); if (IS_ERR(fqs_task)) { firsterr = PTR_ERR(fqs_task); - VERBOSE_PRINTK_ERRSTRING("Failed to create fqs"); + VERBOSE_TOROUT_ERRSTRING("Failed to create fqs"); fqs_task = NULL; goto unwind; } @@ -2052,7 +2052,7 @@ rcu_torture_init(void) "rcu_torture_shutdown"); if (IS_ERR(shutdown_task)) { firsterr = PTR_ERR(shutdown_task); - VERBOSE_PRINTK_ERRSTRING("Failed to create shutdown"); + VERBOSE_TOROUT_ERRSTRING("Failed to create shutdown"); shutdown_task = NULL; goto unwind; } From c2884de38e01134ae040d55aa5644049d1bb850f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 29 Jan 2014 07:30:50 -0800 Subject: [PATCH 38/77] rcutorture: Abstract TOROUT_STRING() and friends These diagnostic macros are not confined to torturing RCU, so this commit makes them available to other torture tests. Also removed the do-while from TOROUT_STRING() in response to checkpatch complaints. Signed-off-by: Paul E. McKenney --- include/linux/torture.h | 8 ++++++++ kernel/rcu/rcutorture.c | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 5aae880b6b4e..09be8887fb08 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -41,6 +41,14 @@ module_param(name, type, 0444); \ MODULE_PARM_DESC(name, msg); +#define TORTURE_FLAG "-torture:" +#define TOROUT_STRING(s) \ + pr_alert("%s" TORTURE_FLAG s "\n", torture_type) +#define VERBOSE_TOROUT_STRING(s) \ + do { if (verbose) pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0) +#define VERBOSE_TOROUT_ERRSTRING(s) \ + do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0) + /* Low-rider random number generator. */ struct torture_random_state { unsigned long trs_state; diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 34a75b1170e8..86fd8c11257b 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -97,14 +97,6 @@ static char *torture_type = "rcu"; module_param(torture_type, charp, 0444); MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)"); -#define TORTURE_FLAG "-torture:" -#define TOROUT_STRING(s) \ - do { pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0) -#define VERBOSE_TOROUT_STRING(s) \ - do { if (verbose) pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0) -#define VERBOSE_TOROUT_ERRSTRING(s) \ - do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0) - static int nrealreaders; static struct task_struct *writer_task; static struct task_struct **fakewriter_tasks; From f67a33561e6e5463b548219df98130da95f2e4a7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 29 Jan 2014 07:40:27 -0800 Subject: [PATCH 39/77] rcutorture: Abstract torture_shutdown_absorb() Because handling races between rmmod and normal shutdown is not specific to rcutorture, this commit renames rcutorture_shutdown_absorb() to torture_shutdown_absorb() and pulls it out into then kernel/torture.c module. This implies pulling the fullstop mechanism into kernel/torture.c as well. The exporting of fullstop and fullstop_mutex is ugly and must die. And it does in fact die in later commits that introduce higher-level APIs that encapsulate both of these variables. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett ` --- include/linux/torture.h | 15 +++++++++++ kernel/rcu/rcutorture.c | 57 +++++++++++++---------------------------- kernel/torture.c | 20 +++++++++++++++ 3 files changed, 53 insertions(+), 39 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 09be8887fb08..8474d776c864 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -41,6 +41,18 @@ module_param(name, type, 0444); \ MODULE_PARM_DESC(name, msg); +/* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ +#define FULLSTOP_DONTSTOP 0 /* Normal operation. */ +#define FULLSTOP_SHUTDOWN 1 /* System shutdown with rcutorture running. */ +#define FULLSTOP_RMMOD 2 /* Normal rmmod of rcutorture. */ +extern int fullstop; +/* Protect fullstop transitions and spawning of kthreads. */ +extern struct mutex fullstop_mutex; + +/* Common module parameters. */ +extern char *torture_type; +extern bool verbose; + #define TORTURE_FLAG "-torture:" #define TOROUT_STRING(s) \ pr_alert("%s" TORTURE_FLAG s "\n", torture_type) @@ -57,4 +69,7 @@ struct torture_random_state { #define DEFINE_TORTURE_RANDOM(name) struct torture_random_state name = { 0, 0 } unsigned long torture_random(struct torture_random_state *trsp); +/* Shutdown task absorption, for when the tasks cannot safely be killed. */ +void torture_shutdown_absorb(const char *title); + #endif /* __LINUX_TORTURE_H */ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 86fd8c11257b..a868758a6f9c 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -91,11 +91,15 @@ torture_param(int, test_boost_interval, 7, "Interval between boost tests, seconds."); torture_param(bool, test_no_idle_hz, true, "Test support for tickless idle CPUs"); -torture_param(bool, verbose, false, "Enable verbose debugging printk()s"); -static char *torture_type = "rcu"; +char *torture_type = "rcu"; +EXPORT_SYMBOL_GPL(torture_type); module_param(torture_type, charp, 0444); MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)"); +bool verbose; +EXPORT_SYMBOL_GPL(verbose); +module_param(verbose, bool, 0444); +MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s"); static int nrealreaders; static struct task_struct *writer_task; @@ -200,17 +204,6 @@ static atomic_t barrier_cbs_invoked; /* Barrier callbacks invoked. */ static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */ static DECLARE_WAIT_QUEUE_HEAD(barrier_wq); -/* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ - -#define FULLSTOP_DONTSTOP 0 /* Normal operation. */ -#define FULLSTOP_SHUTDOWN 1 /* System shutdown with rcutorture running. */ -#define FULLSTOP_RMMOD 2 /* Normal rmmod of rcutorture. */ -static int fullstop = FULLSTOP_RMMOD; -/* - * Protect fullstop transitions and spawning of kthreads. - */ -static DEFINE_MUTEX(fullstop_mutex); - /* Forward reference. */ static void rcu_torture_cleanup(void); @@ -231,20 +224,6 @@ rcutorture_shutdown_notify(struct notifier_block *unused1, return NOTIFY_DONE; } -/* - * Absorb kthreads into a kernel function that won't return, so that - * they won't ever access module text or data again. - */ -static void rcutorture_shutdown_absorb(const char *title) -{ - if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) { - pr_notice( - "rcutorture thread %s parking due to system shutdown\n", - title); - schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT); - } -} - /* * Allocate an element from the rcu_tortures pool. */ @@ -286,7 +265,7 @@ rcu_stutter_wait(const char *title) schedule_timeout_interruptible(1); else schedule_timeout_interruptible(round_jiffies_relative(HZ)); - rcutorture_shutdown_absorb(title); + torture_shutdown_absorb(title); } } @@ -681,7 +660,7 @@ checkwait: rcu_stutter_wait("rcu_torture_boost"); /* Clean up and exit. */ VERBOSE_TOROUT_STRING("rcu_torture_boost task stopping"); - rcutorture_shutdown_absorb("rcu_torture_boost"); + torture_shutdown_absorb("rcu_torture_boost"); while (!kthread_should_stop() || rbi.inflight) schedule_timeout_uninterruptible(1); smp_mb(); /* order accesses to ->inflight before stack-frame death. */ @@ -717,7 +696,7 @@ rcu_torture_fqs(void *arg) rcu_stutter_wait("rcu_torture_fqs"); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); VERBOSE_TOROUT_STRING("rcu_torture_fqs task stopping"); - rcutorture_shutdown_absorb("rcu_torture_fqs"); + torture_shutdown_absorb("rcu_torture_fqs"); while (!kthread_should_stop()) schedule_timeout_uninterruptible(1); return 0; @@ -789,7 +768,7 @@ rcu_torture_writer(void *arg) rcu_stutter_wait("rcu_torture_writer"); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); VERBOSE_TOROUT_STRING("rcu_torture_writer task stopping"); - rcutorture_shutdown_absorb("rcu_torture_writer"); + torture_shutdown_absorb("rcu_torture_writer"); while (!kthread_should_stop()) schedule_timeout_uninterruptible(1); return 0; @@ -827,7 +806,7 @@ rcu_torture_fakewriter(void *arg) } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task stopping"); - rcutorture_shutdown_absorb("rcu_torture_fakewriter"); + torture_shutdown_absorb("rcu_torture_fakewriter"); while (!kthread_should_stop()) schedule_timeout_uninterruptible(1); return 0; @@ -971,7 +950,7 @@ rcu_torture_reader(void *arg) rcu_stutter_wait("rcu_torture_reader"); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); VERBOSE_TOROUT_STRING("rcu_torture_reader task stopping"); - rcutorture_shutdown_absorb("rcu_torture_reader"); + torture_shutdown_absorb("rcu_torture_reader"); if (irqreader && cur_ops->irq_capable) del_timer_sync(&t); while (!kthread_should_stop()) @@ -1095,7 +1074,7 @@ rcu_torture_stats(void *arg) do { schedule_timeout_interruptible(stat_interval * HZ); rcu_torture_stats_print(); - rcutorture_shutdown_absorb("rcu_torture_stats"); + torture_shutdown_absorb("rcu_torture_stats"); } while (!kthread_should_stop()); VERBOSE_TOROUT_STRING("rcu_torture_stats task stopping"); return 0; @@ -1179,7 +1158,7 @@ rcu_torture_shuffle(void *arg) do { schedule_timeout_interruptible(shuffle_interval * HZ); rcu_torture_shuffle_tasks(); - rcutorture_shutdown_absorb("rcu_torture_shuffle"); + torture_shutdown_absorb("rcu_torture_shuffle"); } while (!kthread_should_stop()); VERBOSE_TOROUT_STRING("rcu_torture_shuffle task stopping"); return 0; @@ -1198,7 +1177,7 @@ rcu_torture_stutter(void *arg) if (!kthread_should_stop()) schedule_timeout_interruptible(stutter * HZ); stutter_pause_test = 0; - rcutorture_shutdown_absorb("rcu_torture_stutter"); + torture_shutdown_absorb("rcu_torture_stutter"); } while (!kthread_should_stop()); VERBOSE_TOROUT_STRING("rcu_torture_stutter task stopping"); return 0; @@ -1470,7 +1449,7 @@ static int rcu_torture_stall(void *args) rcu_read_unlock(); pr_alert("rcu_torture_stall end.\n"); } - rcutorture_shutdown_absorb("rcu_torture_stall"); + torture_shutdown_absorb("rcu_torture_stall"); while (!kthread_should_stop()) schedule_timeout_interruptible(10 * HZ); return 0; @@ -1534,7 +1513,7 @@ static int rcu_torture_barrier_cbs(void *arg) wake_up(&barrier_wq); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); VERBOSE_TOROUT_STRING("rcu_torture_barrier_cbs task stopping"); - rcutorture_shutdown_absorb("rcu_torture_barrier_cbs"); + torture_shutdown_absorb("rcu_torture_barrier_cbs"); while (!kthread_should_stop()) schedule_timeout_interruptible(1); cur_ops->cb_barrier(); @@ -1571,7 +1550,7 @@ static int rcu_torture_barrier(void *arg) schedule_timeout_interruptible(HZ / 10); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); VERBOSE_TOROUT_STRING("rcu_torture_barrier task stopping"); - rcutorture_shutdown_absorb("rcu_torture_barrier"); + torture_shutdown_absorb("rcu_torture_barrier"); while (!kthread_should_stop()) schedule_timeout_interruptible(1); return 0; diff --git a/kernel/torture.c b/kernel/torture.c index c82c70f7828e..f05042036ae8 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -49,6 +49,11 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Paul E. McKenney "); +int fullstop = FULLSTOP_RMMOD; +EXPORT_SYMBOL_GPL(fullstop); +DEFINE_MUTEX(fullstop_mutex); +EXPORT_SYMBOL_GPL(fullstop_mutex); + #define TORTURE_RANDOM_MULT 39916801 /* prime */ #define TORTURE_RANDOM_ADD 479001701 /* prime */ #define TORTURE_RANDOM_REFRESH 10000 @@ -69,3 +74,18 @@ torture_random(struct torture_random_state *trsp) return swahw32(trsp->trs_state); } EXPORT_SYMBOL_GPL(torture_random); + +/* + * Absorb kthreads into a kernel function that won't return, so that + * they won't ever access module text or data again. + */ +void torture_shutdown_absorb(const char *title) +{ + while (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) { + pr_notice( + "torture thread %s parking due to system shutdown\n", + title); + schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT); + } +} +EXPORT_SYMBOL_GPL(torture_shutdown_absorb); From 3808dc9fab05913060626d7f0edd0f195cb9dcab Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 28 Jan 2014 15:29:21 -0800 Subject: [PATCH 40/77] rcutorture: Abstract torture_shuffle() The torture_shuffle() function forces each CPU in turn to go idle periodically in order to check for problems interacting with per-CPU variables and with dyntick-idle mode. Because this sort of debugging is not specific to RCU, this commit abstracts that functionality. This in turn requires abstracting some additional infrastructure. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 5 ++ kernel/rcu/rcutorture.c | 124 ++++----------------------------- kernel/torture.c | 151 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 109 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 8474d776c864..544a2c33c1ae 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -69,6 +69,11 @@ struct torture_random_state { #define DEFINE_TORTURE_RANDOM(name) struct torture_random_state name = { 0, 0 } unsigned long torture_random(struct torture_random_state *trsp); +/* Task shuffler, which causes CPUs to occasionally go idle. */ +void torture_shuffle_task_register(struct task_struct *tp); +int torture_shuffle_init(long shuffint); +void torture_shuffle_cleanup(void); + /* Shutdown task absorption, for when the tasks cannot safely be killed. */ void torture_shutdown_absorb(const char *title); diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index a868758a6f9c..0380696f1844 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -106,7 +106,6 @@ static struct task_struct *writer_task; static struct task_struct **fakewriter_tasks; static struct task_struct **reader_tasks; static struct task_struct *stats_task; -static struct task_struct *shuffler_task; static struct task_struct *stutter_task; static struct task_struct *fqs_task; static struct task_struct *boost_tasks[NR_CPUS]; @@ -161,7 +160,6 @@ static int max_online; static long n_barrier_attempts; static long n_barrier_successes; static struct list_head rcu_torture_removed; -static cpumask_var_t shuffle_tmp_mask; static int stutter_pause_test; @@ -1080,90 +1078,6 @@ rcu_torture_stats(void *arg) return 0; } -static int rcu_idle_cpu; /* Force all torture tasks off this CPU */ - -/* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case - * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs. - */ -static void rcu_torture_shuffle_tasks(void) -{ - int i; - - cpumask_setall(shuffle_tmp_mask); - get_online_cpus(); - - /* No point in shuffling if there is only one online CPU (ex: UP) */ - if (num_online_cpus() == 1) { - put_online_cpus(); - return; - } - - if (rcu_idle_cpu != -1) - cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask); - - set_cpus_allowed_ptr(current, shuffle_tmp_mask); - - if (reader_tasks) { - for (i = 0; i < nrealreaders; i++) - if (reader_tasks[i]) - set_cpus_allowed_ptr(reader_tasks[i], - shuffle_tmp_mask); - } - if (fakewriter_tasks) { - for (i = 0; i < nfakewriters; i++) - if (fakewriter_tasks[i]) - set_cpus_allowed_ptr(fakewriter_tasks[i], - shuffle_tmp_mask); - } - if (writer_task) - set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask); - if (stats_task) - set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask); - if (stutter_task) - set_cpus_allowed_ptr(stutter_task, shuffle_tmp_mask); - if (fqs_task) - set_cpus_allowed_ptr(fqs_task, shuffle_tmp_mask); - if (shutdown_task) - set_cpus_allowed_ptr(shutdown_task, shuffle_tmp_mask); -#ifdef CONFIG_HOTPLUG_CPU - if (onoff_task) - set_cpus_allowed_ptr(onoff_task, shuffle_tmp_mask); -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ - if (stall_task) - set_cpus_allowed_ptr(stall_task, shuffle_tmp_mask); - if (barrier_cbs_tasks) - for (i = 0; i < n_barrier_cbs; i++) - if (barrier_cbs_tasks[i]) - set_cpus_allowed_ptr(barrier_cbs_tasks[i], - shuffle_tmp_mask); - if (barrier_task) - set_cpus_allowed_ptr(barrier_task, shuffle_tmp_mask); - - if (rcu_idle_cpu == -1) - rcu_idle_cpu = num_online_cpus() - 1; - else - rcu_idle_cpu--; - - put_online_cpus(); -} - -/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the - * system to become idle at a time and cut off its timer ticks. This is meant - * to test the support for such tickless idle CPU in RCU. - */ -static int -rcu_torture_shuffle(void *arg) -{ - VERBOSE_TOROUT_STRING("rcu_torture_shuffle task started"); - do { - schedule_timeout_interruptible(shuffle_interval * HZ); - rcu_torture_shuffle_tasks(); - torture_shutdown_absorb("rcu_torture_shuffle"); - } while (!kthread_should_stop()); - VERBOSE_TOROUT_STRING("rcu_torture_shuffle task stopping"); - return 0; -} - /* Cause the rcutorture test to "stutter", starting and stopping all * threads periodically. */ @@ -1397,6 +1311,7 @@ rcu_torture_onoff_init(void) onoff_task = NULL; return ret; } + torture_shuffle_task_register(onoff_task); return 0; } @@ -1468,6 +1383,7 @@ static int __init rcu_torture_stall_init(void) stall_task = NULL; return ret; } + torture_shuffle_task_register(stall_task); return 0; } @@ -1594,6 +1510,7 @@ static int rcu_torture_barrier_init(void) barrier_cbs_tasks[i] = NULL; return ret; } + torture_shuffle_task_register(barrier_cbs_tasks[i]); } barrier_task = kthread_run(rcu_torture_barrier, NULL, "rcu_torture_barrier"); @@ -1602,6 +1519,7 @@ static int rcu_torture_barrier_init(void) VERBOSE_TOROUT_ERRSTRING("Failed to create rcu_torture_barrier"); barrier_task = NULL; } + torture_shuffle_task_register(barrier_task); return 0; } @@ -1674,6 +1592,8 @@ rcu_torture_cleanup(void) fullstop = FULLSTOP_RMMOD; mutex_unlock(&fullstop_mutex); unregister_reboot_notifier(&rcutorture_shutdown_nb); + + torture_shuffle_cleanup(); /* Must be first task cleaned up. */ rcu_torture_barrier_cleanup(); rcu_torture_stall_cleanup(); if (stutter_task) { @@ -1681,12 +1601,6 @@ rcu_torture_cleanup(void) kthread_stop(stutter_task); } stutter_task = NULL; - if (shuffler_task) { - VERBOSE_TOROUT_STRING("Stopping rcu_torture_shuffle task"); - kthread_stop(shuffler_task); - free_cpumask_var(shuffle_tmp_mask); - } - shuffler_task = NULL; if (writer_task) { VERBOSE_TOROUT_STRING("Stopping rcu_torture_writer task"); @@ -1904,6 +1818,7 @@ rcu_torture_init(void) writer_task = NULL; goto unwind; } + torture_shuffle_task_register(writer_task); wake_up_process(writer_task); fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]), GFP_KERNEL); @@ -1922,6 +1837,7 @@ rcu_torture_init(void) fakewriter_tasks[i] = NULL; goto unwind; } + torture_shuffle_task_register(fakewriter_tasks[i]); } reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]), GFP_KERNEL); @@ -1940,6 +1856,7 @@ rcu_torture_init(void) reader_tasks[i] = NULL; goto unwind; } + torture_shuffle_task_register(reader_tasks[i]); } if (stat_interval > 0) { VERBOSE_TOROUT_STRING("Creating rcu_torture_stats task"); @@ -1951,26 +1868,12 @@ rcu_torture_init(void) stats_task = NULL; goto unwind; } + torture_shuffle_task_register(stats_task); } if (test_no_idle_hz) { - rcu_idle_cpu = num_online_cpus() - 1; - - if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) { - firsterr = -ENOMEM; - VERBOSE_TOROUT_ERRSTRING("Failed to alloc mask"); + firsterr = torture_shuffle_init(shuffle_interval * HZ); + if (firsterr) goto unwind; - } - - /* Create the shuffler thread */ - shuffler_task = kthread_run(rcu_torture_shuffle, NULL, - "rcu_torture_shuffle"); - if (IS_ERR(shuffler_task)) { - free_cpumask_var(shuffle_tmp_mask); - firsterr = PTR_ERR(shuffler_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create shuffler"); - shuffler_task = NULL; - goto unwind; - } } if (stutter < 0) stutter = 0; @@ -1984,6 +1887,7 @@ rcu_torture_init(void) stutter_task = NULL; goto unwind; } + torture_shuffle_task_register(stutter_task); } if (fqs_duration < 0) fqs_duration = 0; @@ -1997,6 +1901,7 @@ rcu_torture_init(void) fqs_task = NULL; goto unwind; } + torture_shuffle_task_register(fqs_task); } if (test_boost_interval < 1) test_boost_interval = 1; @@ -2027,6 +1932,7 @@ rcu_torture_init(void) shutdown_task = NULL; goto unwind; } + torture_shuffle_task_register(shutdown_task); wake_up_process(shutdown_task); } i = rcu_torture_onoff_init(); diff --git a/kernel/torture.c b/kernel/torture.c index f05042036ae8..26058f20ee83 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -75,6 +75,157 @@ torture_random(struct torture_random_state *trsp) } EXPORT_SYMBOL_GPL(torture_random); +/* + * Variables for shuffling. The idea is to ensure that each CPU stays + * idle for an extended period to test interactions with dyntick idle, + * as well as interactions with any per-CPU varibles. + */ +struct shuffle_task { + struct list_head st_l; + struct task_struct *st_t; +}; + +static long shuffle_interval; /* In jiffies. */ +static struct task_struct *shuffler_task; +static cpumask_var_t shuffle_tmp_mask; +static int shuffle_idle_cpu; /* Force all torture tasks off this CPU */ +static struct list_head shuffle_task_list = LIST_HEAD_INIT(shuffle_task_list); +static DEFINE_MUTEX(shuffle_task_mutex); + +/* + * Register a task to be shuffled. If there is no memory, just splat + * and don't bother registering. + */ +void torture_shuffle_task_register(struct task_struct *tp) +{ + struct shuffle_task *stp; + + if (WARN_ON_ONCE(tp == NULL)) + return; + stp = kmalloc(sizeof(*stp), GFP_KERNEL); + if (WARN_ON_ONCE(stp == NULL)) + return; + stp->st_t = tp; + mutex_lock(&shuffle_task_mutex); + list_add(&stp->st_l, &shuffle_task_list); + mutex_unlock(&shuffle_task_mutex); +} +EXPORT_SYMBOL_GPL(torture_shuffle_task_register); + +/* + * Unregister all tasks, for example, at the end of the torture run. + */ +static void torture_shuffle_task_unregister_all(void) +{ + struct shuffle_task *stp; + struct shuffle_task *p; + + mutex_lock(&shuffle_task_mutex); + list_for_each_entry_safe(stp, p, &shuffle_task_list, st_l) { + list_del(&stp->st_l); + kfree(stp); + } + mutex_unlock(&shuffle_task_mutex); +} + +/* Shuffle tasks such that we allow shuffle_idle_cpu to become idle. + * A special case is when shuffle_idle_cpu = -1, in which case we allow + * the tasks to run on all CPUs. + */ +static void torture_shuffle_tasks(void) +{ + struct shuffle_task *stp; + + cpumask_setall(shuffle_tmp_mask); + get_online_cpus(); + + /* No point in shuffling if there is only one online CPU (ex: UP) */ + if (num_online_cpus() == 1) { + put_online_cpus(); + return; + } + + /* Advance to the next CPU. Upon overflow, don't idle any CPUs. */ + shuffle_idle_cpu = cpumask_next(shuffle_idle_cpu, shuffle_tmp_mask); + if (shuffle_idle_cpu >= nr_cpu_ids) + shuffle_idle_cpu = -1; + if (shuffle_idle_cpu != -1) { + cpumask_clear_cpu(shuffle_idle_cpu, shuffle_tmp_mask); + if (cpumask_empty(shuffle_tmp_mask)) { + put_online_cpus(); + return; + } + } + + mutex_lock(&shuffle_task_mutex); + list_for_each_entry(stp, &shuffle_task_list, st_l) + set_cpus_allowed_ptr(stp->st_t, shuffle_tmp_mask); + mutex_unlock(&shuffle_task_mutex); + + put_online_cpus(); +} + +/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the + * system to become idle at a time and cut off its timer ticks. This is meant + * to test the support for such tickless idle CPU in RCU. + */ +static int torture_shuffle(void *arg) +{ + VERBOSE_TOROUT_STRING("torture_shuffle task started"); + do { + schedule_timeout_interruptible(shuffle_interval); + torture_shuffle_tasks(); + torture_shutdown_absorb("torture_shuffle"); + } while (!torture_must_stop()); + VERBOSE_TOROUT_STRING("torture_shuffle task stopping"); + return 0; +} + +/* + * Start the shuffler, with shuffint in jiffies. + */ +int torture_shuffle_init(long shuffint) +{ + int ret; + + shuffle_interval = shuffint; + + shuffle_idle_cpu = -1; + + if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) { + VERBOSE_TOROUT_ERRSTRING("Failed to alloc mask"); + return -ENOMEM; + } + + /* Create the shuffler thread */ + shuffler_task = kthread_run(torture_shuffle, NULL, "torture_shuffle"); + if (IS_ERR(shuffler_task)) { + ret = PTR_ERR(shuffler_task); + free_cpumask_var(shuffle_tmp_mask); + VERBOSE_TOROUT_ERRSTRING("Failed to create shuffler"); + shuffler_task = NULL; + return ret; + } + torture_shuffle_task_register(shuffler_task); + return 0; +} +EXPORT_SYMBOL_GPL(torture_shuffle_init); + +/* + * Stop the shuffling. + */ +void torture_shuffle_cleanup(void) +{ + torture_shuffle_task_unregister_all(); + if (shuffler_task) { + VERBOSE_TOROUT_STRING("Stopping torture_shuffle task"); + kthread_stop(shuffler_task); + free_cpumask_var(shuffle_tmp_mask); + } + shuffler_task = NULL; +} +EXPORT_SYMBOL_GPL(torture_shuffle_cleanup); + /* * Absorb kthreads into a kernel function that won't return, so that * they won't ever access module text or data again. From 2e9e8081d2e7a4efb582a240aa7fee991bbbabb0 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 28 Jan 2014 15:58:22 -0800 Subject: [PATCH 41/77] rcutorture: Abstract torture_onoff() Because online/offline torturing is not specific to RCU, this commit abstracts it into the kernel/torture.c module to allow other torture tests to use it. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 12 +++ kernel/rcu/rcutorture.c | 162 +--------------------------------- kernel/torture.c | 186 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 158 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 544a2c33c1ae..be3694a702e9 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -61,6 +61,18 @@ extern bool verbose; #define VERBOSE_TOROUT_ERRSTRING(s) \ do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0) +/* Definitions for a non-string torture-test module parameter. */ +#define torture_parm(type, name, init, msg) \ + static type name = init; \ + module_param(name, type, 0444); \ + MODULE_PARM_DESC(name, msg); + +/* Definitions for online/offline exerciser. */ +int torture_onoff_init(long ooholdoff, long oointerval); +void torture_onoff_cleanup(void); +char *torture_onoff_stats(char *page); +bool torture_onoff_failures(void); + /* Low-rider random number generator. */ struct torture_random_state { unsigned long trs_state; diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 0380696f1844..0e8b52b71d76 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -110,9 +110,6 @@ static struct task_struct *stutter_task; static struct task_struct *fqs_task; static struct task_struct *boost_tasks[NR_CPUS]; static struct task_struct *shutdown_task; -#ifdef CONFIG_HOTPLUG_CPU -static struct task_struct *onoff_task; -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ static struct task_struct *stall_task; static struct task_struct **barrier_cbs_tasks; static struct task_struct *barrier_task; @@ -147,16 +144,6 @@ static long n_rcu_torture_boost_rterror; static long n_rcu_torture_boost_failure; static long n_rcu_torture_boosts; static long n_rcu_torture_timers; -static long n_offline_attempts; -static long n_offline_successes; -static unsigned long sum_offline; -static int min_offline = -1; -static int max_offline; -static long n_online_attempts; -static long n_online_successes; -static unsigned long sum_online; -static int min_online = -1; -static int max_online; static long n_barrier_attempts; static long n_barrier_successes; static struct list_head rcu_torture_removed; @@ -994,13 +981,7 @@ rcu_torture_printk(char *page) n_rcu_torture_boost_failure, n_rcu_torture_boosts, n_rcu_torture_timers); - page += sprintf(page, - "onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ", - n_online_successes, n_online_attempts, - n_offline_successes, n_offline_attempts, - min_online, max_online, - min_offline, max_offline, - sum_online, sum_offline, HZ); + page = torture_onoff_stats(page); page += sprintf(page, "barrier: %ld/%ld:%ld", n_barrier_successes, n_barrier_attempts, @@ -1204,140 +1185,6 @@ rcu_torture_shutdown(void *arg) return 0; } -#ifdef CONFIG_HOTPLUG_CPU - -/* - * Execute random CPU-hotplug operations at the interval specified - * by the onoff_interval. - */ -static int -rcu_torture_onoff(void *arg) -{ - int cpu; - unsigned long delta; - int maxcpu = -1; - DEFINE_TORTURE_RANDOM(rand); - int ret; - unsigned long starttime; - - VERBOSE_TOROUT_STRING("rcu_torture_onoff task started"); - for_each_online_cpu(cpu) - maxcpu = cpu; - WARN_ON(maxcpu < 0); - if (onoff_holdoff > 0) { - VERBOSE_TOROUT_STRING("rcu_torture_onoff begin holdoff"); - schedule_timeout_interruptible(onoff_holdoff * HZ); - VERBOSE_TOROUT_STRING("rcu_torture_onoff end holdoff"); - } - while (!kthread_should_stop()) { - cpu = (torture_random(&rand) >> 4) % (maxcpu + 1); - if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "rcu_torture_onoff task: offlining %d\n", - torture_type, cpu); - starttime = jiffies; - n_offline_attempts++; - ret = cpu_down(cpu); - if (ret) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "rcu_torture_onoff task: offline %d failed: errno %d\n", - torture_type, cpu, ret); - } else { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "rcu_torture_onoff task: offlined %d\n", - torture_type, cpu); - n_offline_successes++; - delta = jiffies - starttime; - sum_offline += delta; - if (min_offline < 0) { - min_offline = delta; - max_offline = delta; - } - if (min_offline > delta) - min_offline = delta; - if (max_offline < delta) - max_offline = delta; - } - } else if (cpu_is_hotpluggable(cpu)) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "rcu_torture_onoff task: onlining %d\n", - torture_type, cpu); - starttime = jiffies; - n_online_attempts++; - ret = cpu_up(cpu); - if (ret) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "rcu_torture_onoff task: online %d failed: errno %d\n", - torture_type, cpu, ret); - } else { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "rcu_torture_onoff task: onlined %d\n", - torture_type, cpu); - n_online_successes++; - delta = jiffies - starttime; - sum_online += delta; - if (min_online < 0) { - min_online = delta; - max_online = delta; - } - if (min_online > delta) - min_online = delta; - if (max_online < delta) - max_online = delta; - } - } - schedule_timeout_interruptible(onoff_interval * HZ); - } - VERBOSE_TOROUT_STRING("rcu_torture_onoff task stopping"); - return 0; -} - -static int -rcu_torture_onoff_init(void) -{ - int ret; - - if (onoff_interval <= 0) - return 0; - onoff_task = kthread_run(rcu_torture_onoff, NULL, "rcu_torture_onoff"); - if (IS_ERR(onoff_task)) { - ret = PTR_ERR(onoff_task); - onoff_task = NULL; - return ret; - } - torture_shuffle_task_register(onoff_task); - return 0; -} - -static void rcu_torture_onoff_cleanup(void) -{ - if (onoff_task == NULL) - return; - VERBOSE_TOROUT_STRING("Stopping rcu_torture_onoff task"); - kthread_stop(onoff_task); - onoff_task = NULL; -} - -#else /* #ifdef CONFIG_HOTPLUG_CPU */ - -static int -rcu_torture_onoff_init(void) -{ - return 0; -} - -static void rcu_torture_onoff_cleanup(void) -{ -} - -#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */ - /* * CPU-stall kthread. It waits as specified by stall_cpu_holdoff, then * induces a CPU stall for the time specified by stall_cpu. @@ -1657,7 +1504,7 @@ rcu_torture_cleanup(void) kthread_stop(shutdown_task); } shutdown_task = NULL; - rcu_torture_onoff_cleanup(); + torture_onoff_cleanup(); /* Wait for all RCU callbacks to fire. */ @@ -1668,8 +1515,7 @@ rcu_torture_cleanup(void) if (atomic_read(&n_rcu_torture_error) || n_rcu_torture_barrier_error) rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE"); - else if (n_online_successes != n_online_attempts || - n_offline_successes != n_offline_attempts) + else if (torture_onoff_failures()) rcu_torture_print_module_parms(cur_ops, "End of test: RCU_HOTPLUG"); else @@ -1935,7 +1781,7 @@ rcu_torture_init(void) torture_shuffle_task_register(shutdown_task); wake_up_process(shutdown_task); } - i = rcu_torture_onoff_init(); + i = torture_onoff_init(onoff_holdoff * HZ, onoff_interval * HZ); if (i != 0) { firsterr = i; goto unwind; diff --git a/kernel/torture.c b/kernel/torture.c index 26058f20ee83..a7ec8a7d561e 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -54,6 +54,192 @@ EXPORT_SYMBOL_GPL(fullstop); DEFINE_MUTEX(fullstop_mutex); EXPORT_SYMBOL_GPL(fullstop_mutex); +#ifdef CONFIG_HOTPLUG_CPU + +/* + * Variables for online-offline handling. Only present if CPU hotplug + * is enabled, otherwise does nothing. + */ + +static struct task_struct *onoff_task; +static long onoff_holdoff; +static long onoff_interval; +static long n_offline_attempts; +static long n_offline_successes; +static unsigned long sum_offline; +static int min_offline = -1; +static int max_offline; +static long n_online_attempts; +static long n_online_successes; +static unsigned long sum_online; +static int min_online = -1; +static int max_online; + +/* + * Execute random CPU-hotplug operations at the interval specified + * by the onoff_interval. + */ +static int +torture_onoff(void *arg) +{ + int cpu; + unsigned long delta; + int maxcpu = -1; + DEFINE_TORTURE_RANDOM(rand); + int ret; + unsigned long starttime; + + VERBOSE_TOROUT_STRING("torture_onoff task started"); + for_each_online_cpu(cpu) + maxcpu = cpu; + WARN_ON(maxcpu < 0); + if (onoff_holdoff > 0) { + VERBOSE_TOROUT_STRING("torture_onoff begin holdoff"); + schedule_timeout_interruptible(onoff_holdoff); + VERBOSE_TOROUT_STRING("torture_onoff end holdoff"); + } + while (!torture_must_stop()) { + cpu = (torture_random(&rand) >> 4) % (maxcpu + 1); + if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: offlining %d\n", + torture_type, cpu); + starttime = jiffies; + n_offline_attempts++; + ret = cpu_down(cpu); + if (ret) { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: offline %d failed: errno %d\n", + torture_type, cpu, ret); + } else { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: offlined %d\n", + torture_type, cpu); + n_offline_successes++; + delta = jiffies - starttime; + sum_offline += delta; + if (min_offline < 0) { + min_offline = delta; + max_offline = delta; + } + if (min_offline > delta) + min_offline = delta; + if (max_offline < delta) + max_offline = delta; + } + } else if (cpu_is_hotpluggable(cpu)) { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: onlining %d\n", + torture_type, cpu); + starttime = jiffies; + n_online_attempts++; + ret = cpu_up(cpu); + if (ret) { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: online %d failed: errno %d\n", + torture_type, cpu, ret); + } else { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: onlined %d\n", + torture_type, cpu); + n_online_successes++; + delta = jiffies - starttime; + sum_online += delta; + if (min_online < 0) { + min_online = delta; + max_online = delta; + } + if (min_online > delta) + min_online = delta; + if (max_online < delta) + max_online = delta; + } + } + schedule_timeout_interruptible(onoff_interval); + } + VERBOSE_TOROUT_STRING("torture_onoff task stopping"); + return 0; +} + +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ + +/* + * Initiate online-offline handling. + */ +int torture_onoff_init(long ooholdoff, long oointerval) +{ +#ifdef CONFIG_HOTPLUG_CPU + int ret; + + onoff_holdoff = ooholdoff; + onoff_interval = oointerval; + if (onoff_interval <= 0) + return 0; + onoff_task = kthread_run(torture_onoff, NULL, "torture_onoff"); + if (IS_ERR(onoff_task)) { + ret = PTR_ERR(onoff_task); + onoff_task = NULL; + return ret; + } + torture_shuffle_task_register(onoff_task); +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ + return 0; +} +EXPORT_SYMBOL_GPL(torture_onoff_init); + +/* + * Clean up after online/offline testing. + */ +void torture_onoff_cleanup(void) +{ +#ifdef CONFIG_HOTPLUG_CPU + if (onoff_task == NULL) + return; + VERBOSE_TOROUT_STRING("Stopping torture_onoff task"); + kthread_stop(onoff_task); + onoff_task = NULL; +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ +} +EXPORT_SYMBOL_GPL(torture_onoff_cleanup); + +/* + * Print online/offline testing statistics. + */ +char *torture_onoff_stats(char *page) +{ +#ifdef CONFIG_HOTPLUG_CPU + page += sprintf(page, + "onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ", + n_online_successes, n_online_attempts, + n_offline_successes, n_offline_attempts, + min_online, max_online, + min_offline, max_offline, + sum_online, sum_offline, HZ); +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ + return page; +} +EXPORT_SYMBOL_GPL(torture_onoff_stats); + +/* + * Were all the online/offline operations successful? + */ +bool torture_onoff_failures(void) +{ +#ifdef CONFIG_HOTPLUG_CPU + return n_online_successes != n_online_attempts || + n_offline_successes != n_offline_attempts; +#else /* #ifdef CONFIG_HOTPLUG_CPU */ + return false; +#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */ +} +EXPORT_SYMBOL_GPL(torture_onoff_failures); + #define TORTURE_RANDOM_MULT 39916801 /* prime */ #define TORTURE_RANDOM_ADD 479001701 /* prime */ #define TORTURE_RANDOM_REFRESH 10000 From b5daa8f3b3b2b0133ad40e13d4f722070119ce36 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 30 Jan 2014 13:38:09 -0800 Subject: [PATCH 42/77] rcutorture: Abstract torture-test initialization This commit creates torture_init_begin() and torture_init_end() functions to abstract locking and allow the torture_type and verbose variables in kernel/torture.o to become static. With a bit more abstraction, fullstop_mutex will also become static. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 9 +++++---- kernel/rcu/rcutorture.c | 19 ++++++++----------- kernel/torture.c | 27 +++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index be3694a702e9..428d2712be04 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -49,10 +49,6 @@ extern int fullstop; /* Protect fullstop transitions and spawning of kthreads. */ extern struct mutex fullstop_mutex; -/* Common module parameters. */ -extern char *torture_type; -extern bool verbose; - #define TORTURE_FLAG "-torture:" #define TOROUT_STRING(s) \ pr_alert("%s" TORTURE_FLAG s "\n", torture_type) @@ -89,4 +85,9 @@ void torture_shuffle_cleanup(void); /* Shutdown task absorption, for when the tasks cannot safely be killed. */ void torture_shutdown_absorb(const char *title); +/* Initialization and cleanup. */ + +void torture_init_begin(char *ttype, bool v); +void torture_init_end(void); + #endif /* __LINUX_TORTURE_H */ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 0e8b52b71d76..93aca2f9261e 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -91,15 +91,12 @@ torture_param(int, test_boost_interval, 7, "Interval between boost tests, seconds."); torture_param(bool, test_no_idle_hz, true, "Test support for tickless idle CPUs"); +torture_param(bool, verbose, true, + "Enable verbose debugging printk()s"); -char *torture_type = "rcu"; -EXPORT_SYMBOL_GPL(torture_type); +static char *torture_type = "rcu"; module_param(torture_type, charp, 0444); MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)"); -bool verbose; -EXPORT_SYMBOL_GPL(verbose); -module_param(verbose, bool, 0444); -MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s"); static int nrealreaders; static struct task_struct *writer_task; @@ -1425,8 +1422,8 @@ rcu_torture_cleanup(void) { int i; - mutex_lock(&fullstop_mutex); rcutorture_record_test_transition(); + mutex_lock(&fullstop_mutex); if (fullstop == FULLSTOP_SHUTDOWN) { pr_warn(/* but going down anyway, so... */ "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); @@ -1589,7 +1586,7 @@ rcu_torture_init(void) &rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops, }; - mutex_lock(&fullstop_mutex); + torture_init_begin(torture_type, verbose); /* Process args and tell the world that the torturer is on the job. */ for (i = 0; i < ARRAY_SIZE(torture_ops); i++) { @@ -1604,7 +1601,7 @@ rcu_torture_init(void) for (i = 0; i < ARRAY_SIZE(torture_ops); i++) pr_alert(" %s", torture_ops[i]->name); pr_alert("\n"); - mutex_unlock(&fullstop_mutex); + torture_init_end(); return -EINVAL; } if (cur_ops->fqs == NULL && fqs_duration != 0) { @@ -1800,11 +1797,11 @@ rcu_torture_init(void) if (object_debug) rcu_test_debug_objects(); rcutorture_record_test_transition(); - mutex_unlock(&fullstop_mutex); + torture_init_end(); return 0; unwind: - mutex_unlock(&fullstop_mutex); + torture_init_end(); rcu_torture_cleanup(); return firsterr; } diff --git a/kernel/torture.c b/kernel/torture.c index a7ec8a7d561e..828d0b1a49b8 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -49,6 +49,9 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Paul E. McKenney "); +static char *torture_type; +static bool verbose; + int fullstop = FULLSTOP_RMMOD; EXPORT_SYMBOL_GPL(fullstop); DEFINE_MUTEX(fullstop_mutex); @@ -426,3 +429,27 @@ void torture_shutdown_absorb(const char *title) } } EXPORT_SYMBOL_GPL(torture_shutdown_absorb); + +/* + * Initialize torture module. Please note that this is -not- invoked via + * the usual module_init() mechanism, but rather by an explicit call from + * the client torture module. This call must be paired with a later + * torture_init_end(). + */ +void __init torture_init_begin(char *ttype, bool v) +{ + mutex_lock(&fullstop_mutex); + torture_type = ttype; + verbose = v; + +} +EXPORT_SYMBOL_GPL(torture_init_begin); + +/* + * Tell the torture module that initialization is complete. + */ +void __init torture_init_end(void) +{ + mutex_unlock(&fullstop_mutex); +} +EXPORT_SYMBOL_GPL(torture_init_end); From cc47ae0830264f07442070b36fe0d0a4d4e3c313 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 30 Jan 2014 14:21:11 -0800 Subject: [PATCH 43/77] rcutorture: Abstract torture-test cleanup This commit creates a torture_cleanup() that handles the generic cleanup actions local to kernel/torture.c. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 4 +--- kernel/rcu/rcutorture.c | 11 +---------- kernel/torture.c | 30 ++++++++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 428d2712be04..31d69930e5cf 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -65,7 +65,6 @@ extern struct mutex fullstop_mutex; /* Definitions for online/offline exerciser. */ int torture_onoff_init(long ooholdoff, long oointerval); -void torture_onoff_cleanup(void); char *torture_onoff_stats(char *page); bool torture_onoff_failures(void); @@ -80,14 +79,13 @@ unsigned long torture_random(struct torture_random_state *trsp); /* Task shuffler, which causes CPUs to occasionally go idle. */ void torture_shuffle_task_register(struct task_struct *tp); int torture_shuffle_init(long shuffint); -void torture_shuffle_cleanup(void); /* Shutdown task absorption, for when the tasks cannot safely be killed. */ void torture_shutdown_absorb(const char *title); /* Initialization and cleanup. */ - void torture_init_begin(char *ttype, bool v); void torture_init_end(void); +bool torture_cleanup(void); #endif /* __LINUX_TORTURE_H */ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 93aca2f9261e..68a689fc6ffa 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1423,21 +1423,13 @@ rcu_torture_cleanup(void) int i; rcutorture_record_test_transition(); - mutex_lock(&fullstop_mutex); - if (fullstop == FULLSTOP_SHUTDOWN) { - pr_warn(/* but going down anyway, so... */ - "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); - mutex_unlock(&fullstop_mutex); - schedule_timeout_uninterruptible(10); + if (torture_cleanup()) { if (cur_ops->cb_barrier != NULL) cur_ops->cb_barrier(); return; } - fullstop = FULLSTOP_RMMOD; - mutex_unlock(&fullstop_mutex); unregister_reboot_notifier(&rcutorture_shutdown_nb); - torture_shuffle_cleanup(); /* Must be first task cleaned up. */ rcu_torture_barrier_cleanup(); rcu_torture_stall_cleanup(); if (stutter_task) { @@ -1501,7 +1493,6 @@ rcu_torture_cleanup(void) kthread_stop(shutdown_task); } shutdown_task = NULL; - torture_onoff_cleanup(); /* Wait for all RCU callbacks to fire. */ diff --git a/kernel/torture.c b/kernel/torture.c index 828d0b1a49b8..41ae5cc3c4c3 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -199,7 +199,7 @@ EXPORT_SYMBOL_GPL(torture_onoff_init); /* * Clean up after online/offline testing. */ -void torture_onoff_cleanup(void) +static void torture_onoff_cleanup(void) { #ifdef CONFIG_HOTPLUG_CPU if (onoff_task == NULL) @@ -403,7 +403,7 @@ EXPORT_SYMBOL_GPL(torture_shuffle_init); /* * Stop the shuffling. */ -void torture_shuffle_cleanup(void) +static void torture_shuffle_cleanup(void) { torture_shuffle_task_unregister_all(); if (shuffler_task) { @@ -453,3 +453,29 @@ void __init torture_init_end(void) mutex_unlock(&fullstop_mutex); } EXPORT_SYMBOL_GPL(torture_init_end); + +/* + * Clean up torture module. Please note that this is -not- invoked via + * the usual module_exit() mechanism, but rather by an explicit call from + * the client torture module. Returns true if a race with system shutdown + * is detected. + * + * This must be called before the caller starts shutting down its own + * kthreads. + */ +bool torture_cleanup(void) +{ + mutex_lock(&fullstop_mutex); + if (fullstop == FULLSTOP_SHUTDOWN) { + pr_warn("Concurrent rmmod and shutdown illegal!\n"); + mutex_unlock(&fullstop_mutex); + schedule_timeout_uninterruptible(10); + return true; + } + fullstop = FULLSTOP_RMMOD; + mutex_unlock(&fullstop_mutex); + torture_shuffle_cleanup(); + torture_onoff_cleanup(); + return false; +} +EXPORT_SYMBOL_GPL(torture_cleanup); From 3c626237eb359cf125051f2fe8b419ddae0f5291 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 30 Jan 2014 15:29:29 -0800 Subject: [PATCH 44/77] rcutorture: Print dates when doing parallel rcutorture runs Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 521f9e01074d..242b52d11cf9 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -286,7 +286,7 @@ awk < $T/cfgcpu.pack \ # Dump out the scripting required to run one test batch. function dump(first, pastlast) { - print "echo ----start batch----" + print "echo ----Start batch: `date`" jn=1 for (j = first; j < pastlast; j++) { builddir=KVM "/b" jn @@ -302,27 +302,27 @@ function dump(first, pastlast) ovf = "(!)"; else ovf = ""; - print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build."; + print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date`"; print "rm -f " builddir ".*"; print "touch " builddir ".wait"; print "mkdir " builddir " > /dev/null 2>&1 || :"; print "mkdir " rd cfr[jn] " || :"; print "kvm-test-1-rcu.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " builddir ".out 2>&1 &" - print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete." + print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`" print "while test -f " builddir ".wait" print "do" print "\tsleep 1" print "done" - print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete." + print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date`" jn++; } for (j = 1; j < jn; j++) { builddir=KVM "/b" j print "rm -f " builddir ".ready" - print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel" + print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`" } print "wait" - print "echo ---- All kernel runs complete" + print "echo ---- All kernel runs complete. `date`" for (j = 1; j < jn; j++) { builddir=KVM "/b" j print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:" From 4622b487ecf0094401ac10e504606e5cbdea5a6e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 30 Jan 2014 15:37:19 -0800 Subject: [PATCH 45/77] rcutorture: Abstract torture_shutdown_notify() Because handling the race between rmmod and system shutdown is not specific to RCU, this commit abstracts torture_shutdown_notify(), placing this code into kernel/torture.c. This change also allows fullstop_mutex to be private to kernel/torture.c. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 2 -- kernel/rcu/rcutorture.c | 23 ----------------------- kernel/torture.c | 29 ++++++++++++++++++++++++----- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 31d69930e5cf..742d8a402f19 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -46,8 +46,6 @@ #define FULLSTOP_SHUTDOWN 1 /* System shutdown with rcutorture running. */ #define FULLSTOP_RMMOD 2 /* Normal rmmod of rcutorture. */ extern int fullstop; -/* Protect fullstop transitions and spawning of kthreads. */ -extern struct mutex fullstop_mutex; #define TORTURE_FLAG "-torture:" #define TOROUT_STRING(s) \ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 68a689fc6ffa..2560e9313887 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -189,23 +189,6 @@ static DECLARE_WAIT_QUEUE_HEAD(barrier_wq); /* Forward reference. */ static void rcu_torture_cleanup(void); -/* - * Detect and respond to a system shutdown. - */ -static int -rcutorture_shutdown_notify(struct notifier_block *unused1, - unsigned long unused2, void *unused3) -{ - mutex_lock(&fullstop_mutex); - if (fullstop == FULLSTOP_DONTSTOP) - fullstop = FULLSTOP_SHUTDOWN; - else - pr_warn(/* but going down anyway, so... */ - "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); - mutex_unlock(&fullstop_mutex); - return NOTIFY_DONE; -} - /* * Allocate an element from the rcu_tortures pool. */ @@ -1098,10 +1081,6 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag) onoff_interval, onoff_holdoff); } -static struct notifier_block rcutorture_shutdown_nb = { - .notifier_call = rcutorture_shutdown_notify, -}; - static void rcutorture_booster_cleanup(int cpu) { struct task_struct *t; @@ -1428,7 +1407,6 @@ rcu_torture_cleanup(void) cur_ops->cb_barrier(); return; } - unregister_reboot_notifier(&rcutorture_shutdown_nb); rcu_torture_barrier_cleanup(); rcu_torture_stall_cleanup(); @@ -1774,7 +1752,6 @@ rcu_torture_init(void) firsterr = i; goto unwind; } - register_reboot_notifier(&rcutorture_shutdown_nb); i = rcu_torture_stall_init(); if (i != 0) { firsterr = i; diff --git a/kernel/torture.c b/kernel/torture.c index 41ae5cc3c4c3..b02fa2785bbb 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -54,8 +54,7 @@ static bool verbose; int fullstop = FULLSTOP_RMMOD; EXPORT_SYMBOL_GPL(fullstop); -DEFINE_MUTEX(fullstop_mutex); -EXPORT_SYMBOL_GPL(fullstop_mutex); +static DEFINE_MUTEX(fullstop_mutex); #ifdef CONFIG_HOTPLUG_CPU @@ -422,14 +421,32 @@ EXPORT_SYMBOL_GPL(torture_shuffle_cleanup); void torture_shutdown_absorb(const char *title) { while (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) { - pr_notice( - "torture thread %s parking due to system shutdown\n", - title); + pr_notice("torture thread %s parking due to system shutdown\n", + title); schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT); } } EXPORT_SYMBOL_GPL(torture_shutdown_absorb); +/* + * Detect and respond to a system shutdown. + */ +static int torture_shutdown_notify(struct notifier_block *unused1, + unsigned long unused2, void *unused3) +{ + mutex_lock(&fullstop_mutex); + if (fullstop == FULLSTOP_DONTSTOP) + fullstop = FULLSTOP_SHUTDOWN; + else + pr_warn("Concurrent rmmod and shutdown illegal!\n"); + mutex_unlock(&fullstop_mutex); + return NOTIFY_DONE; +} + +static struct notifier_block torture_shutdown_nb = { + .notifier_call = torture_shutdown_notify, +}; + /* * Initialize torture module. Please note that this is -not- invoked via * the usual module_init() mechanism, but rather by an explicit call from @@ -451,6 +468,7 @@ EXPORT_SYMBOL_GPL(torture_init_begin); void __init torture_init_end(void) { mutex_unlock(&fullstop_mutex); + register_reboot_notifier(&torture_shutdown_nb); } EXPORT_SYMBOL_GPL(torture_init_end); @@ -474,6 +492,7 @@ bool torture_cleanup(void) } fullstop = FULLSTOP_RMMOD; mutex_unlock(&fullstop_mutex); + unregister_reboot_notifier(&torture_shutdown_nb); torture_shuffle_cleanup(); torture_onoff_cleanup(); return false; From 36970bb91d89618d3495babf44b934e9c9db6bbc Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 30 Jan 2014 15:49:29 -0800 Subject: [PATCH 46/77] rcutorture: Privatize fullstop This commit introduces the torture_must_stop() function in order to keep use of the fullstop variable local to kernel/torture.c. There is also a torture_must_stop_irq() counterpart for use from RCU callbacks, timeout handlers, and the like. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 8 ++------ kernel/rcu/rcutorture.c | 38 +++++++++++++++----------------------- kernel/torture.c | 27 +++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 742d8a402f19..0259db38bfb0 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -41,12 +41,6 @@ module_param(name, type, 0444); \ MODULE_PARM_DESC(name, msg); -/* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ -#define FULLSTOP_DONTSTOP 0 /* Normal operation. */ -#define FULLSTOP_SHUTDOWN 1 /* System shutdown with rcutorture running. */ -#define FULLSTOP_RMMOD 2 /* Normal rmmod of rcutorture. */ -extern int fullstop; - #define TORTURE_FLAG "-torture:" #define TOROUT_STRING(s) \ pr_alert("%s" TORTURE_FLAG s "\n", torture_type) @@ -85,5 +79,7 @@ void torture_shutdown_absorb(const char *title); void torture_init_begin(char *ttype, bool v); void torture_init_end(void); bool torture_cleanup(void); +bool torture_must_stop(void); +bool torture_must_stop_irq(void); #endif /* __LINUX_TORTURE_H */ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 2560e9313887..9357c88cc8cc 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -304,7 +304,7 @@ rcu_torture_cb(struct rcu_head *p) int i; struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu); - if (fullstop != FULLSTOP_DONTSTOP) { + if (torture_must_stop_irq()) { /* Test is ending, just drop callbacks on the floor. */ /* The next initialization will pick up the pieces. */ return; @@ -572,8 +572,7 @@ static int rcu_torture_boost(void *arg) while (ULONG_CMP_LT(jiffies, oldstarttime)) { schedule_timeout_interruptible(oldstarttime - jiffies); rcu_stutter_wait("rcu_torture_boost"); - if (kthread_should_stop() || - fullstop != FULLSTOP_DONTSTOP) + if (torture_must_stop()) goto checkwait; } @@ -595,8 +594,7 @@ static int rcu_torture_boost(void *arg) } cond_resched(); rcu_stutter_wait("rcu_torture_boost"); - if (kthread_should_stop() || - fullstop != FULLSTOP_DONTSTOP) + if (torture_must_stop()) goto checkwait; } @@ -621,7 +619,7 @@ static int rcu_torture_boost(void *arg) /* Go do the stutter. */ checkwait: rcu_stutter_wait("rcu_torture_boost"); - } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); + } while (!torture_must_stop()); /* Clean up and exit. */ VERBOSE_TOROUT_STRING("rcu_torture_boost task stopping"); @@ -659,7 +657,7 @@ rcu_torture_fqs(void *arg) fqs_burst_remaining -= fqs_holdoff; } rcu_stutter_wait("rcu_torture_fqs"); - } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); + } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_fqs task stopping"); torture_shutdown_absorb("rcu_torture_fqs"); while (!kthread_should_stop()) @@ -731,7 +729,7 @@ rcu_torture_writer(void *arg) } rcutorture_record_progress(++rcu_torture_current_version); rcu_stutter_wait("rcu_torture_writer"); - } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); + } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_writer task stopping"); torture_shutdown_absorb("rcu_torture_writer"); while (!kthread_should_stop()) @@ -768,7 +766,7 @@ rcu_torture_fakewriter(void *arg) cur_ops->exp_sync(); } rcu_stutter_wait("rcu_torture_fakewriter"); - } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); + } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task stopping"); torture_shutdown_absorb("rcu_torture_fakewriter"); @@ -913,7 +911,7 @@ rcu_torture_reader(void *arg) cur_ops->readunlock(idx); schedule(); rcu_stutter_wait("rcu_torture_reader"); - } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); + } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_reader task stopping"); torture_shutdown_absorb("rcu_torture_reader"); if (irqreader && cur_ops->irq_capable) @@ -1022,9 +1020,6 @@ rcu_torture_stats_print(void) /* * Periodically prints torture statistics, if periodic statistics printing * was specified via the stat_interval module parameter. - * - * No need to worry about fullstop here, since this one doesn't reference - * volatile state or register callbacks. */ static int rcu_torture_stats(void *arg) @@ -1034,7 +1029,7 @@ rcu_torture_stats(void *arg) schedule_timeout_interruptible(stat_interval * HZ); rcu_torture_stats_print(); torture_shutdown_absorb("rcu_torture_stats"); - } while (!kthread_should_stop()); + } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_stats task stopping"); return 0; } @@ -1241,16 +1236,15 @@ static int rcu_torture_barrier_cbs(void *arg) wait_event(barrier_cbs_wq[myid], (newphase = ACCESS_ONCE(barrier_phase)) != lastphase || - kthread_should_stop() || - fullstop != FULLSTOP_DONTSTOP); + torture_must_stop()); lastphase = newphase; smp_mb(); /* ensure barrier_phase load before ->call(). */ - if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP) + if (torture_must_stop()) break; cur_ops->call(&rcu, rcu_torture_barrier_cbf); if (atomic_dec_and_test(&barrier_cbs_count)) wake_up(&barrier_wq); - } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); + } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_barrier_cbs task stopping"); torture_shutdown_absorb("rcu_torture_barrier_cbs"); while (!kthread_should_stop()) @@ -1275,9 +1269,8 @@ static int rcu_torture_barrier(void *arg) wake_up(&barrier_cbs_wq[i]); wait_event(barrier_wq, atomic_read(&barrier_cbs_count) == 0 || - kthread_should_stop() || - fullstop != FULLSTOP_DONTSTOP); - if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP) + torture_must_stop()); + if (torture_must_stop()) break; n_barrier_attempts++; cur_ops->cb_barrier(); /* Implies smp_mb() for wait_event(). */ @@ -1287,7 +1280,7 @@ static int rcu_torture_barrier(void *arg) } n_barrier_successes++; schedule_timeout_interruptible(HZ / 10); - } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); + } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_barrier task stopping"); torture_shutdown_absorb("rcu_torture_barrier"); while (!kthread_should_stop()) @@ -1585,7 +1578,6 @@ rcu_torture_init(void) else nrealreaders = 2 * num_online_cpus(); rcu_torture_print_module_parms(cur_ops, "Start of test"); - fullstop = FULLSTOP_DONTSTOP; /* Set up the freelist. */ diff --git a/kernel/torture.c b/kernel/torture.c index b02fa2785bbb..ed360cf948da 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -52,8 +52,11 @@ MODULE_AUTHOR("Paul E. McKenney "); static char *torture_type; static bool verbose; -int fullstop = FULLSTOP_RMMOD; -EXPORT_SYMBOL_GPL(fullstop); +/* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ +#define FULLSTOP_DONTSTOP 0 /* Normal operation. */ +#define FULLSTOP_SHUTDOWN 1 /* System shutdown with torture running. */ +#define FULLSTOP_RMMOD 2 /* Normal rmmod of torture. */ +static int fullstop = FULLSTOP_RMMOD; static DEFINE_MUTEX(fullstop_mutex); #ifdef CONFIG_HOTPLUG_CPU @@ -458,6 +461,7 @@ void __init torture_init_begin(char *ttype, bool v) mutex_lock(&fullstop_mutex); torture_type = ttype; verbose = v; + fullstop = FULLSTOP_DONTSTOP; } EXPORT_SYMBOL_GPL(torture_init_begin); @@ -498,3 +502,22 @@ bool torture_cleanup(void) return false; } EXPORT_SYMBOL_GPL(torture_cleanup); + +/* + * Is it time for the current torture test to stop? + */ +bool torture_must_stop(void) +{ + return torture_must_stop_irq() || kthread_should_stop(); +} +EXPORT_SYMBOL_GPL(torture_must_stop); + +/* + * Is it time for the current torture test to stop? This is the irq-safe + * version, hence no check for kthread_should_stop(). + */ +bool torture_must_stop_irq(void) +{ + return fullstop != FULLSTOP_DONTSTOP; +} +EXPORT_SYMBOL_GPL(torture_must_stop_irq); From fac480efcba6a9f0aea91947f151fd569538b0af Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 30 Jan 2014 17:06:30 -0800 Subject: [PATCH 47/77] rcutorture: Add diagnostic for unscheduled system shutdown Currently, rcutorture can terminate via rmmod, via self-shutdown, via something else shutting the system down, or of course the usual catastrophic termination. The first two get flagged, so this commit adds a message for the third. For the fourth, your warranty is void as always. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/torture.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/torture.c b/kernel/torture.c index ed360cf948da..d51de3029a5c 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -438,10 +438,12 @@ static int torture_shutdown_notify(struct notifier_block *unused1, unsigned long unused2, void *unused3) { mutex_lock(&fullstop_mutex); - if (fullstop == FULLSTOP_DONTSTOP) + if (fullstop == FULLSTOP_DONTSTOP) { + VERBOSE_TOROUT_STRING("Unscheduled system shutdown detected"); fullstop = FULLSTOP_SHUTDOWN; - else + } else { pr_warn("Concurrent rmmod and shutdown illegal!\n"); + } mutex_unlock(&fullstop_mutex); return NOTIFY_DONE; } From 628edaa5062282b6e3d76c886fd2cbccae5cb87b Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Jan 2014 11:57:43 -0800 Subject: [PATCH 48/77] rcutorture: Abstract stutter_wait() Because stuttering the test load (stopping and restarting it) is useful for non-RCU testing, this commit moves the load-stuttering functionality to kernel/torture.c. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 7 +++- kernel/rcu/rcutorture.c | 69 ++++++-------------------------- kernel/torture.c | 87 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 59 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 0259db38bfb0..203f127d9ddf 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -75,8 +75,13 @@ int torture_shuffle_init(long shuffint); /* Shutdown task absorption, for when the tasks cannot safely be killed. */ void torture_shutdown_absorb(const char *title); +/* Task stuttering, which forces load/no-load transitions. */ +void stutter_wait(const char *title); +int torture_stutter_init(int s); +void torture_stutter_cleanup(void); + /* Initialization and cleanup. */ -void torture_init_begin(char *ttype, bool v); +void torture_init_begin(char *ttype, bool v, int *runnable); void torture_init_end(void); bool torture_cleanup(void); bool torture_must_stop(void); diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 9357c88cc8cc..4329ad14f8dc 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -103,7 +103,6 @@ static struct task_struct *writer_task; static struct task_struct **fakewriter_tasks; static struct task_struct **reader_tasks; static struct task_struct *stats_task; -static struct task_struct *stutter_task; static struct task_struct *fqs_task; static struct task_struct *boost_tasks[NR_CPUS]; static struct task_struct *shutdown_task; @@ -145,8 +144,6 @@ static long n_barrier_attempts; static long n_barrier_successes; static struct list_head rcu_torture_removed; -static int stutter_pause_test; - #if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE) #define RCUTORTURE_RUNNABLE_INIT 1 #else @@ -222,18 +219,6 @@ rcu_torture_free(struct rcu_torture *p) spin_unlock_bh(&rcu_torture_lock); } -static void -rcu_stutter_wait(const char *title) -{ - while (stutter_pause_test || !rcutorture_runnable) { - if (rcutorture_runnable) - schedule_timeout_interruptible(1); - else - schedule_timeout_interruptible(round_jiffies_relative(HZ)); - torture_shutdown_absorb(title); - } -} - /* * Operations vector for selecting different types of tests. */ @@ -571,7 +556,7 @@ static int rcu_torture_boost(void *arg) oldstarttime = boost_starttime; while (ULONG_CMP_LT(jiffies, oldstarttime)) { schedule_timeout_interruptible(oldstarttime - jiffies); - rcu_stutter_wait("rcu_torture_boost"); + stutter_wait("rcu_torture_boost"); if (torture_must_stop()) goto checkwait; } @@ -593,7 +578,7 @@ static int rcu_torture_boost(void *arg) call_rcu_time = jiffies; } cond_resched(); - rcu_stutter_wait("rcu_torture_boost"); + stutter_wait("rcu_torture_boost"); if (torture_must_stop()) goto checkwait; } @@ -618,7 +603,7 @@ static int rcu_torture_boost(void *arg) } /* Go do the stutter. */ -checkwait: rcu_stutter_wait("rcu_torture_boost"); +checkwait: stutter_wait("rcu_torture_boost"); } while (!torture_must_stop()); /* Clean up and exit. */ @@ -656,7 +641,7 @@ rcu_torture_fqs(void *arg) udelay(fqs_holdoff); fqs_burst_remaining -= fqs_holdoff; } - rcu_stutter_wait("rcu_torture_fqs"); + stutter_wait("rcu_torture_fqs"); } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_fqs task stopping"); torture_shutdown_absorb("rcu_torture_fqs"); @@ -728,7 +713,7 @@ rcu_torture_writer(void *arg) } } rcutorture_record_progress(++rcu_torture_current_version); - rcu_stutter_wait("rcu_torture_writer"); + stutter_wait("rcu_torture_writer"); } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_writer task stopping"); torture_shutdown_absorb("rcu_torture_writer"); @@ -765,7 +750,7 @@ rcu_torture_fakewriter(void *arg) } else { cur_ops->exp_sync(); } - rcu_stutter_wait("rcu_torture_fakewriter"); + stutter_wait("rcu_torture_fakewriter"); } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task stopping"); @@ -910,7 +895,7 @@ rcu_torture_reader(void *arg) preempt_enable(); cur_ops->readunlock(idx); schedule(); - rcu_stutter_wait("rcu_torture_reader"); + stutter_wait("rcu_torture_reader"); } while (!torture_must_stop()); VERBOSE_TOROUT_STRING("rcu_torture_reader task stopping"); torture_shutdown_absorb("rcu_torture_reader"); @@ -1034,25 +1019,6 @@ rcu_torture_stats(void *arg) return 0; } -/* Cause the rcutorture test to "stutter", starting and stopping all - * threads periodically. - */ -static int -rcu_torture_stutter(void *arg) -{ - VERBOSE_TOROUT_STRING("rcu_torture_stutter task started"); - do { - schedule_timeout_interruptible(stutter * HZ); - stutter_pause_test = 1; - if (!kthread_should_stop()) - schedule_timeout_interruptible(stutter * HZ); - stutter_pause_test = 0; - torture_shutdown_absorb("rcu_torture_stutter"); - } while (!kthread_should_stop()); - VERBOSE_TOROUT_STRING("rcu_torture_stutter task stopping"); - return 0; -} - static inline void rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag) { @@ -1403,11 +1369,7 @@ rcu_torture_cleanup(void) rcu_torture_barrier_cleanup(); rcu_torture_stall_cleanup(); - if (stutter_task) { - VERBOSE_TOROUT_STRING("Stopping rcu_torture_stutter task"); - kthread_stop(stutter_task); - } - stutter_task = NULL; + torture_stutter_cleanup(); if (writer_task) { VERBOSE_TOROUT_STRING("Stopping rcu_torture_writer task"); @@ -1548,7 +1510,7 @@ rcu_torture_init(void) &rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops, }; - torture_init_begin(torture_type, verbose); + torture_init_begin(torture_type, verbose, &rcutorture_runnable); /* Process args and tell the world that the torturer is on the job. */ for (i = 0; i < ARRAY_SIZE(torture_ops); i++) { @@ -1682,21 +1644,14 @@ rcu_torture_init(void) if (stutter < 0) stutter = 0; if (stutter) { - /* Create the stutter thread */ - stutter_task = kthread_run(rcu_torture_stutter, NULL, - "rcu_torture_stutter"); - if (IS_ERR(stutter_task)) { - firsterr = PTR_ERR(stutter_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create stutter"); - stutter_task = NULL; + firsterr = torture_stutter_init(stutter * HZ); + if (firsterr) goto unwind; - } - torture_shuffle_task_register(stutter_task); } if (fqs_duration < 0) fqs_duration = 0; if (fqs_duration) { - /* Create the stutter thread */ + /* Create the fqs thread */ fqs_task = kthread_run(rcu_torture_fqs, NULL, "rcu_torture_fqs"); if (IS_ERR(fqs_task)) { diff --git a/kernel/torture.c b/kernel/torture.c index d51de3029a5c..b30c2ee78580 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -58,6 +58,7 @@ static bool verbose; #define FULLSTOP_RMMOD 2 /* Normal rmmod of torture. */ static int fullstop = FULLSTOP_RMMOD; static DEFINE_MUTEX(fullstop_mutex); +static int *torture_runnable; #ifdef CONFIG_HOTPLUG_CPU @@ -452,17 +453,101 @@ static struct notifier_block torture_shutdown_nb = { .notifier_call = torture_shutdown_notify, }; +/* + * Variables for stuttering, which means to periodically pause and + * restart testing in order to catch bugs that appear when load is + * suddenly applied to or removed from the system. + */ +static struct task_struct *stutter_task; +static int stutter_pause_test; +static int stutter; + +/* + * Block until the stutter interval ends. This must be called periodically + * by all running kthreads that need to be subject to stuttering. + */ +void stutter_wait(const char *title) +{ + while (ACCESS_ONCE(stutter_pause_test) || + (torture_runnable && !ACCESS_ONCE(*torture_runnable))) { + if (stutter_pause_test) + schedule_timeout_interruptible(1); + else + schedule_timeout_interruptible(round_jiffies_relative(HZ)); + torture_shutdown_absorb(title); + } +} +EXPORT_SYMBOL_GPL(stutter_wait); + +/* + * Cause the torture test to "stutter", starting and stopping all + * threads periodically. + */ +static int torture_stutter(void *arg) +{ + VERBOSE_TOROUT_STRING("torture_stutter task started"); + do { + if (!torture_must_stop()) { + schedule_timeout_interruptible(stutter); + ACCESS_ONCE(stutter_pause_test) = 1; + } + if (!torture_must_stop()) + schedule_timeout_interruptible(stutter); + ACCESS_ONCE(stutter_pause_test) = 0; + torture_shutdown_absorb("torture_stutter"); + } while (!torture_must_stop()); + VERBOSE_TOROUT_STRING("torture_stutter task stopping"); + return 0; +} + +/* + * Initialize and kick off the torture_stutter kthread. + */ +int torture_stutter_init(int s) +{ + int ret; + + stutter = s; + stutter_task = kthread_run(torture_stutter, NULL, "torture_stutter"); + if (IS_ERR(stutter_task)) { + ret = PTR_ERR(stutter_task); + VERBOSE_TOROUT_ERRSTRING("Failed to create stutter"); + stutter_task = NULL; + return ret; + } + torture_shuffle_task_register(stutter_task); + return 0; +} +EXPORT_SYMBOL_GPL(torture_stutter_init); + +/* + * Cleanup after the torture_stutter kthread. + */ +void torture_stutter_cleanup(void) +{ + if (!stutter_task) + return; + VERBOSE_TOROUT_STRING("Stopping torture_stutter task"); + kthread_stop(stutter_task); + stutter_task = NULL; +} +EXPORT_SYMBOL_GPL(torture_stutter_cleanup); + /* * Initialize torture module. Please note that this is -not- invoked via * the usual module_init() mechanism, but rather by an explicit call from * the client torture module. This call must be paired with a later * torture_init_end(). + * + * The runnable parameter points to a flag that controls whether or not + * the test is currently runnable. If there is no such flag, pass in NULL. */ -void __init torture_init_begin(char *ttype, bool v) +void __init torture_init_begin(char *ttype, bool v, int *runnable) { mutex_lock(&fullstop_mutex); torture_type = ttype; verbose = v; + torture_runnable = runnable; fullstop = FULLSTOP_DONTSTOP; } From 57a2fe90fcdaa812ac1aa6c91ba0e591c30f461a Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Jan 2014 12:58:39 -0800 Subject: [PATCH 49/77] rcutorture: Apply ACCESS_ONCE() to racy fullstop accesses Because the fullstop variable can be accessed while it is being updated, this commit avoids any resulting compiler mischief through use of ACCESS_ONCE() for non-initialization accesses to this shared variable. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/torture.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/torture.c b/kernel/torture.c index b30c2ee78580..1bafd02d1eed 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -439,9 +439,9 @@ static int torture_shutdown_notify(struct notifier_block *unused1, unsigned long unused2, void *unused3) { mutex_lock(&fullstop_mutex); - if (fullstop == FULLSTOP_DONTSTOP) { + if (ACCESS_ONCE(fullstop) == FULLSTOP_DONTSTOP) { VERBOSE_TOROUT_STRING("Unscheduled system shutdown detected"); - fullstop = FULLSTOP_SHUTDOWN; + ACCESS_ONCE(fullstop) = FULLSTOP_SHUTDOWN; } else { pr_warn("Concurrent rmmod and shutdown illegal!\n"); } @@ -575,13 +575,13 @@ EXPORT_SYMBOL_GPL(torture_init_end); bool torture_cleanup(void) { mutex_lock(&fullstop_mutex); - if (fullstop == FULLSTOP_SHUTDOWN) { + if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) { pr_warn("Concurrent rmmod and shutdown illegal!\n"); mutex_unlock(&fullstop_mutex); schedule_timeout_uninterruptible(10); return true; } - fullstop = FULLSTOP_RMMOD; + ACCESS_ONCE(fullstop) = FULLSTOP_RMMOD; mutex_unlock(&fullstop_mutex); unregister_reboot_notifier(&torture_shutdown_nb); torture_shuffle_cleanup(); @@ -605,6 +605,6 @@ EXPORT_SYMBOL_GPL(torture_must_stop); */ bool torture_must_stop_irq(void) { - return fullstop != FULLSTOP_DONTSTOP; + return ACCESS_ONCE(fullstop) != FULLSTOP_DONTSTOP; } EXPORT_SYMBOL_GPL(torture_must_stop_irq); From e991dbc0770b01b7dc7d6d7660442e83ebd11828 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Jan 2014 14:52:13 -0800 Subject: [PATCH 50/77] rcutorture: Abstract torture_shutdown() Because auto-shutdown of torture testing is not specific to RCU, this commit moves the auto-shutdown function to kernel/torture.c. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 4 +- kernel/rcu/rcutorture.c | 63 +++---------------------------- kernel/torture.c | 84 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 59 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 203f127d9ddf..c79c41d543ef 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -72,8 +72,10 @@ unsigned long torture_random(struct torture_random_state *trsp); void torture_shuffle_task_register(struct task_struct *tp); int torture_shuffle_init(long shuffint); -/* Shutdown task absorption, for when the tasks cannot safely be killed. */ +/* Test auto-shutdown handling. */ void torture_shutdown_absorb(const char *title); +int torture_shutdown_init(int ssecs, void (*cleanup)(void)); +void torture_shutdown_cleanup(void); /* Task stuttering, which forces load/no-load transitions. */ void stutter_wait(const char *title); diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 4329ad14f8dc..897b0f91f899 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -105,7 +105,6 @@ static struct task_struct **reader_tasks; static struct task_struct *stats_task; static struct task_struct *fqs_task; static struct task_struct *boost_tasks[NR_CPUS]; -static struct task_struct *shutdown_task; static struct task_struct *stall_task; static struct task_struct **barrier_cbs_tasks; static struct task_struct *barrier_task; @@ -173,7 +172,6 @@ static u64 notrace rcu_trace_clock_local(void) } #endif /* #else #ifdef CONFIG_RCU_TRACE */ -static unsigned long shutdown_time; /* jiffies to system shutdown. */ static unsigned long boost_starttime; /* jiffies of next boost test start. */ DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ /* and boost task create/destroy. */ @@ -183,9 +181,6 @@ static atomic_t barrier_cbs_invoked; /* Barrier callbacks invoked. */ static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */ static DECLARE_WAIT_QUEUE_HEAD(barrier_wq); -/* Forward reference. */ -static void rcu_torture_cleanup(void); - /* * Allocate an element from the rcu_tortures pool. */ @@ -1086,42 +1081,6 @@ static int rcutorture_booster_init(int cpu) return 0; } -/* - * Cause the rcutorture test to shutdown the system after the test has - * run for the time specified by the shutdown_secs module parameter. - */ -static int -rcu_torture_shutdown(void *arg) -{ - long delta; - unsigned long jiffies_snap; - - VERBOSE_TOROUT_STRING("rcu_torture_shutdown task started"); - jiffies_snap = ACCESS_ONCE(jiffies); - while (ULONG_CMP_LT(jiffies_snap, shutdown_time) && - !kthread_should_stop()) { - delta = shutdown_time - jiffies_snap; - if (verbose) - pr_alert("%s" TORTURE_FLAG - "rcu_torture_shutdown task: %lu jiffies remaining\n", - torture_type, delta); - schedule_timeout_interruptible(delta); - jiffies_snap = ACCESS_ONCE(jiffies); - } - if (kthread_should_stop()) { - VERBOSE_TOROUT_STRING("rcu_torture_shutdown task stopping"); - return 0; - } - - /* OK, shut down the system. */ - - VERBOSE_TOROUT_STRING("rcu_torture_shutdown task shutting down system"); - shutdown_task = NULL; /* Avoid self-kill deadlock. */ - rcu_torture_cleanup(); /* Get the success/failure message. */ - kernel_power_off(); /* Shut down the system. */ - return 0; -} - /* * CPU-stall kthread. It waits as specified by stall_cpu_holdoff, then * induces a CPU stall for the time specified by stall_cpu. @@ -1421,11 +1380,7 @@ rcu_torture_cleanup(void) for_each_possible_cpu(i) rcutorture_booster_cleanup(i); } - if (shutdown_task != NULL) { - VERBOSE_TOROUT_STRING("Stopping rcu_torture_shutdown task"); - kthread_stop(shutdown_task); - } - shutdown_task = NULL; + torture_shutdown_cleanup(); /* Wait for all RCU callbacks to fire. */ @@ -1681,18 +1636,10 @@ rcu_torture_init(void) } } } - if (shutdown_secs > 0) { - shutdown_time = jiffies + shutdown_secs * HZ; - shutdown_task = kthread_create(rcu_torture_shutdown, NULL, - "rcu_torture_shutdown"); - if (IS_ERR(shutdown_task)) { - firsterr = PTR_ERR(shutdown_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create shutdown"); - shutdown_task = NULL; - goto unwind; - } - torture_shuffle_task_register(shutdown_task); - wake_up_process(shutdown_task); + i = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup); + if (i != 0) { + firsterr = i; + goto unwind; } i = torture_onoff_init(onoff_holdoff * HZ, onoff_interval * HZ); if (i != 0) { diff --git a/kernel/torture.c b/kernel/torture.c index 1bafd02d1eed..df2c700e96e4 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -418,6 +418,15 @@ static void torture_shuffle_cleanup(void) } EXPORT_SYMBOL_GPL(torture_shuffle_cleanup); +/* + * Variables for auto-shutdown. This allows "lights out" torture runs + * to be fully scripted. + */ +static int shutdown_secs; /* desired test duration in seconds. */ +static struct task_struct *shutdown_task; +static unsigned long shutdown_time; /* jiffies to system shutdown. */ +static void (*torture_shutdown_hook)(void); + /* * Absorb kthreads into a kernel function that won't return, so that * they won't ever access module text or data again. @@ -432,6 +441,81 @@ void torture_shutdown_absorb(const char *title) } EXPORT_SYMBOL_GPL(torture_shutdown_absorb); +/* + * Cause the torture test to shutdown the system after the test has + * run for the time specified by the shutdown_secs parameter. + */ +static int torture_shutdown(void *arg) +{ + long delta; + unsigned long jiffies_snap; + + VERBOSE_TOROUT_STRING("torture_shutdown task started"); + jiffies_snap = jiffies; + while (ULONG_CMP_LT(jiffies_snap, shutdown_time) && + !torture_must_stop()) { + delta = shutdown_time - jiffies_snap; + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_shutdown task: %lu jiffies remaining\n", + torture_type, delta); + schedule_timeout_interruptible(delta); + jiffies_snap = jiffies; + } + if (torture_must_stop()) { + VERBOSE_TOROUT_STRING("torture_shutdown task stopping"); + return 0; + } + + /* OK, shut down the system. */ + + VERBOSE_TOROUT_STRING("torture_shutdown task shutting down system"); + shutdown_task = NULL; /* Avoid self-kill deadlock. */ + torture_shutdown_hook();/* Shut down the enclosing torture test. */ + kernel_power_off(); /* Shut down the system. */ + return 0; +} + +/* + * Start up the shutdown task. + */ +int torture_shutdown_init(int ssecs, void (*cleanup)(void)) +{ + int ret; + + shutdown_secs = ssecs; + torture_shutdown_hook = cleanup; + if (shutdown_secs > 0) { + shutdown_time = jiffies + shutdown_secs * HZ; + shutdown_task = kthread_create(torture_shutdown, NULL, + "torture_shutdown"); + if (IS_ERR(shutdown_task)) { + ret = PTR_ERR(shutdown_task); + VERBOSE_TOROUT_ERRSTRING("Failed to create shutdown"); + shutdown_task = NULL; + return ret; + } + torture_shuffle_task_register(shutdown_task); + wake_up_process(shutdown_task); + } + return 0; +} +EXPORT_SYMBOL_GPL(torture_shutdown_init); + +/* + * Shut down the shutdown task. Say what??? Heh! This can happen if + * the torture module gets an rmmod before the shutdown time arrives. ;-) + */ +void torture_shutdown_cleanup(void) +{ + if (shutdown_task != NULL) { + VERBOSE_TOROUT_STRING("Stopping torture_shutdown task"); + kthread_stop(shutdown_task); + } + shutdown_task = NULL; +} +EXPORT_SYMBOL_GPL(torture_shutdown_cleanup); + /* * Detect and respond to a system shutdown. */ From 01025ebc99e39ac962c32e063cad9a3012ee8b0a Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Jan 2014 15:15:02 -0800 Subject: [PATCH 51/77] rcutorture: Clean up rcu_torture_init() error checking This commit applies some simple cleanups to rcu_torture_init() error checking. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/rcutorture.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 897b0f91f899..746c4278ea5e 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1460,7 +1460,6 @@ rcu_torture_init(void) int i; int cpu; int firsterr = 0; - int retval; static struct rcu_torture_ops *torture_ops[] = { &rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops, }; @@ -1629,33 +1628,23 @@ rcu_torture_init(void) for_each_possible_cpu(i) { if (cpu_is_offline(i)) continue; /* Heuristic: CPU can go offline. */ - retval = rcutorture_booster_init(i); - if (retval < 0) { - firsterr = retval; + firsterr = rcutorture_booster_init(i); + if (firsterr) goto unwind; - } } } - i = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup); - if (i != 0) { - firsterr = i; + firsterr = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup); + if (firsterr) goto unwind; - } - i = torture_onoff_init(onoff_holdoff * HZ, onoff_interval * HZ); - if (i != 0) { - firsterr = i; + firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval * HZ); + if (firsterr) goto unwind; - } - i = rcu_torture_stall_init(); - if (i != 0) { - firsterr = i; + firsterr = rcu_torture_stall_init(); + if (firsterr) goto unwind; - } - retval = rcu_torture_barrier_init(); - if (retval != 0) { - firsterr = retval; + firsterr = rcu_torture_barrier_init(); + if (firsterr) goto unwind; - } if (object_debug) rcu_test_debug_objects(); rcutorture_record_test_transition(); From 14562d1cf12b434da2c69b5603a4149ac43f3b48 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Jan 2014 15:39:52 -0800 Subject: [PATCH 52/77] rcutorture: Announce task creation A few "stealth-start rcutorture kthreads" have accumulated over the years, so this commit adds console-log announcements (but only if the torture tests are running verbose). Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/rcutorture.c | 4 ++++ kernel/torture.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 746c4278ea5e..6e9ba51b23b9 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1120,6 +1120,7 @@ static int __init rcu_torture_stall_init(void) if (stall_cpu <= 0) return 0; + VERBOSE_TOROUT_STRING("Creating rcu_torture_stall task"); stall_task = kthread_run(rcu_torture_stall, NULL, "rcu_torture_stall"); if (IS_ERR(stall_task)) { ret = PTR_ERR(stall_task); @@ -1242,6 +1243,7 @@ static int rcu_torture_barrier_init(void) return -ENOMEM; for (i = 0; i < n_barrier_cbs; i++) { init_waitqueue_head(&barrier_cbs_wq[i]); + VERBOSE_TOROUT_STRING("Creating rcu_torture_barrier_cbs task"); barrier_cbs_tasks[i] = kthread_run(rcu_torture_barrier_cbs, (void *)(long)i, "rcu_torture_barrier_cbs"); @@ -1253,6 +1255,7 @@ static int rcu_torture_barrier_init(void) } torture_shuffle_task_register(barrier_cbs_tasks[i]); } + VERBOSE_TOROUT_STRING("Creating rcu_torture_barrier task"); barrier_task = kthread_run(rcu_torture_barrier, NULL, "rcu_torture_barrier"); if (IS_ERR(barrier_task)) { @@ -1606,6 +1609,7 @@ rcu_torture_init(void) fqs_duration = 0; if (fqs_duration) { /* Create the fqs thread */ + VERBOSE_TOROUT_STRING("Creating rcu_torture_fqs task"); fqs_task = kthread_run(rcu_torture_fqs, NULL, "rcu_torture_fqs"); if (IS_ERR(fqs_task)) { diff --git a/kernel/torture.c b/kernel/torture.c index df2c700e96e4..5e2838f902f9 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -187,6 +187,7 @@ int torture_onoff_init(long ooholdoff, long oointerval) onoff_interval = oointerval; if (onoff_interval <= 0) return 0; + VERBOSE_TOROUT_STRING("Creating torture_onoff task"); onoff_task = kthread_run(torture_onoff, NULL, "torture_onoff"); if (IS_ERR(onoff_task)) { ret = PTR_ERR(onoff_task); @@ -390,6 +391,7 @@ int torture_shuffle_init(long shuffint) } /* Create the shuffler thread */ + VERBOSE_TOROUT_STRING("Creating torture_shuffle task"); shuffler_task = kthread_run(torture_shuffle, NULL, "torture_shuffle"); if (IS_ERR(shuffler_task)) { ret = PTR_ERR(shuffler_task); @@ -486,6 +488,7 @@ int torture_shutdown_init(int ssecs, void (*cleanup)(void)) shutdown_secs = ssecs; torture_shutdown_hook = cleanup; if (shutdown_secs > 0) { + VERBOSE_TOROUT_STRING("Creating torture_shutdown task"); shutdown_time = jiffies + shutdown_secs * HZ; shutdown_task = kthread_create(torture_shutdown, NULL, "torture_shutdown"); @@ -592,6 +595,7 @@ int torture_stutter_init(int s) int ret; stutter = s; + VERBOSE_TOROUT_STRING("Creating torture_stutter task"); stutter_task = kthread_run(torture_stutter, NULL, "torture_stutter"); if (IS_ERR(stutter_task)) { ret = PTR_ERR(stutter_task); From 7fafaac5b9ce22cc57777865390520476ad2262d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Jan 2014 17:37:28 -0800 Subject: [PATCH 53/77] rcutorture: Fix rcutorture shutdown races Not all of the rcutorture kthreads waited for kthread_should_stop() before returning from their top-level functions, and none of them used torture_shutdown_absorb() properly. These problems can result in segfaults and hangs at shutdown time, and some recent changes perturbed timing sufficiently to make them much more probable. This commit therefore creates a torture_kthread_stopping() function that does the proper kthread shutdown dance in one centralized location. Accommodate this grouping by making VERBOSE_TOROUT_STRING() capable of taking a non-const string as its argument, which allows the new torture_kthread_stopping() to pass its "title" argument directly to the updated version of VERBOSE_TOROUT_STRING(). Signed-off-by: Paul E. McKenney --- include/linux/torture.h | 3 ++- kernel/rcu/rcutorture.c | 39 +++++++++++---------------------------- kernel/torture.c | 26 ++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index c79c41d543ef..2ea11094daf6 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -45,7 +45,7 @@ #define TOROUT_STRING(s) \ pr_alert("%s" TORTURE_FLAG s "\n", torture_type) #define VERBOSE_TOROUT_STRING(s) \ - do { if (verbose) pr_alert("%s" TORTURE_FLAG s "\n", torture_type); } while (0) + do { if (verbose) pr_alert("%s" TORTURE_FLAG " %s\n", torture_type, s); } while (0) #define VERBOSE_TOROUT_ERRSTRING(s) \ do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0) @@ -88,5 +88,6 @@ void torture_init_end(void); bool torture_cleanup(void); bool torture_must_stop(void); bool torture_must_stop_irq(void); +void torture_kthread_stopping(char *title); #endif /* __LINUX_TORTURE_H */ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 6e9ba51b23b9..bcaafd6cf633 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -602,12 +602,13 @@ checkwait: stutter_wait("rcu_torture_boost"); } while (!torture_must_stop()); /* Clean up and exit. */ - VERBOSE_TOROUT_STRING("rcu_torture_boost task stopping"); - torture_shutdown_absorb("rcu_torture_boost"); - while (!kthread_should_stop() || rbi.inflight) + while (!kthread_should_stop() || rbi.inflight) { + torture_shutdown_absorb("rcu_torture_boost"); schedule_timeout_uninterruptible(1); + } smp_mb(); /* order accesses to ->inflight before stack-frame death. */ destroy_rcu_head_on_stack(&rbi.rcu); + torture_kthread_stopping("rcu_torture_boost"); return 0; } @@ -638,10 +639,7 @@ rcu_torture_fqs(void *arg) } stutter_wait("rcu_torture_fqs"); } while (!torture_must_stop()); - VERBOSE_TOROUT_STRING("rcu_torture_fqs task stopping"); - torture_shutdown_absorb("rcu_torture_fqs"); - while (!kthread_should_stop()) - schedule_timeout_uninterruptible(1); + torture_kthread_stopping("rcu_torture_fqs"); return 0; } @@ -710,10 +708,7 @@ rcu_torture_writer(void *arg) rcutorture_record_progress(++rcu_torture_current_version); stutter_wait("rcu_torture_writer"); } while (!torture_must_stop()); - VERBOSE_TOROUT_STRING("rcu_torture_writer task stopping"); - torture_shutdown_absorb("rcu_torture_writer"); - while (!kthread_should_stop()) - schedule_timeout_uninterruptible(1); + torture_kthread_stopping("rcu_torture_writer"); return 0; } @@ -748,10 +743,7 @@ rcu_torture_fakewriter(void *arg) stutter_wait("rcu_torture_fakewriter"); } while (!torture_must_stop()); - VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task stopping"); - torture_shutdown_absorb("rcu_torture_fakewriter"); - while (!kthread_should_stop()) - schedule_timeout_uninterruptible(1); + torture_kthread_stopping("rcu_torture_fakewriter"); return 0; } @@ -892,12 +884,9 @@ rcu_torture_reader(void *arg) schedule(); stutter_wait("rcu_torture_reader"); } while (!torture_must_stop()); - VERBOSE_TOROUT_STRING("rcu_torture_reader task stopping"); - torture_shutdown_absorb("rcu_torture_reader"); if (irqreader && cur_ops->irq_capable) del_timer_sync(&t); - while (!kthread_should_stop()) - schedule_timeout_uninterruptible(1); + torture_kthread_stopping("rcu_torture_reader"); return 0; } @@ -1010,7 +999,7 @@ rcu_torture_stats(void *arg) rcu_torture_stats_print(); torture_shutdown_absorb("rcu_torture_stats"); } while (!torture_must_stop()); - VERBOSE_TOROUT_STRING("rcu_torture_stats task stopping"); + torture_kthread_stopping("rcu_torture_stats"); return 0; } @@ -1171,12 +1160,9 @@ static int rcu_torture_barrier_cbs(void *arg) if (atomic_dec_and_test(&barrier_cbs_count)) wake_up(&barrier_wq); } while (!torture_must_stop()); - VERBOSE_TOROUT_STRING("rcu_torture_barrier_cbs task stopping"); - torture_shutdown_absorb("rcu_torture_barrier_cbs"); - while (!kthread_should_stop()) - schedule_timeout_interruptible(1); cur_ops->cb_barrier(); destroy_rcu_head_on_stack(&rcu); + torture_kthread_stopping("rcu_torture_barrier_cbs"); return 0; } @@ -1207,10 +1193,7 @@ static int rcu_torture_barrier(void *arg) n_barrier_successes++; schedule_timeout_interruptible(HZ / 10); } while (!torture_must_stop()); - VERBOSE_TOROUT_STRING("rcu_torture_barrier task stopping"); - torture_shutdown_absorb("rcu_torture_barrier"); - while (!kthread_should_stop()) - schedule_timeout_interruptible(1); + torture_kthread_stopping("rcu_torture_barrier"); return 0; } diff --git a/kernel/torture.c b/kernel/torture.c index 5e2838f902f9..330576660cf4 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -169,7 +169,7 @@ torture_onoff(void *arg) } schedule_timeout_interruptible(onoff_interval); } - VERBOSE_TOROUT_STRING("torture_onoff task stopping"); + torture_kthread_stopping("torture_onoff"); return 0; } @@ -370,7 +370,7 @@ static int torture_shuffle(void *arg) torture_shuffle_tasks(); torture_shutdown_absorb("torture_shuffle"); } while (!torture_must_stop()); - VERBOSE_TOROUT_STRING("torture_shuffle task stopping"); + torture_kthread_stopping("torture_shuffle"); return 0; } @@ -465,7 +465,7 @@ static int torture_shutdown(void *arg) jiffies_snap = jiffies; } if (torture_must_stop()) { - VERBOSE_TOROUT_STRING("torture_shutdown task stopping"); + torture_kthread_stopping("torture_shutdown"); return 0; } @@ -583,7 +583,7 @@ static int torture_stutter(void *arg) ACCESS_ONCE(stutter_pause_test) = 0; torture_shutdown_absorb("torture_stutter"); } while (!torture_must_stop()); - VERBOSE_TOROUT_STRING("torture_stutter task stopping"); + torture_kthread_stopping("torture_stutter"); return 0; } @@ -696,3 +696,21 @@ bool torture_must_stop_irq(void) return ACCESS_ONCE(fullstop) != FULLSTOP_DONTSTOP; } EXPORT_SYMBOL_GPL(torture_must_stop_irq); + +/* + * Each kthread must wait for kthread_should_stop() before returning from + * its top-level function, otherwise segfaults ensue. This function + * prints a "stopping" message and waits for kthread_should_stop(), and + * should be called from all torture kthreads immediately prior to + * returning. + */ +void torture_kthread_stopping(char *title) +{ + if (verbose) + VERBOSE_TOROUT_STRING(title); + while (!kthread_should_stop()) { + torture_shutdown_absorb(title); + schedule_timeout_uninterruptible(1); + } +} +EXPORT_SYMBOL_GPL(torture_kthread_stopping); From bc8f83e2c0d585b201dfbb52e98f6f8741d324ea Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 3 Feb 2014 10:02:41 -0800 Subject: [PATCH 54/77] rcutorture: Fix missing-return bug in rcu_torture_barrier_init() This commit adds a missing error return to the code path that creates the rcu_torture_barrier() kthread. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/rcutorture.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index bcaafd6cf633..25e9b16fe7f0 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1245,6 +1245,7 @@ static int rcu_torture_barrier_init(void) ret = PTR_ERR(barrier_task); VERBOSE_TOROUT_ERRSTRING("Failed to create rcu_torture_barrier"); barrier_task = NULL; + return ret; } torture_shuffle_task_register(barrier_task); return 0; From 47cf29b9e721967aac95ebda9e50408219755852 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 3 Feb 2014 11:52:27 -0800 Subject: [PATCH 55/77] rcutorture: Abstract torture_create_kthread() Creation of kthreads is not RCU-specific, so this commit abstracts out torture_create_kthread(), saving a few tens of lines of code in the process. This change requires modifying VERBOSE_TOROUT_ERRSTRING() to take a non-const string, so that _torture_create_kthread() can avoid an open-coded substitute. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 8 +++- kernel/rcu/rcutorture.c | 98 +++++++++-------------------------------- kernel/torture.c | 80 ++++++++++++++------------------- 3 files changed, 60 insertions(+), 126 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 2ea11094daf6..430cc3008628 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -47,7 +47,7 @@ #define VERBOSE_TOROUT_STRING(s) \ do { if (verbose) pr_alert("%s" TORTURE_FLAG " %s\n", torture_type, s); } while (0) #define VERBOSE_TOROUT_ERRSTRING(s) \ - do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0) + do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0) /* Definitions for a non-string torture-test module parameter. */ #define torture_parm(type, name, init, msg) \ @@ -89,5 +89,11 @@ bool torture_cleanup(void); bool torture_must_stop(void); bool torture_must_stop_irq(void); void torture_kthread_stopping(char *title); +int _torture_create_kthread(int (*fn)(void *arg), void *arg, char *s, char *m, + char *f, struct task_struct **tp); + +#define torture_create_kthread(n, arg, tp) \ + _torture_create_kthread(n, (arg), #n, "Creating " #n " task", \ + "Failed to create " #n, &(tp)) #endif /* __LINUX_TORTURE_H */ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 25e9b16fe7f0..a6f6c8418d87 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1105,19 +1105,9 @@ static int rcu_torture_stall(void *args) /* Spawn CPU-stall kthread, if stall_cpu specified. */ static int __init rcu_torture_stall_init(void) { - int ret; - if (stall_cpu <= 0) return 0; - VERBOSE_TOROUT_STRING("Creating rcu_torture_stall task"); - stall_task = kthread_run(rcu_torture_stall, NULL, "rcu_torture_stall"); - if (IS_ERR(stall_task)) { - ret = PTR_ERR(stall_task); - stall_task = NULL; - return ret; - } - torture_shuffle_task_register(stall_task); - return 0; + return torture_create_kthread(rcu_torture_stall, NULL, stall_task); } /* Clean up after the CPU-stall kthread, if one was spawned. */ @@ -1226,29 +1216,13 @@ static int rcu_torture_barrier_init(void) return -ENOMEM; for (i = 0; i < n_barrier_cbs; i++) { init_waitqueue_head(&barrier_cbs_wq[i]); - VERBOSE_TOROUT_STRING("Creating rcu_torture_barrier_cbs task"); - barrier_cbs_tasks[i] = kthread_run(rcu_torture_barrier_cbs, - (void *)(long)i, - "rcu_torture_barrier_cbs"); - if (IS_ERR(barrier_cbs_tasks[i])) { - ret = PTR_ERR(barrier_cbs_tasks[i]); - VERBOSE_TOROUT_ERRSTRING("Failed to create rcu_torture_barrier_cbs"); - barrier_cbs_tasks[i] = NULL; + ret = torture_create_kthread(rcu_torture_barrier_cbs, + (void *)(long)i, + barrier_cbs_tasks[i]); + if (ret) return ret; - } - torture_shuffle_task_register(barrier_cbs_tasks[i]); } - VERBOSE_TOROUT_STRING("Creating rcu_torture_barrier task"); - barrier_task = kthread_run(rcu_torture_barrier, NULL, - "rcu_torture_barrier"); - if (IS_ERR(barrier_task)) { - ret = PTR_ERR(barrier_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create rcu_torture_barrier"); - barrier_task = NULL; - return ret; - } - torture_shuffle_task_register(barrier_task); - return 0; + return torture_create_kthread(rcu_torture_barrier, NULL, barrier_task); } /* Clean up after RCU barrier testing. */ @@ -1516,17 +1490,10 @@ rcu_torture_init(void) /* Start up the kthreads. */ - VERBOSE_TOROUT_STRING("Creating rcu_torture_writer task"); - writer_task = kthread_create(rcu_torture_writer, NULL, - "rcu_torture_writer"); - if (IS_ERR(writer_task)) { - firsterr = PTR_ERR(writer_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create writer"); - writer_task = NULL; + firsterr = torture_create_kthread(rcu_torture_writer, NULL, + writer_task); + if (firsterr) goto unwind; - } - torture_shuffle_task_register(writer_task); - wake_up_process(writer_task); fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]), GFP_KERNEL); if (fakewriter_tasks == NULL) { @@ -1535,16 +1502,10 @@ rcu_torture_init(void) goto unwind; } for (i = 0; i < nfakewriters; i++) { - VERBOSE_TOROUT_STRING("Creating rcu_torture_fakewriter task"); - fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL, - "rcu_torture_fakewriter"); - if (IS_ERR(fakewriter_tasks[i])) { - firsterr = PTR_ERR(fakewriter_tasks[i]); - VERBOSE_TOROUT_ERRSTRING("Failed to create fakewriter"); - fakewriter_tasks[i] = NULL; + firsterr = torture_create_kthread(rcu_torture_fakewriter, + NULL, fakewriter_tasks[i]); + if (firsterr) goto unwind; - } - torture_shuffle_task_register(fakewriter_tasks[i]); } reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]), GFP_KERNEL); @@ -1554,28 +1515,16 @@ rcu_torture_init(void) goto unwind; } for (i = 0; i < nrealreaders; i++) { - VERBOSE_TOROUT_STRING("Creating rcu_torture_reader task"); - reader_tasks[i] = kthread_run(rcu_torture_reader, NULL, - "rcu_torture_reader"); - if (IS_ERR(reader_tasks[i])) { - firsterr = PTR_ERR(reader_tasks[i]); - VERBOSE_TOROUT_ERRSTRING("Failed to create reader"); - reader_tasks[i] = NULL; + firsterr = torture_create_kthread(rcu_torture_reader, NULL, + reader_tasks[i]); + if (firsterr) goto unwind; - } - torture_shuffle_task_register(reader_tasks[i]); } if (stat_interval > 0) { - VERBOSE_TOROUT_STRING("Creating rcu_torture_stats task"); - stats_task = kthread_run(rcu_torture_stats, NULL, - "rcu_torture_stats"); - if (IS_ERR(stats_task)) { - firsterr = PTR_ERR(stats_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create stats"); - stats_task = NULL; + firsterr = torture_create_kthread(rcu_torture_stats, NULL, + stats_task); + if (firsterr) goto unwind; - } - torture_shuffle_task_register(stats_task); } if (test_no_idle_hz) { firsterr = torture_shuffle_init(shuffle_interval * HZ); @@ -1593,16 +1542,9 @@ rcu_torture_init(void) fqs_duration = 0; if (fqs_duration) { /* Create the fqs thread */ - VERBOSE_TOROUT_STRING("Creating rcu_torture_fqs task"); - fqs_task = kthread_run(rcu_torture_fqs, NULL, - "rcu_torture_fqs"); - if (IS_ERR(fqs_task)) { - firsterr = PTR_ERR(fqs_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create fqs"); - fqs_task = NULL; + torture_create_kthread(rcu_torture_fqs, NULL, fqs_task); + if (firsterr) goto unwind; - } - torture_shuffle_task_register(fqs_task); } if (test_boost_interval < 1) test_boost_interval = 1; diff --git a/kernel/torture.c b/kernel/torture.c index 330576660cf4..439451821a7f 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -180,23 +180,16 @@ torture_onoff(void *arg) */ int torture_onoff_init(long ooholdoff, long oointerval) { -#ifdef CONFIG_HOTPLUG_CPU - int ret; + int ret = 0; +#ifdef CONFIG_HOTPLUG_CPU onoff_holdoff = ooholdoff; onoff_interval = oointerval; if (onoff_interval <= 0) return 0; - VERBOSE_TOROUT_STRING("Creating torture_onoff task"); - onoff_task = kthread_run(torture_onoff, NULL, "torture_onoff"); - if (IS_ERR(onoff_task)) { - ret = PTR_ERR(onoff_task); - onoff_task = NULL; - return ret; - } - torture_shuffle_task_register(onoff_task); + ret = torture_create_kthread(torture_onoff, NULL, onoff_task); #endif /* #ifdef CONFIG_HOTPLUG_CPU */ - return 0; + return ret; } EXPORT_SYMBOL_GPL(torture_onoff_init); @@ -379,8 +372,6 @@ static int torture_shuffle(void *arg) */ int torture_shuffle_init(long shuffint) { - int ret; - shuffle_interval = shuffint; shuffle_idle_cpu = -1; @@ -391,17 +382,7 @@ int torture_shuffle_init(long shuffint) } /* Create the shuffler thread */ - VERBOSE_TOROUT_STRING("Creating torture_shuffle task"); - shuffler_task = kthread_run(torture_shuffle, NULL, "torture_shuffle"); - if (IS_ERR(shuffler_task)) { - ret = PTR_ERR(shuffler_task); - free_cpumask_var(shuffle_tmp_mask); - VERBOSE_TOROUT_ERRSTRING("Failed to create shuffler"); - shuffler_task = NULL; - return ret; - } - torture_shuffle_task_register(shuffler_task); - return 0; + return torture_create_kthread(torture_shuffle, NULL, shuffler_task); } EXPORT_SYMBOL_GPL(torture_shuffle_init); @@ -483,25 +464,16 @@ static int torture_shutdown(void *arg) */ int torture_shutdown_init(int ssecs, void (*cleanup)(void)) { - int ret; + int ret = 0; shutdown_secs = ssecs; torture_shutdown_hook = cleanup; if (shutdown_secs > 0) { - VERBOSE_TOROUT_STRING("Creating torture_shutdown task"); shutdown_time = jiffies + shutdown_secs * HZ; - shutdown_task = kthread_create(torture_shutdown, NULL, - "torture_shutdown"); - if (IS_ERR(shutdown_task)) { - ret = PTR_ERR(shutdown_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create shutdown"); - shutdown_task = NULL; - return ret; - } - torture_shuffle_task_register(shutdown_task); - wake_up_process(shutdown_task); + ret = torture_create_kthread(torture_shutdown, NULL, + shutdown_task); } - return 0; + return ret; } EXPORT_SYMBOL_GPL(torture_shutdown_init); @@ -595,16 +567,8 @@ int torture_stutter_init(int s) int ret; stutter = s; - VERBOSE_TOROUT_STRING("Creating torture_stutter task"); - stutter_task = kthread_run(torture_stutter, NULL, "torture_stutter"); - if (IS_ERR(stutter_task)) { - ret = PTR_ERR(stutter_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create stutter"); - stutter_task = NULL; - return ret; - } - torture_shuffle_task_register(stutter_task); - return 0; + ret = torture_create_kthread(torture_stutter, NULL, stutter_task); + return ret; } EXPORT_SYMBOL_GPL(torture_stutter_init); @@ -714,3 +678,25 @@ void torture_kthread_stopping(char *title) } } EXPORT_SYMBOL_GPL(torture_kthread_stopping); + +/* + * Create a generic torture kthread that is immediately runnable. If you + * need the kthread to be stopped so that you can do something to it before + * it starts, you will need to open-code your own. + */ +int _torture_create_kthread(int (*fn)(void *arg), void *arg, char *s, char *m, + char *f, struct task_struct **tp) +{ + int ret = 0; + + VERBOSE_TOROUT_STRING(m); + *tp = kthread_run(fn, arg, s); + if (IS_ERR(*tp)) { + ret = PTR_ERR(*tp); + VERBOSE_TOROUT_ERRSTRING(f); + *tp = NULL; + } + torture_shuffle_task_register(*tp); + return ret; +} +EXPORT_SYMBOL_GPL(_torture_create_kthread); From 9c029b86098decd4660eec511b8d2d42da3e7dd9 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 4 Feb 2014 11:47:08 -0800 Subject: [PATCH 56/77] rcutorture: Abstract torture_stop_kthread() Stopping of kthreads is not RCU-specific, so this commit abstracts out torture_stop_kthread(), saving a few lines of code in the process. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 3 ++ kernel/rcu/rcutorture.c | 72 ++++++++--------------------------------- kernel/torture.c | 13 ++++++++ 3 files changed, 30 insertions(+), 58 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 430cc3008628..7ccfb0a16728 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -91,9 +91,12 @@ bool torture_must_stop_irq(void); void torture_kthread_stopping(char *title); int _torture_create_kthread(int (*fn)(void *arg), void *arg, char *s, char *m, char *f, struct task_struct **tp); +void _torture_stop_kthread(char *m, struct task_struct **tp); #define torture_create_kthread(n, arg, tp) \ _torture_create_kthread(n, (arg), #n, "Creating " #n " task", \ "Failed to create " #n, &(tp)) +#define torture_stop_kthread(n, tp) \ + _torture_stop_kthread("Stopping " #n " task", &(tp)) #endif /* __LINUX_TORTURE_H */ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index a6f6c8418d87..37bd4beea198 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1033,14 +1033,12 @@ static void rcutorture_booster_cleanup(int cpu) if (boost_tasks[cpu] == NULL) return; mutex_lock(&boost_mutex); - VERBOSE_TOROUT_STRING("Stopping rcu_torture_boost task"); t = boost_tasks[cpu]; boost_tasks[cpu] = NULL; mutex_unlock(&boost_mutex); /* This must be outside of the mutex, otherwise deadlock! */ - kthread_stop(t); - boost_tasks[cpu] = NULL; + torture_stop_kthread(rcu_torture_boost, t); } static int rcutorture_booster_init(int cpu) @@ -1110,16 +1108,6 @@ static int __init rcu_torture_stall_init(void) return torture_create_kthread(rcu_torture_stall, NULL, stall_task); } -/* Clean up after the CPU-stall kthread, if one was spawned. */ -static void rcu_torture_stall_cleanup(void) -{ - if (stall_task == NULL) - return; - VERBOSE_TOROUT_STRING("Stopping rcu_torture_stall_task."); - kthread_stop(stall_task); - stall_task = NULL; -} - /* Callback function for RCU barrier testing. */ void rcu_torture_barrier_cbf(struct rcu_head *rcu) { @@ -1230,19 +1218,11 @@ static void rcu_torture_barrier_cleanup(void) { int i; - if (barrier_task != NULL) { - VERBOSE_TOROUT_STRING("Stopping rcu_torture_barrier task"); - kthread_stop(barrier_task); - barrier_task = NULL; - } + torture_stop_kthread(rcu_torture_barrier, barrier_task); if (barrier_cbs_tasks != NULL) { - for (i = 0; i < n_barrier_cbs; i++) { - if (barrier_cbs_tasks[i] != NULL) { - VERBOSE_TOROUT_STRING("Stopping rcu_torture_barrier_cbs task"); - kthread_stop(barrier_cbs_tasks[i]); - barrier_cbs_tasks[i] = NULL; - } - } + for (i = 0; i < n_barrier_cbs; i++) + torture_stop_kthread(rcu_torture_barrier_cbs, + barrier_cbs_tasks[i]); kfree(barrier_cbs_tasks); barrier_cbs_tasks = NULL; } @@ -1288,53 +1268,29 @@ rcu_torture_cleanup(void) } rcu_torture_barrier_cleanup(); - rcu_torture_stall_cleanup(); + torture_stop_kthread(rcu_torture_stall, stall_task); torture_stutter_cleanup(); - - if (writer_task) { - VERBOSE_TOROUT_STRING("Stopping rcu_torture_writer task"); - kthread_stop(writer_task); - } - writer_task = NULL; + torture_stop_kthread(rcu_torture_writer, writer_task); if (reader_tasks) { - for (i = 0; i < nrealreaders; i++) { - if (reader_tasks[i]) { - VERBOSE_TOROUT_STRING( - "Stopping rcu_torture_reader task"); - kthread_stop(reader_tasks[i]); - } - reader_tasks[i] = NULL; - } + for (i = 0; i < nrealreaders; i++) + torture_stop_kthread(rcu_torture_reader, + reader_tasks[i]); kfree(reader_tasks); - reader_tasks = NULL; } rcu_torture_current = NULL; if (fakewriter_tasks) { for (i = 0; i < nfakewriters; i++) { - if (fakewriter_tasks[i]) { - VERBOSE_TOROUT_STRING( - "Stopping rcu_torture_fakewriter task"); - kthread_stop(fakewriter_tasks[i]); - } - fakewriter_tasks[i] = NULL; + torture_stop_kthread(rcu_torture_fakewriter, + fakewriter_tasks[i]); } kfree(fakewriter_tasks); fakewriter_tasks = NULL; } - if (stats_task) { - VERBOSE_TOROUT_STRING("Stopping rcu_torture_stats task"); - kthread_stop(stats_task); - } - stats_task = NULL; - - if (fqs_task) { - VERBOSE_TOROUT_STRING("Stopping rcu_torture_fqs task"); - kthread_stop(fqs_task); - } - fqs_task = NULL; + torture_stop_kthread(rcu_torture_stats, stats_task); + torture_stop_kthread(rcu_torture_fqs, fqs_task); if ((test_boost == 1 && cur_ops->can_boost) || test_boost == 2) { unregister_cpu_notifier(&rcutorture_cpu_nb); diff --git a/kernel/torture.c b/kernel/torture.c index 439451821a7f..871f63611f7f 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -700,3 +700,16 @@ int _torture_create_kthread(int (*fn)(void *arg), void *arg, char *s, char *m, return ret; } EXPORT_SYMBOL_GPL(_torture_create_kthread); + +/* + * Stop a generic kthread, emitting a message. + */ +void _torture_stop_kthread(char *m, struct task_struct **tp) +{ + if (*tp == NULL) + return; + VERBOSE_TOROUT_STRING(m); + kthread_stop(*tp); + *tp = NULL; +} +EXPORT_SYMBOL_GPL(_torture_stop_kthread); From bfefc73aa1d1bad317bccef8a15da39263d3d962 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 4 Feb 2014 12:35:27 -0800 Subject: [PATCH 57/77] rcutorture: Stop generic kthreads in torture_cleanup() The specific torture modules (like rcutorture) need to call torture_cleanup() in any case, so this commit makes torture_cleanup() deal with torture_shutdown_cleanup() and torture_stutter_cleanup() so that the specific modules don't have to deal with these details. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/torture.h | 2 -- kernel/rcu/rcutorture.c | 7 ------- kernel/torture.c | 37 +++++++++++++++++++------------------ 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/include/linux/torture.h b/include/linux/torture.h index 7ccfb0a16728..b2e2b468e511 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -75,12 +75,10 @@ int torture_shuffle_init(long shuffint); /* Test auto-shutdown handling. */ void torture_shutdown_absorb(const char *title); int torture_shutdown_init(int ssecs, void (*cleanup)(void)); -void torture_shutdown_cleanup(void); /* Task stuttering, which forces load/no-load transitions. */ void stutter_wait(const char *title); int torture_stutter_init(int s); -void torture_stutter_cleanup(void); /* Initialization and cleanup. */ void torture_init_begin(char *ttype, bool v, int *runnable); diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 37bd4beea198..40792e76a116 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -53,11 +53,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Paul E. McKenney and Josh Triplett "); -MODULE_ALIAS("rcutorture"); -#ifdef MODULE_PARAM_PREFIX -#undef MODULE_PARAM_PREFIX -#endif -#define MODULE_PARAM_PREFIX "rcutorture." torture_param(int, fqs_duration, 0, "Duration of fqs bursts (us), 0 to disable"); @@ -1269,7 +1264,6 @@ rcu_torture_cleanup(void) rcu_torture_barrier_cleanup(); torture_stop_kthread(rcu_torture_stall, stall_task); - torture_stutter_cleanup(); torture_stop_kthread(rcu_torture_writer, writer_task); if (reader_tasks) { @@ -1297,7 +1291,6 @@ rcu_torture_cleanup(void) for_each_possible_cpu(i) rcutorture_booster_cleanup(i); } - torture_shutdown_cleanup(); /* Wait for all RCU callbacks to fire. */ diff --git a/kernel/torture.c b/kernel/torture.c index 871f63611f7f..b26c7b42becd 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -477,20 +477,6 @@ int torture_shutdown_init(int ssecs, void (*cleanup)(void)) } EXPORT_SYMBOL_GPL(torture_shutdown_init); -/* - * Shut down the shutdown task. Say what??? Heh! This can happen if - * the torture module gets an rmmod before the shutdown time arrives. ;-) - */ -void torture_shutdown_cleanup(void) -{ - if (shutdown_task != NULL) { - VERBOSE_TOROUT_STRING("Stopping torture_shutdown task"); - kthread_stop(shutdown_task); - } - shutdown_task = NULL; -} -EXPORT_SYMBOL_GPL(torture_shutdown_cleanup); - /* * Detect and respond to a system shutdown. */ @@ -512,6 +498,20 @@ static struct notifier_block torture_shutdown_nb = { .notifier_call = torture_shutdown_notify, }; +/* + * Shut down the shutdown task. Say what??? Heh! This can happen if + * the torture module gets an rmmod before the shutdown time arrives. ;-) + */ +static void torture_shutdown_cleanup(void) +{ + unregister_reboot_notifier(&torture_shutdown_nb); + if (shutdown_task != NULL) { + VERBOSE_TOROUT_STRING("Stopping torture_shutdown task"); + kthread_stop(shutdown_task); + } + shutdown_task = NULL; +} + /* * Variables for stuttering, which means to periodically pause and * restart testing in order to catch bugs that appear when load is @@ -575,7 +575,7 @@ EXPORT_SYMBOL_GPL(torture_stutter_init); /* * Cleanup after the torture_stutter kthread. */ -void torture_stutter_cleanup(void) +static void torture_stutter_cleanup(void) { if (!stutter_task) return; @@ -583,7 +583,6 @@ void torture_stutter_cleanup(void) kthread_stop(stutter_task); stutter_task = NULL; } -EXPORT_SYMBOL_GPL(torture_stutter_cleanup); /* * Initialize torture module. Please note that this is -not- invoked via @@ -619,7 +618,8 @@ EXPORT_SYMBOL_GPL(torture_init_end); * Clean up torture module. Please note that this is -not- invoked via * the usual module_exit() mechanism, but rather by an explicit call from * the client torture module. Returns true if a race with system shutdown - * is detected. + * is detected, otherwise, all kthreads started by functions in this file + * will be shut down. * * This must be called before the caller starts shutting down its own * kthreads. @@ -635,8 +635,9 @@ bool torture_cleanup(void) } ACCESS_ONCE(fullstop) = FULLSTOP_RMMOD; mutex_unlock(&fullstop_mutex); - unregister_reboot_notifier(&torture_shutdown_nb); + torture_shutdown_cleanup(); torture_shuffle_cleanup(); + torture_stutter_cleanup(); torture_onoff_cleanup(); return false; } From 2193e1604eac422df05f77b53667237fcf130bf5 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 7 Feb 2014 15:16:25 -0800 Subject: [PATCH 58/77] rcutorture: Abstract kvm-recheck.sh This commit creates a plug-in to allow kvm-recheck.sh to process non-rcutorture console output. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- .../rcutorture/bin/kvm-recheck-rcu.sh | 51 +++++++++++++++++++ .../selftests/rcutorture/bin/kvm-recheck.sh | 20 +------- 2 files changed, 52 insertions(+), 19 deletions(-) create mode 100755 tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh new file mode 100755 index 000000000000..d75b1dc5ae53 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Analyze a given results directory for rcutorture progress. +# +# Usage: sh kvm-recheck-rcu.sh resdir +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2014 +# +# Authors: Paul E. McKenney + +i="$1" +if test -d $i +then + : +else + echo Unreadable results directory: $i + exit 1 +fi + +configfile=`echo $i | sed -e 's/^.*\///'` +ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'` +if test -z "$ngps" +then + echo $configfile +else + title="$configfile ------- $ngps grace periods" + dur=`sed -e 's/^.* rcutorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null` + if test -z "$dur" + then + : + else + ngpsps=`awk -v ngps=$ngps -v dur=$dur ' + BEGIN { print ngps / dur }' < /dev/null` + title="$title ($ngpsps per second)" + fi + echo $title +fi diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh index 89b5dbac5327..31c87063231d 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh @@ -37,25 +37,7 @@ do resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'` head -1 $resdir/log fi - configfile=`echo $i | sed -e 's/^.*\///'` - ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'` - if test -z "$ngps" - then - echo $configfile - else - title="$configfile ------- $ngps grace periods" - dur=`sed -e 's/^.* rcutorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null` - if test -z "$dur" - then - : - else - ngpsps=$((ngps / dur)) - ngpsps=`awk -v ngps=$ngps -v dur=$dur ' - BEGIN { print ngps / dur }' < /dev/null` - title="$title ($ngpsps per second)" - fi - echo $title - fi + kvm-recheck-rcu.sh $i configcheck.sh $i/.config $i/ConfigFragment parse-build.sh $i/Make.out $configfile parse-rcutorture.sh $i/console.log $configfile From 0af3fe1efa534a43385fe2694c42ffec7a310e46 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 4 Feb 2014 15:51:41 -0800 Subject: [PATCH 59/77] locktorture: Add a lock-torture kernel module This commit adds the locking counterpart to rcutorture. Signed-off-by: Paul E. McKenney [ paulmck: Make n_lock_torture_errors and torture_spinlock static as suggested by Fengguang Wu. ] Reviewed-by: Josh Triplett --- kernel/locking/Makefile | 1 + kernel/locking/locktorture.c | 421 +++++++++++++++++++++++++++++++++++ lib/Kconfig.debug | 15 ++ 3 files changed, 437 insertions(+) create mode 100644 kernel/locking/locktorture.c diff --git a/kernel/locking/Makefile b/kernel/locking/Makefile index baab8e5e7f66..a28ea6d9e6e8 100644 --- a/kernel/locking/Makefile +++ b/kernel/locking/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem-xadd.o obj-$(CONFIG_PERCPU_RWSEM) += percpu-rwsem.o +obj-$(CONFIG_LOCK_TORTURE_TEST) += locktorture.o diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c new file mode 100644 index 000000000000..d69d20d9c9db --- /dev/null +++ b/kernel/locking/locktorture.c @@ -0,0 +1,421 @@ +/* + * Module-based torture test facility for locking + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright (C) IBM Corporation, 2014 + * + * Author: Paul E. McKenney + * Based on kernel/rcu/torture.c. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Paul E. McKenney "); + +torture_param(int, nwriters_stress, -1, + "Number of write-locking stress-test threads"); +torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)"); +torture_param(int, onoff_interval, 0, + "Time between CPU hotplugs (s), 0=disable"); +torture_param(int, shuffle_interval, 3, + "Number of jiffies between shuffles, 0=disable"); +torture_param(int, shutdown_secs, 0, "Shutdown time (j), <= zero to disable."); +torture_param(int, stat_interval, 60, + "Number of seconds between stats printk()s"); +torture_param(int, stutter, 5, "Number of jiffies to run/halt test, 0=disable"); +torture_param(bool, verbose, true, + "Enable verbose debugging printk()s"); + +static char *torture_type = "spin_lock"; +module_param(torture_type, charp, 0444); +MODULE_PARM_DESC(torture_type, + "Type of lock to torture (spin_lock, spin_lock_irq, ...)"); + +static atomic_t n_lock_torture_errors; + +static struct task_struct *stats_task; +static struct task_struct **writer_tasks; + +static int nrealwriters_stress; +static bool lock_is_write_held; + +struct lock_writer_stress_stats { + long n_write_lock_fail; + long n_write_lock_acquired; +}; +static struct lock_writer_stress_stats *lwsa; + +#if defined(MODULE) || defined(CONFIG_LOCK_TORTURE_TEST_RUNNABLE) +#define LOCKTORTURE_RUNNABLE_INIT 1 +#else +#define LOCKTORTURE_RUNNABLE_INIT 0 +#endif +int locktorture_runnable = LOCKTORTURE_RUNNABLE_INIT; +module_param(locktorture_runnable, int, 0444); +MODULE_PARM_DESC(locktorture_runnable, "Start locktorture at boot"); + +/* Forward reference. */ +static void lock_torture_cleanup(void); + +/* + * Operations vector for selecting different types of tests. + */ +struct lock_torture_ops { + void (*init)(void); + int (*writelock)(void); + void (*write_delay)(struct torture_random_state *trsp); + void (*writeunlock)(void); + unsigned long flags; + const char *name; +}; + +static struct lock_torture_ops *cur_ops; + +/* + * Definitions for lock torture testing. + */ + +static DEFINE_SPINLOCK(torture_spinlock); + +static int torture_spin_lock_write_lock(void) __acquires(torture_spinlock) +{ + spin_lock(&torture_spinlock); + return 0; +} + +static void torture_spin_lock_write_delay(struct torture_random_state *trsp) +{ + const unsigned long shortdelay_us = 2; + const unsigned long longdelay_us = 100; + + /* We want a short delay mostly to emulate likely code, and + * we want a long delay occasionally to force massive contention. + */ + if (!(torture_random(trsp) % + (nrealwriters_stress * 2000 * longdelay_us))) + mdelay(longdelay_us); + if (!(torture_random(trsp) % + (nrealwriters_stress * 2 * shortdelay_us))) + udelay(shortdelay_us); +#ifdef CONFIG_PREEMPT + if (!(torture_random(trsp) % (nrealwriters_stress * 20000))) + preempt_schedule(); /* Allow test to be preempted. */ +#endif +} + +static void torture_spin_lock_write_unlock(void) __releases(torture_spinlock) +{ + spin_unlock(&torture_spinlock); +} + +static struct lock_torture_ops spin_lock_ops = { + .writelock = torture_spin_lock_write_lock, + .write_delay = torture_spin_lock_write_delay, + .writeunlock = torture_spin_lock_write_unlock, + .name = "spin_lock" +}; + +static int torture_spin_lock_write_lock_irq(void) +__acquires(torture_spinlock_irq) +{ + unsigned long flags; + + spin_lock_irqsave(&torture_spinlock, flags); + cur_ops->flags = flags; + return 0; +} + +static void torture_lock_spin_write_unlock_irq(void) +__releases(torture_spinlock) +{ + spin_unlock_irqrestore(&torture_spinlock, cur_ops->flags); +} + +static struct lock_torture_ops spin_lock_irq_ops = { + .writelock = torture_spin_lock_write_lock_irq, + .write_delay = torture_spin_lock_write_delay, + .writeunlock = torture_lock_spin_write_unlock_irq, + .name = "spin_lock_irq" +}; + +/* + * Lock torture writer kthread. Repeatedly acquires and releases + * the lock, checking for duplicate acquisitions. + */ +static int lock_torture_writer(void *arg) +{ + struct lock_writer_stress_stats *lwsp = arg; + static DEFINE_TORTURE_RANDOM(rand); + + VERBOSE_TOROUT_STRING("lock_torture_writer task started"); + set_user_nice(current, 19); + + do { + schedule_timeout_uninterruptible(1); + cur_ops->writelock(); + if (WARN_ON_ONCE(lock_is_write_held)) + lwsp->n_write_lock_fail++; + lock_is_write_held = 1; + lwsp->n_write_lock_acquired++; + cur_ops->write_delay(&rand); + lock_is_write_held = 0; + cur_ops->writeunlock(); + stutter_wait("lock_torture_writer"); + } while (!torture_must_stop()); + torture_kthread_stopping("lock_torture_writer"); + return 0; +} + +/* + * Create an lock-torture-statistics message in the specified buffer. + */ +static void lock_torture_printk(char *page) +{ + bool fail = 0; + int i; + long max = 0; + long min = lwsa[0].n_write_lock_acquired; + long long sum = 0; + + for (i = 0; i < nrealwriters_stress; i++) { + if (lwsa[i].n_write_lock_fail) + fail = true; + sum += lwsa[i].n_write_lock_acquired; + if (max < lwsa[i].n_write_lock_fail) + max = lwsa[i].n_write_lock_fail; + if (min > lwsa[i].n_write_lock_fail) + min = lwsa[i].n_write_lock_fail; + } + page += sprintf(page, "%s%s ", torture_type, TORTURE_FLAG); + page += sprintf(page, + "Writes: Total: %lld Max/Min: %ld/%ld %s Fail: %d %s\n", + sum, max, min, max / 2 > min ? "???" : "", + fail, fail ? "!!!" : ""); + if (fail) + atomic_inc(&n_lock_torture_errors); +} + +/* + * Print torture statistics. Caller must ensure that there is only one + * call to this function at a given time!!! This is normally accomplished + * by relying on the module system to only have one copy of the module + * loaded, and then by giving the lock_torture_stats kthread full control + * (or the init/cleanup functions when lock_torture_stats thread is not + * running). + */ +static void lock_torture_stats_print(void) +{ + int size = nrealwriters_stress * 200 + 8192; + char *buf; + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) { + pr_err("lock_torture_stats_print: Out of memory, need: %d", + size); + return; + } + lock_torture_printk(buf); + pr_alert("%s", buf); + kfree(buf); +} + +/* + * Periodically prints torture statistics, if periodic statistics printing + * was specified via the stat_interval module parameter. + * + * No need to worry about fullstop here, since this one doesn't reference + * volatile state or register callbacks. + */ +static int lock_torture_stats(void *arg) +{ + VERBOSE_TOROUT_STRING("lock_torture_stats task started"); + do { + schedule_timeout_interruptible(stat_interval * HZ); + lock_torture_stats_print(); + torture_shutdown_absorb("lock_torture_stats"); + } while (!torture_must_stop()); + torture_kthread_stopping("lock_torture_stats"); + return 0; +} + +static inline void +lock_torture_print_module_parms(struct lock_torture_ops *cur_ops, + const char *tag) +{ + pr_alert("%s" TORTURE_FLAG + "--- %s: nwriters_stress=%d stat_interval=%d verbose=%d shuffle_interval=%d stutter=%d shutdown_secs=%d onoff_interval=%d onoff_holdoff=%d\n", + torture_type, tag, nrealwriters_stress, stat_interval, verbose, + shuffle_interval, stutter, shutdown_secs, + onoff_interval, onoff_holdoff); +} + +static void lock_torture_cleanup(void) +{ + int i; + + if (torture_cleanup()) + return; + + if (writer_tasks) { + for (i = 0; i < nrealwriters_stress; i++) + torture_stop_kthread(lock_torture_writer, + writer_tasks[i]); + kfree(writer_tasks); + writer_tasks = NULL; + } + + torture_stop_kthread(lock_torture_stats, stats_task); + lock_torture_stats_print(); /* -After- the stats thread is stopped! */ + + if (atomic_read(&n_lock_torture_errors)) + lock_torture_print_module_parms(cur_ops, + "End of test: FAILURE"); + else if (torture_onoff_failures()) + lock_torture_print_module_parms(cur_ops, + "End of test: LOCK_HOTPLUG"); + else + lock_torture_print_module_parms(cur_ops, + "End of test: SUCCESS"); +} + +static int __init lock_torture_init(void) +{ + int i; + int firsterr = 0; + static struct lock_torture_ops *torture_ops[] = { + &spin_lock_ops, &spin_lock_irq_ops, + }; + + torture_init_begin(torture_type, verbose, &locktorture_runnable); + + /* Process args and tell the world that the torturer is on the job. */ + for (i = 0; i < ARRAY_SIZE(torture_ops); i++) { + cur_ops = torture_ops[i]; + if (strcmp(torture_type, cur_ops->name) == 0) + break; + } + if (i == ARRAY_SIZE(torture_ops)) { + pr_alert("lock-torture: invalid torture type: \"%s\"\n", + torture_type); + pr_alert("lock-torture types:"); + for (i = 0; i < ARRAY_SIZE(torture_ops); i++) + pr_alert(" %s", torture_ops[i]->name); + pr_alert("\n"); + torture_init_end(); + return -EINVAL; + } + if (cur_ops->init) + cur_ops->init(); /* no "goto unwind" prior to this point!!! */ + + if (nwriters_stress >= 0) + nrealwriters_stress = nwriters_stress; + else + nrealwriters_stress = 2 * num_online_cpus(); + lock_torture_print_module_parms(cur_ops, "Start of test"); + + /* Initialize the statistics so that each run gets its own numbers. */ + + lock_is_write_held = 0; + lwsa = kmalloc(sizeof(*lwsa) * nrealwriters_stress, GFP_KERNEL); + if (lwsa == NULL) { + VERBOSE_TOROUT_STRING("lwsa: Out of memory"); + firsterr = -ENOMEM; + goto unwind; + } + for (i = 0; i < nrealwriters_stress; i++) { + lwsa[i].n_write_lock_fail = 0; + lwsa[i].n_write_lock_acquired = 0; + } + + /* Start up the kthreads. */ + + if (onoff_interval > 0) { + firsterr = torture_onoff_init(onoff_holdoff * HZ, + onoff_interval * HZ); + if (firsterr) + goto unwind; + } + if (shuffle_interval > 0) { + firsterr = torture_shuffle_init(shuffle_interval); + if (firsterr) + goto unwind; + } + if (shutdown_secs > 0) { + firsterr = torture_shutdown_init(shutdown_secs, + lock_torture_cleanup); + if (firsterr) + goto unwind; + } + if (stutter > 0) { + firsterr = torture_stutter_init(stutter); + if (firsterr) + goto unwind; + } + + writer_tasks = kzalloc(nrealwriters_stress * sizeof(writer_tasks[0]), + GFP_KERNEL); + if (writer_tasks == NULL) { + VERBOSE_TOROUT_ERRSTRING("writer_tasks: Out of memory"); + firsterr = -ENOMEM; + goto unwind; + } + for (i = 0; i < nrealwriters_stress; i++) { + firsterr = torture_create_kthread(lock_torture_writer, &lwsa[i], + writer_tasks[i]); + if (firsterr) + goto unwind; + } + if (stat_interval > 0) { + firsterr = torture_create_kthread(lock_torture_stats, NULL, + stats_task); + if (firsterr) + goto unwind; + } + torture_init_end(); + return 0; + +unwind: + torture_init_end(); + lock_torture_cleanup(); + return firsterr; +} + +module_init(lock_torture_init); +module_exit(lock_torture_cleanup); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2bfb4e5cdf8c..dd7f8858188a 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -980,6 +980,21 @@ config DEBUG_LOCKING_API_SELFTESTS The following locking APIs are covered: spinlocks, rwlocks, mutexes and rwsems. +config LOCK_TORTURE_TEST + tristate "torture tests for locking" + depends on DEBUG_KERNEL + select TORTURE_TEST + default n + help + This option provides a kernel module that runs torture tests + on kernel locking primitives. The kernel module may be built + after the fact on the running kernel to be tested, if desired. + + Say Y here if you want kernel locking-primitive torture tests + to be built into the kernel. + Say M if you want these torture tests to build as a module. + Say N if you are unsure. + endmenu # lock debugging config TRACE_IRQFLAGS From ff20e251c409da81f2b850c81964908fb4c6fe66 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 6 Feb 2014 08:45:56 -0800 Subject: [PATCH 60/77] rcutorture: Add an rcu_busted to test the test This commit adds a deliberately buggy RCU implementation into rcutorture to allow easy checking that rcutorture correctly flags buggy RCU implementations. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/rcu/rcutorture.c | 44 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 40792e76a116..da6c38d909f1 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -371,6 +371,48 @@ static struct rcu_torture_ops rcu_bh_ops = { .name = "rcu_bh" }; +/* + * Don't even think about trying any of these in real life!!! + * The names includes "busted", and they really means it! + * The only purpose of these functions is to provide a buggy RCU + * implementation to make sure that rcutorture correctly emits + * buggy-RCU error messages. + */ +static void rcu_busted_torture_deferred_free(struct rcu_torture *p) +{ + /* This is a deliberate bug for testing purposes only! */ + rcu_torture_cb(&p->rtort_rcu); +} + +static void synchronize_rcu_busted(void) +{ + /* This is a deliberate bug for testing purposes only! */ +} + +static void +call_rcu_busted(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) +{ + /* This is a deliberate bug for testing purposes only! */ + func(head); +} + +static struct rcu_torture_ops rcu_busted_ops = { + .init = rcu_sync_torture_init, + .readlock = rcu_torture_read_lock, + .read_delay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = rcu_torture_read_unlock, + .completed = rcu_no_completed, + .deferred_free = rcu_busted_torture_deferred_free, + .sync = synchronize_rcu_busted, + .exp_sync = synchronize_rcu_busted, + .call = call_rcu_busted, + .cb_barrier = NULL, + .fqs = NULL, + .stats = NULL, + .irq_capable = 1, + .name = "rcu_busted" +}; + /* * Definitions for srcu torture testing. */ @@ -1371,7 +1413,7 @@ rcu_torture_init(void) int cpu; int firsterr = 0; static struct rcu_torture_ops *torture_ops[] = { - &rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops, + &rcu_ops, &rcu_bh_ops, &rcu_busted_ops, &srcu_ops, &sched_ops, }; torture_init_begin(torture_type, verbose, &rcutorture_runnable); From a1be00d9533f75bb46b9b64526d5254c6be0f122 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 6 Feb 2014 09:02:51 -0800 Subject: [PATCH 61/77] rcutorture: Create config files for scripted test-the-test testing This commit adds a pair of files in the configs directory to allow test-the-test runs of rcutorture via a "--configs BUSTED" argument to the kvm.sh script. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/configs/BUSTED | 8 ++++++++ tools/testing/selftests/rcutorture/configs/BUSTED.boot | 1 + 2 files changed, 9 insertions(+) create mode 100644 tools/testing/selftests/rcutorture/configs/BUSTED create mode 100644 tools/testing/selftests/rcutorture/configs/BUSTED.boot diff --git a/tools/testing/selftests/rcutorture/configs/BUSTED b/tools/testing/selftests/rcutorture/configs/BUSTED new file mode 100644 index 000000000000..46fb6cf30cc2 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/BUSTED @@ -0,0 +1,8 @@ +CONFIG_RCU_TRACE=n +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/BUSTED.boot b/tools/testing/selftests/rcutorture/configs/BUSTED.boot new file mode 100644 index 000000000000..6804f9dcfc1b --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/BUSTED.boot @@ -0,0 +1 @@ +rcutorture.torture_type=rcu_busted From d2ebf7eea0d3fd450ca5b1cb2243fe1d69d399ce Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 6 Feb 2014 11:54:32 -0800 Subject: [PATCH 62/77] rcutorture: Create CFcommon file for common Kconfig parameters Currently, CONFIG_RCU_TORTURE_TEST=y is hardcoded into the kvm-test-1-rcu.sh script and CONFIG_PRINTK_TIME=y is mentioned in each and every configs file. This commit creates a CFcommon file for these two Kconfig parameters, and modifies kvm-test-1-rcu.sh to copy this new file into the .config file during the build. This change will allow these scripts to operate on torture types other than just rcutorture. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh | 8 +++++--- tools/testing/selftests/rcutorture/configs/BUSTED | 1 - tools/testing/selftests/rcutorture/configs/CFcommon | 2 ++ tools/testing/selftests/rcutorture/configs/SRCU-N | 1 - tools/testing/selftests/rcutorture/configs/SRCU-P | 1 - tools/testing/selftests/rcutorture/configs/TINY01 | 1 - tools/testing/selftests/rcutorture/configs/TINY02 | 1 - tools/testing/selftests/rcutorture/configs/TREE01 | 1 - tools/testing/selftests/rcutorture/configs/TREE02 | 1 - tools/testing/selftests/rcutorture/configs/TREE03 | 1 - tools/testing/selftests/rcutorture/configs/TREE04 | 1 - tools/testing/selftests/rcutorture/configs/TREE05 | 1 - tools/testing/selftests/rcutorture/configs/TREE06 | 1 - tools/testing/selftests/rcutorture/configs/TREE07 | 1 - tools/testing/selftests/rcutorture/configs/TREE08 | 1 - tools/testing/selftests/rcutorture/configs/TREE08-T | 1 - tools/testing/selftests/rcutorture/configs/TREE09 | 1 - 17 files changed, 7 insertions(+), 18 deletions(-) create mode 100644 tools/testing/selftests/rcutorture/configs/CFcommon diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh index 41ea7810354f..30cfbc8f3a0b 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh @@ -47,6 +47,7 @@ trap 'rm -rf $T' 0 . $KVPATH/ver_functions.sh config_template=${1} +config_dir=`echo $config_template | sed -e 's,/[^/]*$,,'` title=`echo $config_template | sed -e 's/^.*\///'` builddir=${2} if test -z "$builddir" -o ! -d "$builddir" -o ! -w "$builddir" @@ -63,9 +64,10 @@ fi cp $config_template $resdir/ConfigFragment echo ' ---' `date`: Starting build echo ' ---' Kconfig fragment at: $config_template >> $resdir/log -cat << '___EOF___' >> $T -CONFIG_RCU_TORTURE_TEST=y -___EOF___ +if test -r "$config_dir/CFcommon" +then + cat < $config_dir/CFcommon >> $T +fi # Optimizations below this point # CONFIG_USB=n # CONFIG_SECURITY=n diff --git a/tools/testing/selftests/rcutorture/configs/BUSTED b/tools/testing/selftests/rcutorture/configs/BUSTED index 46fb6cf30cc2..48d8a245c7fa 100644 --- a/tools/testing/selftests/rcutorture/configs/BUSTED +++ b/tools/testing/selftests/rcutorture/configs/BUSTED @@ -5,4 +5,3 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/CFcommon b/tools/testing/selftests/rcutorture/configs/CFcommon new file mode 100644 index 000000000000..d2d2a86139db --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/CFcommon @@ -0,0 +1,2 @@ +CONFIG_RCU_TORTURE_TEST=y +CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N b/tools/testing/selftests/rcutorture/configs/SRCU-N index b4c6340d920a..9fbb41b9b314 100644 --- a/tools/testing/selftests/rcutorture/configs/SRCU-N +++ b/tools/testing/selftests/rcutorture/configs/SRCU-N @@ -5,4 +5,3 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=y CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-P b/tools/testing/selftests/rcutorture/configs/SRCU-P index 6650e00c6d91..4b6f272dba27 100644 --- a/tools/testing/selftests/rcutorture/configs/SRCU-P +++ b/tools/testing/selftests/rcutorture/configs/SRCU-P @@ -5,4 +5,3 @@ CONFIG_HOTPLUG_CPU=y CONFIG_PREEMPT_NONE=n CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TINY01 b/tools/testing/selftests/rcutorture/configs/TINY01 index 0c2823f21712..0a63e073a00c 100644 --- a/tools/testing/selftests/rcutorture/configs/TINY01 +++ b/tools/testing/selftests/rcutorture/configs/TINY01 @@ -10,4 +10,3 @@ CONFIG_RCU_TRACE=n CONFIG_DEBUG_LOCK_ALLOC=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_PREEMPT_COUNT=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TINY02 b/tools/testing/selftests/rcutorture/configs/TINY02 index e5072d7528b6..f4feaee40776 100644 --- a/tools/testing/selftests/rcutorture/configs/TINY02 +++ b/tools/testing/selftests/rcutorture/configs/TINY02 @@ -10,4 +10,3 @@ CONFIG_RCU_TRACE=y CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=n CONFIG_PREEMPT_COUNT=y -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE01 b/tools/testing/selftests/rcutorture/configs/TREE01 index 141119a00044..9c827ec59a97 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE01 +++ b/tools/testing/selftests/rcutorture/configs/TREE01 @@ -20,4 +20,3 @@ CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE02 b/tools/testing/selftests/rcutorture/configs/TREE02 index 2d4d09608528..bca03f6b3046 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE02 +++ b/tools/testing/selftests/rcutorture/configs/TREE02 @@ -23,4 +23,3 @@ CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE03 b/tools/testing/selftests/rcutorture/configs/TREE03 index a47de5be8a04..c1f111c1561b 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE03 +++ b/tools/testing/selftests/rcutorture/configs/TREE03 @@ -20,4 +20,3 @@ CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=y CONFIG_RCU_BOOST_PRIO=2 CONFIG_DEBUG_OBJECTS_RCU_HEAD=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE04 b/tools/testing/selftests/rcutorture/configs/TREE04 index 8d839b86a1d5..7dbd27ce17a4 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE04 +++ b/tools/testing/selftests/rcutorture/configs/TREE04 @@ -22,4 +22,3 @@ CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=y CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE05 b/tools/testing/selftests/rcutorture/configs/TREE05 index b5ba72ea25cb..d0f32e574743 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE05 +++ b/tools/testing/selftests/rcutorture/configs/TREE05 @@ -22,4 +22,3 @@ CONFIG_PROVE_RCU_DELAY=y CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE06 b/tools/testing/selftests/rcutorture/configs/TREE06 index 7c95ab48d29f..2e477dfb9c57 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE06 +++ b/tools/testing/selftests/rcutorture/configs/TREE06 @@ -23,4 +23,3 @@ CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=y -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE07 b/tools/testing/selftests/rcutorture/configs/TREE07 index 1467404bdec1..042f86ef362a 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE07 +++ b/tools/testing/selftests/rcutorture/configs/TREE07 @@ -21,4 +21,3 @@ CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=y CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE08 b/tools/testing/selftests/rcutorture/configs/TREE08 index 7d097a61ac2a..3438cee1e3c5 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE08 +++ b/tools/testing/selftests/rcutorture/configs/TREE08 @@ -23,4 +23,3 @@ CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE08-T b/tools/testing/selftests/rcutorture/configs/TREE08-T index 442c4e450ab3..bf4523d3e44c 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE08-T +++ b/tools/testing/selftests/rcutorture/configs/TREE08-T @@ -23,4 +23,3 @@ CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n -CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/TREE09 b/tools/testing/selftests/rcutorture/configs/TREE09 index 0d1ec0d3dfee..81e4f7c0bf0b 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE09 +++ b/tools/testing/selftests/rcutorture/configs/TREE09 @@ -18,4 +18,3 @@ CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n -CONFIG_PRINTK_TIME=y From a5afdeb13c86564bdbd27e8d154933fb65ea2426 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 6 Feb 2014 17:50:32 -0800 Subject: [PATCH 63/77] rcutorture: Remove RCU dependencies from ver_functions.sh API The current set of functions in ver_functions.sh have APIs that are specific to RCU. This commit therefore makes an RCU-independent function that outputs version-specific boot arguments. This has the benefit that a test-type-independent call in kvm-test-1-rcu.sh can now handle any type of test, given a test-type-specific set of files in a configs directory. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- .../rcutorture/bin/kvm-test-1-rcu.sh | 8 ++---- .../rcutorture/configs/v0.0/ver_functions.sh | 20 +++++++-------- .../rcutorture/configs/v3.3/ver_functions.sh | 25 +++++++++++-------- .../rcutorture/configs/v3.5/ver_functions.sh | 23 ++++++++++++----- .../rcutorture/configs/ver_functions.sh | 21 ++++++++++++---- 5 files changed, 58 insertions(+), 39 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh index 30cfbc8f3a0b..7986b3e7f318 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh @@ -148,12 +148,8 @@ qemu_append="`identify_qemu_append "$QEMU"`" # Pull in Kconfig-fragment boot parameters boot_args="`configfrag_boot_params "$boot_args" "$config_template"`" -# Generate CPU-hotplug boot parameters -boot_args="`rcutorture_param_onoff "$boot_args" $builddir/.config`" -# Generate rcu_barrier() boot parameter -boot_args="`rcutorture_param_n_barrier_cbs "$boot_args"`" -# Pull in standard rcutorture boot arguments -boot_args="$boot_args rcutorture.stat_interval=15 rcutorture.shutdown_secs=$seconds rcutorture.rcutorture_runnable=1 rcutorture.test_no_idle_hz=1 rcutorture.verbose=1" +# Generate kernel-version-specific boot parameters +boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`" echo $QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd if test -n "$RCU_BUILDONLY" diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh index e8052539af54..5ace37a89780 100644 --- a/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh @@ -20,16 +20,14 @@ # # Authors: Paul E. McKenney -# rcutorture_param_n_barrier_cbs bootparam-string +# per_version_boot_params bootparam-string config-file seconds # -# Adds n_barrier_cbs rcutorture module parameter to kernels having it. -rcutorture_param_n_barrier_cbs () { - echo $1 -} - -# rcutorture_param_onoff bootparam-string config-file -# -# Adds onoff rcutorture module parameters to kernels having it. -rcutorture_param_onoff () { - echo $1 +# Adds per-version torture-module parameters to kernels supporting them. +# Which old kernels do not. +per_version_boot_params () { + echo rcutorture.stat_interval=15 \ + rcutorture.shutdown_secs=$3 \ + rcutorture.rcutorture_runnable=1 \ + rcutorture.test_no_idle_hz=1 \ + rcutorture.verbose=1 } diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh index c37432f3572c..bae55692ce6e 100644 --- a/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh @@ -20,22 +20,25 @@ # # Authors: Paul E. McKenney -# rcutorture_param_n_barrier_cbs bootparam-string -# -# Adds n_barrier_cbs rcutorture module parameter to kernels having it. -rcutorture_param_n_barrier_cbs () { - echo $1 -} - # rcutorture_param_onoff bootparam-string config-file # # Adds onoff rcutorture module parameters to kernels having it. rcutorture_param_onoff () { if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" then - echo CPU-hotplug kernel, adding rcutorture onoff. - echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 - else - echo $1 + echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2 + echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 fi } + +# per_version_boot_params bootparam-string config-file seconds +# +# Adds per-version torture-module parameters to kernels supporting them. +per_version_boot_params () { + echo $1 `rcutorture_param_onoff "$1" "$2"` \ + rcutorture.stat_interval=15 \ + rcutorture.shutdown_secs=$3 \ + rcutorture.rcutorture_runnable=1 \ + rcutorture.test_no_idle_hz=1 \ + rcutorture.verbose=1 +} diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh index 6a5f13aab44d..8977d8d31b19 100644 --- a/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh @@ -26,9 +26,9 @@ rcutorture_param_n_barrier_cbs () { if echo $1 | grep -q "rcutorture\.n_barrier_cbs" then - echo $1 + : else - echo $1 rcutorture.n_barrier_cbs=4 + echo rcutorture.n_barrier_cbs=4 fi } @@ -38,9 +38,20 @@ rcutorture_param_n_barrier_cbs () { rcutorture_param_onoff () { if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" then - echo CPU-hotplug kernel, adding rcutorture onoff. - echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 - else - echo $1 + echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2 + echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 fi } + +# per_version_boot_params bootparam-string config-file seconds +# +# Adds per-version torture-module parameters to kernels supporting them. +per_version_boot_params () { + echo $1 `rcutorture_param_onoff "$1" "$2"` \ + `rcutorture_param_n_barrier_cbs "$1"` \ + rcutorture.stat_interval=15 \ + rcutorture.shutdown_secs=$3 \ + rcutorture.rcutorture_runnable=1 \ + rcutorture.test_no_idle_hz=1 \ + rcutorture.verbose=1 +} diff --git a/tools/testing/selftests/rcutorture/configs/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/ver_functions.sh index 5e40eadea777..8977d8d31b19 100644 --- a/tools/testing/selftests/rcutorture/configs/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/ver_functions.sh @@ -26,9 +26,9 @@ rcutorture_param_n_barrier_cbs () { if echo $1 | grep -q "rcutorture\.n_barrier_cbs" then - echo $1 + : else - echo $1 rcutorture.n_barrier_cbs=4 + echo rcutorture.n_barrier_cbs=4 fi } @@ -39,8 +39,19 @@ rcutorture_param_onoff () { if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" then echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2 - echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 - else - echo $1 + echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 fi } + +# per_version_boot_params bootparam-string config-file seconds +# +# Adds per-version torture-module parameters to kernels supporting them. +per_version_boot_params () { + echo $1 `rcutorture_param_onoff "$1" "$2"` \ + `rcutorture_param_n_barrier_cbs "$1"` \ + rcutorture.stat_interval=15 \ + rcutorture.shutdown_secs=$3 \ + rcutorture.rcutorture_runnable=1 \ + rcutorture.test_no_idle_hz=1 \ + rcutorture.verbose=1 +} From d3b1548aa247d7b436834dbe518189bb9c1ebd4b Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 6 Feb 2014 20:35:41 -0800 Subject: [PATCH 64/77] rcutorture: Rename kvm-test-1-rcu.sh The kvm-test-1-rcu.sh is not specific to RCU, so this commit renames it to kvm-test-1-run.sh. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- .../{kvm-test-1-rcu.sh => kvm-test-1-run.sh} | 18 +++++++++--------- tools/testing/selftests/rcutorture/bin/kvm.sh | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) rename tools/testing/selftests/rcutorture/bin/{kvm-test-1-rcu.sh => kvm-test-1-run.sh} (91%) diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh similarity index 91% rename from tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh rename to tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 7986b3e7f318..015d35bc43cb 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -6,13 +6,13 @@ # Execute this in the source tree. Do not run it as a background task # because qemu does not seem to like that much. # -# Usage: sh kvm-test-1-rcu.sh config builddir resdir minutes qemu-args boot_args +# Usage: sh kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args # -# qemu-args defaults to "" -- you will want "-nographic" if running headless. -# boot_args defaults to "root=/dev/sda noapic selinux=0 console=ttyS0" -# "initcall_debug debug rcutorture.stat_interval=15" -# "rcutorture.shutdown_secs=$((minutes * 60))" -# "rcutorture.rcutorture_runnable=1" +# qemu-args defaults to "-nographic", along with arguments specifying the +# number of CPUs and other options generated from +# the underlying CPU architecture. +# boot_args defaults to value returned by the per_version_boot_params +# shell function. # # Anything you specify for either qemu-args or boot_args is appended to # the default values. The "-smp" value is deduced from the contents of @@ -40,7 +40,7 @@ grace=120 -T=/tmp/kvm-test-1-rcu.sh.$$ +T=/tmp/kvm-test-1-run.sh.$$ trap 'rm -rf $T' 0 . $KVM/bin/functions.sh @@ -52,13 +52,13 @@ title=`echo $config_template | sed -e 's/^.*\///'` builddir=${2} if test -z "$builddir" -o ! -d "$builddir" -o ! -w "$builddir" then - echo "kvm-test-1-rcu.sh :$builddir: Not a writable directory, cannot build into it" + echo "kvm-test-1-run.sh :$builddir: Not a writable directory, cannot build into it" exit 1 fi resdir=${3} if test -z "$resdir" -o ! -d "$resdir" -o ! -w "$resdir" then - echo "kvm-test-1-rcu.sh :$resdir: Not a writable directory, cannot store results into it" + echo "kvm-test-1-run.sh :$resdir: Not a writable directory, cannot store results into it" exit 1 fi cp $config_template $resdir/ConfigFragment diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 242b52d11cf9..767097e2a293 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -307,7 +307,7 @@ function dump(first, pastlast) print "touch " builddir ".wait"; print "mkdir " builddir " > /dev/null 2>&1 || :"; print "mkdir " rd cfr[jn] " || :"; - print "kvm-test-1-rcu.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " builddir ".out 2>&1 &" + print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " builddir ".out 2>&1 &" print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`" print "while test -f " builddir ".wait" print "do" From 61010e74d76ca51dd452290d6c340c681df498ce Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 7 Feb 2014 10:29:49 -0800 Subject: [PATCH 65/77] rcutorture: Introduce "rcu" directory level underneath configs This commit uses the standard software ploy of introducing another level of indirection below the configs directory. This allows each torture-test suite to have its own set of Kconfig files, boot parameters, and version-specific scripts. Initially, we have only rcu, but lock will follow soonish. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- .../selftests/rcutorture/bin/kvm-test-1-run.sh | 2 +- tools/testing/selftests/rcutorture/bin/kvm.sh | 17 ++++++++++++++--- .../rcutorture/configs/{ => rcu}/BUSTED | 0 .../rcutorture/configs/{ => rcu}/BUSTED.boot | 0 .../rcutorture/configs/{ => rcu}/CFLIST | 0 .../rcutorture/configs/{ => rcu}/CFcommon | 0 .../rcutorture/configs/{ => rcu}/SRCU-N | 0 .../rcutorture/configs/{ => rcu}/SRCU-N.boot | 0 .../rcutorture/configs/{ => rcu}/SRCU-P | 0 .../rcutorture/configs/{ => rcu}/SRCU-P.boot | 0 .../rcutorture/configs/{ => rcu}/TINY01 | 0 .../rcutorture/configs/{ => rcu}/TINY02 | 0 .../rcutorture/configs/{ => rcu}/TREE01 | 0 .../rcutorture/configs/{ => rcu}/TREE01.boot | 0 .../rcutorture/configs/{ => rcu}/TREE02 | 2 +- .../rcutorture/configs/{ => rcu}/TREE03 | 0 .../rcutorture/configs/{ => rcu}/TREE04 | 0 .../rcutorture/configs/{ => rcu}/TREE04.boot | 0 .../rcutorture/configs/{ => rcu}/TREE05 | 0 .../rcutorture/configs/{ => rcu}/TREE05.boot | 0 .../rcutorture/configs/{ => rcu}/TREE06 | 0 .../rcutorture/configs/{ => rcu}/TREE07 | 0 .../rcutorture/configs/{ => rcu}/TREE08 | 0 .../rcutorture/configs/{ => rcu}/TREE08-T | 0 .../rcutorture/configs/{ => rcu}/TREE09 | 0 .../rcutorture/configs/{ => rcu}/v0.0/CFLIST | 0 .../configs/{ => rcu}/v0.0/N1-S-T-NH-SD-SMP-HP | 0 .../configs/{ => rcu}/v0.0/N2-2-t-nh-sd-SMP-hp | 0 .../configs/{ => rcu}/v0.0/N3-3-T-nh-SD-SMP-hp | 0 .../configs/{ => rcu}/v0.0/N4-A-t-NH-sd-SMP-HP | 0 .../configs/{ => rcu}/v0.0/N5-U-T-NH-sd-SMP-hp | 0 .../rcutorture/configs/{ => rcu}/v0.0/NT1-nh | 0 .../rcutorture/configs/{ => rcu}/v0.0/NT3-NH | 0 .../configs/{ => rcu}/v0.0/P1-S-T-NH-SD-SMP-HP | 0 .../configs/{ => rcu}/v0.0/P2-2-t-nh-sd-SMP-hp | 0 .../configs/{ => rcu}/v0.0/P3-3-T-nh-SD-SMP-hp | 0 .../configs/{ => rcu}/v0.0/P4-A-t-NH-sd-SMP-HP | 0 .../configs/{ => rcu}/v0.0/P5-U-T-NH-sd-SMP-hp | 0 .../rcutorture/configs/{ => rcu}/v0.0/PT1-nh | 0 .../rcutorture/configs/{ => rcu}/v0.0/PT2-NH | 0 .../configs/{ => rcu}/v0.0/ver_functions.sh | 0 .../rcutorture/configs/{ => rcu}/v3.12/CFLIST | 0 .../configs/{ => rcu}/v3.12/N1-S-T-NH-SD-SMP-HP | 0 .../configs/{ => rcu}/v3.12/N2-2-t-nh-sd-SMP-hp | 0 .../configs/{ => rcu}/v3.12/N3-3-T-nh-SD-SMP-hp | 0 .../configs/{ => rcu}/v3.12/N4-A-t-NH-sd-SMP-HP | 0 .../configs/{ => rcu}/v3.12/N5-U-T-NH-sd-SMP-hp | 0 .../configs/{ => rcu}/v3.12/N6---t-nh-SD-smp-hp | 0 .../configs/{ => rcu}/v3.12/N7-4-T-NH-SD-SMP-HP | 0 .../configs/{ => rcu}/v3.12/N8-2-T-NH-SD-SMP-HP | 0 .../rcutorture/configs/{ => rcu}/v3.12/NT1-nh | 0 .../rcutorture/configs/{ => rcu}/v3.12/NT3-NH | 0 .../configs/{ => rcu}/v3.12/P1-S-T-NH-SD-SMP-HP | 0 .../configs/{ => rcu}/v3.12/P2-2-t-nh-sd-SMP-hp | 0 .../configs/{ => rcu}/v3.12/P3-3-T-nh-SD-SMP-hp | 0 .../configs/{ => rcu}/v3.12/P4-A-t-NH-sd-SMP-HP | 0 .../configs/{ => rcu}/v3.12/P5-U-T-NH-sd-SMP-hp | 0 .../configs/{ => rcu}/v3.12/P6---t-nh-SD-smp-hp | 0 .../configs/{ => rcu}/v3.12/P7-4-T-NH-SD-SMP-HP | 0 .../{ => rcu}/v3.12/P7-4-T-NH-SD-SMP-HP-all | 0 .../{ => rcu}/v3.12/P7-4-T-NH-SD-SMP-HP-none | 0 .../configs/{ => rcu}/v3.12/P7-4-T-NH-SD-SMP-hp | 0 .../rcutorture/configs/{ => rcu}/v3.12/PT1-nh | 0 .../rcutorture/configs/{ => rcu}/v3.12/PT2-NH | 0 .../rcutorture/configs/{ => rcu}/v3.3/CFLIST | 0 .../configs/{ => rcu}/v3.3/N1-S-T-NH-SD-SMP-HP | 0 .../configs/{ => rcu}/v3.3/N2-2-t-nh-sd-SMP-hp | 0 .../configs/{ => rcu}/v3.3/N3-3-T-nh-SD-SMP-hp | 0 .../configs/{ => rcu}/v3.3/N4-A-t-NH-sd-SMP-HP | 0 .../configs/{ => rcu}/v3.3/N5-U-T-NH-sd-SMP-hp | 0 .../rcutorture/configs/{ => rcu}/v3.3/NT1-nh | 0 .../rcutorture/configs/{ => rcu}/v3.3/NT3-NH | 0 .../configs/{ => rcu}/v3.3/P1-S-T-NH-SD-SMP-HP | 0 .../configs/{ => rcu}/v3.3/P2-2-t-nh-sd-SMP-hp | 0 .../configs/{ => rcu}/v3.3/P3-3-T-nh-SD-SMP-hp | 0 .../configs/{ => rcu}/v3.3/P4-A-t-NH-sd-SMP-HP | 0 .../configs/{ => rcu}/v3.3/P5-U-T-NH-sd-SMP-hp | 0 .../rcutorture/configs/{ => rcu}/v3.3/PT1-nh | 0 .../rcutorture/configs/{ => rcu}/v3.3/PT2-NH | 0 .../configs/{ => rcu}/v3.3/ver_functions.sh | 0 .../rcutorture/configs/{ => rcu}/v3.5/CFLIST | 0 .../configs/{ => rcu}/v3.5/N1-S-T-NH-SD-SMP-HP | 0 .../configs/{ => rcu}/v3.5/N2-2-t-nh-sd-SMP-hp | 0 .../configs/{ => rcu}/v3.5/N3-3-T-nh-SD-SMP-hp | 0 .../configs/{ => rcu}/v3.5/N4-A-t-NH-sd-SMP-HP | 0 .../configs/{ => rcu}/v3.5/N5-U-T-NH-sd-SMP-hp | 0 .../rcutorture/configs/{ => rcu}/v3.5/NT1-nh | 0 .../rcutorture/configs/{ => rcu}/v3.5/NT3-NH | 0 .../configs/{ => rcu}/v3.5/P1-S-T-NH-SD-SMP-HP | 0 .../configs/{ => rcu}/v3.5/P2-2-t-nh-sd-SMP-hp | 0 .../configs/{ => rcu}/v3.5/P3-3-T-nh-SD-SMP-hp | 0 .../configs/{ => rcu}/v3.5/P4-A-t-NH-sd-SMP-HP | 0 .../configs/{ => rcu}/v3.5/P5-U-T-NH-sd-SMP-hp | 0 .../rcutorture/configs/{ => rcu}/v3.5/PT1-nh | 0 .../rcutorture/configs/{ => rcu}/v3.5/PT2-NH | 0 .../configs/{ => rcu}/v3.5/ver_functions.sh | 0 .../configs/{ => rcu}/ver_functions.sh | 0 97 files changed, 16 insertions(+), 5 deletions(-) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/BUSTED (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/BUSTED.boot (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/CFLIST (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/CFcommon (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/SRCU-N (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/SRCU-N.boot (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/SRCU-P (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/SRCU-P.boot (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TINY01 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TINY02 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE01 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE01.boot (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE02 (95%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE03 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE04 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE04.boot (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE05 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE05.boot (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE06 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE07 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE08 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE08-T (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/TREE09 (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/CFLIST (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/N1-S-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/N2-2-t-nh-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/N3-3-T-nh-SD-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/N4-A-t-NH-sd-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/N5-U-T-NH-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/NT1-nh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/NT3-NH (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/P1-S-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/P2-2-t-nh-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/P3-3-T-nh-SD-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/P4-A-t-NH-sd-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/P5-U-T-NH-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/PT1-nh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/PT2-NH (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v0.0/ver_functions.sh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/CFLIST (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/N1-S-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/N2-2-t-nh-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/N3-3-T-nh-SD-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/N4-A-t-NH-sd-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/N5-U-T-NH-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/N6---t-nh-SD-smp-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/N7-4-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/N8-2-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/NT1-nh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/NT3-NH (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P1-S-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P2-2-t-nh-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P3-3-T-nh-SD-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P4-A-t-NH-sd-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P5-U-T-NH-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P6---t-nh-SD-smp-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P7-4-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P7-4-T-NH-SD-SMP-HP-all (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P7-4-T-NH-SD-SMP-HP-none (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/P7-4-T-NH-SD-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/PT1-nh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.12/PT2-NH (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/CFLIST (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/N1-S-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/N2-2-t-nh-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/N3-3-T-nh-SD-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/N4-A-t-NH-sd-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/N5-U-T-NH-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/NT1-nh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/NT3-NH (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/P1-S-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/P2-2-t-nh-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/P3-3-T-nh-SD-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/P4-A-t-NH-sd-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/P5-U-T-NH-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/PT1-nh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/PT2-NH (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.3/ver_functions.sh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/CFLIST (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/N1-S-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/N2-2-t-nh-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/N3-3-T-nh-SD-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/N4-A-t-NH-sd-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/N5-U-T-NH-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/NT1-nh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/NT3-NH (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/P1-S-T-NH-SD-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/P2-2-t-nh-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/P3-3-T-nh-SD-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/P4-A-t-NH-sd-SMP-HP (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/P5-U-T-NH-sd-SMP-hp (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/PT1-nh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/PT2-NH (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/v3.5/ver_functions.sh (100%) rename tools/testing/selftests/rcutorture/configs/{ => rcu}/ver_functions.sh (100%) diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 015d35bc43cb..94b28bb37d36 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -199,5 +199,5 @@ then fi cp $builddir/console.log $resdir -parse-rcutorture.sh $resdir/console.log $title +parse-${TORTURE_SUITE}torture.sh $resdir/console.log $title parse-console.sh $resdir/console.log $title diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 767097e2a293..c24092ce981c 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -41,6 +41,7 @@ PATH=${KVM}/bin:$PATH; export PATH builddir="${KVM}/b1" RCU_INITRD="$KVM/initrd"; export RCU_INITRD RCU_KMAKE_ARG=""; export RCU_KMAKE_ARG +TORTURE_SUITE=rcu resdir="" configs="" cpus=0 @@ -66,8 +67,9 @@ usage () { echo " --no-initrd" echo " --qemu-args qemu-system-..." echo " --qemu-cmd qemu-system-..." - echo " --results absolute-pathname" echo " --relbuilddir relative-pathname" + echo " --results absolute-pathname" + echo " --torture rcu" exit 1 } @@ -156,6 +158,11 @@ do resdir=$2 shift ;; + --torture) + checkarg --torture "(suite name)" "$#" "$2" '^rcu$' '^--' + TORTURE_SUITE=$2 + shift + ;; *) echo Unknown argument $1 usage @@ -164,7 +171,7 @@ do shift done -CONFIGFRAG=${KVM}/configs; export CONFIGFRAG +CONFIGFRAG=${KVM}/configs/${TORTURE_SUITE}; export CONFIGFRAG KVPATH=${CONFIGFRAG}/$kversion; export KVPATH if test -z "$configs" @@ -191,6 +198,7 @@ then touch $resdir/$ds/log echo $scriptname $args >> $resdir/$ds/log + echo ${TORTURE_SUITE} > $resdir/$ds/TORTURE_SUITE pwd > $resdir/$ds/testid.txt if test -d .git @@ -265,6 +273,9 @@ END { }' # Generate a script to execute the tests in appropriate batches. +cat << ___EOF___ > $T/script +TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE +___EOF___ awk < $T/cfgcpu.pack \ -v CONFIGDIR="$CONFIGFRAG/$kversion/" \ -v KVM="$KVM" \ @@ -353,7 +364,7 @@ END { # Dump the last batch. if (ncpus != 0) dump(first, i); -}' > $T/script +}' >> $T/script if test "$dryrun" = script then diff --git a/tools/testing/selftests/rcutorture/configs/BUSTED b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED similarity index 100% rename from tools/testing/selftests/rcutorture/configs/BUSTED rename to tools/testing/selftests/rcutorture/configs/rcu/BUSTED diff --git a/tools/testing/selftests/rcutorture/configs/BUSTED.boot b/tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot similarity index 100% rename from tools/testing/selftests/rcutorture/configs/BUSTED.boot rename to tools/testing/selftests/rcutorture/configs/rcu/BUSTED.boot diff --git a/tools/testing/selftests/rcutorture/configs/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST similarity index 100% rename from tools/testing/selftests/rcutorture/configs/CFLIST rename to tools/testing/selftests/rcutorture/configs/rcu/CFLIST diff --git a/tools/testing/selftests/rcutorture/configs/CFcommon b/tools/testing/selftests/rcutorture/configs/rcu/CFcommon similarity index 100% rename from tools/testing/selftests/rcutorture/configs/CFcommon rename to tools/testing/selftests/rcutorture/configs/rcu/CFcommon diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N similarity index 100% rename from tools/testing/selftests/rcutorture/configs/SRCU-N rename to tools/testing/selftests/rcutorture/configs/rcu/SRCU-N diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N.boot b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N.boot similarity index 100% rename from tools/testing/selftests/rcutorture/configs/SRCU-N.boot rename to tools/testing/selftests/rcutorture/configs/rcu/SRCU-N.boot diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-P b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P similarity index 100% rename from tools/testing/selftests/rcutorture/configs/SRCU-P rename to tools/testing/selftests/rcutorture/configs/rcu/SRCU-P diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-P.boot b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot similarity index 100% rename from tools/testing/selftests/rcutorture/configs/SRCU-P.boot rename to tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot diff --git a/tools/testing/selftests/rcutorture/configs/TINY01 b/tools/testing/selftests/rcutorture/configs/rcu/TINY01 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TINY01 rename to tools/testing/selftests/rcutorture/configs/rcu/TINY01 diff --git a/tools/testing/selftests/rcutorture/configs/TINY02 b/tools/testing/selftests/rcutorture/configs/rcu/TINY02 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TINY02 rename to tools/testing/selftests/rcutorture/configs/rcu/TINY02 diff --git a/tools/testing/selftests/rcutorture/configs/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE01 rename to tools/testing/selftests/rcutorture/configs/rcu/TREE01 diff --git a/tools/testing/selftests/rcutorture/configs/TREE01.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE01.boot rename to tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot diff --git a/tools/testing/selftests/rcutorture/configs/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 similarity index 95% rename from tools/testing/selftests/rcutorture/configs/TREE02 rename to tools/testing/selftests/rcutorture/configs/rcu/TREE02 index bca03f6b3046..1a777b5f68b5 100644 --- a/tools/testing/selftests/rcutorture/configs/TREE02 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 @@ -7,7 +7,7 @@ CONFIG_PREEMPT=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_FULL=n -CONFIG_RCU_FAST_NO_HZ=n +CONFIG_RCU_FAST_NO_HZ=n CONFIG_RCU_TRACE=n CONFIG_HOTPLUG_CPU=n CONFIG_SUSPEND=n diff --git a/tools/testing/selftests/rcutorture/configs/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE03 rename to tools/testing/selftests/rcutorture/configs/rcu/TREE03 diff --git a/tools/testing/selftests/rcutorture/configs/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE04 rename to tools/testing/selftests/rcutorture/configs/rcu/TREE04 diff --git a/tools/testing/selftests/rcutorture/configs/TREE04.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE04.boot rename to tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot diff --git a/tools/testing/selftests/rcutorture/configs/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE05 rename to tools/testing/selftests/rcutorture/configs/rcu/TREE05 diff --git a/tools/testing/selftests/rcutorture/configs/TREE05.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE05.boot rename to tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot diff --git a/tools/testing/selftests/rcutorture/configs/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE06 rename to tools/testing/selftests/rcutorture/configs/rcu/TREE06 diff --git a/tools/testing/selftests/rcutorture/configs/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE07 rename to tools/testing/selftests/rcutorture/configs/rcu/TREE07 diff --git a/tools/testing/selftests/rcutorture/configs/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE08 rename to tools/testing/selftests/rcutorture/configs/rcu/TREE08 diff --git a/tools/testing/selftests/rcutorture/configs/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE08-T rename to tools/testing/selftests/rcutorture/configs/rcu/TREE08-T diff --git a/tools/testing/selftests/rcutorture/configs/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09 similarity index 100% rename from tools/testing/selftests/rcutorture/configs/TREE09 rename to tools/testing/selftests/rcutorture/configs/rcu/TREE09 diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/CFLIST rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh rename to tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/CFLIST rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH rename to tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/CFLIST rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh rename to tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/CFLIST rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh rename to tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh diff --git a/tools/testing/selftests/rcutorture/configs/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh similarity index 100% rename from tools/testing/selftests/rcutorture/configs/ver_functions.sh rename to tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh From 9dfa5b35c190e3ce9325a356f54282a4b8dc0336 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 7 Feb 2014 13:56:37 -0800 Subject: [PATCH 66/77] locktorture: Add vestigial locktorture configuration This commit adds a trivial set of configuration files for lock torturing. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 2 +- .../selftests/rcutorture/configs/lock/BUSTED | 6 +++ .../rcutorture/configs/lock/BUSTED.boot | 1 + .../selftests/rcutorture/configs/lock/CFLIST | 1 + .../rcutorture/configs/lock/CFcommon | 2 + .../selftests/rcutorture/configs/lock/LOCK01 | 6 +++ .../rcutorture/configs/lock/ver_functions.sh | 43 +++++++++++++++++++ 7 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/rcutorture/configs/lock/BUSTED create mode 100644 tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot create mode 100644 tools/testing/selftests/rcutorture/configs/lock/CFLIST create mode 100644 tools/testing/selftests/rcutorture/configs/lock/CFcommon create mode 100644 tools/testing/selftests/rcutorture/configs/lock/LOCK01 create mode 100644 tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index c24092ce981c..8d3a6e916811 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -159,7 +159,7 @@ do shift ;; --torture) - checkarg --torture "(suite name)" "$#" "$2" '^rcu$' '^--' + checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--' TORTURE_SUITE=$2 shift ;; diff --git a/tools/testing/selftests/rcutorture/configs/lock/BUSTED b/tools/testing/selftests/rcutorture/configs/lock/BUSTED new file mode 100644 index 000000000000..1d1da1477fc3 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/lock/BUSTED @@ -0,0 +1,6 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y diff --git a/tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot b/tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot new file mode 100644 index 000000000000..6386c15e9770 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/lock/BUSTED.boot @@ -0,0 +1 @@ +locktorture.torture_type=lock_busted diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFLIST b/tools/testing/selftests/rcutorture/configs/lock/CFLIST new file mode 100644 index 000000000000..a061b22d1892 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/lock/CFLIST @@ -0,0 +1 @@ +LOCK01 diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFcommon b/tools/testing/selftests/rcutorture/configs/lock/CFcommon new file mode 100644 index 000000000000..e372dc269254 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/lock/CFcommon @@ -0,0 +1,2 @@ +CONFIG_LOCK_TORTURE_TEST=y +CONFIG_PRINTK_TIME=y diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK01 b/tools/testing/selftests/rcutorture/configs/lock/LOCK01 new file mode 100644 index 000000000000..a9625e3d6cd9 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK01 @@ -0,0 +1,6 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y diff --git a/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh new file mode 100644 index 000000000000..9746ea1cd6c7 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# +# Kernel-version-dependent shell functions for the rest of the scripts. +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2014 +# +# Authors: Paul E. McKenney + +# locktorture_param_onoff bootparam-string config-file +# +# Adds onoff locktorture module parameters to kernels having it. +locktorture_param_onoff () { + if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" + then + echo CPU-hotplug kernel, adding locktorture onoff. 1>&2 + echo locktorture.onoff_interval=3 locktorture.onoff_holdoff=30 + fi +} + +# per_version_boot_params bootparam-string config-file seconds +# +# Adds per-version torture-module parameters to kernels supporting them. +per_version_boot_params () { + echo $1 `locktorture_param_onoff "$1" "$2"` \ + locktorture.stat_interval=15 \ + locktorture.shutdown_secs=$3 \ + locktorture.locktorture_runnable=1 \ + locktorture.verbose=1 +} From f881825a73543e9664c7fe7166e06f5f4d569834 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 7 Feb 2014 14:42:51 -0800 Subject: [PATCH 67/77] rcutorture: Gracefully handle NULL cleanup hooks Although most torture tests will have some cleanup hook, it is possible that one might not. This commit therefore enables graceful handling of a NULL cleanup hook during torture-test shutdown. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/torture.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/torture.c b/kernel/torture.c index b26c7b42becd..acc9afc2f26e 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -454,7 +454,10 @@ static int torture_shutdown(void *arg) VERBOSE_TOROUT_STRING("torture_shutdown task shutting down system"); shutdown_task = NULL; /* Avoid self-kill deadlock. */ - torture_shutdown_hook();/* Shut down the enclosing torture test. */ + if (torture_shutdown_hook) + torture_shutdown_hook(); + else + VERBOSE_TOROUT_STRING("No torture_shutdown_hook(), skipping."); kernel_power_off(); /* Shut down the system. */ return 0; } From 02736b81dd74ea141ac5d55e909ac58ddc5f610d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 7 Feb 2014 15:47:12 -0800 Subject: [PATCH 68/77] locktorture: Add kvm-recheck.sh plug-in for locktorture This commit adds the kvm-recheck-lock.sh plug-in for locktorture to print out lock-specific progress statistics. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- .../rcutorture/bin/kvm-recheck-lock.sh | 51 +++++++++++++++++++ .../selftests/rcutorture/bin/kvm-recheck.sh | 5 +- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100755 tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh new file mode 100755 index 000000000000..829186e19eb1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Analyze a given results directory for locktorture progress. +# +# Usage: sh kvm-recheck-lock.sh resdir +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2014 +# +# Authors: Paul E. McKenney + +i="$1" +if test -d $i +then + : +else + echo Unreadable results directory: $i + exit 1 +fi + +configfile=`echo $i | sed -e 's/^.*\///'` +ncs=`grep "Writes: Total:" $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* Total: //' -e 's/ .*$//'` +if test -z "$ncs" +then + echo $configfile +else + title="$configfile ------- $ncs acquisitions/releases" + dur=`sed -e 's/^.* locktorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null` + if test -z "$dur" + then + : + else + ncsps=`awk -v ncs=$ncs -v dur=$dur ' + BEGIN { print ncs / dur }' < /dev/null` + title="$title ($ncsps per second)" + fi + echo $title +fi diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh index 31c87063231d..a44daaa259a9 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Given the results directories for previous KVM runs of rcutorture, +# Given the results directories for previous KVM-based torture runs, # check the build and console output for errors. Given a directory # containing results directories, this recursively checks them all. # @@ -37,7 +37,8 @@ do resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'` head -1 $resdir/log fi - kvm-recheck-rcu.sh $i + TORTURE_SUITE="`cat $i/../TORTURE_SUITE`" + kvm-recheck-${TORTURE_SUITE}.sh $i configcheck.sh $i/.config $i/ConfigFragment parse-build.sh $i/Make.out $configfile parse-rcutorture.sh $i/console.log $configfile From 48a21d5cf05912ed3b2237f417a959a90fd6907d Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sat, 8 Feb 2014 18:06:57 -0800 Subject: [PATCH 69/77] rcutorture: Rename TREE_RCU-Kconfig.txt It used to be that: git ls-files "*Kconfig*" would find all Kconfig files and would only find Kconfig files. This commit renames TREE_RCU-Kconfig.txt to TREE_RCU-kconfig.txt so that this is once again true. Signed-off-by: Paul Bolle Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- .../rcutorture/doc/{TREE_RCU-Kconfig.txt => TREE_RCU-kconfig.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/testing/selftests/rcutorture/doc/{TREE_RCU-Kconfig.txt => TREE_RCU-kconfig.txt} (100%) diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt similarity index 100% rename from tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt rename to tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt From b46f358ae5e3558a9072f0354128d5749a584d01 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 10 Feb 2014 19:59:05 -0800 Subject: [PATCH 70/77] rcutorture: Place kvm-test-1-run.sh output into res directory The output of each kvm-test-1-run.sh script is placed into a file whose name parallels that of the build directory. This means that the kvm-test-1-run.sh output is overwritten by later run. This commit therefore places the kvm-test-1-run.sh output into the per-test-case directory in the "res" hierarchy. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 8d3a6e916811..48b27e9716ae 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -318,7 +318,7 @@ function dump(first, pastlast) print "touch " builddir ".wait"; print "mkdir " builddir " > /dev/null 2>&1 || :"; print "mkdir " rd cfr[jn] " || :"; - print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " builddir ".out 2>&1 &" + print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " rd cfr[jn] "/kvm-test-1-run.sh.out 2>&1 &" print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`" print "while test -f " builddir ".wait" print "do" @@ -337,7 +337,7 @@ function dump(first, pastlast) for (j = 1; j < jn; j++) { builddir=KVM "/b" j print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:" - print "cat " builddir ".out" + print "cat " rd cfr[j] "/kvm-test-1-run.sh.out" } } From e086481baf9d0436bdd6e9b739bfa4a83fb89ef5 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 11 Feb 2014 08:05:07 -0800 Subject: [PATCH 71/77] rcutorture: Add a lock_busted to test the test This commit adds a maximally broken locking primitive in which lock acquisition and release are both no-ops. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- kernel/locking/locktorture.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c index d69d20d9c9db..f26b1a18e34e 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c @@ -112,6 +112,37 @@ static struct lock_torture_ops *cur_ops; * Definitions for lock torture testing. */ +static int torture_lock_busted_write_lock(void) +{ + return 0; /* BUGGY, do not use in real life!!! */ +} + +static void torture_lock_busted_write_delay(struct torture_random_state *trsp) +{ + const unsigned long longdelay_us = 100; + + /* We want a long delay occasionally to force massive contention. */ + if (!(torture_random(trsp) % + (nrealwriters_stress * 2000 * longdelay_us))) + mdelay(longdelay_us); +#ifdef CONFIG_PREEMPT + if (!(torture_random(trsp) % (nrealwriters_stress * 20000))) + preempt_schedule(); /* Allow test to be preempted. */ +#endif +} + +static void torture_lock_busted_write_unlock(void) +{ + /* BUGGY, do not use in real life!!! */ +} + +static struct lock_torture_ops lock_busted_ops = { + .writelock = torture_lock_busted_write_lock, + .write_delay = torture_lock_busted_write_delay, + .writeunlock = torture_lock_busted_write_unlock, + .name = "lock_busted" +}; + static DEFINE_SPINLOCK(torture_spinlock); static int torture_spin_lock_write_lock(void) __acquires(torture_spinlock) @@ -320,7 +351,7 @@ static int __init lock_torture_init(void) int i; int firsterr = 0; static struct lock_torture_ops *torture_ops[] = { - &spin_lock_ops, &spin_lock_irq_ops, + &lock_busted_ops, &spin_lock_ops, &spin_lock_irq_ops, }; torture_init_begin(torture_type, verbose, &locktorture_runnable); From 73fa867e2c705cf5cf0a38df8618fa20eee3d75a Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 11 Feb 2014 12:16:14 -0800 Subject: [PATCH 72/77] rcutorture: Save kvm.sh output to log This commit logs the progress text that kvm.sh outputs, improving after-the-fact troubleshooting. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- tools/testing/selftests/rcutorture/bin/kvm.sh | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 48b27e9716ae..5a78cbf55f06 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -297,7 +297,8 @@ awk < $T/cfgcpu.pack \ # Dump out the scripting required to run one test batch. function dump(first, pastlast) { - print "echo ----Start batch: `date`" + print "echo ----Start batch: `date`"; + print "echo ----Start batch: `date` >> " rd "/log"; jn=1 for (j = first; j < pastlast; j++) { builddir=KVM "/b" jn @@ -314,30 +315,37 @@ function dump(first, pastlast) else ovf = ""; print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date`"; + print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date` >> " rd "/log"; print "rm -f " builddir ".*"; print "touch " builddir ".wait"; print "mkdir " builddir " > /dev/null 2>&1 || :"; print "mkdir " rd cfr[jn] " || :"; print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" RCU_QEMU_ARG "\" \"" RCU_BOOTARGS "\" > " rd cfr[jn] "/kvm-test-1-run.sh.out 2>&1 &" - print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`" + print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`"; + print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` >> " rd "/log"; print "while test -f " builddir ".wait" print "do" print "\tsleep 1" print "done" - print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date`" + print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date`"; + print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date` >> " rd "/log"; jn++; } for (j = 1; j < jn; j++) { builddir=KVM "/b" j print "rm -f " builddir ".ready" - print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`" + print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`"; + print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log"; } print "wait" - print "echo ---- All kernel runs complete. `date`" + print "echo ---- All kernel runs complete. `date`"; + print "echo ---- All kernel runs complete. `date` >> " rd "/log"; for (j = 1; j < jn; j++) { builddir=KVM "/b" j - print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:" - print "cat " rd cfr[j] "/kvm-test-1-run.sh.out" + print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:"; + print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results: >> " rd "/log"; + print "cat " rd cfr[j] "/kvm-test-1-run.sh.out"; + print "cat " rd cfr[j] "/kvm-test-1-run.sh.out >> " rd "/log"; } } From 8dd853d7b6efcabba631a590dad3ed55bba7f0f2 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 23 Feb 2014 08:34:24 -0800 Subject: [PATCH 73/77] Documentation/memory-barriers.txt: Clarify release/acquire ordering This commit fixes a couple of typos and clarifies what happens when the CPU chooses to execute a later lock acquisition before a prior lock release, in particular, why deadlock is avoided. Reported-by: Peter Hurley Reported-by: James Bottomley Reported-by: Stefan Richter Signed-off-by: Paul E. McKenney --- Documentation/memory-barriers.txt | 89 +++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 29 deletions(-) diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 9dde54c55b24..11c1d2049662 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -1674,12 +1674,12 @@ for each construct. These operations all imply certain barriers: Memory operations issued after the ACQUIRE will be completed after the ACQUIRE operation has completed. - Memory operations issued before the ACQUIRE may be completed after the - ACQUIRE operation has completed. An smp_mb__before_spinlock(), combined - with a following ACQUIRE, orders prior loads against subsequent stores and - stores and prior stores against subsequent stores. Note that this is - weaker than smp_mb()! The smp_mb__before_spinlock() primitive is free on - many architectures. + Memory operations issued before the ACQUIRE may be completed after + the ACQUIRE operation has completed. An smp_mb__before_spinlock(), + combined with a following ACQUIRE, orders prior loads against + subsequent loads and stores and also orders prior stores against + subsequent stores. Note that this is weaker than smp_mb()! The + smp_mb__before_spinlock() primitive is free on many architectures. (2) RELEASE operation implication: @@ -1724,24 +1724,21 @@ may occur as: ACQUIRE M, STORE *B, STORE *A, RELEASE M -This same reordering can of course occur if the lock's ACQUIRE and RELEASE are -to the same lock variable, but only from the perspective of another CPU not -holding that lock. +When the ACQUIRE and RELEASE are a lock acquisition and release, +respectively, this same reordering can occur if the lock's ACQUIRE and +RELEASE are to the same lock variable, but only from the perspective of +another CPU not holding that lock. In short, a ACQUIRE followed by an +RELEASE may -not- be assumed to be a full memory barrier. -In short, a RELEASE followed by an ACQUIRE may -not- be assumed to be a full -memory barrier because it is possible for a preceding RELEASE to pass a -later ACQUIRE from the viewpoint of the CPU, but not from the viewpoint -of the compiler. Note that deadlocks cannot be introduced by this -interchange because if such a deadlock threatened, the RELEASE would -simply complete. - -If it is necessary for a RELEASE-ACQUIRE pair to produce a full barrier, the -ACQUIRE can be followed by an smp_mb__after_unlock_lock() invocation. This -will produce a full barrier if either (a) the RELEASE and the ACQUIRE are -executed by the same CPU or task, or (b) the RELEASE and ACQUIRE act on the -same variable. The smp_mb__after_unlock_lock() primitive is free on many -architectures. Without smp_mb__after_unlock_lock(), the critical sections -corresponding to the RELEASE and the ACQUIRE can cross: +Similarly, the reverse case of a RELEASE followed by an ACQUIRE does not +imply a full memory barrier. If it is necessary for a RELEASE-ACQUIRE +pair to produce a full barrier, the ACQUIRE can be followed by an +smp_mb__after_unlock_lock() invocation. This will produce a full barrier +if either (a) the RELEASE and the ACQUIRE are executed by the same +CPU or task, or (b) the RELEASE and ACQUIRE act on the same variable. +The smp_mb__after_unlock_lock() primitive is free on many architectures. +Without smp_mb__after_unlock_lock(), the CPU's execution of the critical +sections corresponding to the RELEASE and the ACQUIRE can cross, so that: *A = a; RELEASE M @@ -1752,7 +1749,36 @@ could occur as: ACQUIRE N, STORE *B, STORE *A, RELEASE M -With smp_mb__after_unlock_lock(), they cannot, so that: +It might appear that this reordering could introduce a deadlock. +However, this cannot happen because if such a deadlock threatened, +the RELEASE would simply complete, thereby avoiding the deadlock. + + Why does this work? + + One key point is that we are only talking about the CPU doing + the reordering, not the compiler. If the compiler (or, for + that matter, the developer) switched the operations, deadlock + -could- occur. + + But suppose the CPU reordered the operations. In this case, + the unlock precedes the lock in the assembly code. The CPU + simply elected to try executing the later lock operation first. + If there is a deadlock, this lock operation will simply spin (or + try to sleep, but more on that later). The CPU will eventually + execute the unlock operation (which preceded the lock operation + in the assembly code), which will unravel the potential deadlock, + allowing the lock operation to succeed. + + But what if the lock is a sleeplock? In that case, the code will + try to enter the scheduler, where it will eventually encounter + a memory barrier, which will force the earlier unlock operation + to complete, again unraveling the deadlock. There might be + a sleep-unlock race, but the locking primitive needs to resolve + such races properly in any case. + +With smp_mb__after_unlock_lock(), the two critical sections cannot overlap. +For example, with the following code, the store to *A will always be +seen by other CPUs before the store to *B: *A = a; RELEASE M @@ -1760,13 +1786,18 @@ With smp_mb__after_unlock_lock(), they cannot, so that: smp_mb__after_unlock_lock(); *B = b; -will always occur as either of the following: +The operations will always occur in one of the following orders: - STORE *A, RELEASE, ACQUIRE, STORE *B - STORE *A, ACQUIRE, RELEASE, STORE *B + STORE *A, RELEASE, ACQUIRE, smp_mb__after_unlock_lock(), STORE *B + STORE *A, ACQUIRE, RELEASE, smp_mb__after_unlock_lock(), STORE *B + ACQUIRE, STORE *A, RELEASE, smp_mb__after_unlock_lock(), STORE *B If the RELEASE and ACQUIRE were instead both operating on the same lock -variable, only the first of these two alternatives can occur. +variable, only the first of these alternatives can occur. In addition, +the more strongly ordered systems may rule out some of the above orders. +But in any case, as noted earlier, the smp_mb__after_unlock_lock() +ensures that the store to *A will always be seen as happening before +the store to *B. Locks and semaphores may not provide any guarantee of ordering on UP compiled systems, and so cannot be counted on in such a situation to actually achieve @@ -2787,7 +2818,7 @@ in that order, but, without intervention, the sequence may have almost any combination of elements combined or discarded, provided the program's view of the world remains consistent. Note that ACCESS_ONCE() is -not- optional in the above example, as there are architectures where a given CPU might -interchange successive loads to the same location. On such architectures, +reorder successive loads to the same location. On such architectures, ACCESS_ONCE() does whatever is necessary to prevent this, for example, on Itanium the volatile casts used by ACCESS_ONCE() cause GCC to emit the special ld.acq and st.rel instructions that prevent such reordering. From 8857563b819b140aa8c9be920cfe44d5d3f808b7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 12 Feb 2014 13:02:22 -0800 Subject: [PATCH 74/77] notifier: Substitute rcu_access_pointer() for rcu_dereference_raw() (Trivial patch.) If the code is looking at the RCU-protected pointer itself, but not dereferencing it, the rcu_dereference() functions can be downgraded to rcu_access_pointer(). This commit makes this downgrade in __blocking_notifier_call_chain() which simply compares the RCU-protected pointer against NULL with no dereferencing. Signed-off-by: Paul E. McKenney Cc: Andrew Morton Cc: Linus Torvalds Reviewed-by: Josh Triplett --- kernel/notifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/notifier.c b/kernel/notifier.c index 2d5cc4ccff7f..db4c8b08a50c 100644 --- a/kernel/notifier.c +++ b/kernel/notifier.c @@ -309,7 +309,7 @@ int __blocking_notifier_call_chain(struct blocking_notifier_head *nh, * racy then it does not matter what the result of the test * is, we re-check the list after having taken the lock anyway: */ - if (rcu_dereference_raw(nh->head)) { + if (rcu_access_pointer(nh->head)) { down_read(&nh->rwsem); ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); From 7a754743185a4b05818e10058fa2fbe4e6969085 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 11 Feb 2014 16:10:12 -0500 Subject: [PATCH 75/77] rcu: Fix sparse warning for rcu_expedited from kernel/ksysfs.c This commit fixes the follwoing warning: kernel/ksysfs.c:143:5: warning: symbol 'rcu_expedited' was not declared. Should it be static? Signed-off-by: Paul Gortmaker [ paulmck: Moved the declaration to include/linux/rcupdate.h to avoid including the RCU-internal rcu.h file outside of RCU. ] Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/rcupdate.h | 1 + kernel/ksysfs.c | 2 ++ kernel/rcu/rcu.h | 2 -- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 32decf1a9c6c..f3706c6b2e21 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -46,6 +46,7 @@ #include #include +extern int rcu_expedited; /* for sysctl */ #ifdef CONFIG_RCU_TORTURE_TEST extern int rcutorture_runnable; /* for sysctl */ #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index d945a949760f..e660964086e2 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -19,6 +19,8 @@ #include #include +#include /* rcu_expedited */ + #define KERNEL_ATTR_RO(_name) \ static struct kobj_attribute _name##_attr = __ATTR_RO(_name) diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index 1bd787fddcb2..af2e60a8425d 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -116,8 +116,6 @@ static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head) } } -extern int rcu_expedited; - #ifdef CONFIG_RCU_STALL_COMMON extern int rcu_cpu_stall_suppress; From 5cb5c6e18f822b19bd41a2c0f9930c82b3ec0bc9 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 19 Feb 2014 14:33:27 -0500 Subject: [PATCH 76/77] rcu: Ensure kernel/rcu/rcu.h can be sourced/used stand-alone The kbuild test bot uncovered an implicit dependence on the trace header being present before rcu.h in ia64 allmodconfig that looks like this: In file included from kernel/ksysfs.c:22:0: kernel/rcu/rcu.h: In function '__rcu_reclaim': kernel/rcu/rcu.h:107:3: error: implicit declaration of function 'trace_rcu_invoke_kfree_callback' [-Werror=implicit-function-declaration] kernel/rcu/rcu.h:112:3: error: implicit declaration of function 'trace_rcu_invoke_callback' [-Werror=implicit-function-declaration] cc1: some warnings being treated as errors Looking at other rcu.h users, we can find that they all were sourcing the trace header in advance of rcu.h itself, as seen in the context of this diff. There were also some inconsistencies as to whether it was or wasn't sourced based on the parent tracing Kconfig. Rather than "fix" it at each use site, and have inconsistent use based on whether "#ifdef CONFIG_RCU_TRACE" was used or not, lets just source the trace header just once, in the actual consumer of it, which is rcu.h itself. We include it unconditionally, as build testing shows us that is a hard requirement for some files. Reported-by: kbuild test robot Signed-off-by: Paul Gortmaker Signed-off-by: Paul E. McKenney --- kernel/rcu/rcu.h | 1 + kernel/rcu/srcu.c | 2 -- kernel/rcu/tiny.c | 4 ---- kernel/rcu/tree.c | 2 -- kernel/rcu/update.c | 1 - 5 files changed, 1 insertion(+), 9 deletions(-) diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index af2e60a8425d..bfda2726ca45 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -23,6 +23,7 @@ #ifndef __LINUX_RCU_H #define __LINUX_RCU_H +#include #ifdef CONFIG_RCU_TRACE #define RCU_TRACE(stmt) stmt #else /* #ifdef CONFIG_RCU_TRACE */ diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index 2359779e1daa..c639556f3fa0 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c @@ -36,8 +36,6 @@ #include #include -#include - #include "rcu.h" /* diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 53b95bbf4abb..d9efcc13008c 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -37,10 +37,6 @@ #include #include -#ifdef CONFIG_RCU_TRACE -#include -#endif /* #else #ifdef CONFIG_RCU_TRACE */ - #include "rcu.h" /* Forward declarations for tiny_plugin.h. */ diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 73c3cd2b87ac..c7ed5db2dd79 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -58,8 +58,6 @@ #include #include "tree.h" -#include - #include "rcu.h" MODULE_ALIAS("rcutree"); diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index fd0d5b5b8e7c..4c0a9b0af469 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -49,7 +49,6 @@ #include #define CREATE_TRACE_POINTS -#include #include "rcu.h" From 765a3f4fed708ae429ee095914a7897acb3a65bd Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 14 Mar 2014 16:37:08 -0700 Subject: [PATCH 77/77] rcu: Provide grace-period piggybacking API The following pattern is currently not well supported by RCU: 1. Make data element inaccessible to RCU readers. 2. Do work that probably lasts for more than one grace period. 3. Do something to make sure RCU readers in flight before #1 above have completed. Here are some things that could currently be done: a. Do a synchronize_rcu() unconditionally at either #1 or #3 above. This works, but imposes needless work and latency. b. Post an RCU callback at #1 above that does a wakeup, then wait for the wakeup at #3. This works well, but likely results in an extra unneeded grace period. Open-coding this is also a bit more semi-tricky code than would be good. This commit therefore adds get_state_synchronize_rcu() and cond_synchronize_rcu() APIs. Call get_state_synchronize_rcu() at #1 above and pass its return value to cond_synchronize_rcu() at #3 above. This results in a call to synchronize_rcu() if no grace period has elapsed between #1 and #3, but requires only a load, comparison, and memory barrier if a full grace period did elapse. Requested-by: Peter Zijlstra Signed-off-by: Paul E. McKenney Acked-by: Peter Zijlstra --- include/linux/rcutiny.h | 10 +++++++ include/linux/rcutree.h | 2 ++ kernel/rcu/tree.c | 62 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index e8cb6e3b52a7..425c659d54e5 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -27,6 +27,16 @@ #include +static inline unsigned long get_state_synchronize_rcu(void) +{ + return 0; +} + +static inline void cond_synchronize_rcu(unsigned long oldstate) +{ + might_sleep(); +} + static inline void rcu_barrier_bh(void) { wait_rcu_gp(call_rcu_bh); diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index e9c63884df0a..a59ca05fd4e3 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -76,6 +76,8 @@ static inline void synchronize_rcu_bh_expedited(void) void rcu_barrier(void); void rcu_barrier_bh(void); void rcu_barrier_sched(void); +unsigned long get_state_synchronize_rcu(void); +void cond_synchronize_rcu(unsigned long oldstate); extern unsigned long rcutorture_testseq; extern unsigned long rcutorture_vernum; diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 351faba48b91..0c47e300210a 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1421,13 +1421,14 @@ static int rcu_gp_init(struct rcu_state *rsp) /* Advance to a new grace period and initialize state. */ record_gp_stall_check_time(rsp); - smp_wmb(); /* Record GP times before starting GP. */ - rsp->gpnum++; + /* Record GP times before starting GP, hence smp_store_release(). */ + smp_store_release(&rsp->gpnum, rsp->gpnum + 1); trace_rcu_grace_period(rsp->name, rsp->gpnum, TPS("start")); raw_spin_unlock_irq(&rnp->lock); /* Exclude any concurrent CPU-hotplug operations. */ mutex_lock(&rsp->onoff_mutex); + smp_mb__after_unlock_lock(); /* ->gpnum increment before GP! */ /* * Set the quiescent-state-needed bits in all the rcu_node @@ -1555,10 +1556,11 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) } rnp = rcu_get_root(rsp); raw_spin_lock_irq(&rnp->lock); - smp_mb__after_unlock_lock(); + smp_mb__after_unlock_lock(); /* Order GP before ->completed update. */ rcu_nocb_gp_set(rnp, nocb); - rsp->completed = rsp->gpnum; /* Declare grace period done. */ + /* Declare grace period done. */ + ACCESS_ONCE(rsp->completed) = rsp->gpnum; trace_rcu_grace_period(rsp->name, rsp->completed, TPS("end")); rsp->fqs_state = RCU_GP_IDLE; rdp = this_cpu_ptr(rsp->rda); @@ -2637,6 +2639,58 @@ void synchronize_rcu_bh(void) } EXPORT_SYMBOL_GPL(synchronize_rcu_bh); +/** + * get_state_synchronize_rcu - Snapshot current RCU state + * + * Returns a cookie that is used by a later call to cond_synchronize_rcu() + * to determine whether or not a full grace period has elapsed in the + * meantime. + */ +unsigned long get_state_synchronize_rcu(void) +{ + /* + * Any prior manipulation of RCU-protected data must happen + * before the load from ->gpnum. + */ + smp_mb(); /* ^^^ */ + + /* + * Make sure this load happens before the purportedly + * time-consuming work between get_state_synchronize_rcu() + * and cond_synchronize_rcu(). + */ + return smp_load_acquire(&rcu_state->gpnum); +} +EXPORT_SYMBOL_GPL(get_state_synchronize_rcu); + +/** + * cond_synchronize_rcu - Conditionally wait for an RCU grace period + * + * @oldstate: return value from earlier call to get_state_synchronize_rcu() + * + * If a full RCU grace period has elapsed since the earlier call to + * get_state_synchronize_rcu(), just return. Otherwise, invoke + * synchronize_rcu() to wait for a full grace period. + * + * Yes, this function does not take counter wrap into account. But + * counter wrap is harmless. If the counter wraps, we have waited for + * more than 2 billion grace periods (and way more on a 64-bit system!), + * so waiting for one additional grace period should be just fine. + */ +void cond_synchronize_rcu(unsigned long oldstate) +{ + unsigned long newstate; + + /* + * Ensure that this load happens before any RCU-destructive + * actions the caller might carry out after we return. + */ + newstate = smp_load_acquire(&rcu_state->completed); + if (ULONG_CMP_GE(oldstate, newstate)) + synchronize_rcu(); +} +EXPORT_SYMBOL_GPL(cond_synchronize_rcu); + static int synchronize_sched_expedited_cpu_stop(void *data) { /*