RCU changes for v3.7
Subsystems (19)
Ingo Molnar
maintainerLinus,
Please pull the latest core-rcu-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core-rcu-for-linus
HEAD: fa34da708cbe1e2d9a2ee7fc68ea8fccbf095d12 Merge branch 'rcu/idle' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu into core/rcu
Quite a few of changes:
0. 'idle RCU':
Adds RCU APIs that allow non-idle tasks to enter RCU idle mode and provides x86 code to make use of them, allowing RCU to treat user-mode execution as an extended quiescent state when the new RCU_USER_QS kernel configuration parameter is specified. (Work is in progress to port this to a few other architectures, but is not part of this series.)
1. A fix for a latent bug that has been in RCU ever since the addition of CPU stall warnings. This bug results in false-positive stall warnings, but thus far only on embedded systems with severely cut-down userspace configurations.
2. Further reductions in latency spikes for huge systems, along with additional boot-time adaptation to the actual hardware.
This is a large change, as it moves RCU grace-period initialization and cleanup, along with quiescent-state forcing, from softirq to a kthread. However, it appears to be in quite good shape (famous last words).
3. Updates to documentation and rcutorture, the latter category including keeping statistics on CPU-hotplug latencies and fixing some initialization-time races.
4. CPU-hotplug fixes and improvements.
5. Idle-loop fixes that were omitted on an earlier submission.
6. Miscellaneous fixes and improvements
In certain RCU configurations new kernel threads will show up (rcu_bh, rcu_sched), showing RCU processing overhead.
Thanks,
Ingo
------------------>
Dimitri Sivanich (1):
rcu: Segregate rcu_state fields to improve cache locality
Frederic Weisbecker (25):
alpha: Fix preemption handling in idle loop
alpha: Add missing RCU idle APIs on idle loop
cris: Add missing RCU idle APIs on idle loop
frv: Add missing RCU idle APIs on idle loop
h8300: Add missing RCU idle APIs on idle loop
m32r: Add missing RCU idle APIs on idle loop
m68k: Add missing RCU idle APIs on idle loop
mn10300: Add missing RCU idle APIs on idle loop
parisc: Add missing RCU idle APIs on idle loop
score: Add missing RCU idle APIs on idle loop
xtensa: Add missing RCU idle APIs on idle loop
rcu: New rcu_user_enter() and rcu_user_exit() APIs
rcu: New rcu_user_enter_after_irq() and rcu_user_exit_after_irq() APIs
rcu: Settle config for userspace extended quiescent state
rcu: Allow rcu_user_enter()/exit() to nest
rcu: Ignore userspace extended quiescent state by default
rcu: Switch task's syscall hooks on context switch
x86: Syscall hooks for userspace RCU extended QS
x86: Unspaghettize do_general_protection()
x86: Exception hooks for userspace RCU extended QS
rcu: Exit RCU extended QS on kernel preemption after irq/exception
rcu: Exit RCU extended QS on user preemption
x86: Use the new schedule_user API on userspace preemption
x86: Exit RCU extended QS on notify resume
rcu: Userspace RCU extended QS selftest
Josh Triplett (1):
trace: Don't declare trace_*_rcuidle functions in modules
Li Zhong (1):
rcu: Move TINY_RCU quiescent state out of extended quiescent state
Michael Wang (1):
kmemleak: Replace list_for_each_continue_rcu with new interface
Paul E. McKenney (52):
hotplug: Fix UP bug in smpboot hotplug code
rcu: Use smp_hotplug_thread facility for RCUs per-CPU kthread
infiniband: ehca: Fix while->do-while conversion typo
infiniband: ehca: Fix compiler warnings
rcu: Fix day-one dyntick-idle stall-warning bug
rcu: Move RCU grace-period initialization into a kthread
rcu: Prevent initialization-time quiescent-state race
rcu: Allow RCU grace-period initialization to be preempted
rcu: Move RCU grace-period cleanup into kthread
rcu: Allow RCU grace-period cleanup to be preempted
rcu: Break up rcu_gp_kthread() into subfunctions
rcu: Prevent offline CPUs from executing RCU core code
rcu: Provide OOM handler to motivate lazy RCU callbacks
rcu: Move quiescent-state forcing into kthread
rcu: Allow RCU quiescent-state forcing to be preempted
rcu: Adjust debugfs tracing for kthread-based quiescent-state forcing
rcu: Prevent force_quiescent_state() memory contention
rcu: Control grace-period duration from sysfs
rcu: Make rcutree module parameters visible in sysfs
rcu: Fix day-zero grace-period initialization/cleanup race
rcu: Add random PROVE_RCU_DELAY to grace-period initialization
rcu: Adjust for unconditional ->completed assignment
rcu: Eliminate signed overflow in synchronize_rcu_expedited()
rcu: Reduce synchronize_rcu_expedited() latency
rcu: Simplify quiescent-state detection
rcu: Handle unbalanced rcu_node configurations with few CPUs
rcu: Shrink RCU based on number of CPUs
rcu: Update rcutorture defaults
rcu: Track CPU-hotplug duration statistics
rcu: Document SRCU dead-CPU capabilities, emphasize read-side limits
rcu: Switch rcutorture to pr_alert() and friends
rcu: Prevent initialization race in rcutorture kthreads
rcu: Add PROVE_RCU_DELAY to provoke difficult races
rcu: Pull TINY_RCU dyntick-idle tracing into non-idle region
rcu: Properly initialize ->boost_tasks on CPU offline
rcu: Permit RCU_NONIDLE() to be used from interrupt context
rcu: Improve boost selection when moving tasks to root rcu_node
rcu: Make offline-CPU checking allow for indefinite delays
rcu: Fix obsolete rcu_initiate_boost() header comment
rcu: Apply for_each_rcu_flavor() to increment_cpu_stall_ticks()
rcu: Avoid rcu_print_detail_task_stall_rnp() segfault
rcu: Protect rcu_node accesses during CPU stall warnings
rcu: Avoid spurious RCU CPU stall warnings
rcu: Remove redundant memory barrier from __call_rcu()
rcu: Move TINY_PREEMPT_RCU away from raw_local_irq_save()
time: RCU permitted to stop idle entry via softirq
rcu: Fix CONFIG_RCU_FAST_NO_HZ stall warning message
rcu: Remove _rcu_barrier() dependency on __stop_machine()
rcu: Disallow callback registry on offline CPUs
ia64: Add missing RCU idle APIs on idle loop
rcu: Make RCU_FAST_NO_HZ handle adaptive ticks
rcu: Apply micro-optimization and int/bool fixes to RCU's idle handling
Peter Zijlstra (1):
sched: Fix load avg vs cpu-hotplug
Silas Boyd-Wickizer (2):
Use get_online_cpus to avoid races involving CPU hotplug Use get_online_cpus to avoid races involving CPU hotplug
Thomas Gleixner (6):
rcu: Yield simpler
kthread: Implement park/unpark facility
smpboot: Provide infrastructure for percpu hotplug threads
softirq: Use hotplug thread infrastructure
watchdog: Use hotplug thread infrastructure
infiniband: Ehca: Use hotplug thread infrastructure
Documentation/RCU/checklist.txt | 6 + Documentation/RCU/stallwarn.txt | 16 +- Documentation/RCU/trace.txt | 43 +- Documentation/RCU/whatisRCU.txt | 9 +- Documentation/kernel-parameters.txt | 11 + arch/Kconfig | 10 + arch/alpha/kernel/process.c | 6 +- arch/alpha/kernel/smp.c | 1 + arch/cris/kernel/process.c | 3 + arch/frv/kernel/process.c | 3 + arch/h8300/kernel/process.c | 3 + arch/ia64/kernel/process.c | 3 + arch/m32r/kernel/process.c | 3 + arch/m68k/kernel/process.c | 3 + arch/mn10300/kernel/process.c | 3 + arch/parisc/kernel/process.c | 3 + arch/score/kernel/process.c | 4 +- arch/um/drivers/mconsole_kern.c | 1 + arch/x86/Kconfig | 1 + arch/x86/include/asm/rcu.h | 32 ++ arch/x86/include/asm/thread_info.h | 10 +- arch/x86/kernel/cpuid.c | 5 + arch/x86/kernel/entry_64.S | 9 +- arch/x86/kernel/msr.c | 5 + arch/x86/kernel/ptrace.c | 5 + arch/x86/kernel/signal.c | 4 + arch/x86/kernel/traps.c | 109 ++-- arch/x86/mm/fault.c | 13 +- arch/xtensa/kernel/process.c | 3 + drivers/infiniband/hw/ehca/ehca_irq.c | 250 ++++------ drivers/infiniband/hw/ehca/ehca_irq.h | 6 +- include/linux/interrupt.h | 2 + include/linux/kthread.h | 11 +- include/linux/rcupdate.h | 21 +- include/linux/sched.h | 8 + include/linux/smpboot.h | 43 ++ include/linux/tracepoint.h | 28 +- init/Kconfig | 18 + kernel/Makefile | 3 +- kernel/cpu.c | 10 +- kernel/kthread.c | 185 ++++++- kernel/rcupdate.c | 4 + kernel/rcutiny.c | 33 +- kernel/rcutiny_plugin.h | 10 +- kernel/rcutorture.c | 159 +++--- kernel/rcutree.c | 916 ++++++++++++++++++++-------------- kernel/rcutree.h | 50 +- kernel/rcutree_plugin.h | 597 +++++++++------------- kernel/rcutree_trace.c | 22 +- kernel/sched/core.c | 19 + kernel/smpboot.c | 233 +++++++++ kernel/smpboot.h | 4 + kernel/softirq.c | 111 +--- kernel/time/tick-sched.c | 3 +- kernel/watchdog.c | 263 ++++------ lib/Kconfig.debug | 14 + mm/kmemleak.c | 6 +- 57 files changed, 1932 insertions(+), 1424 deletions(-) create mode 100644 arch/x86/include/asm/rcu.h create mode 100644 include/linux/smpboot.h
Documentation/RCU/checklist.txt +6 -0
@@ -310,6 +310,12 @@ over a rather long period of time, but improvements are always welcome! code under the influence of preempt_disable(), you instead need to use synchronize_irq() or synchronize_sched(). + This same limitation also applies to synchronize_rcu_bh() + and synchronize_srcu(), as well as to the asynchronous and + expedited forms of the three primitives, namely call_rcu(), + call_rcu_bh(), call_srcu(), synchronize_rcu_expedited(), + synchronize_rcu_bh_expedited(), and synchronize_srcu_expedited(). + 12. Any lock acquired by an RCU callback must be acquired elsewhere with softirq disabled, e.g., via spin_lock_irqsave(), spin_lock_bh(), etc. Failing to disable irq on a given
Documentation/RCU/stallwarn.txt +8 -8
@@ -99,7 +99,7 @@ In kernels with CONFIG_RCU_FAST_NO_HZ, even more information is printed: INFO: rcu_preempt detected stall on CPU - 0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 drain=0 . timer=-1 + 0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 drain=0 . timer not pending (t=65000 jiffies) The "(64628 ticks this GP)" indicates that this CPU has taken more
@@ -116,13 +116,13 @@ number between the two "/"s is the value of the nesting, which will be a small positive number if in the idle loop and a very large positive number (as shown above) otherwise. -For CONFIG_RCU_FAST_NO_HZ kernels, the "drain=0" indicates that the -CPU is not in the process of trying to force itself into dyntick-idle -state, the "." indicates that the CPU has not given up forcing RCU -into dyntick-idle mode (it would be "H" otherwise), and the "timer=-1" -indicates that the CPU has not recented forced RCU into dyntick-idle -mode (it would otherwise indicate the number of microseconds remaining -in this forced state). +For CONFIG_RCU_FAST_NO_HZ kernels, the "drain=0" indicates that the CPU is +not in the process of trying to force itself into dyntick-idle state, the +"." indicates that the CPU has not given up forcing RCU into dyntick-idle +mode (it would be "H" otherwise), and the "timer not pending" indicates +that the CPU has not recently forced RCU into dyntick-idle mode (it +would otherwise indicate the number of microseconds remaining in this +forced state). Multiple Warnings From One Stall
Documentation/RCU/trace.txt +16 -27
56 lines not on this page · raw message
Documentation/RCU/whatisRCU.txt +7 -2
@@ -873,7 +873,7 @@ d. Do you need to treat NMI handlers, hardirq handlers, and code segments with preemption disabled (whether via preempt_disable(), local_irq_save(), local_bh_disable(), or some other mechanism) as if they were explicit RCU readers? - If so, you need RCU-sched. + If so, RCU-sched is the only choice that will work for you. e. Do you need RCU grace periods to complete even in the face of softirq monopolization of one or more of the CPUs? For
@@ -884,7 +884,12 @@ f. Is your workload too update-intensive for normal use of RCU, but inappropriate for other synchronization mechanisms? If so, consider SLAB_DESTROY_BY_RCU. But please be careful! -g. Otherwise, use RCU. +g. Do you need read-side critical sections that are respected + even though they are in the middle of the idle loop, during + user-mode execution, or on an offlined CPU? If so, SRCU is the + only choice that will work for you. + +h. Otherwise, use RCU. Of course, this all assumes that you have determined that RCU is in fact the right tool for your job.
Documentation/kernel-parameters.txt +11 -0
@@ -2385,6 +2385,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted. rcutree.rcu_cpu_stall_timeout= [KNL,BOOT] Set timeout for RCU CPU stall warning messages. + rcutree.jiffies_till_first_fqs= [KNL,BOOT] + Set delay from grace-period initialization to + first attempt to force quiescent states. + Units are jiffies, minimum value is zero, + and maximum value is HZ. + + rcutree.jiffies_till_next_fqs= [KNL,BOOT] + Set delay between subsequent attempts to force + quiescent states. Units are jiffies, minimum + value is one, and maximum value is HZ. + rcutorture.fqs_duration= [KNL,BOOT] Set duration of force_quiescent_state bursts.
arch/Kconfig +10 -0
@@ -281,4 +281,14 @@ config SECCOMP_FILTER See Documentation/prctl/seccomp_filter.txt for details. +config HAVE_RCU_USER_QS + bool + help + Provide kernel entry/exit hooks necessary for userspace + RCU extended quiescent state. Syscalls need to be wrapped inside + rcu_user_exit()-rcu_user_enter() through the slow path using + TIF_NOHZ flag. Exceptions handlers must be wrapped as well. Irqs + are already protected inside rcu_irq_enter/rcu_irq_exit() but + preemption or signal handling on irq exit still need to be protected. + source "kernel/gcov/Kconfig"
arch/alpha/kernel/process.c +5 -1
@@ -28,6 +28,7 @@#include <linux/tty.h> #include <linux/console.h> #include <linux/slab.h> +#include <linux/rcupdate.h> #include <asm/reg.h> #include <asm/uaccess.h>
@@ -54,9 +55,12 @@ cpu_idle(void)/* FIXME -- EV6 and LCA45 know how to power down the CPU. */ +rcu_idle_enter ();while (!need_resched ())cpu_relax (); -schedule (); + +rcu_idle_exit (); +schedule_preempt_disabled (); } }
arch/alpha/kernel/smp.c +1 -0
@@ -166,6 +166,7 @@ smp_callin(void)DBGS (("smp_callin: commencing CPU %d current %p active_mm %p\n" , cpuid, current, current->active_mm)); +preempt_disable ();/* Do nothing. */ cpu_idle (); }
arch/cris/kernel/process.c +3 -0
@@ -25,6 +25,7 @@#include <linux/elfcore.h> #include <linux/mqueue.h> #include <linux/reboot.h> +#include <linux/rcupdate.h> //#define DEBUG
@@ -74,6 +75,7 @@ void cpu_idle (void) {/* endless idle loop with no priority at all */ while (1 ) { +rcu_idle_enter ();while (!need_resched ()) {void (*idle)(void );/*
@@ -86,6 +88,7 @@ void cpu_idle (void) idle = default_idle;idle (); } +rcu_idle_exit ();schedule_preempt_disabled (); } }
arch/frv/kernel/process.c +3 -0
@@ -25,6 +25,7 @@#include <linux/reboot.h> #include <linux/interrupt.h> #include <linux/pagemap.h> +#include <linux/rcupdate.h> #include <asm/asm-offsets.h> #include <asm/uaccess.h>
@@ -69,12 +70,14 @@ void cpu_idle(void) {/* endless idle loop with no priority at all */ while (1 ) { +rcu_idle_enter ();while (!need_resched ()) {check_pgt_cache ();if (!frv_dma_inprogress && idle)idle (); } +rcu_idle_exit ();schedule_preempt_disabled (); }
arch/h8300/kernel/process.c +3 -0
@@ -36,6 +36,7 @@#include <linux/reboot.h> #include <linux/fs.h> #include <linux/slab.h> +#include <linux/rcupdate.h> #include <asm/uaccess.h> #include <asm/traps.h>
@@ -78,8 +79,10 @@ void (*idle)(void) = default_idle;void cpu_idle (void ) {while (1 ) { +rcu_idle_enter ();while (!need_resched ())idle (); +rcu_idle_exit ();schedule_preempt_disabled (); } }
arch/ia64/kernel/process.c +3 -0
@@ -29,6 +29,7 @@#include <linux/kdebug.h> #include <linux/utsname.h> #include <linux/tracehook.h> +#include <linux/rcupdate.h> #include <asm/cpu.h> #include <asm/delay.h>
@@ -279,6 +280,7 @@ cpu_idle (void)/* endless idle loop with no priority at all */ while (1 ) { +rcu_idle_enter ();if (can_do_pal_halt) {current_thread_info ()->status &= ~TS_POLLING ;/*
@@ -309,6 +311,7 @@ cpu_idle (void)normal_xtp ();#endif } +rcu_idle_exit ();schedule_preempt_disabled ();check_pgt_cache ();if (cpu_is_offline (cpu))
arch/m32r/kernel/process.c +3 -0
@@ -26,6 +26,7 @@#include <linux/ptrace.h> #include <linux/unistd.h> #include <linux/hardirq.h> +#include <linux/rcupdate.h> #include <asm/io.h> #include <asm/uaccess.h>
@@ -82,6 +83,7 @@ void cpu_idle (void) {/* endless idle loop with no priority at all */ while (1 ) { +rcu_idle_enter ();while (!need_resched ()) {void (*idle)(void ) = pm_idle;
@@ -90,6 +92,7 @@ void cpu_idle (void)idle (); } +rcu_idle_exit ();schedule_preempt_disabled (); } }
arch/m68k/kernel/process.c +3 -0
@@ -25,6 +25,7 @@#include <linux/reboot.h> #include <linux/init_task.h> #include <linux/mqueue.h> +#include <linux/rcupdate.h> #include <asm/uaccess.h> #include <asm/traps.h>
@@ -75,8 +76,10 @@ void cpu_idle(void) {/* endless idle loop with no priority at all */ while (1 ) { +rcu_idle_enter ();while (!need_resched ())idle (); +rcu_idle_exit ();schedule_preempt_disabled (); } }
arch/mn10300/kernel/process.c +3 -0
@@ -25,6 +25,7 @@#include <linux/err.h> #include <linux/fs.h> #include <linux/slab.h> +#include <linux/rcupdate.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h>
@@ -107,6 +108,7 @@ void cpu_idle(void) {/* endless idle loop with no priority at all */ for (;;) { +rcu_idle_enter ();while (!need_resched ()) {void (*idle)(void );
@@ -121,6 +123,7 @@ void cpu_idle(void) }idle (); } +rcu_idle_exit ();schedule_preempt_disabled (); }
arch/parisc/kernel/process.c +3 -0
@@ -48,6 +48,7 @@#include <linux/unistd.h> #include <linux/kallsyms.h> #include <linux/uaccess.h> +#include <linux/rcupdate.h> #include <asm/io.h> #include <asm/asm-offsets.h>
@@ -69,8 +70,10 @@ void cpu_idle(void)/* endless idle loop with no priority at all */ while (1 ) { +rcu_idle_enter ();while (!need_resched ())barrier (); +rcu_idle_exit ();schedule_preempt_disabled ();check_pgt_cache (); }
arch/score/kernel/process.c +3 -1
@@ -27,6 +27,7 @@#include <linux/reboot.h> #include <linux/elfcore.h> #include <linux/pm.h> +#include <linux/rcupdate.h> void (*pm_power_off)(void );EXPORT_SYMBOL (pm_power_off);
@@ -50,9 +51,10 @@ void __noreturn cpu_idle(void) {/* endless idle loop with no priority at all */ while (1 ) { +rcu_idle_enter ();while (!need_resched ())barrier (); - +rcu_idle_exit ();schedule_preempt_disabled (); } }
arch/um/drivers/mconsole_kern.c +1 -0
@@ -705,6 +705,7 @@ static void stack_proc(void *arg)struct task_struct *from = current, *to = arg; to->thread.saved_task = from; +rcu_switch (from, to);switch_to (from, to, from); }
arch/x86/Kconfig +1 -0
@@ -97,6 +97,7 @@ config X86 select KTIME_SCALAR if X86_32 select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER + select HAVE_RCU_USER_QS if X86_64 config INSTRUCTION_DECODER def_bool (KPROBES || PERF_EVENTS || UPROBES)
arch/x86/include/asm/rcu.h new file +32 -0
@@ -0,0 +1,32 @@ +#ifndef _ASM_X86_RCU_H +#define _ASM_X86_RCU_H + +#ifndef __ASSEMBLY__ + +#include <linux/rcupdate.h> +#include <asm/ptrace.h> + +static inline void exception_enter (struct pt_regs *regs) +{ +rcu_user_exit (); +} + +static inline void exception_exit (struct pt_regs *regs) +{ +#ifdef CONFIG_RCU_USER_QS +if (user_mode (regs)) +rcu_user_enter (); +#endif +} + +#else /* __ASSEMBLY__ */ + +#ifdef CONFIG_RCU_USER_QS +# define SCHEDULE_USER call schedule_user +#else +# define SCHEDULE_USER call schedule +#endif + +#endif /* !__ASSEMBLY__ */ + +#endif
arch/x86/include/asm/thread_info.h +7 -3
@@ -89,6 +89,7 @@ struct thread_info {#define TIF_NOTSC 16/* TSC is not accessible in userland */ #define TIF_IA32 17/* IA32 compatibility process */ #define TIF_FORK 18/* ret_from_fork */ +#define TIF_NOHZ 19/* in adaptive nohz mode */ #define TIF_MEMDIE 20/* is terminating due to OOM killer */ #define TIF_DEBUG 21/* uses debug registers */ #define TIF_IO_BITMAP 22/* uses I/O bitmap */
@@ -114,6 +115,7 @@ struct thread_info {#define _TIF_NOTSC (1 << TIF_NOTSC)#define _TIF_IA32 (1 << TIF_IA32)#define _TIF_FORK (1 << TIF_FORK) +#define _TIF_NOHZ (1 << TIF_NOHZ)#define _TIF_DEBUG (1 << TIF_DEBUG)#define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP)#define _TIF_FORCED_TF (1 << TIF_FORCED_TF)
@@ -126,12 +128,13 @@ struct thread_info {/* work to do in syscall_trace_enter() */ #define _TIF_WORK_SYSCALL_ENTRY \ (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT | \ - _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT) + _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT | \ + _TIF_NOHZ)/* work to do in syscall_trace_leave() */ #define _TIF_WORK_SYSCALL_EXIT \ (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP | \ - _TIF_SYSCALL_TRACEPOINT) + _TIF_SYSCALL_TRACEPOINT | _TIF_NOHZ)/* work to do on interrupt/exception return */ #define _TIF_WORK_MASK \
@@ -141,7 +144,8 @@ struct thread_info {/* work to do on any return to user space */ #define _TIF_ALLWORK_MASK \ - ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT) + ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT | \ + _TIF_NOHZ)/* Only used for 64 bit */ #define _TIF_DO_NOTIFY_MASK \
arch/x86/kernel/cpuid.c +5 -0
@@ -199,12 +199,14 @@ static int __init cpuid_init(void) goto out_chrdev; } cpuid_class->devnode = cpuid_devnode; +get_online_cpus ();for_each_online_cpu (i) { err =cpuid_device_create (i);if (err !=0 ) goto out_class; }register_hotcpu_notifier (&cpuid_class_cpu_notifier); +put_online_cpus (); err =0 ; goto out;
@@ -214,6 +216,7 @@ out_class:for_each_online_cpu (i) {cpuid_device_destroy (i); } +put_online_cpus ();class_destroy (cpuid_class); out_chrdev:__unregister_chrdev (CPUID_MAJOR ,0 ,NR_CPUS ,"cpu/cpuid" );
@@ -225,11 +228,13 @@ static void __exit cpuid_exit(void) {int cpu =0 ; +get_online_cpus ();for_each_online_cpu (cpu)cpuid_device_destroy (cpu);class_destroy (cpuid_class);__unregister_chrdev (CPUID_MAJOR ,0 ,NR_CPUS ,"cpu/cpuid" );unregister_hotcpu_notifier (&cpuid_class_cpu_notifier); +put_online_cpus (); }module_init (cpuid_init);
arch/x86/kernel/entry_64.S +5 -4
@@ -56,6 +56,7 @@ #include <asm/ftrace.h> #include <asm/percpu.h> #include <asm/asm.h> +#include <asm/rcu.h> #include <linux/err.h> /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
@@ -565,7 +566,7 @@ sysret_careful: TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) pushq_cfi %rdi - call schedule + SCHEDULE_USER popq_cfi %rdi jmp sysret_check
@@ -678,7 +679,7 @@ int_careful: TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) pushq_cfi %rdi - call schedule + SCHEDULE_USER popq_cfi %rdi DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF
@@ -974,7 +975,7 @@ retint_careful: TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) pushq_cfi %rdi - call schedule + SCHEDULE_USER popq_cfi %rdi GET_THREAD_INFO(%rcx) DISABLE_INTERRUPTS(CLBR_NONE)
@@ -1449,7 +1450,7 @@ paranoid_userspace: paranoid_schedule: TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_ANY) - call schedule + SCHEDULE_USER DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_OFF jmp paranoid_userspace
arch/x86/kernel/msr.c +5 -0
@@ -257,12 +257,14 @@ static int __init msr_init(void) goto out_chrdev; } msr_class->devnode = msr_devnode; +get_online_cpus ();for_each_online_cpu (i) { err =msr_device_create (i);if (err !=0 ) goto out_class; }register_hotcpu_notifier (&msr_class_cpu_notifier); +put_online_cpus (); err =0 ; goto out;
@@ -271,6 +273,7 @@ out_class: i =0 ;for_each_online_cpu (i)msr_device_destroy (i); +put_online_cpus ();class_destroy (msr_class); out_chrdev:__unregister_chrdev (MSR_MAJOR ,0 ,NR_CPUS ,"cpu/msr" );
@@ -281,11 +284,13 @@ out: static void __exit msr_exit(void) {int cpu =0 ; +get_online_cpus ();for_each_online_cpu (cpu)msr_device_destroy (cpu);class_destroy (msr_class);__unregister_chrdev (MSR_MAJOR ,0 ,NR_CPUS ,"cpu/msr" );unregister_hotcpu_notifier (&msr_class_cpu_notifier); +put_online_cpus (); }module_init (msr_init);
arch/x86/kernel/ptrace.c +5 -0
@@ -21,6 +21,7 @@#include <linux/signal.h> #include <linux/perf_event.h> #include <linux/hw_breakpoint.h> +#include <linux/rcupdate.h> #include <asm/uaccess.h> #include <asm/pgtable.h>
@@ -1463,6 +1464,8 @@ long syscall_trace_enter(struct pt_regs *regs) {long ret =0 ; +rcu_user_exit (); +/* * If we stepped into a sysenter/syscall insn, it trapped in * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP.
@@ -1526,4 +1529,6 @@ void syscall_trace_leave(struct pt_regs *regs) !test_thread_flag (TIF_SYSCALL_EMU );if (step ||test_thread_flag (TIF_SYSCALL_TRACE ))tracehook_report_syscall_exit (regs, step); + +rcu_user_enter (); }
arch/x86/kernel/signal.c +4 -0
@@ -779,6 +779,8 @@ static void do_signal(struct pt_regs *regs)void do_notify_resume (struct pt_regs *regs,void *unused,__u32 thread_info_flags) { +rcu_user_exit (); +#ifdef CONFIG_X86_MCE /* notify userspace of pending MCEs */ if (thread_info_flags & _TIF_MCE_NOTIFY)
@@ -804,6 +806,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)#ifdef CONFIG_X86_32 clear_thread_flag (TIF_IRET );#endif /* CONFIG_X86_32 */ + +rcu_user_enter (); }void signal_fault (struct pt_regs *regs,void __user *frame,char *where)
arch/x86/kernel/traps.c +66 -43
256 lines not on this page · raw message
arch/x86/mm/fault.c +11 -2
@@ -18,6 +18,7 @@#include <asm/pgalloc.h> /* pgd_*(), ... */ #include <asm/kmemcheck.h> /* kmemcheck_*(), ... */ #include <asm/fixmap.h> /* VSYSCALL_START */ +#include <asm/rcu.h> /* exception_enter(), ... */ /* * Page fault error code bits:
@@ -1000,8 +1001,8 @@ static int fault_in_kernel_space(unsigned long address)* and the problem, and then passes it off to one of the appropriate * routines. */ -dotraplinkage void __kprobes -do_page_fault (struct pt_regs *regs,unsigned long error_code) +static void __kprobes +__do_page_fault (struct pt_regs *regs,unsigned long error_code) {struct vm_area_struct *vma;struct task_struct *tsk;
@@ -1209,3 +1210,11 @@ good_area:up_read (&mm->mmap_sem); } + +dotraplinkage void __kprobes +do_page_fault (struct pt_regs *regs,unsigned long error_code) +{ +exception_enter (regs); +__do_page_fault (regs, error_code); +exception_exit (regs); +}
arch/xtensa/kernel/process.c +3 -0
@@ -31,6 +31,7 @@#include <linux/mqueue.h> #include <linux/fs.h> #include <linux/slab.h> +#include <linux/rcupdate.h> #include <asm/pgtable.h> #include <asm/uaccess.h>
@@ -110,8 +111,10 @@ void cpu_idle(void)/* endless idle loop with no priority at all */ while (1 ) { +rcu_idle_enter ();while (!need_resched ())platform_idle (); +rcu_idle_exit ();schedule_preempt_disabled (); } }
drivers/infiniband/hw/ehca/ehca_irq.c +89 -161
364 lines not on this page · raw message
drivers/infiniband/hw/ehca/ehca_irq.h +3 -3
@@ -58,15 +58,15 @@ void ehca_tasklet_eq(unsigned long data);void ehca_process_eq (struct ehca_shca *shca,int is_irq);struct ehca_cpu_comp_task { -wait_queue_head_t wait_queue;struct list_head cq_list; -struct task_struct *task;spinlock_t task_lock;int cq_jobs; +int active; };struct ehca_comp_pool { -struct ehca_cpu_comp_task *cpu_comp_tasks; +struct ehca_cpu_comp_task __percpu *cpu_comp_tasks; +struct task_struct *__percpu *cpu_comp_threads;int last_cpu;spinlock_t last_cpu_lock; };
include/linux/interrupt.h +2 -0
@@ -430,6 +430,8 @@ enum NR_SOFTIRQS }; +#define SOFTIRQ_STOP_IDLE_MASK (~(1 << RCU_SOFTIRQ)) +/* map softirq index to softirq name. update 'softirq_to_name' in * kernel/softirq.c when adding a new softirq. */
include/linux/kthread.h +10 -1
@@ -14,6 +14,11 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), kthread_create_on_node(threadfn, data, -1, namefmt, ##arg) +struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data), + void *data, + unsigned int cpu, + const char *namefmt); +/** * kthread_run - create and wake a thread. * @threadfn: the function to run until signal_pending(current).
@@ -34,9 +39,13 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),void kthread_bind (struct task_struct *k,unsigned int cpu);int kthread_stop (struct task_struct *k); -int kthread_should_stop (void ); +bool kthread_should_stop (void ); +bool kthread_should_park (void );bool kthread_freezable_should_stop (bool *was_frozen);void *kthread_data (struct task_struct *k); +int kthread_park (struct task_struct *k); +void kthread_unpark (struct task_struct *k); +void kthread_parkme (void );int kthreadd (void *unused);extern struct task_struct *kthreadd_task;
include/linux/rcupdate.h +17 -4
@@ -191,6 +191,21 @@ extern void rcu_idle_enter(void);extern void rcu_idle_exit (void );extern void rcu_irq_enter (void );extern void rcu_irq_exit (void ); + +#ifdef CONFIG_RCU_USER_QS +extern void rcu_user_enter (void ); +extern void rcu_user_exit (void ); +extern void rcu_user_enter_after_irq (void ); +extern void rcu_user_exit_after_irq (void ); +extern void rcu_user_hooks_switch (struct task_struct *prev, +struct task_struct *next); +#else +static inline void rcu_user_enter (void ) { } +static inline void rcu_user_exit (void ) { } +static inline void rcu_user_enter_after_irq (void ) { } +static inline void rcu_user_exit_after_irq (void ) { } +#endif /* CONFIG_RCU_USER_QS */ +extern void exit_rcu (void );/**
@@ -210,14 +225,12 @@ extern void exit_rcu(void);* to nest RCU_NONIDLE() wrappers, but the nesting level is currently * quite limited. If deeper nesting is required, it will be necessary * to adjust DYNTICK_TASK_NESTING_VALUE accordingly. -* -* This macro may be used from process-level code only. */ #define RCU_NONIDLE (a) \ do { \ - rcu_idle_exit(); \ + rcu_irq_enter(); \ do { a; } while (0); \ - rcu_idle_enter(); \ + rcu_irq_exit(); \ } while (0)/*
include/linux/sched.h +8 -0
@@ -1885,6 +1885,14 @@ static inline void rcu_copy_process(struct task_struct *p)#endif +static inline void rcu_switch (struct task_struct *prev, +struct task_struct *next) +{ +#ifdef CONFIG_RCU_USER_QS +rcu_user_hooks_switch (prev, next); +#endif +} +static inline void tsk_restore_flags (struct task_struct *task,unsigned long orig_flags,unsigned long flags) {
include/linux/smpboot.h new file +43 -0
43 lines not on this page · raw message
include/linux/tracepoint.h +18 -10
@@ -136,6 +136,22 @@ static inline void tracepoint_synchronize_unregister(void) postrcu; \ } while (0) +#ifndef MODULE +#define __DECLARE_TRACE_RCU (name, proto, args, cond, data_proto, data_args) \ + static inline void trace_##name##_rcuidle(proto) \ + { \ + if (static_key_false(&__tracepoint_##name.key)) \ + __DO_TRACE(&__tracepoint_##name, \ + TP_PROTO(data_proto), \ + TP_ARGS(data_args), \ + TP_CONDITION(cond), \ + rcu_idle_exit(), \ + rcu_idle_enter()); \ + } +#else +#define __DECLARE_TRACE_RCU (name, proto, args, cond, data_proto, data_args) +#endif +/* * Make sure the alignment of the structure in the __tracepoints section will * not add unwanted padding between the beginning of the section and the
@@ -151,16 +167,8 @@ static inline void tracepoint_synchronize_unregister(void)TP_ARGS (data_args), \ TP_CONDITION(cond),,); \ } \ - static inline void trace_##name##_rcuidle(proto) \ - { \ - if (static_key_false(&__tracepoint_##name.key)) \ - __DO_TRACE(&__tracepoint_##name, \ - TP_PROTO(data_proto), \ - TP_ARGS(data_args), \ - TP_CONDITION(cond), \ - rcu_idle_exit(), \ - rcu_idle_enter()); \ - } \ +__DECLARE_TRACE_RCU (name,PARAMS (proto),PARAMS (args), \ + PARAMS(cond), PARAMS(data_proto), PARAMS(data_args)) \ static inline int \ register_trace_##name(void (*probe)(data_proto), void *data) \ { \
init/Kconfig +18 -0
@@ -441,6 +441,24 @@ config PREEMPT_RCU This option enables preemptible-RCU code that is common between the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations. +config RCU_USER_QS + bool "Consider userspace as in RCU extended quiescent state" + depends on HAVE_RCU_USER_QS && SMP + help + This option sets hooks on kernel / userspace boundaries and + puts RCU in extended quiescent state when the CPU runs in + userspace. It means that when a CPU runs in userspace, it is + excluded from the global RCU state machine and thus doesn't + to keep the timer tick on for RCU. + +config RCU_USER_QS_FORCE + bool "Force userspace extended QS by default" + depends on RCU_USER_QS + help + Set the hooks in user/kernel boundaries by default in order to + test this feature that treats userspace as an extended quiescent + state until we have a real user like a full adaptive nohz option. + config RCU_FANOUT int "Tree-based hierarchical RCU fanout value" range 2 64 if 64BIT
kernel/Makefile +1 -2
@@ -10,7 +10,7 @@ obj-y = fork.o exec_domain.o panic.o printk.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ notifier.o ksysfs.o cred.o \ - async.o range.o groups.o lglock.o + async.o range.o groups.o lglock.o smpboot.o ifdef CONFIG_FUNCTION_TRACER # Do not trace debug files and internal ftrace files
@@ -46,7 +46,6 @@ obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_SMP) += smpboot.o ifneq ($(CONFIG_SMP),y) obj-y += up.o endif
kernel/cpu.c +9 -1
@@ -280,12 +280,13 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) __func__, cpu); goto out_release; } +smpboot_park_threads (cpu); err =__stop_machine (take_cpu_down, &tcd_param,cpumask_of (cpu));if (err) {/* CPU didn't die: tell everyone. Can't complain. */ +smpboot_unpark_threads (cpu);cpu_notify_nofail (CPU_DOWN_FAILED | mod, hcpu); - goto out_release; }BUG_ON (cpu_online (cpu));
@@ -354,6 +355,10 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) goto out; } + ret =smpboot_create_threads (cpu); +if (ret) + goto out; + ret =__cpu_notify (CPU_UP_PREPARE | mod, hcpu,-1 , &nr_calls);if (ret) { nr_calls--;
@@ -368,6 +373,9 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) goto out_notify;BUG_ON (!cpu_online (cpu)); +/* Wake the per cpu threads */ +smpboot_unpark_threads (cpu); +/* Now call notifier in preparation. */ cpu_notify (CPU_ONLINE | mod, hcpu);
kernel/kthread.c +166 -19
258 lines not on this page · raw message
kernel/rcupdate.c +4 -0
@@ -45,6 +45,7 @@#include <linux/mutex.h> #include <linux/export.h> #include <linux/hardirq.h> +#include <linux/delay.h> #define CREATE_TRACE_POINTS #include <trace/events/rcu.h>
@@ -81,6 +82,9 @@ void __rcu_read_unlock(void) }else {barrier ();/* critical section before exit code. */ t->rcu_read_lock_nesting =INT_MIN ; +#ifdef CONFIG_PROVE_RCU_DELAY +udelay (10 );/* Make preemption more probable. */ +#endif /* #ifdef CONFIG_PROVE_RCU_DELAY */ barrier ();/* assign before ->rcu_read_unlock_special load */ if (unlikely (ACCESS_ONCE (t->rcu_read_unlock_special)))rcu_read_unlock_special (t);
kernel/rcutiny.c +18 -15
@@ -56,25 +56,28 @@ static void __call_rcu(struct rcu_head *head,static long long rcu_dynticks_nesting =DYNTICK_TASK_EXIT_IDLE ;/* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */ -static void rcu_idle_enter_common (long long oldval) +static void rcu_idle_enter_common (long long newval) { -if (rcu_dynticks_nesting) { +if (newval) {RCU_TRACE (trace_rcu_dyntick ("--=" , - oldval, rcu_dynticks_nesting)); + rcu_dynticks_nesting, newval)); + rcu_dynticks_nesting = newval;return ; } -RCU_TRACE (trace_rcu_dyntick ("Start" , oldval, rcu_dynticks_nesting)); +RCU_TRACE (trace_rcu_dyntick ("Start" , rcu_dynticks_nesting, newval));if (!is_idle_task (current)) {struct task_struct *idle =idle_task (smp_processor_id ());RCU_TRACE (trace_rcu_dyntick ("Error on entry: not idle task" , - oldval, rcu_dynticks_nesting)); + rcu_dynticks_nesting, newval));ftrace_dump (DUMP_ALL );WARN_ONCE (1 ,"Current pid: %d comm: %s / Idle pid: %d comm: %s" , current->pid, current->comm, idle->pid, idle->comm);/* must be idle task! */ }rcu_sched_qs (0 );/* implies rcu_bh_qsctr_inc(0) */ +barrier (); + rcu_dynticks_nesting = newval; }/*
@@ -84,17 +87,16 @@ static void rcu_idle_enter_common(long long oldval)void rcu_idle_enter (void ) {unsigned long flags; -long long oldval; +long long newval;local_irq_save (flags); - oldval = rcu_dynticks_nesting;WARN_ON_ONCE ((rcu_dynticks_nesting &DYNTICK_TASK_NEST_MASK ) ==0 );if ((rcu_dynticks_nesting &DYNTICK_TASK_NEST_MASK ) ==DYNTICK_TASK_NEST_VALUE ) - rcu_dynticks_nesting =0 ; + newval =0 ;else - rcu_dynticks_nesting -=DYNTICK_TASK_NEST_VALUE ; -rcu_idle_enter_common (oldval); + newval = rcu_dynticks_nesting -DYNTICK_TASK_NEST_VALUE ; +rcu_idle_enter_common (newval);local_irq_restore (flags); }EXPORT_SYMBOL_GPL (rcu_idle_enter);
@@ -105,15 +107,15 @@ EXPORT_SYMBOL_GPL(rcu_idle_enter);void rcu_irq_exit (void ) {unsigned long flags; -long long oldval; +long long newval;local_irq_save (flags); - oldval = rcu_dynticks_nesting; - rcu_dynticks_nesting--; -WARN_ON_ONCE (rcu_dynticks_nesting <0 ); -rcu_idle_enter_common (oldval); + newval = rcu_dynticks_nesting -1 ; +WARN_ON_ONCE (newval <0 ); +rcu_idle_enter_common (newval);local_irq_restore (flags); } +EXPORT_SYMBOL_GPL (rcu_irq_exit);/* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcutree.c. */ static void rcu_idle_exit_common (long long oldval)
@@ -171,6 +173,7 @@ void rcu_irq_enter(void)rcu_idle_exit_common (oldval);local_irq_restore (flags); } +EXPORT_SYMBOL_GPL (rcu_irq_enter);#ifdef CONFIG_DEBUG_LOCK_ALLOC
kernel/rcutiny_plugin.h +5 -5
@@ -278,7 +278,7 @@ static int rcu_boost(void) rcu_preempt_ctrlblk.exp_tasks == NULL)return 0 ;/* Nothing to boost. */ -raw_local_irq_save (flags); +local_irq_save (flags);/* * Recheck with irqs disabled: all tasks in need of boosting
@@ -287,7 +287,7 @@ static int rcu_boost(void)*/ if (rcu_preempt_ctrlblk.boost_tasks ==NULL && rcu_preempt_ctrlblk.exp_tasks ==NULL ) { -raw_local_irq_restore (flags); +local_irq_restore (flags);return 0 ; }
@@ -317,7 +317,7 @@ static int rcu_boost(void) t = container_of(tb, struct task_struct, rcu_node_entry);rt_mutex_init_proxy_locked (&mtx, t); t->rcu_boost_mutex = &mtx; -raw_local_irq_restore (flags); +local_irq_restore (flags);rt_mutex_lock (&mtx);rt_mutex_unlock (&mtx);/* Keep lockdep happy. */
@@ -991,9 +991,9 @@ static void rcu_trace_sub_qlen(struct rcu_ctrlblk *rcp, int n) {unsigned long flags; -raw_local_irq_save (flags); +local_irq_save (flags); rcp->qlen -= n; -raw_local_irq_restore (flags); +local_irq_restore (flags); }/*
kernel/rcutorture.c +97 -62
302 lines not on this page · raw message
kernel/rcutree.c +539 -377
809 lines not on this page · raw message
kernel/rcutree.h +19 -31
50 lines not on this page · raw message
kernel/rcutree_plugin.h +231 -366
597 lines not on this page · raw message
kernel/smpboot.c +233 -0
233 lines not on this page · raw message
kernel/softirq.c +27 -84
111 lines not on this page · raw message
kernel/watchdog.c +89 -174
263 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.