diff options
-rw-r--r-- | include/linux/rcupdate.h | 2 | ||||
-rw-r--r-- | include/linux/rcutiny.h | 6 | ||||
-rw-r--r-- | include/linux/rcutree.h | 2 | ||||
-rw-r--r-- | include/trace/events/rcu.h | 63 | ||||
-rw-r--r-- | kernel/rcu.h | 4 | ||||
-rw-r--r-- | kernel/rcutiny.c | 4 | ||||
-rw-r--r-- | kernel/rcutree.c | 29 | ||||
-rw-r--r-- | kernel/rcutree.h | 3 | ||||
-rw-r--r-- | kernel/rcutree_plugin.h | 79 | ||||
-rw-r--r-- | kernel/rcutree_trace.c | 8 |
10 files changed, 153 insertions, 47 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 81c04f4348ec..a67d5f1072ea 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
@@ -841,7 +841,7 @@ void __kfree_rcu(struct rcu_head *head, unsigned long offset) | |||
841 | /* See the kfree_rcu() header comment. */ | 841 | /* See the kfree_rcu() header comment. */ |
842 | BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); | 842 | BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); |
843 | 843 | ||
844 | call_rcu(head, (rcu_callback)offset); | 844 | kfree_call_rcu(head, (rcu_callback)offset); |
845 | } | 845 | } |
846 | 846 | ||
847 | /** | 847 | /** |
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 00b7a5e493d2..51bf29c81485 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h | |||
@@ -83,6 +83,12 @@ static inline void synchronize_sched_expedited(void) | |||
83 | synchronize_sched(); | 83 | synchronize_sched(); |
84 | } | 84 | } |
85 | 85 | ||
86 | static inline void kfree_call_rcu(struct rcu_head *head, | ||
87 | void (*func)(struct rcu_head *rcu)) | ||
88 | { | ||
89 | call_rcu(head, func); | ||
90 | } | ||
91 | |||
86 | #ifdef CONFIG_TINY_RCU | 92 | #ifdef CONFIG_TINY_RCU |
87 | 93 | ||
88 | static inline void rcu_preempt_note_context_switch(void) | 94 | static inline void rcu_preempt_note_context_switch(void) |
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 73e7195f9997..73892483fd05 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h | |||
@@ -61,6 +61,8 @@ extern void synchronize_rcu_bh(void); | |||
61 | extern void synchronize_sched_expedited(void); | 61 | extern void synchronize_sched_expedited(void); |
62 | extern void synchronize_rcu_expedited(void); | 62 | extern void synchronize_rcu_expedited(void); |
63 | 63 | ||
64 | void kfree_call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); | ||
65 | |||
64 | static inline void synchronize_rcu_bh_expedited(void) | 66 | static inline void synchronize_rcu_bh_expedited(void) |
65 | { | 67 | { |
66 | synchronize_sched_expedited(); | 68 | synchronize_sched_expedited(); |
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h index d2d88bed891b..337099783f37 100644 --- a/include/trace/events/rcu.h +++ b/include/trace/events/rcu.h | |||
@@ -313,19 +313,22 @@ TRACE_EVENT(rcu_prep_idle, | |||
313 | /* | 313 | /* |
314 | * Tracepoint for the registration of a single RCU callback function. | 314 | * Tracepoint for the registration of a single RCU callback function. |
315 | * The first argument is the type of RCU, the second argument is | 315 | * The first argument is the type of RCU, the second argument is |
316 | * a pointer to the RCU callback itself, and the third element is the | 316 | * a pointer to the RCU callback itself, the third element is the |
317 | * new RCU callback queue length for the current CPU. | 317 | * number of lazy callbacks queued, and the fourth element is the |
318 | * total number of callbacks queued. | ||
318 | */ | 319 | */ |
319 | TRACE_EVENT(rcu_callback, | 320 | TRACE_EVENT(rcu_callback, |
320 | 321 | ||
321 | TP_PROTO(char *rcuname, struct rcu_head *rhp, long qlen), | 322 | TP_PROTO(char *rcuname, struct rcu_head *rhp, long qlen_lazy, |
323 | long qlen), | ||
322 | 324 | ||
323 | TP_ARGS(rcuname, rhp, qlen), | 325 | TP_ARGS(rcuname, rhp, qlen_lazy, qlen), |
324 | 326 | ||
325 | TP_STRUCT__entry( | 327 | TP_STRUCT__entry( |
326 | __field(char *, rcuname) | 328 | __field(char *, rcuname) |
327 | __field(void *, rhp) | 329 | __field(void *, rhp) |
328 | __field(void *, func) | 330 | __field(void *, func) |
331 | __field(long, qlen_lazy) | ||
329 | __field(long, qlen) | 332 | __field(long, qlen) |
330 | ), | 333 | ), |
331 | 334 | ||
@@ -333,11 +336,13 @@ TRACE_EVENT(rcu_callback, | |||
333 | __entry->rcuname = rcuname; | 336 | __entry->rcuname = rcuname; |
334 | __entry->rhp = rhp; | 337 | __entry->rhp = rhp; |
335 | __entry->func = rhp->func; | 338 | __entry->func = rhp->func; |
339 | __entry->qlen_lazy = qlen_lazy; | ||
336 | __entry->qlen = qlen; | 340 | __entry->qlen = qlen; |
337 | ), | 341 | ), |
338 | 342 | ||
339 | TP_printk("%s rhp=%p func=%pf %ld", | 343 | TP_printk("%s rhp=%p func=%pf %ld/%ld", |
340 | __entry->rcuname, __entry->rhp, __entry->func, __entry->qlen) | 344 | __entry->rcuname, __entry->rhp, __entry->func, |
345 | __entry->qlen_lazy, __entry->qlen) | ||
341 | ); | 346 | ); |
342 | 347 | ||
343 | /* | 348 | /* |
@@ -345,20 +350,21 @@ TRACE_EVENT(rcu_callback, | |||
345 | * kfree() form. The first argument is the RCU type, the second argument | 350 | * kfree() form. The first argument is the RCU type, the second argument |
346 | * is a pointer to the RCU callback, the third argument is the offset | 351 | * is a pointer to the RCU callback, the third argument is the offset |
347 | * of the callback within the enclosing RCU-protected data structure, | 352 | * of the callback within the enclosing RCU-protected data structure, |
348 | * and the fourth argument is the new RCU callback queue length for the | 353 | * the fourth argument is the number of lazy callbacks queued, and the |
349 | * current CPU. | 354 | * fifth argument is the total number of callbacks queued. |
350 | */ | 355 | */ |
351 | TRACE_EVENT(rcu_kfree_callback, | 356 | TRACE_EVENT(rcu_kfree_callback, |
352 | 357 | ||
353 | TP_PROTO(char *rcuname, struct rcu_head *rhp, unsigned long offset, | 358 | TP_PROTO(char *rcuname, struct rcu_head *rhp, unsigned long offset, |
354 | long qlen), | 359 | long qlen_lazy, long qlen), |
355 | 360 | ||
356 | TP_ARGS(rcuname, rhp, offset, qlen), | 361 | TP_ARGS(rcuname, rhp, offset, qlen_lazy, qlen), |
357 | 362 | ||
358 | TP_STRUCT__entry( | 363 | TP_STRUCT__entry( |
359 | __field(char *, rcuname) | 364 | __field(char *, rcuname) |
360 | __field(void *, rhp) | 365 | __field(void *, rhp) |
361 | __field(unsigned long, offset) | 366 | __field(unsigned long, offset) |
367 | __field(long, qlen_lazy) | ||
362 | __field(long, qlen) | 368 | __field(long, qlen) |
363 | ), | 369 | ), |
364 | 370 | ||
@@ -366,41 +372,45 @@ TRACE_EVENT(rcu_kfree_callback, | |||
366 | __entry->rcuname = rcuname; | 372 | __entry->rcuname = rcuname; |
367 | __entry->rhp = rhp; | 373 | __entry->rhp = rhp; |
368 | __entry->offset = offset; | 374 | __entry->offset = offset; |
375 | __entry->qlen_lazy = qlen_lazy; | ||
369 | __entry->qlen = qlen; | 376 | __entry->qlen = qlen; |
370 | ), | 377 | ), |
371 | 378 | ||
372 | TP_printk("%s rhp=%p func=%ld %ld", | 379 | TP_printk("%s rhp=%p func=%ld %ld/%ld", |
373 | __entry->rcuname, __entry->rhp, __entry->offset, | 380 | __entry->rcuname, __entry->rhp, __entry->offset, |
374 | __entry->qlen) | 381 | __entry->qlen_lazy, __entry->qlen) |
375 | ); | 382 | ); |
376 | 383 | ||
377 | /* | 384 | /* |
378 | * Tracepoint for marking the beginning rcu_do_batch, performed to start | 385 | * Tracepoint for marking the beginning rcu_do_batch, performed to start |
379 | * RCU callback invocation. The first argument is the RCU flavor, | 386 | * RCU callback invocation. The first argument is the RCU flavor, |
380 | * the second is the total number of callbacks (including those that | 387 | * the second is the number of lazy callbacks queued, the third is |
381 | * are not yet ready to be invoked), and the third argument is the | 388 | * the total number of callbacks queued, and the fourth argument is |
382 | * current RCU-callback batch limit. | 389 | * the current RCU-callback batch limit. |
383 | */ | 390 | */ |
384 | TRACE_EVENT(rcu_batch_start, | 391 | TRACE_EVENT(rcu_batch_start, |
385 | 392 | ||
386 | TP_PROTO(char *rcuname, long qlen, int blimit), | 393 | TP_PROTO(char *rcuname, long qlen_lazy, long qlen, int blimit), |
387 | 394 | ||
388 | TP_ARGS(rcuname, qlen, blimit), | 395 | TP_ARGS(rcuname, qlen_lazy, qlen, blimit), |
389 | 396 | ||
390 | TP_STRUCT__entry( | 397 | TP_STRUCT__entry( |
391 | __field(char *, rcuname) | 398 | __field(char *, rcuname) |
399 | __field(long, qlen_lazy) | ||
392 | __field(long, qlen) | 400 | __field(long, qlen) |
393 | __field(int, blimit) | 401 | __field(int, blimit) |
394 | ), | 402 | ), |
395 | 403 | ||
396 | TP_fast_assign( | 404 | TP_fast_assign( |
397 | __entry->rcuname = rcuname; | 405 | __entry->rcuname = rcuname; |
406 | __entry->qlen_lazy = qlen_lazy; | ||
398 | __entry->qlen = qlen; | 407 | __entry->qlen = qlen; |
399 | __entry->blimit = blimit; | 408 | __entry->blimit = blimit; |
400 | ), | 409 | ), |
401 | 410 | ||
402 | TP_printk("%s CBs=%ld bl=%d", | 411 | TP_printk("%s CBs=%ld/%ld bl=%d", |
403 | __entry->rcuname, __entry->qlen, __entry->blimit) | 412 | __entry->rcuname, __entry->qlen_lazy, __entry->qlen, |
413 | __entry->blimit) | ||
404 | ); | 414 | ); |
405 | 415 | ||
406 | /* | 416 | /* |
@@ -531,16 +541,21 @@ TRACE_EVENT(rcu_torture_read, | |||
531 | #else /* #ifdef CONFIG_RCU_TRACE */ | 541 | #else /* #ifdef CONFIG_RCU_TRACE */ |
532 | 542 | ||
533 | #define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0) | 543 | #define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0) |
534 | #define trace_rcu_grace_period_init(rcuname, gpnum, level, grplo, grphi, qsmask) do { } while (0) | 544 | #define trace_rcu_grace_period_init(rcuname, gpnum, level, grplo, grphi, \ |
545 | qsmask) do { } while (0) | ||
535 | #define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0) | 546 | #define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0) |
536 | #define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0) | 547 | #define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0) |
537 | #define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks) do { } while (0) | 548 | #define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, \ |
549 | grplo, grphi, gp_tasks) do { } \ | ||
550 | while (0) | ||
538 | #define trace_rcu_fqs(rcuname, gpnum, cpu, qsevent) do { } while (0) | 551 | #define trace_rcu_fqs(rcuname, gpnum, cpu, qsevent) do { } while (0) |
539 | #define trace_rcu_dyntick(polarity, oldnesting, newnesting) do { } while (0) | 552 | #define trace_rcu_dyntick(polarity, oldnesting, newnesting) do { } while (0) |
540 | #define trace_rcu_prep_idle(reason) do { } while (0) | 553 | #define trace_rcu_prep_idle(reason) do { } while (0) |
541 | #define trace_rcu_callback(rcuname, rhp, qlen) do { } while (0) | 554 | #define trace_rcu_callback(rcuname, rhp, qlen_lazy, qlen) do { } while (0) |
542 | #define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen) do { } while (0) | 555 | #define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen_lazy, qlen) \ |
543 | #define trace_rcu_batch_start(rcuname, qlen, blimit) do { } while (0) | 556 | do { } while (0) |
557 | #define trace_rcu_batch_start(rcuname, qlen_lazy, qlen, blimit) \ | ||
558 | do { } while (0) | ||
544 | #define trace_rcu_invoke_callback(rcuname, rhp) do { } while (0) | 559 | #define trace_rcu_invoke_callback(rcuname, rhp) do { } while (0) |
545 | #define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0) | 560 | #define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0) |
546 | #define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \ | 561 | #define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \ |
diff --git a/kernel/rcu.h b/kernel/rcu.h index aa88baab5f78..a074b0b43fc2 100644 --- a/kernel/rcu.h +++ b/kernel/rcu.h | |||
@@ -76,16 +76,18 @@ static inline void debug_rcu_head_unqueue(struct rcu_head *head) | |||
76 | 76 | ||
77 | extern void kfree(const void *); | 77 | extern void kfree(const void *); |
78 | 78 | ||
79 | static inline void __rcu_reclaim(char *rn, struct rcu_head *head) | 79 | static inline bool __rcu_reclaim(char *rn, struct rcu_head *head) |
80 | { | 80 | { |
81 | unsigned long offset = (unsigned long)head->func; | 81 | unsigned long offset = (unsigned long)head->func; |
82 | 82 | ||
83 | if (__is_kfree_rcu_offset(offset)) { | 83 | if (__is_kfree_rcu_offset(offset)) { |
84 | RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset)); | 84 | RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset)); |
85 | kfree((void *)head - offset); | 85 | kfree((void *)head - offset); |
86 | return 1; | ||
86 | } else { | 87 | } else { |
87 | RCU_TRACE(trace_rcu_invoke_callback(rn, head)); | 88 | RCU_TRACE(trace_rcu_invoke_callback(rn, head)); |
88 | head->func(head); | 89 | head->func(head); |
90 | return 0; | ||
89 | } | 91 | } |
90 | } | 92 | } |
91 | 93 | ||
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c index 8e00d461911e..4eb34fcc2a75 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c | |||
@@ -258,7 +258,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) | |||
258 | 258 | ||
259 | /* If no RCU callbacks ready to invoke, just return. */ | 259 | /* If no RCU callbacks ready to invoke, just return. */ |
260 | if (&rcp->rcucblist == rcp->donetail) { | 260 | if (&rcp->rcucblist == rcp->donetail) { |
261 | RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, -1)); | 261 | RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, 0, -1)); |
262 | RCU_TRACE(trace_rcu_batch_end(rcp->name, 0, | 262 | RCU_TRACE(trace_rcu_batch_end(rcp->name, 0, |
263 | ACCESS_ONCE(rcp->rcucblist), | 263 | ACCESS_ONCE(rcp->rcucblist), |
264 | need_resched(), | 264 | need_resched(), |
@@ -269,7 +269,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) | |||
269 | 269 | ||
270 | /* Move the ready-to-invoke callbacks to a local list. */ | 270 | /* Move the ready-to-invoke callbacks to a local list. */ |
271 | local_irq_save(flags); | 271 | local_irq_save(flags); |
272 | RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, -1)); | 272 | RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1)); |
273 | list = rcp->rcucblist; | 273 | list = rcp->rcucblist; |
274 | rcp->rcucblist = *rcp->donetail; | 274 | rcp->rcucblist = *rcp->donetail; |
275 | *rcp->donetail = NULL; | 275 | *rcp->donetail = NULL; |
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 570f7530f4b3..acf2d67ad2f4 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -1261,6 +1261,7 @@ static void rcu_send_cbs_to_online(struct rcu_state *rsp) | |||
1261 | 1261 | ||
1262 | *receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxtlist; | 1262 | *receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxtlist; |
1263 | receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; | 1263 | receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; |
1264 | receive_rdp->qlen_lazy += rdp->qlen_lazy; | ||
1264 | receive_rdp->qlen += rdp->qlen; | 1265 | receive_rdp->qlen += rdp->qlen; |
1265 | receive_rdp->n_cbs_adopted += rdp->qlen; | 1266 | receive_rdp->n_cbs_adopted += rdp->qlen; |
1266 | rdp->n_cbs_orphaned += rdp->qlen; | 1267 | rdp->n_cbs_orphaned += rdp->qlen; |
@@ -1268,6 +1269,7 @@ static void rcu_send_cbs_to_online(struct rcu_state *rsp) | |||
1268 | rdp->nxtlist = NULL; | 1269 | rdp->nxtlist = NULL; |
1269 | for (i = 0; i < RCU_NEXT_SIZE; i++) | 1270 | for (i = 0; i < RCU_NEXT_SIZE; i++) |
1270 | rdp->nxttail[i] = &rdp->nxtlist; | 1271 | rdp->nxttail[i] = &rdp->nxtlist; |
1272 | rdp->qlen_lazy = 0; | ||
1271 | rdp->qlen = 0; | 1273 | rdp->qlen = 0; |
1272 | } | 1274 | } |
1273 | 1275 | ||
@@ -1368,11 +1370,11 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1368 | { | 1370 | { |
1369 | unsigned long flags; | 1371 | unsigned long flags; |
1370 | struct rcu_head *next, *list, **tail; | 1372 | struct rcu_head *next, *list, **tail; |
1371 | int bl, count; | 1373 | int bl, count, count_lazy; |
1372 | 1374 | ||
1373 | /* If no callbacks are ready, just return.*/ | 1375 | /* If no callbacks are ready, just return.*/ |
1374 | if (!cpu_has_callbacks_ready_to_invoke(rdp)) { | 1376 | if (!cpu_has_callbacks_ready_to_invoke(rdp)) { |
1375 | trace_rcu_batch_start(rsp->name, 0, 0); | 1377 | trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, 0); |
1376 | trace_rcu_batch_end(rsp->name, 0, !!ACCESS_ONCE(rdp->nxtlist), | 1378 | trace_rcu_batch_end(rsp->name, 0, !!ACCESS_ONCE(rdp->nxtlist), |
1377 | need_resched(), is_idle_task(current), | 1379 | need_resched(), is_idle_task(current), |
1378 | rcu_is_callbacks_kthread()); | 1380 | rcu_is_callbacks_kthread()); |
@@ -1385,7 +1387,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1385 | */ | 1387 | */ |
1386 | local_irq_save(flags); | 1388 | local_irq_save(flags); |
1387 | bl = rdp->blimit; | 1389 | bl = rdp->blimit; |
1388 | trace_rcu_batch_start(rsp->name, rdp->qlen, bl); | 1390 | trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, bl); |
1389 | list = rdp->nxtlist; | 1391 | list = rdp->nxtlist; |
1390 | rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL]; | 1392 | rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL]; |
1391 | *rdp->nxttail[RCU_DONE_TAIL] = NULL; | 1393 | *rdp->nxttail[RCU_DONE_TAIL] = NULL; |
@@ -1396,12 +1398,13 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1396 | local_irq_restore(flags); | 1398 | local_irq_restore(flags); |
1397 | 1399 | ||
1398 | /* Invoke callbacks. */ | 1400 | /* Invoke callbacks. */ |
1399 | count = 0; | 1401 | count = count_lazy = 0; |
1400 | while (list) { | 1402 | while (list) { |
1401 | next = list->next; | 1403 | next = list->next; |
1402 | prefetch(next); | 1404 | prefetch(next); |
1403 | debug_rcu_head_unqueue(list); | 1405 | debug_rcu_head_unqueue(list); |
1404 | __rcu_reclaim(rsp->name, list); | 1406 | if (__rcu_reclaim(rsp->name, list)) |
1407 | count_lazy++; | ||
1405 | list = next; | 1408 | list = next; |
1406 | /* Stop only if limit reached and CPU has something to do. */ | 1409 | /* Stop only if limit reached and CPU has something to do. */ |
1407 | if (++count >= bl && | 1410 | if (++count >= bl && |
@@ -1416,6 +1419,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1416 | rcu_is_callbacks_kthread()); | 1419 | rcu_is_callbacks_kthread()); |
1417 | 1420 | ||
1418 | /* Update count, and requeue any remaining callbacks. */ | 1421 | /* Update count, and requeue any remaining callbacks. */ |
1422 | rdp->qlen_lazy -= count_lazy; | ||
1419 | rdp->qlen -= count; | 1423 | rdp->qlen -= count; |
1420 | rdp->n_cbs_invoked += count; | 1424 | rdp->n_cbs_invoked += count; |
1421 | if (list != NULL) { | 1425 | if (list != NULL) { |
@@ -1702,7 +1706,7 @@ static void invoke_rcu_core(void) | |||
1702 | 1706 | ||
1703 | static void | 1707 | static void |
1704 | __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | 1708 | __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), |
1705 | struct rcu_state *rsp) | 1709 | struct rcu_state *rsp, bool lazy) |
1706 | { | 1710 | { |
1707 | unsigned long flags; | 1711 | unsigned long flags; |
1708 | struct rcu_data *rdp; | 1712 | struct rcu_data *rdp; |
@@ -1727,12 +1731,14 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | |||
1727 | *rdp->nxttail[RCU_NEXT_TAIL] = head; | 1731 | *rdp->nxttail[RCU_NEXT_TAIL] = head; |
1728 | rdp->nxttail[RCU_NEXT_TAIL] = &head->next; | 1732 | rdp->nxttail[RCU_NEXT_TAIL] = &head->next; |
1729 | rdp->qlen++; | 1733 | rdp->qlen++; |
1734 | if (lazy) | ||
1735 | rdp->qlen_lazy++; | ||
1730 | 1736 | ||
1731 | if (__is_kfree_rcu_offset((unsigned long)func)) | 1737 | if (__is_kfree_rcu_offset((unsigned long)func)) |
1732 | trace_rcu_kfree_callback(rsp->name, head, (unsigned long)func, | 1738 | trace_rcu_kfree_callback(rsp->name, head, (unsigned long)func, |
1733 | rdp->qlen); | 1739 | rdp->qlen_lazy, rdp->qlen); |
1734 | else | 1740 | else |
1735 | trace_rcu_callback(rsp->name, head, rdp->qlen); | 1741 | trace_rcu_callback(rsp->name, head, rdp->qlen_lazy, rdp->qlen); |
1736 | 1742 | ||
1737 | /* If interrupts were disabled, don't dive into RCU core. */ | 1743 | /* If interrupts were disabled, don't dive into RCU core. */ |
1738 | if (irqs_disabled_flags(flags)) { | 1744 | if (irqs_disabled_flags(flags)) { |
@@ -1779,16 +1785,16 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | |||
1779 | */ | 1785 | */ |
1780 | void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) | 1786 | void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) |
1781 | { | 1787 | { |
1782 | __call_rcu(head, func, &rcu_sched_state); | 1788 | __call_rcu(head, func, &rcu_sched_state, 0); |
1783 | } | 1789 | } |
1784 | EXPORT_SYMBOL_GPL(call_rcu_sched); | 1790 | EXPORT_SYMBOL_GPL(call_rcu_sched); |
1785 | 1791 | ||
1786 | /* | 1792 | /* |
1787 | * Queue an RCU for invocation after a quicker grace period. | 1793 | * Queue an RCU callback for invocation after a quicker grace period. |
1788 | */ | 1794 | */ |
1789 | void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) | 1795 | void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) |
1790 | { | 1796 | { |
1791 | __call_rcu(head, func, &rcu_bh_state); | 1797 | __call_rcu(head, func, &rcu_bh_state, 0); |
1792 | } | 1798 | } |
1793 | EXPORT_SYMBOL_GPL(call_rcu_bh); | 1799 | EXPORT_SYMBOL_GPL(call_rcu_bh); |
1794 | 1800 | ||
@@ -2036,6 +2042,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) | |||
2036 | rdp->nxtlist = NULL; | 2042 | rdp->nxtlist = NULL; |
2037 | for (i = 0; i < RCU_NEXT_SIZE; i++) | 2043 | for (i = 0; i < RCU_NEXT_SIZE; i++) |
2038 | rdp->nxttail[i] = &rdp->nxtlist; | 2044 | rdp->nxttail[i] = &rdp->nxtlist; |
2045 | rdp->qlen_lazy = 0; | ||
2039 | rdp->qlen = 0; | 2046 | rdp->qlen = 0; |
2040 | rdp->dynticks = &per_cpu(rcu_dynticks, cpu); | 2047 | rdp->dynticks = &per_cpu(rcu_dynticks, cpu); |
2041 | WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_NESTING); | 2048 | WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_NESTING); |
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index fddff92d6676..af2af3cc5e65 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
@@ -265,7 +265,8 @@ struct rcu_data { | |||
265 | */ | 265 | */ |
266 | struct rcu_head *nxtlist; | 266 | struct rcu_head *nxtlist; |
267 | struct rcu_head **nxttail[RCU_NEXT_SIZE]; | 267 | struct rcu_head **nxttail[RCU_NEXT_SIZE]; |
268 | long qlen; /* # of queued callbacks */ | 268 | long qlen_lazy; /* # of lazy queued callbacks */ |
269 | long qlen; /* # of queued callbacks, incl lazy */ | ||
269 | long qlen_last_fqs_check; | 270 | long qlen_last_fqs_check; |
270 | /* qlen at last check for QS forcing */ | 271 | /* qlen at last check for QS forcing */ |
271 | unsigned long n_cbs_invoked; /* count of RCU cbs invoked. */ | 272 | unsigned long n_cbs_invoked; /* count of RCU cbs invoked. */ |
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 3680b6b35bf3..7adf232bb66b 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h | |||
@@ -671,10 +671,24 @@ static void rcu_preempt_do_callbacks(void) | |||
671 | */ | 671 | */ |
672 | void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) | 672 | void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) |
673 | { | 673 | { |
674 | __call_rcu(head, func, &rcu_preempt_state); | 674 | __call_rcu(head, func, &rcu_preempt_state, 0); |
675 | } | 675 | } |
676 | EXPORT_SYMBOL_GPL(call_rcu); | 676 | EXPORT_SYMBOL_GPL(call_rcu); |
677 | 677 | ||
678 | /* | ||
679 | * Queue an RCU callback for lazy invocation after a grace period. | ||
680 | * This will likely be later named something like "call_rcu_lazy()", | ||
681 | * but this change will require some way of tagging the lazy RCU | ||
682 | * callbacks in the list of pending callbacks. Until then, this | ||
683 | * function may only be called from __kfree_rcu(). | ||
684 | */ | ||
685 | void kfree_call_rcu(struct rcu_head *head, | ||
686 | void (*func)(struct rcu_head *rcu)) | ||
687 | { | ||
688 | __call_rcu(head, func, &rcu_preempt_state, 1); | ||
689 | } | ||
690 | EXPORT_SYMBOL_GPL(kfree_call_rcu); | ||
691 | |||
678 | /** | 692 | /** |
679 | * synchronize_rcu - wait until a grace period has elapsed. | 693 | * synchronize_rcu - wait until a grace period has elapsed. |
680 | * | 694 | * |
@@ -1065,6 +1079,22 @@ static void rcu_preempt_process_callbacks(void) | |||
1065 | } | 1079 | } |
1066 | 1080 | ||
1067 | /* | 1081 | /* |
1082 | * Queue an RCU callback for lazy invocation after a grace period. | ||
1083 | * This will likely be later named something like "call_rcu_lazy()", | ||
1084 | * but this change will require some way of tagging the lazy RCU | ||
1085 | * callbacks in the list of pending callbacks. Until then, this | ||
1086 | * function may only be called from __kfree_rcu(). | ||
1087 | * | ||
1088 | * Because there is no preemptible RCU, we use RCU-sched instead. | ||
1089 | */ | ||
1090 | void kfree_call_rcu(struct rcu_head *head, | ||
1091 | void (*func)(struct rcu_head *rcu)) | ||
1092 | { | ||
1093 | __call_rcu(head, func, &rcu_sched_state, 1); | ||
1094 | } | ||
1095 | EXPORT_SYMBOL_GPL(kfree_call_rcu); | ||
1096 | |||
1097 | /* | ||
1068 | * Wait for an rcu-preempt grace period, but make it happen quickly. | 1098 | * Wait for an rcu-preempt grace period, but make it happen quickly. |
1069 | * But because preemptible RCU does not exist, map to rcu-sched. | 1099 | * But because preemptible RCU does not exist, map to rcu-sched. |
1070 | */ | 1100 | */ |
@@ -2052,6 +2082,48 @@ int rcu_needs_cpu(int cpu) | |||
2052 | } | 2082 | } |
2053 | 2083 | ||
2054 | /* | 2084 | /* |
2085 | * Does the specified flavor of RCU have non-lazy callbacks pending on | ||
2086 | * the specified CPU? Both RCU flavor and CPU are specified by the | ||
2087 | * rcu_data structure. | ||
2088 | */ | ||
2089 | static bool __rcu_cpu_has_nonlazy_callbacks(struct rcu_data *rdp) | ||
2090 | { | ||
2091 | return rdp->qlen != rdp->qlen_lazy; | ||
2092 | } | ||
2093 | |||
2094 | #ifdef CONFIG_TREE_PREEMPT_RCU | ||
2095 | |||
2096 | /* | ||
2097 | * Are there non-lazy RCU-preempt callbacks? (There cannot be if there | ||
2098 | * is no RCU-preempt in the kernel.) | ||
2099 | */ | ||
2100 | static bool rcu_preempt_cpu_has_nonlazy_callbacks(int cpu) | ||
2101 | { | ||
2102 | struct rcu_data *rdp = &per_cpu(rcu_preempt_data, cpu); | ||
2103 | |||
2104 | return __rcu_cpu_has_nonlazy_callbacks(rdp); | ||
2105 | } | ||
2106 | |||
2107 | #else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ | ||
2108 | |||
2109 | static bool rcu_preempt_cpu_has_nonlazy_callbacks(int cpu) | ||
2110 | { | ||
2111 | return 0; | ||
2112 | } | ||
2113 | |||
2114 | #endif /* else #ifdef CONFIG_TREE_PREEMPT_RCU */ | ||
2115 | |||
2116 | /* | ||
2117 | * Does any flavor of RCU have non-lazy callbacks on the specified CPU? | ||
2118 | */ | ||
2119 | static bool rcu_cpu_has_nonlazy_callbacks(int cpu) | ||
2120 | { | ||
2121 | return __rcu_cpu_has_nonlazy_callbacks(&per_cpu(rcu_sched_data, cpu)) || | ||
2122 | __rcu_cpu_has_nonlazy_callbacks(&per_cpu(rcu_bh_data, cpu)) || | ||
2123 | rcu_preempt_cpu_has_nonlazy_callbacks(cpu); | ||
2124 | } | ||
2125 | |||
2126 | /* | ||
2055 | * Timer handler used to force CPU to start pushing its remaining RCU | 2127 | * Timer handler used to force CPU to start pushing its remaining RCU |
2056 | * callbacks in the case where it entered dyntick-idle mode with callbacks | 2128 | * callbacks in the case where it entered dyntick-idle mode with callbacks |
2057 | * pending. The hander doesn't really need to do anything because the | 2129 | * pending. The hander doesn't really need to do anything because the |
@@ -2149,8 +2221,9 @@ static void rcu_prepare_for_idle(int cpu) | |||
2149 | trace_rcu_prep_idle("Dyntick with callbacks"); | 2221 | trace_rcu_prep_idle("Dyntick with callbacks"); |
2150 | per_cpu(rcu_dyntick_drain, cpu) = 0; | 2222 | per_cpu(rcu_dyntick_drain, cpu) = 0; |
2151 | per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1; | 2223 | per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1; |
2152 | hrtimer_start(&per_cpu(rcu_idle_gp_timer, cpu), | 2224 | if (rcu_cpu_has_nonlazy_callbacks(cpu)) |
2153 | rcu_idle_gp_wait, HRTIMER_MODE_REL); | 2225 | hrtimer_start(&per_cpu(rcu_idle_gp_timer, cpu), |
2226 | rcu_idle_gp_wait, HRTIMER_MODE_REL); | ||
2154 | return; /* Nothing more to do immediately. */ | 2227 | return; /* Nothing more to do immediately. */ |
2155 | } else if (--per_cpu(rcu_dyntick_drain, cpu) <= 0) { | 2228 | } else if (--per_cpu(rcu_dyntick_drain, cpu) <= 0) { |
2156 | /* We have hit the limit, so time to give up. */ | 2229 | /* We have hit the limit, so time to give up. */ |
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 654cfe67f0d1..db0987c1e1bd 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c | |||
@@ -73,8 +73,8 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) | |||
73 | rdp->dynticks->dynticks_nmi_nesting, | 73 | rdp->dynticks->dynticks_nmi_nesting, |
74 | rdp->dynticks_fqs); | 74 | rdp->dynticks_fqs); |
75 | seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); | 75 | seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); |
76 | seq_printf(m, " ql=%ld qs=%c%c%c%c", | 76 | seq_printf(m, " ql=%ld/%ld qs=%c%c%c%c", |
77 | rdp->qlen, | 77 | rdp->qlen_lazy, rdp->qlen, |
78 | ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != | 78 | ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != |
79 | rdp->nxttail[RCU_NEXT_TAIL]], | 79 | rdp->nxttail[RCU_NEXT_TAIL]], |
80 | ".R"[rdp->nxttail[RCU_WAIT_TAIL] != | 80 | ".R"[rdp->nxttail[RCU_WAIT_TAIL] != |
@@ -145,7 +145,7 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp) | |||
145 | rdp->dynticks->dynticks_nmi_nesting, | 145 | rdp->dynticks->dynticks_nmi_nesting, |
146 | rdp->dynticks_fqs); | 146 | rdp->dynticks_fqs); |
147 | seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi); | 147 | seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi); |
148 | seq_printf(m, ",%ld,\"%c%c%c%c\"", rdp->qlen, | 148 | seq_printf(m, ",%ld,%ld,\"%c%c%c%c\"", rdp->qlen_lazy, rdp->qlen, |
149 | ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != | 149 | ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != |
150 | rdp->nxttail[RCU_NEXT_TAIL]], | 150 | rdp->nxttail[RCU_NEXT_TAIL]], |
151 | ".R"[rdp->nxttail[RCU_WAIT_TAIL] != | 151 | ".R"[rdp->nxttail[RCU_WAIT_TAIL] != |
@@ -168,7 +168,7 @@ static int show_rcudata_csv(struct seq_file *m, void *unused) | |||
168 | { | 168 | { |
169 | seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pgp\",\"pq\","); | 169 | seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pgp\",\"pq\","); |
170 | seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\","); | 170 | seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\","); |
171 | seq_puts(m, "\"of\",\"ri\",\"ql\",\"qs\""); | 171 | seq_puts(m, "\"of\",\"ri\",\"qll\",\"ql\",\"qs\""); |
172 | #ifdef CONFIG_RCU_BOOST | 172 | #ifdef CONFIG_RCU_BOOST |
173 | seq_puts(m, "\"kt\",\"ktl\""); | 173 | seq_puts(m, "\"kt\",\"ktl\""); |
174 | #endif /* #ifdef CONFIG_RCU_BOOST */ | 174 | #endif /* #ifdef CONFIG_RCU_BOOST */ |