aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcu/srcutree.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/rcu/srcutree.c')
-rw-r--r--kernel/rcu/srcutree.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c
index 9ecf0acc18eb..1c2c1004b3b1 100644
--- a/kernel/rcu/srcutree.c
+++ b/kernel/rcu/srcutree.c
@@ -66,8 +66,12 @@ static void init_srcu_struct_nodes(struct srcu_struct *sp, bool is_static)
66 /* Each pass through this loop initializes one srcu_node structure. */ 66 /* Each pass through this loop initializes one srcu_node structure. */
67 rcu_for_each_node_breadth_first(sp, snp) { 67 rcu_for_each_node_breadth_first(sp, snp) {
68 spin_lock_init(&snp->lock); 68 spin_lock_init(&snp->lock);
69 for (i = 0; i < ARRAY_SIZE(snp->srcu_have_cbs); i++) 69 WARN_ON_ONCE(ARRAY_SIZE(snp->srcu_have_cbs) !=
70 ARRAY_SIZE(snp->srcu_data_have_cbs));
71 for (i = 0; i < ARRAY_SIZE(snp->srcu_have_cbs); i++) {
70 snp->srcu_have_cbs[i] = 0; 72 snp->srcu_have_cbs[i] = 0;
73 snp->srcu_data_have_cbs[i] = 0;
74 }
71 snp->grplo = -1; 75 snp->grplo = -1;
72 snp->grphi = -1; 76 snp->grphi = -1;
73 if (snp == &sp->node[0]) { 77 if (snp == &sp->node[0]) {
@@ -107,6 +111,7 @@ static void init_srcu_struct_nodes(struct srcu_struct *sp, bool is_static)
107 sdp->cpu = cpu; 111 sdp->cpu = cpu;
108 INIT_DELAYED_WORK(&sdp->work, srcu_invoke_callbacks); 112 INIT_DELAYED_WORK(&sdp->work, srcu_invoke_callbacks);
109 sdp->sp = sp; 113 sdp->sp = sp;
114 sdp->grpmask = 1 << (cpu - sdp->mynode->grplo);
110 if (is_static) 115 if (is_static)
111 continue; 116 continue;
112 117
@@ -434,16 +439,21 @@ static void srcu_schedule_cbs_sdp(struct srcu_data *sdp, unsigned long delay)
434 439
435/* 440/*
436 * Schedule callback invocation for all srcu_data structures associated 441 * Schedule callback invocation for all srcu_data structures associated
437 * with the specified srcu_node structure, if possible, on the corresponding 442 * with the specified srcu_node structure that have callbacks for the
438 * CPUs. 443 * just-completed grace period, the one corresponding to idx. If possible,
444 * schedule this invocation on the corresponding CPUs.
439 */ 445 */
440static void srcu_schedule_cbs_snp(struct srcu_struct *sp, struct srcu_node *snp) 446static void srcu_schedule_cbs_snp(struct srcu_struct *sp, struct srcu_node *snp,
447 unsigned long mask)
441{ 448{
442 int cpu; 449 int cpu;
443 450
444 for (cpu = snp->grplo; cpu <= snp->grphi; cpu++) 451 for (cpu = snp->grplo; cpu <= snp->grphi; cpu++) {
452 if (!(mask & (1 << (cpu - snp->grplo))))
453 continue;
445 srcu_schedule_cbs_sdp(per_cpu_ptr(sp->sda, cpu), 454 srcu_schedule_cbs_sdp(per_cpu_ptr(sp->sda, cpu),
446 atomic_read(&sp->srcu_exp_cnt) ? 0 : SRCU_INTERVAL); 455 atomic_read(&sp->srcu_exp_cnt) ? 0 : SRCU_INTERVAL);
456 }
447} 457}
448 458
449/* 459/*
@@ -461,6 +471,7 @@ static void srcu_gp_end(struct srcu_struct *sp)
461 unsigned long gpseq; 471 unsigned long gpseq;
462 int idx; 472 int idx;
463 int idxnext; 473 int idxnext;
474 unsigned long mask;
464 struct srcu_node *snp; 475 struct srcu_node *snp;
465 476
466 /* Prevent more than one additional grace period. */ 477 /* Prevent more than one additional grace period. */
@@ -486,10 +497,12 @@ static void srcu_gp_end(struct srcu_struct *sp)
486 cbs = snp->srcu_have_cbs[idx] == gpseq; 497 cbs = snp->srcu_have_cbs[idx] == gpseq;
487 snp->srcu_have_cbs[idx] = gpseq; 498 snp->srcu_have_cbs[idx] = gpseq;
488 rcu_seq_set_state(&snp->srcu_have_cbs[idx], 1); 499 rcu_seq_set_state(&snp->srcu_have_cbs[idx], 1);
500 mask = snp->srcu_data_have_cbs[idx];
501 snp->srcu_data_have_cbs[idx] = 0;
489 spin_unlock_irq(&snp->lock); 502 spin_unlock_irq(&snp->lock);
490 if (cbs) { 503 if (cbs) {
491 smp_mb(); /* GP end before CB invocation. */ 504 smp_mb(); /* GP end before CB invocation. */
492 srcu_schedule_cbs_snp(sp, snp); 505 srcu_schedule_cbs_snp(sp, snp, mask);
493 } 506 }
494 } 507 }
495 508
@@ -536,6 +549,8 @@ static void srcu_funnel_gp_start(struct srcu_struct *sp,
536 spin_lock_irqsave(&snp->lock, flags); 549 spin_lock_irqsave(&snp->lock, flags);
537 if (ULONG_CMP_GE(snp->srcu_have_cbs[idx], s)) { 550 if (ULONG_CMP_GE(snp->srcu_have_cbs[idx], s)) {
538 snp_seq = snp->srcu_have_cbs[idx]; 551 snp_seq = snp->srcu_have_cbs[idx];
552 if (snp == sdp->mynode && snp_seq == s)
553 snp->srcu_data_have_cbs[idx] |= sdp->grpmask;
539 spin_unlock_irqrestore(&snp->lock, flags); 554 spin_unlock_irqrestore(&snp->lock, flags);
540 if (snp == sdp->mynode && snp_seq != s) { 555 if (snp == sdp->mynode && snp_seq != s) {
541 smp_mb(); /* CBs after GP! */ 556 smp_mb(); /* CBs after GP! */
@@ -544,6 +559,8 @@ static void srcu_funnel_gp_start(struct srcu_struct *sp,
544 return; 559 return;
545 } 560 }
546 snp->srcu_have_cbs[idx] = s; 561 snp->srcu_have_cbs[idx] = s;
562 if (snp == sdp->mynode)
563 snp->srcu_data_have_cbs[idx] |= sdp->grpmask;
547 spin_unlock_irqrestore(&snp->lock, flags); 564 spin_unlock_irqrestore(&snp->lock, flags);
548 } 565 }
549 566