aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/trace/events/rcu.h1
-rw-r--r--kernel/rcu/tree.c72
-rw-r--r--kernel/rcu/tree.h2
-rw-r--r--kernel/rcu/tree_trace.c4
4 files changed, 22 insertions, 57 deletions
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index c78e88ce5ea3..ef72c4aada56 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -661,7 +661,6 @@ TRACE_EVENT(rcu_torture_read,
661 * Tracepoint for _rcu_barrier() execution. The string "s" describes 661 * Tracepoint for _rcu_barrier() execution. The string "s" describes
662 * the _rcu_barrier phase: 662 * the _rcu_barrier phase:
663 * "Begin": _rcu_barrier() started. 663 * "Begin": _rcu_barrier() started.
664 * "Check": _rcu_barrier() checking for piggybacking.
665 * "EarlyExit": _rcu_barrier() piggybacked, thus early exit. 664 * "EarlyExit": _rcu_barrier() piggybacked, thus early exit.
666 * "Inc1": _rcu_barrier() piggyback check counter incremented. 665 * "Inc1": _rcu_barrier() piggyback check counter incremented.
667 * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU 666 * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 338ea61929bd..44245ae4c1c2 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -3568,10 +3568,10 @@ static void rcu_barrier_callback(struct rcu_head *rhp)
3568 struct rcu_state *rsp = rdp->rsp; 3568 struct rcu_state *rsp = rdp->rsp;
3569 3569
3570 if (atomic_dec_and_test(&rsp->barrier_cpu_count)) { 3570 if (atomic_dec_and_test(&rsp->barrier_cpu_count)) {
3571 _rcu_barrier_trace(rsp, "LastCB", -1, rsp->n_barrier_done); 3571 _rcu_barrier_trace(rsp, "LastCB", -1, rsp->barrier_sequence);
3572 complete(&rsp->barrier_completion); 3572 complete(&rsp->barrier_completion);
3573 } else { 3573 } else {
3574 _rcu_barrier_trace(rsp, "CB", -1, rsp->n_barrier_done); 3574 _rcu_barrier_trace(rsp, "CB", -1, rsp->barrier_sequence);
3575 } 3575 }
3576} 3576}
3577 3577
@@ -3583,7 +3583,7 @@ static void rcu_barrier_func(void *type)
3583 struct rcu_state *rsp = type; 3583 struct rcu_state *rsp = type;
3584 struct rcu_data *rdp = raw_cpu_ptr(rsp->rda); 3584 struct rcu_data *rdp = raw_cpu_ptr(rsp->rda);
3585 3585
3586 _rcu_barrier_trace(rsp, "IRQ", -1, rsp->n_barrier_done); 3586 _rcu_barrier_trace(rsp, "IRQ", -1, rsp->barrier_sequence);
3587 atomic_inc(&rsp->barrier_cpu_count); 3587 atomic_inc(&rsp->barrier_cpu_count);
3588 rsp->call(&rdp->barrier_head, rcu_barrier_callback); 3588 rsp->call(&rdp->barrier_head, rcu_barrier_callback);
3589} 3589}
@@ -3596,55 +3596,24 @@ static void _rcu_barrier(struct rcu_state *rsp)
3596{ 3596{
3597 int cpu; 3597 int cpu;
3598 struct rcu_data *rdp; 3598 struct rcu_data *rdp;
3599 unsigned long snap = READ_ONCE(rsp->n_barrier_done); 3599 unsigned long s = rcu_seq_snap(&rsp->barrier_sequence);
3600 unsigned long snap_done;
3601 3600
3602 _rcu_barrier_trace(rsp, "Begin", -1, snap); 3601 _rcu_barrier_trace(rsp, "Begin", -1, s);
3603 3602
3604 /* Take mutex to serialize concurrent rcu_barrier() requests. */ 3603 /* Take mutex to serialize concurrent rcu_barrier() requests. */
3605 mutex_lock(&rsp->barrier_mutex); 3604 mutex_lock(&rsp->barrier_mutex);
3606 3605
3607 /* 3606 /* Did someone else do our work for us? */
3608 * Ensure that all prior references, including to ->n_barrier_done, 3607 if (rcu_seq_done(&rsp->barrier_sequence, s)) {
3609 * are ordered before the _rcu_barrier() machinery. 3608 _rcu_barrier_trace(rsp, "EarlyExit", -1, rsp->barrier_sequence);
3610 */
3611 smp_mb(); /* See above block comment. */
3612
3613 /*
3614 * Recheck ->n_barrier_done to see if others did our work for us.
3615 * This means checking ->n_barrier_done for an even-to-odd-to-even
3616 * transition. The "if" expression below therefore rounds the old
3617 * value up to the next even number and adds two before comparing.
3618 */
3619 snap_done = rsp->n_barrier_done;
3620 _rcu_barrier_trace(rsp, "Check", -1, snap_done);
3621
3622 /*
3623 * If the value in snap is odd, we needed to wait for the current
3624 * rcu_barrier() to complete, then wait for the next one, in other
3625 * words, we need the value of snap_done to be three larger than
3626 * the value of snap. On the other hand, if the value in snap is
3627 * even, we only had to wait for the next rcu_barrier() to complete,
3628 * in other words, we need the value of snap_done to be only two
3629 * greater than the value of snap. The "(snap + 3) & ~0x1" computes
3630 * this for us (thank you, Linus!).
3631 */
3632 if (ULONG_CMP_GE(snap_done, (snap + 3) & ~0x1)) {
3633 _rcu_barrier_trace(rsp, "EarlyExit", -1, snap_done);
3634 smp_mb(); /* caller's subsequent code after above check. */ 3609 smp_mb(); /* caller's subsequent code after above check. */
3635 mutex_unlock(&rsp->barrier_mutex); 3610 mutex_unlock(&rsp->barrier_mutex);
3636 return; 3611 return;
3637 } 3612 }
3638 3613
3639 /* 3614 /* Mark the start of the barrier operation. */
3640 * Increment ->n_barrier_done to avoid duplicate work. Use 3615 rcu_seq_start(&rsp->barrier_sequence);
3641 * WRITE_ONCE() to prevent the compiler from speculating 3616 _rcu_barrier_trace(rsp, "Inc1", -1, rsp->barrier_sequence);
3642 * the increment to precede the early-exit check.
3643 */
3644 WRITE_ONCE(rsp->n_barrier_done, rsp->n_barrier_done + 1);
3645 WARN_ON_ONCE((rsp->n_barrier_done & 0x1) != 1);
3646 _rcu_barrier_trace(rsp, "Inc1", -1, rsp->n_barrier_done);
3647 smp_mb(); /* Order ->n_barrier_done increment with below mechanism. */
3648 3617
3649 /* 3618 /*
3650 * Initialize the count to one rather than to zero in order to 3619 * Initialize the count to one rather than to zero in order to
@@ -3668,10 +3637,10 @@ static void _rcu_barrier(struct rcu_state *rsp)
3668 if (rcu_is_nocb_cpu(cpu)) { 3637 if (rcu_is_nocb_cpu(cpu)) {
3669 if (!rcu_nocb_cpu_needs_barrier(rsp, cpu)) { 3638 if (!rcu_nocb_cpu_needs_barrier(rsp, cpu)) {
3670 _rcu_barrier_trace(rsp, "OfflineNoCB", cpu, 3639 _rcu_barrier_trace(rsp, "OfflineNoCB", cpu,
3671 rsp->n_barrier_done); 3640 rsp->barrier_sequence);
3672 } else { 3641 } else {
3673 _rcu_barrier_trace(rsp, "OnlineNoCB", cpu, 3642 _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,
3674 rsp->n_barrier_done); 3643 rsp->barrier_sequence);
3675 smp_mb__before_atomic(); 3644 smp_mb__before_atomic();
3676 atomic_inc(&rsp->barrier_cpu_count); 3645 atomic_inc(&rsp->barrier_cpu_count);
3677 __call_rcu(&rdp->barrier_head, 3646 __call_rcu(&rdp->barrier_head,
@@ -3679,11 +3648,11 @@ static void _rcu_barrier(struct rcu_state *rsp)
3679 } 3648 }
3680 } else if (READ_ONCE(rdp->qlen)) { 3649 } else if (READ_ONCE(rdp->qlen)) {
3681 _rcu_barrier_trace(rsp, "OnlineQ", cpu, 3650 _rcu_barrier_trace(rsp, "OnlineQ", cpu,
3682 rsp->n_barrier_done); 3651 rsp->barrier_sequence);
3683 smp_call_function_single(cpu, rcu_barrier_func, rsp, 1); 3652 smp_call_function_single(cpu, rcu_barrier_func, rsp, 1);
3684 } else { 3653 } else {
3685 _rcu_barrier_trace(rsp, "OnlineNQ", cpu, 3654 _rcu_barrier_trace(rsp, "OnlineNQ", cpu,
3686 rsp->n_barrier_done); 3655 rsp->barrier_sequence);
3687 } 3656 }
3688 } 3657 }
3689 put_online_cpus(); 3658 put_online_cpus();
@@ -3695,16 +3664,13 @@ static void _rcu_barrier(struct rcu_state *rsp)
3695 if (atomic_dec_and_test(&rsp->barrier_cpu_count)) 3664 if (atomic_dec_and_test(&rsp->barrier_cpu_count))
3696 complete(&rsp->barrier_completion); 3665 complete(&rsp->barrier_completion);
3697 3666
3698 /* Increment ->n_barrier_done to prevent duplicate work. */
3699 smp_mb(); /* Keep increment after above mechanism. */
3700 WRITE_ONCE(rsp->n_barrier_done, rsp->n_barrier_done + 1);
3701 WARN_ON_ONCE((rsp->n_barrier_done & 0x1) != 0);
3702 _rcu_barrier_trace(rsp, "Inc2", -1, rsp->n_barrier_done);
3703 smp_mb(); /* Keep increment before caller's subsequent code. */
3704
3705 /* Wait for all rcu_barrier_callback() callbacks to be invoked. */ 3667 /* Wait for all rcu_barrier_callback() callbacks to be invoked. */
3706 wait_for_completion(&rsp->barrier_completion); 3668 wait_for_completion(&rsp->barrier_completion);
3707 3669
3670 /* Mark the end of the barrier operation. */
3671 _rcu_barrier_trace(rsp, "Inc2", -1, rsp->barrier_sequence);
3672 rcu_seq_end(&rsp->barrier_sequence);
3673
3708 /* Other rcu_barrier() invocations can now safely proceed. */ 3674 /* Other rcu_barrier() invocations can now safely proceed. */
3709 mutex_unlock(&rsp->barrier_mutex); 3675 mutex_unlock(&rsp->barrier_mutex);
3710} 3676}
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index 4edc277d08eb..5c1042d9c310 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -486,7 +486,7 @@ struct rcu_state {
486 struct mutex barrier_mutex; /* Guards barrier fields. */ 486 struct mutex barrier_mutex; /* Guards barrier fields. */
487 atomic_t barrier_cpu_count; /* # CPUs waiting on. */ 487 atomic_t barrier_cpu_count; /* # CPUs waiting on. */
488 struct completion barrier_completion; /* Wake at barrier end. */ 488 struct completion barrier_completion; /* Wake at barrier end. */
489 unsigned long n_barrier_done; /* ++ at start and end of */ 489 unsigned long barrier_sequence; /* ++ at start and end of */
490 /* _rcu_barrier(). */ 490 /* _rcu_barrier(). */
491 /* End of fields guarded by barrier_mutex. */ 491 /* End of fields guarded by barrier_mutex. */
492 492
diff --git a/kernel/rcu/tree_trace.c b/kernel/rcu/tree_trace.c
index 36c04b46d3b8..d9982a2ce305 100644
--- a/kernel/rcu/tree_trace.c
+++ b/kernel/rcu/tree_trace.c
@@ -81,9 +81,9 @@ static void r_stop(struct seq_file *m, void *v)
81static int show_rcubarrier(struct seq_file *m, void *v) 81static int show_rcubarrier(struct seq_file *m, void *v)
82{ 82{
83 struct rcu_state *rsp = (struct rcu_state *)m->private; 83 struct rcu_state *rsp = (struct rcu_state *)m->private;
84 seq_printf(m, "bcc: %d nbd: %lu\n", 84 seq_printf(m, "bcc: %d bseq: %lu\n",
85 atomic_read(&rsp->barrier_cpu_count), 85 atomic_read(&rsp->barrier_cpu_count),
86 rsp->n_barrier_done); 86 rsp->barrier_sequence);
87 return 0; 87 return 0;
88} 88}
89 89