diff options
| author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2008-01-25 15:08:24 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-01-25 15:08:24 -0500 |
| commit | e260be673a15b6125068270e0216a3bfbfc12f87 (patch) | |
| tree | f50760606d395bf6faa9e865f814761a3c88d32c /kernel | |
| parent | e0ecfa7917cafe72f4a75f87e8bb5d8d51dc534f (diff) | |
Preempt-RCU: implementation
This patch implements a new version of RCU which allows its read-side
critical sections to be preempted. It uses a set of counter pairs
to keep track of the read-side critical sections and flips them
when all tasks exit read-side critical section. The details
of this implementation can be found in this paper -
http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf
and the article-
http://lwn.net/Articles/253651/
This patch was developed as a part of the -rt kernel development and
meant to provide better latencies when read-side critical sections of
RCU don't disable preemption. As a consequence of keeping track of RCU
readers, the readers have a slight overhead (optimizations in the paper).
This implementation co-exists with the "classic" RCU implementations
and can be switched to at compiler.
Also includes RCU tracing summarized in debugfs.
[ akpm@linux-foundation.org: build fixes on non-preempt architectures ]
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com>
Signed-off-by: Paul E. McKenney <paulmck@us.ibm.com>
Reviewed-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/Kconfig.preempt | 10 | ||||
| -rw-r--r-- | kernel/Makefile | 7 | ||||
| -rw-r--r-- | kernel/fork.c | 4 | ||||
| -rw-r--r-- | kernel/rcuclassic.c | 1 | ||||
| -rw-r--r-- | kernel/rcupreempt.c | 816 | ||||
| -rw-r--r-- | kernel/rcupreempt_trace.c | 330 |
6 files changed, 1166 insertions, 2 deletions
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt index c64ce9c14207..61fa116efcde 100644 --- a/kernel/Kconfig.preempt +++ b/kernel/Kconfig.preempt | |||
| @@ -63,3 +63,13 @@ config PREEMPT_BKL | |||
| 63 | Say Y here if you are building a kernel for a desktop system. | 63 | Say Y here if you are building a kernel for a desktop system. |
| 64 | Say N if you are unsure. | 64 | Say N if you are unsure. |
| 65 | 65 | ||
| 66 | config RCU_TRACE | ||
| 67 | bool "Enable tracing for RCU - currently stats in debugfs" | ||
| 68 | select DEBUG_FS | ||
| 69 | default y | ||
| 70 | help | ||
| 71 | This option provides tracing in RCU which presents stats | ||
| 72 | in debugfs for debugging RCU implementation. | ||
| 73 | |||
| 74 | Say Y here if you want to enable RCU tracing | ||
| 75 | Say N if you are unsure. | ||
diff --git a/kernel/Makefile b/kernel/Makefile index def5dd6097a0..68755cd9a7e4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
| @@ -6,7 +6,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ | |||
| 6 | exit.o itimer.o time.o softirq.o resource.o \ | 6 | exit.o itimer.o time.o softirq.o resource.o \ |
| 7 | sysctl.o capability.o ptrace.o timer.o user.o user_namespace.o \ | 7 | sysctl.o capability.o ptrace.o timer.o user.o user_namespace.o \ |
| 8 | signal.o sys.o kmod.o workqueue.o pid.o \ | 8 | signal.o sys.o kmod.o workqueue.o pid.o \ |
| 9 | rcupdate.o rcuclassic.o extable.o params.o posix-timers.o \ | 9 | rcupdate.o extable.o params.o posix-timers.o \ |
| 10 | kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ | 10 | kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ |
| 11 | hrtimer.o rwsem.o latency.o nsproxy.o srcu.o \ | 11 | hrtimer.o rwsem.o latency.o nsproxy.o srcu.o \ |
| 12 | utsname.o notifier.o | 12 | utsname.o notifier.o |
| @@ -52,6 +52,11 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o | |||
| 52 | obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ | 52 | obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ |
| 53 | obj-$(CONFIG_SECCOMP) += seccomp.o | 53 | obj-$(CONFIG_SECCOMP) += seccomp.o |
| 54 | obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o | 54 | obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o |
| 55 | obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o | ||
| 56 | obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o | ||
| 57 | ifeq ($(CONFIG_PREEMPT_RCU),y) | ||
| 58 | obj-$(CONFIG_RCU_TRACE) += rcupreempt_trace.o | ||
| 59 | endif | ||
| 55 | obj-$(CONFIG_RELAY) += relay.o | 60 | obj-$(CONFIG_RELAY) += relay.o |
| 56 | obj-$(CONFIG_SYSCTL) += utsname_sysctl.o | 61 | obj-$(CONFIG_SYSCTL) += utsname_sysctl.o |
| 57 | obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o | 62 | obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o |
diff --git a/kernel/fork.c b/kernel/fork.c index 930c51865ab4..9f8ef32cbc7a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -1045,6 +1045,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1045 | copy_flags(clone_flags, p); | 1045 | copy_flags(clone_flags, p); |
| 1046 | INIT_LIST_HEAD(&p->children); | 1046 | INIT_LIST_HEAD(&p->children); |
| 1047 | INIT_LIST_HEAD(&p->sibling); | 1047 | INIT_LIST_HEAD(&p->sibling); |
| 1048 | #ifdef CONFIG_PREEMPT_RCU | ||
| 1049 | p->rcu_read_lock_nesting = 0; | ||
| 1050 | p->rcu_flipctr_idx = 0; | ||
| 1051 | #endif /* #ifdef CONFIG_PREEMPT_RCU */ | ||
| 1048 | p->vfork_done = NULL; | 1052 | p->vfork_done = NULL; |
| 1049 | spin_lock_init(&p->alloc_lock); | 1053 | spin_lock_init(&p->alloc_lock); |
| 1050 | 1054 | ||
diff --git a/kernel/rcuclassic.c b/kernel/rcuclassic.c index ce0cf16cab67..f4ffbd0f306f 100644 --- a/kernel/rcuclassic.c +++ b/kernel/rcuclassic.c | |||
| @@ -45,7 +45,6 @@ | |||
| 45 | #include <linux/moduleparam.h> | 45 | #include <linux/moduleparam.h> |
| 46 | #include <linux/percpu.h> | 46 | #include <linux/percpu.h> |
| 47 | #include <linux/notifier.h> | 47 | #include <linux/notifier.h> |
| 48 | /* #include <linux/rcupdate.h> @@@ */ | ||
| 49 | #include <linux/cpu.h> | 48 | #include <linux/cpu.h> |
| 50 | #include <linux/mutex.h> | 49 | #include <linux/mutex.h> |
| 51 | 50 | ||
diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c new file mode 100644 index 000000000000..a5aabb1677f8 --- /dev/null +++ b/kernel/rcupreempt.c | |||
| @@ -0,0 +1,816 @@ | |||
| 1 | /* | ||
| 2 | * Read-Copy Update mechanism for mutual exclusion, realtime implementation | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | * | ||
| 18 | * Copyright IBM Corporation, 2006 | ||
| 19 | * | ||
| 20 | * Authors: Paul E. McKenney <paulmck@us.ibm.com> | ||
| 21 | * With thanks to Esben Nielsen, Bill Huey, and Ingo Molnar | ||
| 22 | * for pushing me away from locks and towards counters, and | ||
| 23 | * to Suparna Bhattacharya for pushing me completely away | ||
| 24 | * from atomic instructions on the read side. | ||
| 25 | * | ||
| 26 | * Papers: http://www.rdrop.com/users/paulmck/RCU | ||
| 27 | * | ||
| 28 | * Design Document: http://lwn.net/Articles/253651/ | ||
| 29 | * | ||
| 30 | * For detailed explanation of Read-Copy Update mechanism see - | ||
| 31 | * Documentation/RCU/ *.txt | ||
| 32 | * | ||
| 33 | */ | ||
| 34 | #include <linux/types.h> | ||
| 35 | #include <linux/kernel.h> | ||
| 36 | #include <linux/init.h> | ||
| 37 | #include <linux/spinlock.h> | ||
| 38 | #include <linux/smp.h> | ||
| 39 | #include <linux/rcupdate.h> | ||
| 40 | #include <linux/interrupt.h> | ||
| 41 | #include <linux/sched.h> | ||
| 42 | #include <asm/atomic.h> | ||
| 43 | #include <linux/bitops.h> | ||
| 44 | #include <linux/module.h> | ||
| 45 | #include <linux/completion.h> | ||
| 46 | #include <linux/moduleparam.h> | ||
| 47 | #include <linux/percpu.h> | ||
| 48 | #include <linux/notifier.h> | ||
| 49 | #include <linux/rcupdate.h> | ||
| 50 | #include <linux/cpu.h> | ||
| 51 | #include <linux/random.h> | ||
| 52 | #include <linux/delay.h> | ||
| 53 | #include <linux/byteorder/swabb.h> | ||
| 54 | #include <linux/cpumask.h> | ||
| 55 | #include <linux/rcupreempt_trace.h> | ||
| 56 | |||
| 57 | /* | ||
| 58 | * Macro that prevents the compiler from reordering accesses, but does | ||
| 59 | * absolutely -nothing- to prevent CPUs from reordering. This is used | ||
| 60 | * only to mediate communication between mainline code and hardware | ||
| 61 | * interrupt and NMI handlers. | ||
| 62 | */ | ||
| 63 | #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) | ||
| 64 | |||
| 65 | /* | ||
| 66 | * PREEMPT_RCU data structures. | ||
| 67 | */ | ||
| 68 | |||
| 69 | /* | ||
| 70 | * GP_STAGES specifies the number of times the state machine has | ||
| 71 | * to go through the all the rcu_try_flip_states (see below) | ||
| 72 | * in a single Grace Period. | ||
| 73 | * | ||
| 74 | * GP in GP_STAGES stands for Grace Period ;) | ||
| 75 | */ | ||
| 76 | #define GP_STAGES 2 | ||
| 77 | struct rcu_data { | ||
| 78 | spinlock_t lock; /* Protect rcu_data fields. */ | ||
| 79 | long completed; /* Number of last completed batch. */ | ||
| 80 | int waitlistcount; | ||
| 81 | struct tasklet_struct rcu_tasklet; | ||
| 82 | struct rcu_head *nextlist; | ||
| 83 | struct rcu_head **nexttail; | ||
| 84 | struct rcu_head *waitlist[GP_STAGES]; | ||
| 85 | struct rcu_head **waittail[GP_STAGES]; | ||
| 86 | struct rcu_head *donelist; | ||
| 87 | struct rcu_head **donetail; | ||
| 88 | long rcu_flipctr[2]; | ||
| 89 | #ifdef CONFIG_RCU_TRACE | ||
| 90 | struct rcupreempt_trace trace; | ||
| 91 | #endif /* #ifdef CONFIG_RCU_TRACE */ | ||
| 92 | }; | ||
| 93 | |||
| 94 | /* | ||
| 95 | * States for rcu_try_flip() and friends. | ||
| 96 | */ | ||
| 97 | |||
| 98 | enum rcu_try_flip_states { | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Stay here if nothing is happening. Flip the counter if somthing | ||
| 102 | * starts happening. Denoted by "I" | ||
| 103 | */ | ||
| 104 | rcu_try_flip_idle_state, | ||
| 105 | |||
| 106 | /* | ||
| 107 | * Wait here for all CPUs to notice that the counter has flipped. This | ||
| 108 | * prevents the old set of counters from ever being incremented once | ||
| 109 | * we leave this state, which in turn is necessary because we cannot | ||
| 110 | * test any individual counter for zero -- we can only check the sum. | ||
| 111 | * Denoted by "A". | ||
| 112 | */ | ||
| 113 | rcu_try_flip_waitack_state, | ||
| 114 | |||
| 115 | /* | ||
