diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2017-05-02 09:30:12 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2017-05-02 10:21:02 -0400 |
commit | 98059b98619d093366462ff0a4e1258e946accb9 (patch) | |
tree | 305b10fd41b962b42dbf88e5a8e05772b4aa7819 | |
parent | 45753c5f315749711b935a2506ee5c10eef5c23d (diff) |
rcu: Separately compile large rcu_segcblist functions
This commit creates a new kernel/rcu/rcu_segcblist.c file that
contains non-trivial segcblist functions. Trivial functions
remain as static inline functions in kernel/rcu/rcu_segcblist.h
Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | init/Kconfig | 3 | ||||
-rw-r--r-- | kernel/rcu/Makefile | 1 | ||||
-rw-r--r-- | kernel/rcu/rcu_segcblist.c | 505 | ||||
-rw-r--r-- | kernel/rcu/rcu_segcblist.h | 533 |
4 files changed, 544 insertions, 498 deletions
diff --git a/init/Kconfig b/init/Kconfig index 42a346b0df43..1d3475fc9496 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -573,6 +573,9 @@ config RCU_STALL_COMMON | |||
573 | the tiny variants to disable RCU CPU stall warnings, while | 573 | the tiny variants to disable RCU CPU stall warnings, while |
574 | making these warnings mandatory for the tree variants. | 574 | making these warnings mandatory for the tree variants. |
575 | 575 | ||
576 | config RCU_NEED_SEGCBLIST | ||
577 | def_bool ( TREE_RCU || PREEMPT_RCU || TINY_SRCU || TREE_SRCU ) | ||
578 | |||
576 | config CONTEXT_TRACKING | 579 | config CONTEXT_TRACKING |
577 | bool | 580 | bool |
578 | 581 | ||
diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile index 158e6593d58c..23803c7d5180 100644 --- a/kernel/rcu/Makefile +++ b/kernel/rcu/Makefile | |||
@@ -12,3 +12,4 @@ obj-$(CONFIG_TREE_RCU) += tree.o | |||
12 | obj-$(CONFIG_PREEMPT_RCU) += tree.o | 12 | obj-$(CONFIG_PREEMPT_RCU) += tree.o |
13 | obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o | 13 | obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o |
14 | obj-$(CONFIG_TINY_RCU) += tiny.o | 14 | obj-$(CONFIG_TINY_RCU) += tiny.o |
15 | obj-$(CONFIG_RCU_NEED_SEGCBLIST) += rcu_segcblist.o | ||
diff --git a/kernel/rcu/rcu_segcblist.c b/kernel/rcu/rcu_segcblist.c new file mode 100644 index 000000000000..2b62a38b080f --- /dev/null +++ b/kernel/rcu/rcu_segcblist.c | |||
@@ -0,0 +1,505 @@ | |||
1 | /* | ||
2 | * RCU segmented callback lists, function definitions | ||
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, you can access it online at | ||
16 | * http://www.gnu.org/licenses/gpl-2.0.html. | ||
17 | * | ||
18 | * Copyright IBM Corporation, 2017 | ||
19 | * | ||
20 | * Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
21 | */ | ||
22 | |||
23 | #include <linux/types.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | |||
27 | #include "rcu_segcblist.h" | ||
28 | |||
29 | /* Initialize simple callback list. */ | ||
30 | void rcu_cblist_init(struct rcu_cblist *rclp) | ||
31 | { | ||
32 | rclp->head = NULL; | ||
33 | rclp->tail = &rclp->head; | ||
34 | rclp->len = 0; | ||
35 | rclp->len_lazy = 0; | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * Debug function to actually count the number of callbacks. | ||
40 | * If the number exceeds the limit specified, return -1. | ||
41 | */ | ||
42 | long rcu_cblist_count_cbs(struct rcu_cblist *rclp, long lim) | ||
43 | { | ||
44 | int cnt = 0; | ||
45 | struct rcu_head **rhpp = &rclp->head; | ||
46 | |||
47 | for (;;) { | ||
48 | if (!*rhpp) | ||
49 | return cnt; | ||
50 | if (++cnt > lim) | ||
51 | return -1; | ||
52 | rhpp = &(*rhpp)->next; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * Dequeue the oldest rcu_head structure from the specified callback | ||
58 | * list. This function assumes that the callback is non-lazy, but | ||
59 | * the caller can later invoke rcu_cblist_dequeued_lazy() if it | ||
60 | * finds otherwise (and if it cares about laziness). This allows | ||
61 | * different users to have different ways of determining laziness. | ||
62 | */ | ||
63 | struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp) | ||
64 | { | ||
65 | struct rcu_head *rhp; | ||
66 | |||
67 | rhp = rclp->head; | ||
68 | if (!rhp) | ||
69 | return NULL; | ||
70 | rclp->len--; | ||
71 | rclp->head = rhp->next; | ||
72 | if (!rclp->head) | ||
73 | rclp->tail = &rclp->head; | ||
74 | return rhp; | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Initialize an rcu_segcblist structure. | ||
79 | */ | ||
80 | void rcu_segcblist_init(struct rcu_segcblist *rsclp) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | BUILD_BUG_ON(RCU_NEXT_TAIL + 1 != ARRAY_SIZE(rsclp->gp_seq)); | ||
85 | BUILD_BUG_ON(ARRAY_SIZE(rsclp->tails) != ARRAY_SIZE(rsclp->gp_seq)); | ||
86 | rsclp->head = NULL; | ||
87 | for (i = 0; i < RCU_CBLIST_NSEGS; i++) | ||
88 | rsclp->tails[i] = &rsclp->head; | ||
89 | rsclp->len = 0; | ||
90 | rsclp->len_lazy = 0; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Disable the specified rcu_segcblist structure, so that callbacks can | ||
95 | * no longer be posted to it. This structure must be empty. | ||
96 | */ | ||
97 | void rcu_segcblist_disable(struct rcu_segcblist *rsclp) | ||
98 | { | ||
99 | WARN_ON_ONCE(!rcu_segcblist_empty(rsclp)); | ||
100 | WARN_ON_ONCE(rcu_segcblist_n_cbs(rsclp)); | ||
101 | WARN_ON_ONCE(rcu_segcblist_n_lazy_cbs(rsclp)); | ||
102 | rsclp->tails[RCU_NEXT_TAIL] = NULL; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Is the specified segment of the specified rcu_segcblist structure | ||
107 | * empty of callbacks? | ||
108 | */ | ||
109 | bool rcu_segcblist_segempty(struct rcu_segcblist *rsclp, int seg) | ||
110 | { | ||
111 | if (seg == RCU_DONE_TAIL) | ||
112 | return &rsclp->head == rsclp->tails[RCU_DONE_TAIL]; | ||
113 | return rsclp->tails[seg - 1] == rsclp->tails[seg]; | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Does the specified rcu_segcblist structure contain callbacks that | ||
118 | * are ready to be invoked? | ||
119 | */ | ||
120 | bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp) | ||
121 | { | ||
122 | return rcu_segcblist_is_enabled(rsclp) && | ||
123 | &rsclp->head != rsclp->tails[RCU_DONE_TAIL]; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Does the specified rcu_segcblist structure contain callbacks that | ||
128 | * are still pending, that is, not yet ready to be invoked? | ||
129 | */ | ||
130 | bool rcu_segcblist_pend_cbs(struct rcu_segcblist *rsclp) | ||
131 | { | ||
132 | return rcu_segcblist_is_enabled(rsclp) && | ||
133 | !rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL); | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * Dequeue and return the first ready-to-invoke callback. If there | ||
138 | * are no ready-to-invoke callbacks, return NULL. Disables interrupts | ||
139 | * to avoid interference. Does not protect from interference from other | ||
140 | * CPUs or tasks. | ||
141 | */ | ||
142 | struct rcu_head *rcu_segcblist_dequeue(struct rcu_segcblist *rsclp) | ||
143 | { | ||
144 | unsigned long flags; | ||
145 | int i; | ||
146 | struct rcu_head *rhp; | ||
147 | |||
148 | local_irq_save(flags); | ||
149 | if (!rcu_segcblist_ready_cbs(rsclp)) { | ||
150 | local_irq_restore(flags); | ||
151 | return NULL; | ||
152 | } | ||
153 | rhp = rsclp->head; | ||
154 | BUG_ON(!rhp); | ||
155 | rsclp->head = rhp->next; | ||
156 | for (i = RCU_DONE_TAIL; i < RCU_CBLIST_NSEGS; i++) { | ||
157 | if (rsclp->tails[i] != &rhp->next) | ||
158 | break; | ||
159 | rsclp->tails[i] = &rsclp->head; | ||
160 | } | ||
161 | smp_mb(); /* Dequeue before decrement for rcu_barrier(). */ | ||
162 | WRITE_ONCE(rsclp->len, rsclp->len - 1); | ||
163 | local_irq_restore(flags); | ||
164 | return rhp; | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * Account for the fact that a previously dequeued callback turned out | ||
169 | * to be marked as lazy. | ||
170 | */ | ||
171 | void rcu_segcblist_dequeued_lazy(struct rcu_segcblist *rsclp) | ||
172 | { | ||
173 | unsigned long flags; | ||
174 | |||
175 | local_irq_save(flags); | ||
176 | rsclp->len_lazy--; | ||
177 | local_irq_restore(flags); | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Return a pointer to the first callback in the specified rcu_segcblist | ||
182 | * structure. This is useful for diagnostics. | ||
183 | */ | ||
184 | struct rcu_head *rcu_segcblist_first_cb(struct rcu_segcblist *rsclp) | ||
185 | { | ||
186 | if (rcu_segcblist_is_enabled(rsclp)) | ||
187 | return rsclp->head; | ||
188 | return NULL; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Return a pointer to the first pending callback in the specified | ||
193 | * rcu_segcblist structure. This is useful just after posting a given | ||
194 | * callback -- if that callback is the first pending callback, then | ||
195 | * you cannot rely on someone else having already started up the required | ||
196 | * grace period. | ||
197 | */ | ||
198 | struct rcu_head *rcu_segcblist_first_pend_cb(struct rcu_segcblist *rsclp) | ||
199 | { | ||
200 | if (rcu_segcblist_is_enabled(rsclp)) | ||
201 | return *rsclp->tails[RCU_DONE_TAIL]; | ||
202 | return NULL; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Does the specified rcu_segcblist structure contain callbacks that | ||
207 | * have not yet been processed beyond having been posted, that is, | ||
208 | * does it contain callbacks in its last segment? | ||
209 | */ | ||
210 | bool rcu_segcblist_new_cbs(struct rcu_segcblist *rsclp) | ||
211 | { | ||
212 | return rcu_segcblist_is_enabled(rsclp) && | ||
213 | !rcu_segcblist_restempty(rsclp, RCU_NEXT_READY_TAIL); | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * Enqueue the specified callback onto the specified rcu_segcblist | ||
218 | * structure, updating accounting as needed. Note that the ->len | ||
219 | * field may be accessed locklessly, hence the WRITE_ONCE(). | ||
220 | * The ->len field is used by rcu_barrier() and friends to determine | ||
221 | * if it must post a callback on this structure, and it is OK | ||
222 | * for rcu_barrier() to sometimes post callbacks needlessly, but | ||
223 | * absolutely not OK for it to ever miss posting a callback. | ||
224 | */ | ||
225 | void rcu_segcblist_enqueue(struct rcu_segcblist *rsclp, | ||
226 | struct rcu_head *rhp, bool lazy) | ||
227 | { | ||
228 | WRITE_ONCE(rsclp->len, rsclp->len + 1); /* ->len sampled locklessly. */ | ||
229 | if (lazy) | ||
230 | rsclp->len_lazy++; | ||
231 | smp_mb(); /* Ensure counts are updated before callback is enqueued. */ | ||
232 | rhp->next = NULL; | ||
233 | *rsclp->tails[RCU_NEXT_TAIL] = rhp; | ||
234 | rsclp->tails[RCU_NEXT_TAIL] = &rhp->next; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Entrain the specified callback onto the specified rcu_segcblist at | ||
239 | * the end of the last non-empty segment. If the entire rcu_segcblist | ||
240 | * is empty, make no change, but return false. | ||
241 | * | ||
242 | * This is intended for use by rcu_barrier()-like primitives, -not- | ||
243 | * for normal grace-period use. IMPORTANT: The callback you enqueue | ||
244 | * will wait for all prior callbacks, NOT necessarily for a grace | ||
245 | * period. You have been warned. | ||
246 | */ | ||
247 | bool rcu_segcblist_entrain(struct rcu_segcblist *rsclp, | ||
248 | struct rcu_head *rhp, bool lazy) | ||
249 | { | ||
250 | int i; | ||
251 | |||
252 | if (rcu_segcblist_n_cbs(rsclp) == 0) | ||
253 | return false; | ||
254 | WRITE_ONCE(rsclp->len, rsclp->len + 1); | ||
255 | if (lazy) | ||
256 | rsclp->len_lazy++; | ||
257 | smp_mb(); /* Ensure counts are updated before callback is entrained. */ | ||
258 | rhp->next = NULL; | ||
259 | for (i = RCU_NEXT_TAIL; i > RCU_DONE_TAIL; i--) | ||
260 | if (rsclp->tails[i] != rsclp->tails[i - 1]) | ||
261 | break; | ||
262 | *rsclp->tails[i] = rhp; | ||
263 | for (; i <= RCU_NEXT_TAIL; i++) | ||
264 | rsclp->tails[i] = &rhp->next; | ||
265 | return true; | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * Extract only the counts from the specified rcu_segcblist structure, | ||
270 | * and place them in the specified rcu_cblist structure. This function | ||
271 | * supports both callback orphaning and invocation, hence the separation | ||
272 | * of counts and callbacks. (Callbacks ready for invocation must be | ||
273 | * orphaned and adopted separately from pending callbacks, but counts | ||
274 | * apply to all callbacks. Locking must be used to make sure that | ||
275 | * both orphaned-callbacks lists are consistent.) | ||
276 | */ | ||
277 | void rcu_segcblist_extract_count(struct rcu_segcblist *rsclp, | ||
278 | struct rcu_cblist *rclp) | ||
279 | { | ||
280 | rclp->len_lazy += rsclp->len_lazy; | ||
281 | rclp->len += rsclp->len; | ||
282 | rsclp->len_lazy = 0; | ||
283 | WRITE_ONCE(rsclp->len, 0); /* ->len sampled locklessly. */ | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * Extract only those callbacks ready to be invoked from the specified | ||
288 | * rcu_segcblist structure and place them in the specified rcu_cblist | ||
289 | * structure. | ||
290 | */ | ||
291 | void rcu_segcblist_extract_done_cbs(struct rcu_segcblist *rsclp, | ||
292 | struct rcu_cblist *rclp) | ||
293 | { | ||
294 | int i; | ||
295 | |||
296 | if (!rcu_segcblist_ready_cbs(rsclp)) | ||
297 | return; /* Nothing to do. */ | ||
298 | *rclp->tail = rsclp->head; | ||
299 | rsclp->head = *rsclp->tails[RCU_DONE_TAIL]; | ||
300 | *rsclp->tails[RCU_DONE_TAIL] = NULL; | ||
301 | rclp->tail = rsclp->tails[RCU_DONE_TAIL]; | ||
302 | for (i = RCU_CBLIST_NSEGS - 1; i >= RCU_DONE_TAIL; i--) | ||
303 | if (rsclp->tails[i] == rsclp->tails[RCU_DONE_TAIL]) | ||
304 | rsclp->tails[i] = &rsclp->head; | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * Extract only those callbacks still pending (not yet ready to be | ||
309 | * invoked) from the specified rcu_segcblist structure and place them in | ||
310 | * the specified rcu_cblist structure. Note that this loses information | ||
311 | * about any callbacks that might have been partway done waiting for | ||
312 | * their grace period. Too bad! They will have to start over. | ||
313 | */ | ||
314 | void rcu_segcblist_extract_pend_cbs(struct rcu_segcblist *rsclp, | ||
315 | struct rcu_cblist *rclp) | ||
316 | { | ||
317 | int i; | ||
318 | |||
319 | if (!rcu_segcblist_pend_cbs(rsclp)) | ||
320 | return; /* Nothing to do. */ | ||
321 | *rclp->tail = *rsclp->tails[RCU_DONE_TAIL]; | ||
322 | rclp->tail = rsclp->tails[RCU_NEXT_TAIL]; | ||
323 | *rsclp->tails[RCU_DONE_TAIL] = NULL; | ||
324 | for (i = RCU_DONE_TAIL + 1; i < RCU_CBLIST_NSEGS; i++) | ||
325 | rsclp->tails[i] = rsclp->tails[RCU_DONE_TAIL]; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * Insert counts from the specified rcu_cblist structure in the | ||
330 | * specified rcu_segcblist structure. | ||
331 | */ | ||
332 | void rcu_segcblist_insert_count(struct rcu_segcblist *rsclp, | ||
333 | struct rcu_cblist *rclp) | ||
334 | { | ||
335 | rsclp->len_lazy += rclp->len_lazy; | ||
336 | /* ->len sampled locklessly. */ | ||
337 | WRITE_ONCE(rsclp->len, rsclp->len + rclp->len); | ||
338 | rclp->len_lazy = 0; | ||
339 | rclp->len = 0; | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * Move callbacks from the specified rcu_cblist to the beginning of the | ||
344 | * done-callbacks segment of the specified rcu_segcblist. | ||
345 | */ | ||
346 | void rcu_segcblist_insert_done_cbs(struct rcu_segcblist *rsclp, | ||
347 | struct rcu_cblist *rclp) | ||
348 | { | ||
349 | int i; | ||
350 | |||
351 | if (!rclp->head) | ||
352 | return; /* No callbacks to move. */ | ||
353 | *rclp->tail = rsclp->head; | ||
354 | rsclp->head = rclp->head; | ||
355 | for (i = RCU_DONE_TAIL; i < RCU_CBLIST_NSEGS; i++) | ||
356 | if (&rsclp->head == rsclp->tails[i]) | ||
357 | rsclp->tails[i] = rclp->tail; | ||
358 | else | ||
359 | break; | ||
360 | rclp->head = NULL; | ||
361 | rclp->tail = &rclp->head; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * Move callbacks from the specified rcu_cblist to the end of the | ||
366 | * new-callbacks segment of the specified rcu_segcblist. | ||
367 | */ | ||
368 | void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp, | ||
369 | struct rcu_cblist *rclp) | ||
370 | { | ||
371 | if (!rclp->head) | ||
372 | return; /* Nothing to do. */ | ||
373 | *rsclp->tails[RCU_NEXT_TAIL] = rclp->head; | ||
374 | rsclp->tails[RCU_NEXT_TAIL] = rclp->tail; | ||
375 | rclp->head = NULL; | ||
376 | rclp->tail = &rclp->head; | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * Advance the callbacks in the specified rcu_segcblist structure based | ||
381 | * on the current value passed in for the grace-period counter. | ||
382 | */ | ||
383 | void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq) | ||
384 | { | ||
385 | int i, j; | ||
386 | |||
387 | WARN_ON_ONCE(!rcu_segcblist_is_enabled(rsclp)); | ||
388 | if (rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL)) | ||
389 | return; | ||
390 | |||
391 | /* | ||
392 | * Find all callbacks whose ->gp_seq numbers indicate that they | ||
393 | * are ready to invoke, and put them into the RCU_DONE_TAIL segment. | ||
394 | */ | ||
395 | for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) { | ||
396 | if (ULONG_CMP_LT(seq, rsclp->gp_seq[i])) | ||
397 | break; | ||
398 | rsclp->tails[RCU_DONE_TAIL] = rsclp->tails[i]; | ||
399 | } | ||
400 | |||
401 | /* If no callbacks moved, nothing more need be done. */ | ||
402 | if (i == RCU_WAIT_TAIL) | ||
403 | return; | ||
404 | |||
405 | /* Clean up tail pointers that might have been misordered above. */ | ||
406 | for (j = RCU_WAIT_TAIL; j < i; j++) | ||
407 | rsclp->tails[j] = rsclp->tails[RCU_DONE_TAIL]; | ||
408 | |||
409 | /* | ||
410 | * Callbacks moved, so clean up the misordered ->tails[] pointers | ||
411 | * that now point into the middle of the list of ready-to-invoke | ||
412 | * callbacks. The overall effect is to copy down the later pointers | ||
413 | * into the gap that was created by the now-ready segments. | ||
414 | */ | ||
415 | for (j = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++, j++) { | ||
416 | if (rsclp->tails[j] == rsclp->tails[RCU_NEXT_TAIL]) | ||
417 | break; /* No more callbacks. */ | ||
418 | rsclp->tails[j] = rsclp->tails[i]; | ||
419 | rsclp->gp_seq[j] = rsclp->gp_seq[i]; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * "Accelerate" callbacks based on more-accurate grace-period information. | ||
425 | * The reason for this is that RCU does not synchronize the beginnings and | ||
426 | * ends of grace periods, and that callbacks are posted locally. This in | ||
427 | * turn means that the callbacks must be labelled conservatively early | ||
428 | * on, as getting exact information would degrade both performance and | ||
429 | * scalability. When more accurate grace-period information becomes | ||
430 | * available, previously posted callbacks can be "accelerated", marking | ||
431 | * them to complete at the end of the earlier grace period. | ||
432 | * | ||
433 | * This function operates on an rcu_segcblist structure, and also the | ||
434 | * grace-period sequence number seq at which new callbacks would become | ||
435 | * ready to invoke. Returns true if there are callbacks that won't be | ||
436 | * ready to invoke until seq, false otherwise. | ||
437 | */ | ||
438 | bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, unsigned long seq) | ||
439 | { | ||
440 | int i; | ||
441 | |||
442 | WARN_ON_ONCE(!rcu_segcblist_is_enabled(rsclp)); | ||
443 | if (rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL)) | ||
444 | return false; | ||
445 | |||
446 | /* | ||
447 | * Find the segment preceding the oldest segment of callbacks | ||
448 | * whose ->gp_seq[] completion is at or after that passed in via | ||
449 | * "seq", skipping any empty segments. This oldest segment, along | ||
450 | * with any later segments, can be merged in with any newly arrived | ||
451 | * callbacks in the RCU_NEXT_TAIL segment, and assigned "seq" | ||
452 | * as their ->gp_seq[] grace-period completion sequence number. | ||
453 | */ | ||
454 | for (i = RCU_NEXT_READY_TAIL; i > RCU_DONE_TAIL; i--) | ||
455 | if (rsclp->tails[i] != rsclp->tails[i - 1] && | ||
456 | ULONG_CMP_LT(rsclp->gp_seq[i], seq)) | ||
457 | break; | ||
458 | |||
459 | /* | ||
460 | * If all the segments contain callbacks that correspond to | ||
461 | * earlier grace-period sequence numbers than "seq", leave. | ||
462 | * Assuming that the rcu_segcblist structure has enough | ||
463 | * segments in its arrays, this can only happen if some of | ||
464 | * the non-done segments contain callbacks that really are | ||
465 | * ready to invoke. This situation will get straightened | ||
466 | * out by the next call to rcu_segcblist_advance(). | ||
467 | * | ||
468 | * Also advance to the oldest segment of callbacks whose | ||
469 | * ->gp_seq[] completion is at or after that passed in via "seq", | ||
470 | * skipping any empty segments. | ||
471 | */ | ||
472 | if (++i >= RCU_NEXT_TAIL) | ||
473 | return false; | ||
474 | |||
475 | /* | ||
476 | * Merge all later callbacks, including newly arrived callbacks, | ||
477 | * into the segment located by the for-loop above. Assign "seq" | ||
478 | * as the ->gp_seq[] value in order to correctly handle the case | ||
479 | * where there were no pending callbacks in the rcu_segcblist | ||
480 | * structure other than in the RCU_NEXT_TAIL segment. | ||
481 | */ | ||
482 | for (; i < RCU_NEXT_TAIL; i++) { | ||
483 | rsclp->tails[i] = rsclp->tails[RCU_NEXT_TAIL]; | ||
484 | rsclp->gp_seq[i] = seq; | ||
485 | } | ||
486 | return true; | ||
487 | } | ||
488 | |||
489 | /* | ||
490 | * Scan the specified rcu_segcblist structure for callbacks that need | ||
491 | * a grace period later than the one specified by "seq". We don't look | ||
492 | * at the RCU_DONE_TAIL or RCU_NEXT_TAIL segments because they don't | ||
493 | * have a grace-period sequence number. | ||
494 | */ | ||
495 | bool rcu_segcblist_future_gp_needed(struct rcu_segcblist *rsclp, | ||
496 | unsigned long seq) | ||
497 | { | ||
498 | int i; | ||
499 | |||
500 | for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) | ||
501 | if (rsclp->tails[i - 1] != rsclp->tails[i] && | ||
502 | ULONG_CMP_LT(seq, rsclp->gp_seq[i])) | ||
503 | return true; | ||
504 | return false; | ||
505 | } | ||
diff --git a/kernel/rcu/rcu_segcblist.h b/kernel/rcu/rcu_segcblist.h index d98d2f9b8d59..86bc1101b806 100644 --- a/kernel/rcu/rcu_segcblist.h +++ b/kernel/rcu/rcu_segcblist.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * RCU segmented callback lists | 2 | * RCU segmented callback lists, internal-to-rcu header file |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 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 | 5 | * it under the terms of the GNU General Public License as published by |
@@ -22,15 +22,6 @@ | |||
22 | 22 | ||
23 | #include <linux/rcu_segcblist.h> | 23 | #include <linux/rcu_segcblist.h> |
24 | 24 | ||
25 | /* Initialize simple callback list. */ | ||
26 | static inline void rcu_cblist_init(struct rcu_cblist *rclp) | ||
27 | { | ||
28 | rclp->head = NULL; | ||
29 | rclp->tail = &rclp->head; | ||
30 | rclp->len = 0; | ||
31 | rclp->len_lazy = 0; | ||
32 | } | ||
33 | |||
34 | /* Is simple callback list empty? */ | 25 | /* Is simple callback list empty? */ |
35 | static inline bool rcu_cblist_empty(struct rcu_cblist *rclp) | 26 | static inline bool rcu_cblist_empty(struct rcu_cblist *rclp) |
36 | { | 27 | { |
@@ -50,45 +41,6 @@ static inline long rcu_cblist_n_lazy_cbs(struct rcu_cblist *rclp) | |||
50 | } | 41 | } |
51 | 42 | ||
52 | /* | 43 | /* |
53 | * Debug function to actually count the number of callbacks. | ||
54 | * If the number exceeds the limit specified, return -1. | ||
55 | */ | ||
56 | static inline long rcu_cblist_count_cbs(struct rcu_cblist *rclp, long lim) | ||
57 | { | ||
58 | int cnt = 0; | ||
59 | struct rcu_head **rhpp = &rclp->head; | ||
60 | |||
61 | for (;;) { | ||
62 | if (!*rhpp) | ||
63 | return cnt; | ||
64 | if (++cnt > lim) | ||
65 | return -1; | ||
66 | rhpp = &(*rhpp)->next; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * Dequeue the oldest rcu_head structure from the specified callback | ||
72 | * list. This function assumes that the callback is non-lazy, but | ||
73 | * the caller can later invoke rcu_cblist_dequeued_lazy() if it | ||
74 | * finds otherwise (and if it cares about laziness). This allows | ||
75 | * different users to have different ways of determining laziness. | ||
76 | */ | ||
77 | static inline struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp) | ||
78 | { | ||
79 | struct rcu_head *rhp; | ||
80 | |||
81 | rhp = rclp->head; | ||
82 | if (!rhp) | ||
83 | return NULL; | ||
84 | rclp->len--; | ||
85 | rclp->head = rhp->next; | ||
86 | if (!rclp->head) | ||
87 | rclp->tail = &rclp->head; | ||
88 | return rhp; | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Account for the fact that a previously dequeued callback turned out | 44 | * Account for the fact that a previously dequeued callback turned out |
93 | * to be marked as lazy. | 45 | * to be marked as lazy. |
94 | */ | 46 | */ |
@@ -118,21 +70,9 @@ static inline struct rcu_head **rcu_cblist_tail(struct rcu_cblist *rclp) | |||
118 | return rclp->tail; | 70 | return rclp->tail; |
119 | } | 71 | } |
120 | 72 | ||
121 | /* | 73 | void rcu_cblist_init(struct rcu_cblist *rclp); |
122 | * Initialize an rcu_segcblist structure. | 74 | long rcu_cblist_count_cbs(struct rcu_cblist *rclp, long lim); |
123 | */ | 75 | struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp); |
124 | static inline void rcu_segcblist_init(struct rcu_segcblist *rsclp) | ||
125 | { | ||
126 | int i; | ||
127 | |||
128 | BUILD_BUG_ON(RCU_NEXT_TAIL + 1 != ARRAY_SIZE(rsclp->gp_seq)); | ||
129 | BUILD_BUG_ON(ARRAY_SIZE(rsclp->tails) != ARRAY_SIZE(rsclp->gp_seq)); | ||
130 | rsclp->head = NULL; | ||
131 | for (i = 0; i < RCU_CBLIST_NSEGS; i++) | ||
132 | rsclp->tails[i] = &rsclp->head; | ||
133 | rsclp->len = 0; | ||
134 | rsclp->len_lazy = 0; | ||
135 | } | ||
136 | 76 | ||
137 | /* | 77 | /* |
138 | * Is the specified rcu_segcblist structure empty? | 78 | * Is the specified rcu_segcblist structure empty? |
@@ -180,29 +120,6 @@ static inline bool rcu_segcblist_is_enabled(struct rcu_segcblist *rsclp) | |||
180 | } | 120 | } |
181 | 121 | ||
182 | /* | 122 | /* |
183 | * Disable the specified rcu_segcblist structure, so that callbacks can | ||
184 | * no longer be posted to it. This structure must be empty. | ||
185 | */ | ||
186 | static inline void rcu_segcblist_disable(struct rcu_segcblist *rsclp) | ||
187 | { | ||
188 | WARN_ON_ONCE(!rcu_segcblist_empty(rsclp)); | ||
189 | WARN_ON_ONCE(rcu_segcblist_n_cbs(rsclp)); | ||
190 | WARN_ON_ONCE(rcu_segcblist_n_lazy_cbs(rsclp)); | ||
191 | rsclp->tails[RCU_NEXT_TAIL] = NULL; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * Is the specified segment of the specified rcu_segcblist structure | ||
196 | * empty of callbacks? | ||
197 | */ | ||
198 | static inline bool rcu_segcblist_segempty(struct rcu_segcblist *rsclp, int seg) | ||
199 | { | ||
200 | if (seg == RCU_DONE_TAIL) | ||
201 | return &rsclp->head == rsclp->tails[RCU_DONE_TAIL]; | ||
202 | return rsclp->tails[seg - 1] == rsclp->tails[seg]; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Are all segments following the specified segment of the specified | 123 | * Are all segments following the specified segment of the specified |
207 | * rcu_segcblist structure empty of callbacks? (The specified | 124 | * rcu_segcblist structure empty of callbacks? (The specified |
208 | * segment might well contain callbacks.) | 125 | * segment might well contain callbacks.) |
@@ -213,417 +130,6 @@ static inline bool rcu_segcblist_restempty(struct rcu_segcblist *rsclp, int seg) | |||
213 | } | 130 | } |
214 | 131 | ||
215 | /* | 132 | /* |
216 | * Does the specified rcu_segcblist structure contain callbacks that | ||
217 | * are ready to be invoked? | ||
218 | */ | ||
219 | static inline bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp) | ||
220 | { | ||
221 | return rcu_segcblist_is_enabled(rsclp) && | ||
222 | &rsclp->head != rsclp->tails[RCU_DONE_TAIL]; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Does the specified rcu_segcblist structure contain callbacks that | ||
227 | * are still pending, that is, not yet ready to be invoked? | ||
228 | */ | ||
229 | static inline bool rcu_segcblist_pend_cbs(struct rcu_segcblist *rsclp) | ||
230 | { | ||
231 | return rcu_segcblist_is_enabled(rsclp) && | ||
232 | !rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL); | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * Dequeue and return the first ready-to-invoke callback. If there | ||
237 | * are no ready-to-invoke callbacks, return NULL. Disables interrupts | ||
238 | * to avoid interference. Does not protect from interference from other | ||
239 | * CPUs or tasks. | ||
240 | */ | ||
241 | static inline struct rcu_head * | ||
242 | rcu_segcblist_dequeue(struct rcu_segcblist *rsclp) | ||
243 | { | ||
244 | unsigned long flags; | ||
245 | int i; | ||
246 | struct rcu_head *rhp; | ||
247 | |||
248 | local_irq_save(flags); | ||
249 | if (!rcu_segcblist_ready_cbs(rsclp)) { | ||
250 | local_irq_restore(flags); | ||
251 | return NULL; | ||
252 | } | ||
253 | rhp = rsclp->head; | ||
254 | BUG_ON(!rhp); | ||
255 | rsclp->head = rhp->next; | ||
256 | for (i = RCU_DONE_TAIL; i < RCU_CBLIST_NSEGS; i++) { | ||
257 | if (rsclp->tails[i] != &rhp->next) | ||
258 | break; | ||
259 | rsclp->tails[i] = &rsclp->head; | ||
260 | } | ||
261 | smp_mb(); /* Dequeue before decrement for rcu_barrier(). */ | ||
262 | WRITE_ONCE(rsclp->len, rsclp->len - 1); | ||
263 | local_irq_restore(flags); | ||
264 | return rhp; | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * Account for the fact that a previously dequeued callback turned out | ||
269 | * to be marked as lazy. | ||
270 | */ | ||
271 | static inline void rcu_segcblist_dequeued_lazy(struct rcu_segcblist *rsclp) | ||
272 | { | ||
273 | unsigned long flags; | ||
274 | |||
275 | local_irq_save(flags); | ||
276 | rsclp->len_lazy--; | ||
277 | local_irq_restore(flags); | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * Return a pointer to the first callback in the specified rcu_segcblist | ||
282 | * structure. This is useful for diagnostics. | ||
283 | */ | ||
284 | static inline struct rcu_head * | ||
285 | rcu_segcblist_first_cb(struct rcu_segcblist *rsclp) | ||
286 | { | ||
287 | if (rcu_segcblist_is_enabled(rsclp)) | ||
288 | return rsclp->head; | ||
289 | return NULL; | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * Return a pointer to the first pending callback in the specified | ||
294 | * rcu_segcblist structure. This is useful just after posting a given | ||
295 | * callback -- if that callback is the first pending callback, then | ||
296 | * you cannot rely on someone else having already started up the required | ||
297 | * grace period. | ||
298 | */ | ||
299 | static inline struct rcu_head * | ||
300 | rcu_segcblist_first_pend_cb(struct rcu_segcblist *rsclp) | ||
301 | { | ||
302 | if (rcu_segcblist_is_enabled(rsclp)) | ||
303 | return *rsclp->tails[RCU_DONE_TAIL]; | ||
304 | return NULL; | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * Does the specified rcu_segcblist structure contain callbacks that | ||
309 | * have not yet been processed beyond having been posted, that is, | ||
310 | * does it contain callbacks in its last segment? | ||
311 | */ | ||
312 | static inline bool rcu_segcblist_new_cbs(struct rcu_segcblist *rsclp) | ||
313 | { | ||
314 | return rcu_segcblist_is_enabled(rsclp) && | ||
315 | !rcu_segcblist_restempty(rsclp, RCU_NEXT_READY_TAIL); | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Enqueue the specified callback onto the specified rcu_segcblist | ||
320 | * structure, updating accounting as needed. Note that the ->len | ||
321 | * field may be accessed locklessly, hence the WRITE_ONCE(). | ||
322 | * The ->len field is used by rcu_barrier() and friends to determine | ||
323 | * if it must post a callback on this structure, and it is OK | ||
324 | * for rcu_barrier() to sometimes post callbacks needlessly, but | ||
325 | * absolutely not OK for it to ever miss posting a callback. | ||
326 | */ | ||
327 | static inline void rcu_segcblist_enqueue(struct rcu_segcblist *rsclp, | ||
328 | struct rcu_head *rhp, bool lazy) | ||
329 | { | ||
330 | WRITE_ONCE(rsclp->len, rsclp->len + 1); /* ->len sampled locklessly. */ | ||
331 | if (lazy) | ||
332 | rsclp->len_lazy++; | ||
333 | smp_mb(); /* Ensure counts are updated before callback is enqueued. */ | ||
334 | rhp->next = NULL; | ||
335 | *rsclp->tails[RCU_NEXT_TAIL] = rhp; | ||
336 | rsclp->tails[RCU_NEXT_TAIL] = &rhp->next; | ||
337 | } | ||
338 | |||
339 | /* | ||
340 | * Entrain the specified callback onto the specified rcu_segcblist at | ||
341 | * the end of the last non-empty segment. If the entire rcu_segcblist | ||
342 | * is empty, make no change, but return false. | ||
343 | * | ||
344 | * This is intended for use by rcu_barrier()-like primitives, -not- | ||
345 | * for normal grace-period use. IMPORTANT: The callback you enqueue | ||
346 | * will wait for all prior callbacks, NOT necessarily for a grace | ||
347 | * period. You have been warned. | ||
348 | */ | ||
349 | static inline bool rcu_segcblist_entrain(struct rcu_segcblist *rsclp, | ||
350 | struct rcu_head *rhp, bool lazy) | ||
351 | { | ||
352 | int i; | ||
353 | |||
354 | if (rcu_segcblist_n_cbs(rsclp) == 0) | ||
355 | return false; | ||
356 | WRITE_ONCE(rsclp->len, rsclp->len + 1); | ||
357 | if (lazy) | ||
358 | rsclp->len_lazy++; | ||
359 | smp_mb(); /* Ensure counts are updated before callback is entrained. */ | ||
360 | rhp->next = NULL; | ||
361 | for (i = RCU_NEXT_TAIL; i > RCU_DONE_TAIL; i--) | ||
362 | if (rsclp->tails[i] != rsclp->tails[i - 1]) | ||
363 | break; | ||
364 | *rsclp->tails[i] = rhp; | ||
365 | for (; i <= RCU_NEXT_TAIL; i++) | ||
366 | rsclp->tails[i] = &rhp->next; | ||
367 | return true; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * Extract only the counts from the specified rcu_segcblist structure, | ||
372 | * and place them in the specified rcu_cblist structure. This function | ||
373 | * supports both callback orphaning and invocation, hence the separation | ||
374 | * of counts and callbacks. (Callbacks ready for invocation must be | ||
375 | * orphaned and adopted separately from pending callbacks, but counts | ||
376 | * apply to all callbacks. Locking must be used to make sure that | ||
377 | * both orphaned-callbacks lists are consistent.) | ||
378 | */ | ||
379 | static inline void rcu_segcblist_extract_count(struct rcu_segcblist *rsclp, | ||
380 | struct rcu_cblist *rclp) | ||
381 | { | ||
382 | rclp->len_lazy += rsclp->len_lazy; | ||
383 | rclp->len += rsclp->len; | ||
384 | rsclp->len_lazy = 0; | ||
385 | WRITE_ONCE(rsclp->len, 0); /* ->len sampled locklessly. */ | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * Extract only those callbacks ready to be invoked from the specified | ||
390 | * rcu_segcblist structure and place them in the specified rcu_cblist | ||
391 | * structure. | ||
392 | */ | ||
393 | static inline void rcu_segcblist_extract_done_cbs(struct rcu_segcblist *rsclp, | ||
394 | struct rcu_cblist *rclp) | ||
395 | { | ||
396 | int i; | ||
397 | |||
398 | if (!rcu_segcblist_ready_cbs(rsclp)) | ||
399 | return; /* Nothing to do. */ | ||
400 | *rclp->tail = rsclp->head; | ||
401 | rsclp->head = *rsclp->tails[RCU_DONE_TAIL]; | ||
402 | *rsclp->tails[RCU_DONE_TAIL] = NULL; | ||
403 | rclp->tail = rsclp->tails[RCU_DONE_TAIL]; | ||
404 | for (i = RCU_CBLIST_NSEGS - 1; i >= RCU_DONE_TAIL; i--) | ||
405 | if (rsclp->tails[i] == rsclp->tails[RCU_DONE_TAIL]) | ||
406 | rsclp->tails[i] = &rsclp->head; | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * Extract only those callbacks still pending (not yet ready to be | ||
411 | * invoked) from the specified rcu_segcblist structure and place them in | ||
412 | * the specified rcu_cblist structure. Note that this loses information | ||
413 | * about any callbacks that might have been partway done waiting for | ||
414 | * their grace period. Too bad! They will have to start over. | ||
415 | */ | ||
416 | static inline void | ||
417 | rcu_segcblist_extract_pend_cbs(struct rcu_segcblist *rsclp, | ||
418 | struct rcu_cblist *rclp) | ||
419 | { | ||
420 | int i; | ||
421 | |||
422 | if (!rcu_segcblist_pend_cbs(rsclp)) | ||
423 | return; /* Nothing to do. */ | ||
424 | *rclp->tail = *rsclp->tails[RCU_DONE_TAIL]; | ||
425 | rclp->tail = rsclp->tails[RCU_NEXT_TAIL]; | ||
426 | *rsclp->tails[RCU_DONE_TAIL] = NULL; | ||
427 | for (i = RCU_DONE_TAIL + 1; i < RCU_CBLIST_NSEGS; i++) | ||
428 | rsclp->tails[i] = rsclp->tails[RCU_DONE_TAIL]; | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | * Move the entire contents of the specified rcu_segcblist structure, | ||
433 | * counts, callbacks, and all, to the specified rcu_cblist structure. | ||
434 | * @@@ Why do we need this??? Moving early-boot CBs to NOCB lists? | ||
435 | * @@@ Memory barrier needed? (Not if only used at boot time...) | ||
436 | */ | ||
437 | static inline void rcu_segcblist_extract_all(struct rcu_segcblist *rsclp, | ||
438 | struct rcu_cblist *rclp) | ||
439 | { | ||
440 | rcu_segcblist_extract_done_cbs(rsclp, rclp); | ||
441 | rcu_segcblist_extract_pend_cbs(rsclp, rclp); | ||
442 | rcu_segcblist_extract_count(rsclp, rclp); | ||
443 | } | ||
444 | |||
445 | /* | ||
446 | * Insert counts from the specified rcu_cblist structure in the | ||
447 | * specified rcu_segcblist structure. | ||
448 | */ | ||
449 | static inline void rcu_segcblist_insert_count(struct rcu_segcblist *rsclp, | ||
450 | struct rcu_cblist *rclp) | ||
451 | { | ||
452 | rsclp->len_lazy += rclp->len_lazy; | ||
453 | /* ->len sampled locklessly. */ | ||
454 | WRITE_ONCE(rsclp->len, rsclp->len + rclp->len); | ||
455 | rclp->len_lazy = 0; | ||
456 | rclp->len = 0; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * Move callbacks from the specified rcu_cblist to the beginning of the | ||
461 | * done-callbacks segment of the specified rcu_segcblist. | ||
462 | */ | ||
463 | static inline void rcu_segcblist_insert_done_cbs(struct rcu_segcblist *rsclp, | ||
464 | struct rcu_cblist *rclp) | ||
465 | { | ||
466 | int i; | ||
467 | |||
468 | if (!rclp->head) | ||
469 | return; /* No callbacks to move. */ | ||
470 | *rclp->tail = rsclp->head; | ||
471 | rsclp->head = rclp->head; | ||
472 | for (i = RCU_DONE_TAIL; i < RCU_CBLIST_NSEGS; i++) | ||
473 | if (&rsclp->head == rsclp->tails[i]) | ||
474 | rsclp->tails[i] = rclp->tail; | ||
475 | else | ||
476 | break; | ||
477 | rclp->head = NULL; | ||
478 | rclp->tail = &rclp->head; | ||
479 | } | ||
480 | |||
481 | /* | ||
482 | * Move callbacks from the specified rcu_cblist to the end of the | ||
483 | * new-callbacks segment of the specified rcu_segcblist. | ||
484 | */ | ||
485 | static inline void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp, | ||
486 | struct rcu_cblist *rclp) | ||
487 | { | ||
488 | if (!rclp->head) | ||
489 | return; /* Nothing to do. */ | ||
490 | *rsclp->tails[RCU_NEXT_TAIL] = rclp->head; | ||
491 | rsclp->tails[RCU_NEXT_TAIL] = rclp->tail; | ||
492 | rclp->head = NULL; | ||
493 | rclp->tail = &rclp->head; | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | * Advance the callbacks in the specified rcu_segcblist structure based | ||
498 | * on the current value passed in for the grace-period counter. | ||
499 | */ | ||
500 | static inline void rcu_segcblist_advance(struct rcu_segcblist *rsclp, | ||
501 | unsigned long seq) | ||
502 | { | ||
503 | int i, j; | ||
504 | |||
505 | WARN_ON_ONCE(!rcu_segcblist_is_enabled(rsclp)); | ||
506 | if (rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL)) | ||
507 | return; | ||
508 | |||
509 | /* | ||
510 | * Find all callbacks whose ->gp_seq numbers indicate that they | ||
511 | * are ready to invoke, and put them into the RCU_DONE_TAIL segment. | ||
512 | */ | ||
513 | for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) { | ||
514 | if (ULONG_CMP_LT(seq, rsclp->gp_seq[i])) | ||
515 | break; | ||
516 | rsclp->tails[RCU_DONE_TAIL] = rsclp->tails[i]; | ||
517 | } | ||
518 | |||
519 | /* If no callbacks moved, nothing more need be done. */ | ||
520 | if (i == RCU_WAIT_TAIL) | ||
521 | return; | ||
522 | |||
523 | /* Clean up tail pointers that might have been misordered above. */ | ||
524 | for (j = RCU_WAIT_TAIL; j < i; j++) | ||
525 | rsclp->tails[j] = rsclp->tails[RCU_DONE_TAIL]; | ||
526 | |||
527 | /* | ||
528 | * Callbacks moved, so clean up the misordered ->tails[] pointers | ||
529 | * that now point into the middle of the list of ready-to-invoke | ||
530 | * callbacks. The overall effect is to copy down the later pointers | ||
531 | * into the gap that was created by the now-ready segments. | ||
532 | */ | ||
533 | for (j = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++, j++) { | ||
534 | if (rsclp->tails[j] == rsclp->tails[RCU_NEXT_TAIL]) | ||
535 | break; /* No more callbacks. */ | ||
536 | rsclp->tails[j] = rsclp->tails[i]; | ||
537 | rsclp->gp_seq[j] = rsclp->gp_seq[i]; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | /* | ||
542 | * "Accelerate" callbacks based on more-accurate grace-period information. | ||
543 | * The reason for this is that RCU does not synchronize the beginnings and | ||
544 | * ends of grace periods, and that callbacks are posted locally. This in | ||
545 | * turn means that the callbacks must be labelled conservatively early | ||
546 | * on, as getting exact information would degrade both performance and | ||
547 | * scalability. When more accurate grace-period information becomes | ||
548 | * available, previously posted callbacks can be "accelerated", marking | ||
549 | * them to complete at the end of the earlier grace period. | ||
550 | * | ||
551 | * This function operates on an rcu_segcblist structure, and also the | ||
552 | * grace-period sequence number seq at which new callbacks would become | ||
553 | * ready to invoke. Returns true if there are callbacks that won't be | ||
554 | * ready to invoke until seq, false otherwise. | ||
555 | */ | ||
556 | static inline bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, | ||
557 | unsigned long seq) | ||
558 | { | ||
559 | int i; | ||
560 | |||
561 | WARN_ON_ONCE(!rcu_segcblist_is_enabled(rsclp)); | ||
562 | if (rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL)) | ||
563 | return false; | ||
564 | |||
565 | /* | ||
566 | * Find the segment preceding the oldest segment of callbacks | ||
567 | * whose ->gp_seq[] completion is at or after that passed in via | ||
568 | * "seq", skipping any empty segments. This oldest segment, along | ||
569 | * with any later segments, can be merged in with any newly arrived | ||
570 | * callbacks in the RCU_NEXT_TAIL segment, and assigned "seq" | ||
571 | * as their ->gp_seq[] grace-period completion sequence number. | ||
572 | */ | ||
573 | for (i = RCU_NEXT_READY_TAIL; i > RCU_DONE_TAIL; i--) | ||
574 | if (rsclp->tails[i] != rsclp->tails[i - 1] && | ||
575 | ULONG_CMP_LT(rsclp->gp_seq[i], seq)) | ||
576 | break; | ||
577 | |||
578 | /* | ||
579 | * If all the segments contain callbacks that correspond to | ||
580 | * earlier grace-period sequence numbers than "seq", leave. | ||
581 | * Assuming that the rcu_segcblist structure has enough | ||
582 | * segments in its arrays, this can only happen if some of | ||
583 | * the non-done segments contain callbacks that really are | ||
584 | * ready to invoke. This situation will get straightened | ||
585 | * out by the next call to rcu_segcblist_advance(). | ||
586 | * | ||
587 | * Also advance to the oldest segment of callbacks whose | ||
588 | * ->gp_seq[] completion is at or after that passed in via "seq", | ||
589 | * skipping any empty segments. | ||
590 | */ | ||
591 | if (++i >= RCU_NEXT_TAIL) | ||
592 | return false; | ||
593 | |||
594 | /* | ||
595 | * Merge all later callbacks, including newly arrived callbacks, | ||
596 | * into the segment located by the for-loop above. Assign "seq" | ||
597 | * as the ->gp_seq[] value in order to correctly handle the case | ||
598 | * where there were no pending callbacks in the rcu_segcblist | ||
599 | * structure other than in the RCU_NEXT_TAIL segment. | ||
600 | */ | ||
601 | for (; i < RCU_NEXT_TAIL; i++) { | ||
602 | rsclp->tails[i] = rsclp->tails[RCU_NEXT_TAIL]; | ||
603 | rsclp->gp_seq[i] = seq; | ||
604 | } | ||
605 | return true; | ||
606 | } | ||
607 | |||
608 | /* | ||
609 | * Scan the specified rcu_segcblist structure for callbacks that need | ||
610 | * a grace period later than the one specified by "seq". We don't look | ||
611 | * at the RCU_DONE_TAIL or RCU_NEXT_TAIL segments because they don't | ||
612 | * have a grace-period sequence number. | ||
613 | */ | ||
614 | static inline bool rcu_segcblist_future_gp_needed(struct rcu_segcblist *rsclp, | ||
615 | unsigned long seq) | ||
616 | { | ||
617 | int i; | ||
618 | |||
619 | for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) | ||
620 | if (rsclp->tails[i - 1] != rsclp->tails[i] && | ||
621 | ULONG_CMP_LT(seq, rsclp->gp_seq[i])) | ||
622 | return true; | ||
623 | return false; | ||
624 | } | ||
625 | |||
626 | /* | ||
627 | * Interim function to return rcu_segcblist head pointer. Longer term, the | 133 | * Interim function to return rcu_segcblist head pointer. Longer term, the |
628 | * rcu_segcblist will be used more pervasively, removing the need for this | 134 | * rcu_segcblist will be used more pervasively, removing the need for this |
629 | * function. | 135 | * function. |
@@ -643,3 +149,34 @@ static inline struct rcu_head **rcu_segcblist_tail(struct rcu_segcblist *rsclp) | |||
643 | WARN_ON_ONCE(rcu_segcblist_empty(rsclp)); | 149 | WARN_ON_ONCE(rcu_segcblist_empty(rsclp)); |
644 | return rsclp->tails[RCU_NEXT_TAIL]; | 150 | return rsclp->tails[RCU_NEXT_TAIL]; |
645 | } | 151 | } |
152 | |||
153 | void rcu_segcblist_init(struct rcu_segcblist *rsclp); | ||
154 | void rcu_segcblist_disable(struct rcu_segcblist *rsclp); | ||
155 | bool rcu_segcblist_segempty(struct rcu_segcblist *rsclp, int seg); | ||
156 | bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp); | ||
157 | bool rcu_segcblist_pend_cbs(struct rcu_segcblist *rsclp); | ||
158 | struct rcu_head *rcu_segcblist_dequeue(struct rcu_segcblist *rsclp); | ||
159 | void rcu_segcblist_dequeued_lazy(struct rcu_segcblist *rsclp); | ||
160 | struct rcu_head *rcu_segcblist_first_cb(struct rcu_segcblist *rsclp); | ||
161 | struct rcu_head *rcu_segcblist_first_pend_cb(struct rcu_segcblist *rsclp); | ||
162 | bool rcu_segcblist_new_cbs(struct rcu_segcblist *rsclp); | ||
163 | void rcu_segcblist_enqueue(struct rcu_segcblist *rsclp, | ||
164 | struct rcu_head *rhp, bool lazy); | ||
165 | bool rcu_segcblist_entrain(struct rcu_segcblist *rsclp, | ||
166 | struct rcu_head *rhp, bool lazy); | ||
167 | void rcu_segcblist_extract_count(struct rcu_segcblist *rsclp, | ||
168 | struct rcu_cblist *rclp); | ||
169 | void rcu_segcblist_extract_done_cbs(struct rcu_segcblist *rsclp, | ||
170 | struct rcu_cblist *rclp); | ||
171 | void rcu_segcblist_extract_pend_cbs(struct rcu_segcblist *rsclp, | ||
172 | struct rcu_cblist *rclp); | ||
173 | void rcu_segcblist_insert_count(struct rcu_segcblist *rsclp, | ||
174 | struct rcu_cblist *rclp); | ||
175 | void rcu_segcblist_insert_done_cbs(struct rcu_segcblist *rsclp, | ||
176 | struct rcu_cblist *rclp); | ||
177 | void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp, | ||
178 | struct rcu_cblist *rclp); | ||
179 | void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq); | ||
180 | bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, unsigned long seq); | ||
181 | bool rcu_segcblist_future_gp_needed(struct rcu_segcblist *rsclp, | ||
182 | unsigned long seq); | ||