diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2012-12-30 18:21:01 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-03-26 11:04:57 -0400 |
commit | 0446be489795d8bb994125a916ef03211f539e54 (patch) | |
tree | 051b6bce04ab8f9e8b7ea6f42879bb350e306805 | |
parent | 8b425aa8f1acfe48aed919c7aadff2ed290fe969 (diff) |
rcu: Abstract rcu_start_future_gp() from rcu_nocb_wait_gp()
CPUs going idle will need to record the need for a future grace
period, but won't actually need to block waiting on it. This commit
therefore splits rcu_start_future_gp(), which does the recording, from
rcu_nocb_wait_gp(), which now invokes rcu_start_future_gp() to do the
recording, after which rcu_nocb_wait_gp() does the waiting.
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r-- | kernel/rcutree.c | 123 | ||||
-rw-r--r-- | kernel/rcutree.h | 2 | ||||
-rw-r--r-- | kernel/rcutree_plugin.h | 104 |
3 files changed, 130 insertions, 99 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 0d532950baa3..f4b23f16677a 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -224,6 +224,7 @@ static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS; | |||
224 | module_param(jiffies_till_first_fqs, ulong, 0644); | 224 | module_param(jiffies_till_first_fqs, ulong, 0644); |
225 | module_param(jiffies_till_next_fqs, ulong, 0644); | 225 | module_param(jiffies_till_next_fqs, ulong, 0644); |
226 | 226 | ||
227 | static void rcu_start_gp(struct rcu_state *rsp); | ||
227 | static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *)); | 228 | static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *)); |
228 | static void force_quiescent_state(struct rcu_state *rsp); | 229 | static void force_quiescent_state(struct rcu_state *rsp); |
229 | static int rcu_pending(int cpu); | 230 | static int rcu_pending(int cpu); |
@@ -1075,6 +1076,120 @@ static unsigned long rcu_cbs_completed(struct rcu_state *rsp, | |||
1075 | } | 1076 | } |
1076 | 1077 | ||
1077 | /* | 1078 | /* |
1079 | * Trace-event helper function for rcu_start_future_gp() and | ||
1080 | * rcu_nocb_wait_gp(). | ||
1081 | */ | ||
1082 | static void trace_rcu_future_gp(struct rcu_node *rnp, struct rcu_data *rdp, | ||
1083 | unsigned long c, char *s) | ||
1084 | { | ||
1085 | trace_rcu_future_grace_period(rdp->rsp->name, rnp->gpnum, | ||
1086 | rnp->completed, c, rnp->level, | ||
1087 | rnp->grplo, rnp->grphi, s); | ||
1088 | } | ||
1089 | |||
1090 | /* | ||
1091 | * Start some future grace period, as needed to handle newly arrived | ||
1092 | * callbacks. The required future grace periods are recorded in each | ||
1093 | * rcu_node structure's ->need_future_gp field. | ||
1094 | * | ||
1095 | * The caller must hold the specified rcu_node structure's ->lock. | ||
1096 | */ | ||
1097 | static unsigned long __maybe_unused | ||
1098 | rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp) | ||
1099 | { | ||
1100 | unsigned long c; | ||
1101 | int i; | ||
1102 | struct rcu_node *rnp_root = rcu_get_root(rdp->rsp); | ||
1103 | |||
1104 | /* | ||
1105 | * Pick up grace-period number for new callbacks. If this | ||
1106 | * grace period is already marked as needed, return to the caller. | ||
1107 | */ | ||
1108 | c = rcu_cbs_completed(rdp->rsp, rnp); | ||
1109 | trace_rcu_future_gp(rnp, rdp, c, "Startleaf"); | ||
1110 | if (rnp->need_future_gp[c & 0x1]) { | ||
1111 | trace_rcu_future_gp(rnp, rdp, c, "Prestartleaf"); | ||
1112 | return c; | ||
1113 | } | ||
1114 | |||
1115 | /* | ||
1116 | * If either this rcu_node structure or the root rcu_node structure | ||
1117 | * believe that a grace period is in progress, then we must wait | ||
1118 | * for the one following, which is in "c". Because our request | ||
1119 | * will be noticed at the end of the current grace period, we don't | ||
1120 | * need to explicitly start one. | ||
1121 | */ | ||
1122 | if (rnp->gpnum != rnp->completed || | ||
1123 | ACCESS_ONCE(rnp->gpnum) != ACCESS_ONCE(rnp->completed)) { | ||
1124 | rnp->need_future_gp[c & 0x1]++; | ||
1125 | trace_rcu_future_gp(rnp, rdp, c, "Startedleaf"); | ||
1126 | return c; | ||
1127 | } | ||
1128 | |||
1129 | /* | ||
1130 | * There might be no grace period in progress. If we don't already | ||
1131 | * hold it, acquire the root rcu_node structure's lock in order to | ||
1132 | * start one (if needed). | ||
1133 | */ | ||
1134 | if (rnp != rnp_root) | ||
1135 | raw_spin_lock(&rnp_root->lock); | ||
1136 | |||
1137 | /* | ||
1138 | * Get a new grace-period number. If there really is no grace | ||
1139 | * period in progress, it will be smaller than the one we obtained | ||
1140 | * earlier. Adjust callbacks as needed. Note that even no-CBs | ||
1141 | * CPUs have a ->nxtcompleted[] array, so no no-CBs checks needed. | ||
1142 | */ | ||
1143 | c = rcu_cbs_completed(rdp->rsp, rnp_root); | ||
1144 | for (i = RCU_DONE_TAIL; i < RCU_NEXT_TAIL; i++) | ||
1145 | if (ULONG_CMP_LT(c, rdp->nxtcompleted[i])) | ||
1146 | rdp->nxtcompleted[i] = c; | ||
1147 | |||
1148 | /* | ||
1149 | * If the needed for the required grace period is already | ||
1150 | * recorded, trace and leave. | ||
1151 | */ | ||
1152 | if (rnp_root->need_future_gp[c & 0x1]) { | ||
1153 | trace_rcu_future_gp(rnp, rdp, c, "Prestartedroot"); | ||
1154 | goto unlock_out; | ||
1155 | } | ||
1156 | |||
1157 | /* Record the need for the future grace period. */ | ||
1158 | rnp_root->need_future_gp[c & 0x1]++; | ||
1159 | |||
1160 | /* If a grace period is not already in progress, start one. */ | ||
1161 | if (rnp_root->gpnum != rnp_root->completed) { | ||
1162 | trace_rcu_future_gp(rnp, rdp, c, "Startedleafroot"); | ||
1163 | } else { | ||
1164 | trace_rcu_future_gp(rnp, rdp, c, "Startedroot"); | ||
1165 | rcu_start_gp(rdp->rsp); | ||
1166 | } | ||
1167 | unlock_out: | ||
1168 | if (rnp != rnp_root) | ||
1169 | raw_spin_unlock(&rnp_root->lock); | ||
1170 | return c; | ||
1171 | } | ||
1172 | |||
1173 | /* | ||
1174 | * Clean up any old requests for the just-ended grace period. Also return | ||
1175 | * whether any additional grace periods have been requested. Also invoke | ||
1176 | * rcu_nocb_gp_cleanup() in order to wake up any no-callbacks kthreads | ||
1177 | * waiting for this grace period to complete. | ||
1178 | */ | ||
1179 | static int rcu_future_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) | ||
1180 | { | ||
1181 | int c = rnp->completed; | ||
1182 | int needmore; | ||
1183 | struct rcu_data *rdp = this_cpu_ptr(rsp->rda); | ||
1184 | |||
1185 | rcu_nocb_gp_cleanup(rsp, rnp); | ||
1186 | rnp->need_future_gp[c & 0x1] = 0; | ||
1187 | needmore = rnp->need_future_gp[(c + 1) & 0x1]; | ||
1188 | trace_rcu_future_gp(rnp, rdp, c, needmore ? "CleanupMore" : "Cleanup"); | ||
1189 | return needmore; | ||
1190 | } | ||
1191 | |||
1192 | /* | ||
1078 | * If there is room, assign a ->completed number to any callbacks on | 1193 | * If there is room, assign a ->completed number to any callbacks on |
1079 | * this CPU that have not already been assigned. Also accelerate any | 1194 | * this CPU that have not already been assigned. Also accelerate any |
1080 | * callbacks that were previously assigned a ->completed number that has | 1195 | * callbacks that were previously assigned a ->completed number that has |
@@ -1312,9 +1427,9 @@ static int rcu_gp_init(struct rcu_state *rsp) | |||
1312 | rdp = this_cpu_ptr(rsp->rda); | 1427 | rdp = this_cpu_ptr(rsp->rda); |
1313 | rcu_preempt_check_blocked_tasks(rnp); | 1428 | rcu_preempt_check_blocked_tasks(rnp); |
1314 | rnp->qsmask = rnp->qsmaskinit; | 1429 | rnp->qsmask = rnp->qsmaskinit; |
1315 | rnp->gpnum = rsp->gpnum; | 1430 | ACCESS_ONCE(rnp->gpnum) = rsp->gpnum; |
1316 | WARN_ON_ONCE(rnp->completed != rsp->completed); | 1431 | WARN_ON_ONCE(rnp->completed != rsp->completed); |
1317 | rnp->completed = rsp->completed; | 1432 | ACCESS_ONCE(rnp->completed) = rsp->completed; |
1318 | if (rnp == rdp->mynode) | 1433 | if (rnp == rdp->mynode) |
1319 | rcu_start_gp_per_cpu(rsp, rnp, rdp); | 1434 | rcu_start_gp_per_cpu(rsp, rnp, rdp); |
1320 | rcu_preempt_boost_start_gp(rnp); | 1435 | rcu_preempt_boost_start_gp(rnp); |
@@ -1395,11 +1510,11 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) | |||
1395 | */ | 1510 | */ |
1396 | rcu_for_each_node_breadth_first(rsp, rnp) { | 1511 | rcu_for_each_node_breadth_first(rsp, rnp) { |
1397 | raw_spin_lock_irq(&rnp->lock); | 1512 | raw_spin_lock_irq(&rnp->lock); |
1398 | rnp->completed = rsp->gpnum; | 1513 | ACCESS_ONCE(rnp->completed) = rsp->gpnum; |
1399 | rdp = this_cpu_ptr(rsp->rda); | 1514 | rdp = this_cpu_ptr(rsp->rda); |
1400 | if (rnp == rdp->mynode) | 1515 | if (rnp == rdp->mynode) |
1401 | __rcu_process_gp_end(rsp, rnp, rdp); | 1516 | __rcu_process_gp_end(rsp, rnp, rdp); |
1402 | nocb += rcu_nocb_gp_cleanup(rsp, rnp); | 1517 | nocb += rcu_future_gp_cleanup(rsp, rnp); |
1403 | raw_spin_unlock_irq(&rnp->lock); | 1518 | raw_spin_unlock_irq(&rnp->lock); |
1404 | cond_resched(); | 1519 | cond_resched(); |
1405 | } | 1520 | } |
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 034b524594bd..c11b46c33159 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
@@ -526,7 +526,7 @@ static void zero_cpu_stall_ticks(struct rcu_data *rdp); | |||
526 | static void increment_cpu_stall_ticks(void); | 526 | static void increment_cpu_stall_ticks(void); |
527 | static int rcu_nocb_needs_gp(struct rcu_state *rsp); | 527 | static int rcu_nocb_needs_gp(struct rcu_state *rsp); |
528 | static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq); | 528 | static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq); |
529 | static int rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp); | 529 | static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp); |
530 | static void rcu_init_one_nocb(struct rcu_node *rnp); | 530 | static void rcu_init_one_nocb(struct rcu_node *rnp); |
531 | static bool is_nocb_cpu(int cpu); | 531 | static bool is_nocb_cpu(int cpu); |
532 | static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, | 532 | static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, |
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index f3f0020b5b58..723af5f707f0 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h | |||
@@ -2022,22 +2022,12 @@ static int rcu_nocb_needs_gp(struct rcu_state *rsp) | |||
2022 | } | 2022 | } |
2023 | 2023 | ||
2024 | /* | 2024 | /* |
2025 | * Clean up this rcu_node structure's no-CBs state at the end of | 2025 | * Wake up any no-CBs CPUs' kthreads that were waiting on the just-ended |
2026 | * a grace period, and also return whether any no-CBs CPU associated | 2026 | * grace period. |
2027 | * with this rcu_node structure needs another grace period. | ||
2028 | */ | 2027 | */ |
2029 | static int rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) | 2028 | static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) |
2030 | { | 2029 | { |
2031 | int c = rnp->completed; | 2030 | wake_up_all(&rnp->nocb_gp_wq[rnp->completed & 0x1]); |
2032 | int needmore; | ||
2033 | |||
2034 | wake_up_all(&rnp->nocb_gp_wq[c & 0x1]); | ||
2035 | rnp->need_future_gp[c & 0x1] = 0; | ||
2036 | needmore = rnp->need_future_gp[(c + 1) & 0x1]; | ||
2037 | trace_rcu_future_grace_period(rsp->name, rnp->gpnum, rnp->completed, | ||
2038 | c, rnp->level, rnp->grplo, rnp->grphi, | ||
2039 | needmore ? "CleanupMore" : "Cleanup"); | ||
2040 | return needmore; | ||
2041 | } | 2031 | } |
2042 | 2032 | ||
2043 | /* | 2033 | /* |
@@ -2175,84 +2165,16 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp) | |||
2175 | bool d; | 2165 | bool d; |
2176 | unsigned long flags; | 2166 | unsigned long flags; |
2177 | struct rcu_node *rnp = rdp->mynode; | 2167 | struct rcu_node *rnp = rdp->mynode; |
2178 | struct rcu_node *rnp_root = rcu_get_root(rdp->rsp); | ||
2179 | 2168 | ||
2180 | raw_spin_lock_irqsave(&rnp->lock, flags); | 2169 | raw_spin_lock_irqsave(&rnp->lock, flags); |
2181 | c = rnp->completed + 2; | 2170 | c = rcu_start_future_gp(rnp, rdp); |
2182 | 2171 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | |
2183 | /* Count our request for a grace period. */ | ||
2184 | rnp->need_future_gp[c & 0x1]++; | ||
2185 | trace_rcu_future_grace_period(rdp->rsp->name, rnp->gpnum, | ||
2186 | rnp->completed, c, rnp->level, | ||
2187 | rnp->grplo, rnp->grphi, "Startleaf"); | ||
2188 | |||
2189 | if (rnp->gpnum != rnp->completed) { | ||
2190 | |||
2191 | /* | ||
2192 | * This rcu_node structure believes that a grace period | ||
2193 | * is in progress, so we are done. When this grace | ||
2194 | * period ends, our request will be acted upon. | ||
2195 | */ | ||
2196 | trace_rcu_future_grace_period(rdp->rsp->name, rnp->gpnum, | ||
2197 | rnp->completed, c, rnp->level, | ||
2198 | rnp->grplo, rnp->grphi, | ||
2199 | "Startedleaf"); | ||
2200 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | ||
2201 | |||
2202 | } else { | ||
2203 | |||
2204 | /* | ||
2205 | * Might not be a grace period, check root rcu_node | ||
2206 | * structure to see if we must start one. | ||
2207 | */ | ||
2208 | if (rnp != rnp_root) | ||
2209 | raw_spin_lock(&rnp_root->lock); /* irqs disabled. */ | ||
2210 | if (rnp_root->gpnum != rnp_root->completed) { | ||
2211 | trace_rcu_future_grace_period(rdp->rsp->name, | ||
2212 | rnp->gpnum, | ||
2213 | rnp->completed, | ||
2214 | c, rnp->level, | ||
2215 | rnp->grplo, rnp->grphi, | ||
2216 | "Startedleafroot"); | ||
2217 | raw_spin_unlock(&rnp_root->lock); /* irqs disabled. */ | ||
2218 | } else { | ||
2219 | |||
2220 | /* | ||
2221 | * No grace period, so we need to start one. | ||
2222 | * The good news is that we can wait for exactly | ||
2223 | * one grace period instead of part of the current | ||
2224 | * grace period and all of the next grace period. | ||
2225 | * Adjust counters accordingly and start the | ||
2226 | * needed grace period. | ||
2227 | */ | ||
2228 | rnp->need_future_gp[c & 0x1]--; | ||
2229 | c = rnp_root->completed + 1; | ||
2230 | rnp->need_future_gp[c & 0x1]++; | ||
2231 | rnp_root->need_future_gp[c & 0x1]++; | ||
2232 | trace_rcu_future_grace_period(rdp->rsp->name, | ||
2233 | rnp->gpnum, | ||
2234 | rnp->completed, | ||
2235 | c, rnp->level, | ||
2236 | rnp->grplo, rnp->grphi, | ||
2237 | "Startedroot"); | ||
2238 | rcu_start_gp(rdp->rsp); | ||
2239 | raw_spin_unlock(&rnp->lock); | ||
2240 | } | ||
2241 | |||
2242 | /* Clean up locking and irq state. */ | ||
2243 | if (rnp != rnp_root) | ||
2244 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | ||
2245 | else | ||
2246 | local_irq_restore(flags); | ||
2247 | } | ||
2248 | 2172 | ||
2249 | /* | 2173 | /* |
2250 | * Wait for the grace period. Do so interruptibly to avoid messing | 2174 | * Wait for the grace period. Do so interruptibly to avoid messing |
2251 | * up the load average. | 2175 | * up the load average. |
2252 | */ | 2176 | */ |
2253 | trace_rcu_future_grace_period(rdp->rsp->name, rnp->gpnum, | 2177 | trace_rcu_future_gp(rnp, rdp, c, "StartWait"); |
2254 | rnp->completed, c, rnp->level, | ||
2255 | rnp->grplo, rnp->grphi, "StartWait"); | ||
2256 | for (;;) { | 2178 | for (;;) { |
2257 | wait_event_interruptible( | 2179 | wait_event_interruptible( |
2258 | rnp->nocb_gp_wq[c & 0x1], | 2180 | rnp->nocb_gp_wq[c & 0x1], |
@@ -2260,14 +2182,9 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp) | |||
2260 | if (likely(d)) | 2182 | if (likely(d)) |
2261 | break; | 2183 | break; |
2262 | flush_signals(current); | 2184 | flush_signals(current); |
2263 | trace_rcu_future_grace_period(rdp->rsp->name, | 2185 | trace_rcu_future_gp(rnp, rdp, c, "ResumeWait"); |
2264 | rnp->gpnum, rnp->completed, c, | ||
2265 | rnp->level, rnp->grplo, | ||
2266 | rnp->grphi, "ResumeWait"); | ||
2267 | } | 2186 | } |
2268 | trace_rcu_future_grace_period(rdp->rsp->name, rnp->gpnum, | 2187 | trace_rcu_future_gp(rnp, rdp, c, "EndWait"); |
2269 | rnp->completed, c, rnp->level, | ||
2270 | rnp->grplo, rnp->grphi, "EndWait"); | ||
2271 | smp_mb(); /* Ensure that CB invocation happens after GP end. */ | 2188 | smp_mb(); /* Ensure that CB invocation happens after GP end. */ |
2272 | } | 2189 | } |
2273 | 2190 | ||
@@ -2375,9 +2292,8 @@ static int rcu_nocb_needs_gp(struct rcu_state *rsp) | |||
2375 | return 0; | 2292 | return 0; |
2376 | } | 2293 | } |
2377 | 2294 | ||
2378 | static int rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) | 2295 | static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) |
2379 | { | 2296 | { |
2380 | return 0; | ||
2381 | } | 2297 | } |
2382 | 2298 | ||
2383 | static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq) | 2299 | static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq) |