diff options
Diffstat (limited to 'kernel/rcuclassic.c')
-rw-r--r-- | kernel/rcuclassic.c | 51 |
1 files changed, 41 insertions, 10 deletions
diff --git a/kernel/rcuclassic.c b/kernel/rcuclassic.c index dab2676d9d72..5de126630b10 100644 --- a/kernel/rcuclassic.c +++ b/kernel/rcuclassic.c | |||
@@ -87,6 +87,7 @@ static void force_quiescent_state(struct rcu_data *rdp, | |||
87 | int cpu; | 87 | int cpu; |
88 | cpumask_t cpumask; | 88 | cpumask_t cpumask; |
89 | set_need_resched(); | 89 | set_need_resched(); |
90 | spin_lock(&rcp->lock); | ||
90 | if (unlikely(!rcp->signaled)) { | 91 | if (unlikely(!rcp->signaled)) { |
91 | rcp->signaled = 1; | 92 | rcp->signaled = 1; |
92 | /* | 93 | /* |
@@ -112,6 +113,7 @@ static void force_quiescent_state(struct rcu_data *rdp, | |||
112 | for_each_cpu_mask_nr(cpu, cpumask) | 113 | for_each_cpu_mask_nr(cpu, cpumask) |
113 | smp_send_reschedule(cpu); | 114 | smp_send_reschedule(cpu); |
114 | } | 115 | } |
116 | spin_unlock(&rcp->lock); | ||
115 | } | 117 | } |
116 | #else | 118 | #else |
117 | static inline void force_quiescent_state(struct rcu_data *rdp, | 119 | static inline void force_quiescent_state(struct rcu_data *rdp, |
@@ -125,7 +127,9 @@ static void __call_rcu(struct rcu_head *head, struct rcu_ctrlblk *rcp, | |||
125 | struct rcu_data *rdp) | 127 | struct rcu_data *rdp) |
126 | { | 128 | { |
127 | long batch; | 129 | long batch; |
128 | smp_mb(); /* reads the most recently updated value of rcu->cur. */ | 130 | |
131 | head->next = NULL; | ||
132 | smp_mb(); /* Read of rcu->cur must happen after any change by caller. */ | ||
129 | 133 | ||
130 | /* | 134 | /* |
131 | * Determine the batch number of this callback. | 135 | * Determine the batch number of this callback. |
@@ -175,7 +179,6 @@ void call_rcu(struct rcu_head *head, | |||
175 | unsigned long flags; | 179 | unsigned long flags; |
176 | 180 | ||
177 | head->func = func; | 181 | head->func = func; |
178 | head->next = NULL; | ||
179 | local_irq_save(flags); | 182 | local_irq_save(flags); |
180 | __call_rcu(head, &rcu_ctrlblk, &__get_cpu_var(rcu_data)); | 183 | __call_rcu(head, &rcu_ctrlblk, &__get_cpu_var(rcu_data)); |
181 | local_irq_restore(flags); | 184 | local_irq_restore(flags); |
@@ -204,7 +207,6 @@ void call_rcu_bh(struct rcu_head *head, | |||
204 | unsigned long flags; | 207 | unsigned long flags; |
205 | 208 | ||
206 | head->func = func; | 209 | head->func = func; |
207 | head->next = NULL; | ||
208 | local_irq_save(flags); | 210 | local_irq_save(flags); |
209 | __call_rcu(head, &rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data)); | 211 | __call_rcu(head, &rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data)); |
210 | local_irq_restore(flags); | 212 | local_irq_restore(flags); |
@@ -467,17 +469,17 @@ static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list, | |||
467 | static void __rcu_offline_cpu(struct rcu_data *this_rdp, | 469 | static void __rcu_offline_cpu(struct rcu_data *this_rdp, |
468 | struct rcu_ctrlblk *rcp, struct rcu_data *rdp) | 470 | struct rcu_ctrlblk *rcp, struct rcu_data *rdp) |
469 | { | 471 | { |
470 | /* if the cpu going offline owns the grace period | 472 | /* |
473 | * if the cpu going offline owns the grace period | ||
471 | * we can block indefinitely waiting for it, so flush | 474 | * we can block indefinitely waiting for it, so flush |
472 | * it here | 475 | * it here |
473 | */ | 476 | */ |
474 | spin_lock_bh(&rcp->lock); | 477 | spin_lock_bh(&rcp->lock); |
475 | if (rcp->cur != rcp->completed) | 478 | if (rcp->cur != rcp->completed) |
476 | cpu_quiet(rdp->cpu, rcp); | 479 | cpu_quiet(rdp->cpu, rcp); |
477 | spin_unlock_bh(&rcp->lock); | ||
478 | /* spin_lock implies smp_mb() */ | ||
479 | rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail, rcp->cur + 1); | 480 | rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail, rcp->cur + 1); |
480 | rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail[2], rcp->cur + 1); | 481 | rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail[2], rcp->cur + 1); |
482 | spin_unlock_bh(&rcp->lock); | ||
481 | 483 | ||
482 | local_irq_disable(); | 484 | local_irq_disable(); |
483 | this_rdp->qlen += rdp->qlen; | 485 | this_rdp->qlen += rdp->qlen; |
@@ -511,16 +513,19 @@ static void rcu_offline_cpu(int cpu) | |||
511 | static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp, | 513 | static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp, |
512 | struct rcu_data *rdp) | 514 | struct rcu_data *rdp) |
513 | { | 515 | { |
516 | long completed_snap; | ||
517 | |||
514 | if (rdp->nxtlist) { | 518 | if (rdp->nxtlist) { |
515 | local_irq_disable(); | 519 | local_irq_disable(); |
520 | completed_snap = ACCESS_ONCE(rcp->completed); | ||
516 | 521 | ||
517 | /* | 522 | /* |
518 | * move the other grace-period-completed entries to | 523 | * move the other grace-period-completed entries to |
519 | * [rdp->nxtlist, *rdp->nxttail[0]) temporarily | 524 | * [rdp->nxtlist, *rdp->nxttail[0]) temporarily |
520 | */ | 525 | */ |
521 | if (!rcu_batch_before(rcp->completed, rdp->batch)) | 526 | if (!rcu_batch_before(completed_snap, rdp->batch)) |
522 | rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2]; | 527 | rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2]; |
523 | else if (!rcu_batch_before(rcp->completed, rdp->batch - 1)) | 528 | else if (!rcu_batch_before(completed_snap, rdp->batch - 1)) |
524 | rdp->nxttail[0] = rdp->nxttail[1]; | 529 | rdp->nxttail[0] = rdp->nxttail[1]; |
525 | 530 | ||
526 | /* | 531 | /* |
@@ -561,8 +566,24 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp, | |||
561 | 566 | ||
562 | static void rcu_process_callbacks(struct softirq_action *unused) | 567 | static void rcu_process_callbacks(struct softirq_action *unused) |
563 | { | 568 | { |
569 | /* | ||
570 | * Memory references from any prior RCU read-side critical sections | ||
571 | * executed by the interrupted code must be see before any RCU | ||
572 | * grace-period manupulations below. | ||
573 | */ | ||
574 | |||
575 | smp_mb(); /* See above block comment. */ | ||
576 | |||
564 | __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data)); | 577 | __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data)); |
565 | __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data)); | 578 | __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data)); |
579 | |||
580 | /* | ||
581 | * Memory references from any later RCU read-side critical sections | ||
582 | * executed by the interrupted code must be see after any RCU | ||
583 | * grace-period manupulations above. | ||
584 | */ | ||
585 | |||
586 | smp_mb(); /* See above block comment. */ | ||
566 | } | 587 | } |
567 | 588 | ||
568 | static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) | 589 | static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) |
@@ -571,13 +592,15 @@ static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) | |||
571 | check_cpu_stall(rcp, rdp); | 592 | check_cpu_stall(rcp, rdp); |
572 | 593 | ||
573 | if (rdp->nxtlist) { | 594 | if (rdp->nxtlist) { |
595 | long completed_snap = ACCESS_ONCE(rcp->completed); | ||
596 | |||
574 | /* | 597 | /* |
575 | * This cpu has pending rcu entries and the grace period | 598 | * This cpu has pending rcu entries and the grace period |
576 | * for them has completed. | 599 | * for them has completed. |
577 | */ | 600 | */ |
578 | if (!rcu_batch_before(rcp->completed, rdp->batch)) | 601 | if (!rcu_batch_before(completed_snap, rdp->batch)) |
579 | return 1; | 602 | return 1; |
580 | if (!rcu_batch_before(rcp->completed, rdp->batch - 1) && | 603 | if (!rcu_batch_before(completed_snap, rdp->batch - 1) && |
581 | rdp->nxttail[0] != rdp->nxttail[1]) | 604 | rdp->nxttail[0] != rdp->nxttail[1]) |
582 | return 1; | 605 | return 1; |
583 | if (rdp->nxttail[0] != &rdp->nxtlist) | 606 | if (rdp->nxttail[0] != &rdp->nxtlist) |
@@ -628,6 +651,12 @@ int rcu_needs_cpu(int cpu) | |||
628 | return !!rdp->nxtlist || !!rdp_bh->nxtlist || rcu_pending(cpu); | 651 | return !!rdp->nxtlist || !!rdp_bh->nxtlist || rcu_pending(cpu); |
629 | } | 652 | } |
630 | 653 | ||
654 | /* | ||
655 | * Top-level function driving RCU grace-period detection, normally | ||
656 | * invoked from the scheduler-clock interrupt. This function simply | ||
657 | * increments counters that are read only from softirq by this same | ||
658 | * CPU, so there are no memory barriers required. | ||
659 | */ | ||
631 | void rcu_check_callbacks(int cpu, int user) | 660 | void rcu_check_callbacks(int cpu, int user) |
632 | { | 661 | { |
633 | if (user || | 662 | if (user || |
@@ -671,6 +700,7 @@ void rcu_check_callbacks(int cpu, int user) | |||
671 | static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp, | 700 | static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp, |
672 | struct rcu_data *rdp) | 701 | struct rcu_data *rdp) |
673 | { | 702 | { |
703 | spin_lock(&rcp->lock); | ||
674 | memset(rdp, 0, sizeof(*rdp)); | 704 | memset(rdp, 0, sizeof(*rdp)); |
675 | rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2] = &rdp->nxtlist; | 705 | rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2] = &rdp->nxtlist; |
676 | rdp->donetail = &rdp->donelist; | 706 | rdp->donetail = &rdp->donelist; |
@@ -678,6 +708,7 @@ static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp, | |||
678 | rdp->qs_pending = 0; | 708 | rdp->qs_pending = 0; |
679 | rdp->cpu = cpu; | 709 | rdp->cpu = cpu; |
680 | rdp->blimit = blimit; | 710 | rdp->blimit = blimit; |
711 | spin_unlock(&rcp->lock); | ||
681 | } | 712 | } |
682 | 713 | ||
683 | static void __cpuinit rcu_online_cpu(int cpu) | 714 | static void __cpuinit rcu_online_cpu(int cpu) |