diff options
| author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2018-04-26 14:52:09 -0400 |
|---|---|---|
| committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2018-07-12 17:27:46 -0400 |
| commit | de30ad512a668b56e7ad7a5a7c379d7c5d138a94 (patch) | |
| tree | b738dc4cef2074311f09b55da11f1a74a72acf72 /kernel/rcu/tree.c | |
| parent | 609af1cdf040f8d3f3986755586f7833eaa96d2c (diff) | |
rcu: Introduce grace-period sequence numbers
This commit adds grace-period sequence numbers (->gp_seq) to the
rcu_state, rcu_node, and rcu_data structures, and updates them.
It also checks for consistency between rsp->gpnum and rsp->gp_seq.
These ->gp_seq counters will eventually replace the existing ->gpnum
and ->completed counters, allowing a single memory access to determine
whether or not a grace period is in progress and if so, which one.
This in turn will enable changes that will reduce ->lock contention on
the leaf rcu_node structures.
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 | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index a9a4a260ea7d..467cd8e5c6ff 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
| @@ -97,6 +97,7 @@ struct rcu_state sname##_state = { \ | |||
| 97 | .gp_state = RCU_GP_IDLE, \ | 97 | .gp_state = RCU_GP_IDLE, \ |
| 98 | .gpnum = 0UL - 300UL, \ | 98 | .gpnum = 0UL - 300UL, \ |
| 99 | .completed = 0UL - 300UL, \ | 99 | .completed = 0UL - 300UL, \ |
| 100 | .gp_seq = (0UL - 300UL) << RCU_SEQ_CTR_SHIFT, \ | ||
| 100 | .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \ | 101 | .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \ |
| 101 | .name = RCU_STATE_NAME(sname), \ | 102 | .name = RCU_STATE_NAME(sname), \ |
| 102 | .abbr = sabbr, \ | 103 | .abbr = sabbr, \ |
| @@ -1849,6 +1850,8 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, | |||
| 1849 | WRITE_ONCE(rdp->gpwrap, false); | 1850 | WRITE_ONCE(rdp->gpwrap, false); |
| 1850 | rcu_gpnum_ovf(rnp, rdp); | 1851 | rcu_gpnum_ovf(rnp, rdp); |
| 1851 | } | 1852 | } |
| 1853 | if (rdp->gp_seq != rnp->gp_seq) | ||
| 1854 | rdp->gp_seq = rnp->gp_seq; | ||
| 1852 | return ret; | 1855 | return ret; |
| 1853 | } | 1856 | } |
| 1854 | 1857 | ||
| @@ -1910,7 +1913,10 @@ static bool rcu_gp_init(struct rcu_state *rsp) | |||
| 1910 | /* Advance to a new grace period and initialize state. */ | 1913 | /* Advance to a new grace period and initialize state. */ |
| 1911 | record_gp_stall_check_time(rsp); | 1914 | record_gp_stall_check_time(rsp); |
| 1912 | /* Record GP times before starting GP, hence smp_store_release(). */ | 1915 | /* Record GP times before starting GP, hence smp_store_release(). */ |
| 1916 | WARN_ON_ONCE(rsp->gpnum << RCU_SEQ_CTR_SHIFT != rsp->gp_seq); | ||
| 1913 | smp_store_release(&rsp->gpnum, rsp->gpnum + 1); | 1917 | smp_store_release(&rsp->gpnum, rsp->gpnum + 1); |
| 1918 | smp_mb(); /* Pairs with barriers in stall-warning code. */ | ||
| 1919 | rcu_seq_start(&rsp->gp_seq); | ||
| 1914 | trace_rcu_grace_period(rsp->name, rsp->gpnum, TPS("start")); | 1920 | trace_rcu_grace_period(rsp->name, rsp->gpnum, TPS("start")); |
| 1915 | raw_spin_unlock_irq_rcu_node(rnp); | 1921 | raw_spin_unlock_irq_rcu_node(rnp); |
| 1916 | 1922 | ||
| @@ -1984,6 +1990,7 @@ static bool rcu_gp_init(struct rcu_state *rsp) | |||
| 1984 | WRITE_ONCE(rnp->gpnum, rsp->gpnum); | 1990 | WRITE_ONCE(rnp->gpnum, rsp->gpnum); |
| 1985 | if (WARN_ON_ONCE(rnp->completed != rsp->completed)) | 1991 | if (WARN_ON_ONCE(rnp->completed != rsp->completed)) |
| 1986 | WRITE_ONCE(rnp->completed, rsp->completed); | 1992 | WRITE_ONCE(rnp->completed, rsp->completed); |
| 1993 | WRITE_ONCE(rnp->gp_seq, rsp->gp_seq); | ||
| 1987 | if (rnp == rdp->mynode) | 1994 | if (rnp == rdp->mynode) |
| 1988 | (void)__note_gp_changes(rsp, rnp, rdp); | 1995 | (void)__note_gp_changes(rsp, rnp, rdp); |
| 1989 | rcu_preempt_boost_start_gp(rnp); | 1996 | rcu_preempt_boost_start_gp(rnp); |
| @@ -2050,6 +2057,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) | |||
| 2050 | { | 2057 | { |
| 2051 | unsigned long gp_duration; | 2058 | unsigned long gp_duration; |
| 2052 | bool needgp = false; | 2059 | bool needgp = false; |
| 2060 | unsigned long new_gp_seq; | ||
| 2053 | struct rcu_data *rdp; | 2061 | struct rcu_data *rdp; |
| 2054 | struct rcu_node *rnp = rcu_get_root(rsp); | 2062 | struct rcu_node *rnp = rcu_get_root(rsp); |
| 2055 | struct swait_queue_head *sq; | 2063 | struct swait_queue_head *sq; |
| @@ -2079,12 +2087,15 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) | |||
| 2079 | * all of the rcu_node structures before the beginning of the next | 2087 | * all of the rcu_node structures before the beginning of the next |
| 2080 | * grace period is recorded in any of the rcu_node structures. | 2088 | * grace period is recorded in any of the rcu_node structures. |
| 2081 | */ | 2089 | */ |
| 2090 | new_gp_seq = rsp->gp_seq; | ||
| 2091 | rcu_seq_end(&new_gp_seq); | ||
| 2082 | rcu_for_each_node_breadth_first(rsp, rnp) { | 2092 | rcu_for_each_node_breadth_first(rsp, rnp) { |
| 2083 | raw_spin_lock_irq_rcu_node(rnp); | 2093 | raw_spin_lock_irq_rcu_node(rnp); |
| 2084 | if (WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp))) | 2094 | if (WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp))) |
| 2085 | dump_blkd_tasks(rnp, 10); | 2095 | dump_blkd_tasks(rnp, 10); |
| 2086 | WARN_ON_ONCE(rnp->qsmask); | 2096 | WARN_ON_ONCE(rnp->qsmask); |
| 2087 | WRITE_ONCE(rnp->completed, rsp->gpnum); | 2097 | WRITE_ONCE(rnp->completed, rsp->gpnum); |
| 2098 | WRITE_ONCE(rnp->gp_seq, new_gp_seq); | ||
| 2088 | rdp = this_cpu_ptr(rsp->rda); | 2099 | rdp = this_cpu_ptr(rsp->rda); |
| 2089 | if (rnp == rdp->mynode) | 2100 | if (rnp == rdp->mynode) |
| 2090 | needgp = __note_gp_changes(rsp, rnp, rdp) || needgp; | 2101 | needgp = __note_gp_changes(rsp, rnp, rdp) || needgp; |
| @@ -2098,10 +2109,11 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) | |||
| 2098 | rcu_gp_slow(rsp, gp_cleanup_delay); | 2109 | rcu_gp_slow(rsp, gp_cleanup_delay); |
| 2099 | } | 2110 | } |
| 2100 | rnp = rcu_get_root(rsp); | 2111 | rnp = rcu_get_root(rsp); |
| 2101 | raw_spin_lock_irq_rcu_node(rnp); /* Order GP before ->completed update. */ | 2112 | raw_spin_lock_irq_rcu_node(rnp); /* GP before rsp->gp_seq update. */ |
| 2102 | 2113 | ||
| 2103 | /* Declare grace period done. */ | 2114 | /* Declare grace period done. */ |
| 2104 | WRITE_ONCE(rsp->completed, rsp->gpnum); | 2115 | WRITE_ONCE(rsp->completed, rsp->gpnum); |
| 2116 | rcu_seq_end(&rsp->gp_seq); | ||
| 2105 | trace_rcu_grace_period(rsp->name, rsp->completed, TPS("end")); | 2117 | trace_rcu_grace_period(rsp->name, rsp->completed, TPS("end")); |
| 2106 | rsp->gp_state = RCU_GP_IDLE; | 2118 | rsp->gp_state = RCU_GP_IDLE; |
| 2107 | /* Check for GP requests since above loop. */ | 2119 | /* Check for GP requests since above loop. */ |
| @@ -3612,6 +3624,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) | |||
| 3612 | rdp->beenonline = true; /* We have now been online. */ | 3624 | rdp->beenonline = true; /* We have now been online. */ |
| 3613 | rdp->gpnum = rnp->completed; /* Make CPU later note any new GP. */ | 3625 | rdp->gpnum = rnp->completed; /* Make CPU later note any new GP. */ |
| 3614 | rdp->completed = rnp->completed; | 3626 | rdp->completed = rnp->completed; |
| 3627 | rdp->gp_seq = rnp->gp_seq; | ||
| 3615 | rdp->cpu_no_qs.b.norm = true; | 3628 | rdp->cpu_no_qs.b.norm = true; |
| 3616 | rdp->rcu_qs_ctr_snap = per_cpu(rcu_dynticks.rcu_qs_ctr, cpu); | 3629 | rdp->rcu_qs_ctr_snap = per_cpu(rcu_dynticks.rcu_qs_ctr, cpu); |
| 3617 | rdp->core_needs_qs = false; | 3630 | rdp->core_needs_qs = false; |
| @@ -3991,6 +4004,7 @@ static void __init rcu_init_one(struct rcu_state *rsp) | |||
| 3991 | &rcu_fqs_class[i], fqs[i]); | 4004 | &rcu_fqs_class[i], fqs[i]); |
| 3992 | rnp->gpnum = rsp->gpnum; | 4005 | rnp->gpnum = rsp->gpnum; |
| 3993 | rnp->completed = rsp->completed; | 4006 | rnp->completed = rsp->completed; |
| 4007 | rnp->gp_seq = rsp->gp_seq; | ||
| 3994 | rnp->completedqs = rsp->completed; | 4008 | rnp->completedqs = rsp->completed; |
| 3995 | rnp->qsmask = 0; | 4009 | rnp->qsmask = 0; |
| 3996 | rnp->qsmaskinit = 0; | 4010 | rnp->qsmaskinit = 0; |
