Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rcu: Apply rcu_seq operations to _rcu_barrier()

The rcu_seq operations were open-coded in _rcu_barrier(), so this commit
replaces the open-coding with the shiny new rcu_seq operations.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

+22 -57
-1
include/trace/events/rcu.h
··· 661 661 * Tracepoint for _rcu_barrier() execution. The string "s" describes 662 662 * the _rcu_barrier phase: 663 663 * "Begin": _rcu_barrier() started. 664 - * "Check": _rcu_barrier() checking for piggybacking. 665 664 * "EarlyExit": _rcu_barrier() piggybacked, thus early exit. 666 665 * "Inc1": _rcu_barrier() piggyback check counter incremented. 667 666 * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU
+19 -53
kernel/rcu/tree.c
··· 3568 3568 struct rcu_state *rsp = rdp->rsp; 3569 3569 3570 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 3572 complete(&rsp->barrier_completion); 3573 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 3583 struct rcu_state *rsp = type; 3584 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 3587 atomic_inc(&rsp->barrier_cpu_count); 3588 3588 rsp->call(&rdp->barrier_head, rcu_barrier_callback); 3589 3589 } ··· 3596 3596 { 3597 3597 int cpu; 3598 3598 struct rcu_data *rdp; 3599 - unsigned long snap = READ_ONCE(rsp->n_barrier_done); 3600 - unsigned long snap_done; 3599 + unsigned long s = rcu_seq_snap(&rsp->barrier_sequence); 3601 3600 3602 - _rcu_barrier_trace(rsp, "Begin", -1, snap); 3601 + _rcu_barrier_trace(rsp, "Begin", -1, s); 3603 3602 3604 3603 /* Take mutex to serialize concurrent rcu_barrier() requests. */ 3605 3604 mutex_lock(&rsp->barrier_mutex); 3606 3605 3607 - /* 3608 - * Ensure that all prior references, including to ->n_barrier_done, 3609 - * are ordered before the _rcu_barrier() machinery. 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); 3606 + /* Did someone else do our work for us? */ 3607 + if (rcu_seq_done(&rsp->barrier_sequence, s)) { 3608 + _rcu_barrier_trace(rsp, "EarlyExit", -1, rsp->barrier_sequence); 3634 3609 smp_mb(); /* caller's subsequent code after above check. */ 3635 3610 mutex_unlock(&rsp->barrier_mutex); 3636 3611 return; 3637 3612 } 3638 3613 3639 - /* 3640 - * Increment ->n_barrier_done to avoid duplicate work. Use 3641 - * WRITE_ONCE() to prevent the compiler from speculating 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. */ 3614 + /* Mark the start of the barrier operation. */ 3615 + rcu_seq_start(&rsp->barrier_sequence); 3616 + _rcu_barrier_trace(rsp, "Inc1", -1, rsp->barrier_sequence); 3648 3617 3649 3618 /* 3650 3619 * Initialize the count to one rather than to zero in order to ··· 3637 3668 if (rcu_is_nocb_cpu(cpu)) { 3638 3669 if (!rcu_nocb_cpu_needs_barrier(rsp, cpu)) { 3639 3670 _rcu_barrier_trace(rsp, "OfflineNoCB", cpu, 3640 - rsp->n_barrier_done); 3671 + rsp->barrier_sequence); 3641 3672 } else { 3642 3673 _rcu_barrier_trace(rsp, "OnlineNoCB", cpu, 3643 - rsp->n_barrier_done); 3674 + rsp->barrier_sequence); 3644 3675 smp_mb__before_atomic(); 3645 3676 atomic_inc(&rsp->barrier_cpu_count); 3646 3677 __call_rcu(&rdp->barrier_head, ··· 3648 3679 } 3649 3680 } else if (READ_ONCE(rdp->qlen)) { 3650 3681 _rcu_barrier_trace(rsp, "OnlineQ", cpu, 3651 - rsp->n_barrier_done); 3682 + rsp->barrier_sequence); 3652 3683 smp_call_function_single(cpu, rcu_barrier_func, rsp, 1); 3653 3684 } else { 3654 3685 _rcu_barrier_trace(rsp, "OnlineNQ", cpu, 3655 - rsp->n_barrier_done); 3686 + rsp->barrier_sequence); 3656 3687 } 3657 3688 } 3658 3689 put_online_cpus(); ··· 3664 3695 if (atomic_dec_and_test(&rsp->barrier_cpu_count)) 3665 3696 complete(&rsp->barrier_completion); 3666 3697 3667 - /* Increment ->n_barrier_done to prevent duplicate work. */ 3668 - smp_mb(); /* Keep increment after above mechanism. */ 3669 - WRITE_ONCE(rsp->n_barrier_done, rsp->n_barrier_done + 1); 3670 - WARN_ON_ONCE((rsp->n_barrier_done & 0x1) != 0); 3671 - _rcu_barrier_trace(rsp, "Inc2", -1, rsp->n_barrier_done); 3672 - smp_mb(); /* Keep increment before caller's subsequent code. */ 3673 - 3674 3698 /* Wait for all rcu_barrier_callback() callbacks to be invoked. */ 3675 3699 wait_for_completion(&rsp->barrier_completion); 3700 + 3701 + /* Mark the end of the barrier operation. */ 3702 + _rcu_barrier_trace(rsp, "Inc2", -1, rsp->barrier_sequence); 3703 + rcu_seq_end(&rsp->barrier_sequence); 3676 3704 3677 3705 /* Other rcu_barrier() invocations can now safely proceed. */ 3678 3706 mutex_unlock(&rsp->barrier_mutex);
+1 -1
kernel/rcu/tree.h
··· 486 486 struct mutex barrier_mutex; /* Guards barrier fields. */ 487 487 atomic_t barrier_cpu_count; /* # CPUs waiting on. */ 488 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 490 /* _rcu_barrier(). */ 491 491 /* End of fields guarded by barrier_mutex. */ 492 492
+2 -2
kernel/rcu/tree_trace.c
··· 81 81 static int show_rcubarrier(struct seq_file *m, void *v) 82 82 { 83 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 85 atomic_read(&rsp->barrier_cpu_count), 86 - rsp->n_barrier_done); 86 + rsp->barrier_sequence); 87 87 return 0; 88 88 } 89 89