diff options
| author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2015-06-26 14:20:00 -0400 |
|---|---|---|
| committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2015-07-17 17:58:57 -0400 |
| commit | 4f525a528b9e75571c6bedc6202beff1ced24c32 (patch) | |
| tree | 647eca893176e3c61cf81069918fb9a29ad0025c /kernel/rcu/tree.c | |
| parent | 29fd930940193a9a035a75a3847457160d65559a (diff) | |
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>
Diffstat (limited to 'kernel/rcu/tree.c')
| -rw-r--r-- | kernel/rcu/tree.c | 72 |
1 files changed, 19 insertions, 53 deletions
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 | } |
