diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2009-12-02 15:10:15 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-03 05:35:25 -0500 |
commit | d9a3da0699b24a589b27a61e1a5b5bd30d9db669 (patch) | |
tree | f7440e396a6c818f3cef514ccc31ab55d88025ef /kernel/rcutree.h | |
parent | cf244dc01bf68e1ad338b82447f8686d24ea4435 (diff) |
rcu: Add expedited grace-period support for preemptible RCU
Implement an synchronize_rcu_expedited() for preemptible RCU
that actually is expedited. This uses
synchronize_sched_expedited() to force all threads currently
running in a preemptible-RCU read-side critical section onto the
appropriate ->blocked_tasks[] list, then takes a snapshot of all
of these lists and waits for them to drain.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: laijs@cn.fujitsu.com
Cc: dipankar@in.ibm.com
Cc: mathieu.desnoyers@polymtl.ca
Cc: josh@joshtriplett.org
Cc: dvhltc@us.ibm.com
Cc: niv@us.ibm.com
Cc: peterz@infradead.org
Cc: rostedt@goodmis.org
Cc: Valdis.Kletnieks@vt.edu
Cc: dhowells@redhat.com
LKML-Reference: <1259784616158-git-send-email->
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/rcutree.h')
-rw-r--r-- | kernel/rcutree.h | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index df2e0b694744..d2a0046f63b2 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
@@ -104,8 +104,12 @@ struct rcu_node { | |||
104 | /* an rcu_data structure, otherwise, each */ | 104 | /* an rcu_data structure, otherwise, each */ |
105 | /* bit corresponds to a child rcu_node */ | 105 | /* bit corresponds to a child rcu_node */ |
106 | /* structure. */ | 106 | /* structure. */ |
107 | unsigned long expmask; /* Groups that have ->blocked_tasks[] */ | ||
108 | /* elements that need to drain to allow the */ | ||
109 | /* current expedited grace period to */ | ||
110 | /* complete (only for TREE_PREEMPT_RCU). */ | ||
107 | unsigned long qsmaskinit; | 111 | unsigned long qsmaskinit; |
108 | /* Per-GP initialization for qsmask. */ | 112 | /* Per-GP initial value for qsmask & expmask. */ |
109 | unsigned long grpmask; /* Mask to apply to parent qsmask. */ | 113 | unsigned long grpmask; /* Mask to apply to parent qsmask. */ |
110 | /* Only one bit will be set in this mask. */ | 114 | /* Only one bit will be set in this mask. */ |
111 | int grplo; /* lowest-numbered CPU or group here. */ | 115 | int grplo; /* lowest-numbered CPU or group here. */ |
@@ -113,7 +117,7 @@ struct rcu_node { | |||
113 | u8 grpnum; /* CPU/group number for next level up. */ | 117 | u8 grpnum; /* CPU/group number for next level up. */ |
114 | u8 level; /* root is at level 0. */ | 118 | u8 level; /* root is at level 0. */ |
115 | struct rcu_node *parent; | 119 | struct rcu_node *parent; |
116 | struct list_head blocked_tasks[2]; | 120 | struct list_head blocked_tasks[4]; |
117 | /* Tasks blocked in RCU read-side critsect. */ | 121 | /* Tasks blocked in RCU read-side critsect. */ |
118 | /* Grace period number (->gpnum) x blocked */ | 122 | /* Grace period number (->gpnum) x blocked */ |
119 | /* by tasks on the (x & 0x1) element of the */ | 123 | /* by tasks on the (x & 0x1) element of the */ |
@@ -128,6 +132,21 @@ struct rcu_node { | |||
128 | for ((rnp) = &(rsp)->node[0]; \ | 132 | for ((rnp) = &(rsp)->node[0]; \ |
129 | (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++) | 133 | (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++) |
130 | 134 | ||
135 | /* | ||
136 | * Do a breadth-first scan of the non-leaf rcu_node structures for the | ||
137 | * specified rcu_state structure. Note that if there is a singleton | ||
138 | * rcu_node tree with but one rcu_node structure, this loop is a no-op. | ||
139 | */ | ||
140 | #define rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) \ | ||
141 | for ((rnp) = &(rsp)->node[0]; \ | ||
142 | (rnp) < (rsp)->level[NUM_RCU_LVLS - 1]; (rnp)++) | ||
143 | |||
144 | /* | ||
145 | * Scan the leaves of the rcu_node hierarchy for the specified rcu_state | ||
146 | * structure. Note that if there is a singleton rcu_node tree with but | ||
147 | * one rcu_node structure, this loop -will- visit the rcu_node structure. | ||
148 | * It is still a leaf node, even if it is also the root node. | ||
149 | */ | ||
131 | #define rcu_for_each_leaf_node(rsp, rnp) \ | 150 | #define rcu_for_each_leaf_node(rsp, rnp) \ |
132 | for ((rnp) = (rsp)->level[NUM_RCU_LVLS - 1]; \ | 151 | for ((rnp) = (rsp)->level[NUM_RCU_LVLS - 1]; \ |
133 | (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++) | 152 | (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++) |
@@ -261,7 +280,7 @@ struct rcu_state { | |||
261 | long gpnum; /* Current gp number. */ | 280 | long gpnum; /* Current gp number. */ |
262 | long completed; /* # of last completed gp. */ | 281 | long completed; /* # of last completed gp. */ |
263 | 282 | ||
264 | /* End of fields guarded by root rcu_node's lock. */ | 283 | /* End of fields guarded by root rcu_node's lock. */ |
265 | 284 | ||
266 | spinlock_t onofflock; /* exclude on/offline and */ | 285 | spinlock_t onofflock; /* exclude on/offline and */ |
267 | /* starting new GP. Also */ | 286 | /* starting new GP. Also */ |
@@ -293,6 +312,13 @@ struct rcu_state { | |||
293 | #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ | 312 | #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ |
294 | }; | 313 | }; |
295 | 314 | ||
315 | /* Return values for rcu_preempt_offline_tasks(). */ | ||
316 | |||
317 | #define RCU_OFL_TASKS_NORM_GP 0x1 /* Tasks blocking normal */ | ||
318 | /* GP were moved to root. */ | ||
319 | #define RCU_OFL_TASKS_EXP_GP 0x2 /* Tasks blocking expedited */ | ||
320 | /* GP were moved to root. */ | ||
321 | |||
296 | #ifdef RCU_TREE_NONCORE | 322 | #ifdef RCU_TREE_NONCORE |
297 | 323 | ||
298 | /* | 324 | /* |
@@ -333,6 +359,9 @@ static void rcu_preempt_offline_cpu(int cpu); | |||
333 | static void rcu_preempt_check_callbacks(int cpu); | 359 | static void rcu_preempt_check_callbacks(int cpu); |
334 | static void rcu_preempt_process_callbacks(void); | 360 | static void rcu_preempt_process_callbacks(void); |
335 | void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); | 361 | void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); |
362 | #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) | ||
363 | static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp); | ||
364 | #endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) */ | ||
336 | static int rcu_preempt_pending(int cpu); | 365 | static int rcu_preempt_pending(int cpu); |
337 | static int rcu_preempt_needs_cpu(int cpu); | 366 | static int rcu_preempt_needs_cpu(int cpu); |
338 | static void __cpuinit rcu_preempt_init_percpu_data(int cpu); | 367 | static void __cpuinit rcu_preempt_init_percpu_data(int cpu); |