diff options
author | Lai Jiangshan <laijs@cn.fujitsu.com> | 2010-06-28 04:25:04 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2010-08-19 20:18:01 -0400 |
commit | 394f99a9007d4274f7076bb8553ab0ff9707688b (patch) | |
tree | 7d379f91321cec58b87fd5f5089947872689d591 /kernel | |
parent | e546f485e1d7520ca0200502cdcc11b503f4805c (diff) |
rcu: simplify the usage of percpu data
&percpu_data is compatible with allocated percpu data.
And we use it and remove the "->rda[NR_CPUS]" array, saving significant
storage on systems with large numbers of CPUs. This does add an additional
level of indirection and thus an additional cache line referenced, but
because ->rda is not used on the read side, this is OK.
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Reviewed-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/rcutree.c | 42 | ||||
-rw-r--r-- | kernel/rcutree.h | 2 | ||||
-rw-r--r-- | kernel/rcutree_plugin.h | 4 | ||||
-rw-r--r-- | kernel/rcutree_trace.c | 2 |
4 files changed, 19 insertions, 31 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d5bc43976c5a..5b1c3c231bae 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -712,7 +712,7 @@ static void | |||
712 | rcu_start_gp(struct rcu_state *rsp, unsigned long flags) | 712 | rcu_start_gp(struct rcu_state *rsp, unsigned long flags) |
713 | __releases(rcu_get_root(rsp)->lock) | 713 | __releases(rcu_get_root(rsp)->lock) |
714 | { | 714 | { |
715 | struct rcu_data *rdp = rsp->rda[smp_processor_id()]; | 715 | struct rcu_data *rdp = this_cpu_ptr(rsp->rda); |
716 | struct rcu_node *rnp = rcu_get_root(rsp); | 716 | struct rcu_node *rnp = rcu_get_root(rsp); |
717 | 717 | ||
718 | if (!cpu_needs_another_gp(rsp, rdp) || rsp->fqs_active) { | 718 | if (!cpu_needs_another_gp(rsp, rdp) || rsp->fqs_active) { |
@@ -960,7 +960,7 @@ rcu_check_quiescent_state(struct rcu_state *rsp, struct rcu_data *rdp) | |||
960 | static void rcu_send_cbs_to_orphanage(struct rcu_state *rsp) | 960 | static void rcu_send_cbs_to_orphanage(struct rcu_state *rsp) |
961 | { | 961 | { |
962 | int i; | 962 | int i; |
963 | struct rcu_data *rdp = rsp->rda[smp_processor_id()]; | 963 | struct rcu_data *rdp = this_cpu_ptr(rsp->rda); |
964 | 964 | ||
965 | if (rdp->nxtlist == NULL) | 965 | if (rdp->nxtlist == NULL) |
966 | return; /* irqs disabled, so comparison is stable. */ | 966 | return; /* irqs disabled, so comparison is stable. */ |
@@ -984,7 +984,7 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp) | |||
984 | struct rcu_data *rdp; | 984 | struct rcu_data *rdp; |
985 | 985 | ||
986 | raw_spin_lock_irqsave(&rsp->onofflock, flags); | 986 | raw_spin_lock_irqsave(&rsp->onofflock, flags); |
987 | rdp = rsp->rda[smp_processor_id()]; | 987 | rdp = this_cpu_ptr(rsp->rda); |
988 | if (rsp->orphan_cbs_list == NULL) { | 988 | if (rsp->orphan_cbs_list == NULL) { |
989 | raw_spin_unlock_irqrestore(&rsp->onofflock, flags); | 989 | raw_spin_unlock_irqrestore(&rsp->onofflock, flags); |
990 | return; | 990 | return; |
@@ -1007,7 +1007,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) | |||
1007 | unsigned long flags; | 1007 | unsigned long flags; |
1008 | unsigned long mask; | 1008 | unsigned long mask; |
1009 | int need_report = 0; | 1009 | int need_report = 0; |
1010 | struct rcu_data *rdp = rsp->rda[cpu]; | 1010 | struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); |
1011 | struct rcu_node *rnp; | 1011 | struct rcu_node *rnp; |
1012 | 1012 | ||
1013 | /* Exclude any attempts to start a new grace period. */ | 1013 | /* Exclude any attempts to start a new grace period. */ |
@@ -1226,7 +1226,8 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *)) | |||
1226 | cpu = rnp->grplo; | 1226 | cpu = rnp->grplo; |
1227 | bit = 1; | 1227 | bit = 1; |
1228 | for (; cpu <= rnp->grphi; cpu++, bit <<= 1) { | 1228 | for (; cpu <= rnp->grphi; cpu++, bit <<= 1) { |
1229 | if ((rnp->qsmask & bit) != 0 && f(rsp->rda[cpu])) | 1229 | if ((rnp->qsmask & bit) != 0 && |
1230 | f(per_cpu_ptr(rsp->rda, cpu))) | ||
1230 | mask |= bit; | 1231 | mask |= bit; |
1231 | } | 1232 | } |
1232 | if (mask != 0) { | 1233 | if (mask != 0) { |
@@ -1402,7 +1403,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | |||
1402 | * a quiescent state betweentimes. | 1403 | * a quiescent state betweentimes. |
1403 | */ | 1404 | */ |
1404 | local_irq_save(flags); | 1405 | local_irq_save(flags); |
1405 | rdp = rsp->rda[smp_processor_id()]; | 1406 | rdp = this_cpu_ptr(rsp->rda); |
1406 | rcu_process_gp_end(rsp, rdp); | 1407 | rcu_process_gp_end(rsp, rdp); |
1407 | check_for_new_grace_period(rsp, rdp); | 1408 | check_for_new_grace_period(rsp, rdp); |
1408 | 1409 | ||
@@ -1701,7 +1702,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) | |||
1701 | { | 1702 | { |
1702 | unsigned long flags; | 1703 | unsigned long flags; |
1703 | int i; | 1704 | int i; |
1704 | struct rcu_data *rdp = rsp->rda[cpu]; | 1705 | struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); |
1705 | struct rcu_node *rnp = rcu_get_root(rsp); | 1706 | struct rcu_node *rnp = rcu_get_root(rsp); |
1706 | 1707 | ||
1707 | /* Set up local state, ensuring consistent view of global state. */ | 1708 | /* Set up local state, ensuring consistent view of global state. */ |
@@ -1729,7 +1730,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable) | |||
1729 | { | 1730 | { |
1730 | unsigned long flags; | 1731 | unsigned long flags; |
1731 | unsigned long mask; | 1732 | unsigned long mask; |
1732 | struct rcu_data *rdp = rsp->rda[cpu]; | 1733 | struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); |
1733 | struct rcu_node *rnp = rcu_get_root(rsp); | 1734 | struct rcu_node *rnp = rcu_get_root(rsp); |
1734 | 1735 | ||
1735 | /* Set up local state, ensuring consistent view of global state. */ | 1736 | /* Set up local state, ensuring consistent view of global state. */ |
@@ -1865,7 +1866,8 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp) | |||
1865 | /* | 1866 | /* |
1866 | * Helper function for rcu_init() that initializes one rcu_state structure. | 1867 | * Helper function for rcu_init() that initializes one rcu_state structure. |
1867 | */ | 1868 | */ |
1868 | static void __init rcu_init_one(struct rcu_state *rsp) | 1869 | static void __init rcu_init_one(struct rcu_state *rsp, |
1870 | struct rcu_data __percpu *rda) | ||
1869 | { | 1871 | { |
1870 | static char *buf[] = { "rcu_node_level_0", | 1872 | static char *buf[] = { "rcu_node_level_0", |
1871 | "rcu_node_level_1", | 1873 | "rcu_node_level_1", |
@@ -1918,37 +1920,23 @@ static void __init rcu_init_one(struct rcu_state *rsp) | |||
1918 | } | 1920 | } |
1919 | } | 1921 | } |
1920 | 1922 | ||
1923 | rsp->rda = rda; | ||
1921 | rnp = rsp->level[NUM_RCU_LVLS - 1]; | 1924 | rnp = rsp->level[NUM_RCU_LVLS - 1]; |
1922 | for_each_possible_cpu(i) { | 1925 | for_each_possible_cpu(i) { |
1923 | while (i > rnp->grphi) | 1926 | while (i > rnp->grphi) |
1924 | rnp++; | 1927 | rnp++; |
1925 | rsp->rda[i]->mynode = rnp; | 1928 | per_cpu_ptr(rsp->rda, i)->mynode = rnp; |
1926 | rcu_boot_init_percpu_data(i, rsp); | 1929 | rcu_boot_init_percpu_data(i, rsp); |
1927 | } | 1930 | } |
1928 | } | 1931 | } |
1929 | 1932 | ||
1930 | /* | ||
1931 | * Helper macro for __rcu_init() and __rcu_init_preempt(). To be used | ||
1932 | * nowhere else! Assigns leaf node pointers into each CPU's rcu_data | ||
1933 | * structure. | ||
1934 | */ | ||
1935 | #define RCU_INIT_FLAVOR(rsp, rcu_data) \ | ||
1936 | do { \ | ||
1937 | int i; \ | ||
1938 | \ | ||
1939 | for_each_possible_cpu(i) { \ | ||
1940 | (rsp)->rda[i] = &per_cpu(rcu_data, i); \ | ||
1941 | } \ | ||
1942 | rcu_init_one(rsp); \ | ||
1943 | } while (0) | ||
1944 | |||
1945 | void __init rcu_init(void) | 1933 | void __init rcu_init(void) |
1946 | { | 1934 | { |
1947 | int cpu; | 1935 | int cpu; |
1948 | 1936 | ||
1949 | rcu_bootup_announce(); | 1937 | rcu_bootup_announce(); |
1950 | RCU_INIT_FLAVOR(&rcu_sched_state, rcu_sched_data); | 1938 | rcu_init_one(&rcu_sched_state, &rcu_sched_data); |
1951 | RCU_INIT_FLAVOR(&rcu_bh_state, rcu_bh_data); | 1939 | rcu_init_one(&rcu_bh_state, &rcu_bh_data); |
1952 | __rcu_init_preempt(); | 1940 | __rcu_init_preempt(); |
1953 | open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); | 1941 | open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); |
1954 | 1942 | ||
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 14c040b18ed0..5ce197e87792 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
@@ -283,7 +283,7 @@ struct rcu_state { | |||
283 | struct rcu_node *level[NUM_RCU_LVLS]; /* Hierarchy levels. */ | 283 | struct rcu_node *level[NUM_RCU_LVLS]; /* Hierarchy levels. */ |
284 | u32 levelcnt[MAX_RCU_LVLS + 1]; /* # nodes in each level. */ | 284 | u32 levelcnt[MAX_RCU_LVLS + 1]; /* # nodes in each level. */ |
285 | u8 levelspread[NUM_RCU_LVLS]; /* kids/node in each level. */ | 285 | u8 levelspread[NUM_RCU_LVLS]; /* kids/node in each level. */ |
286 | struct rcu_data *rda[NR_CPUS]; /* array of rdp pointers. */ | 286 | struct rcu_data __percpu *rda; /* pointer of percu rcu_data. */ |
287 | 287 | ||
288 | /* The following fields are guarded by the root rcu_node's lock. */ | 288 | /* The following fields are guarded by the root rcu_node's lock. */ |
289 | 289 | ||
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 0e4f420245d9..9906f85c7780 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h | |||
@@ -154,7 +154,7 @@ static void rcu_preempt_note_context_switch(int cpu) | |||
154 | (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) { | 154 | (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) { |
155 | 155 | ||
156 | /* Possibly blocking in an RCU read-side critical section. */ | 156 | /* Possibly blocking in an RCU read-side critical section. */ |
157 | rdp = rcu_preempt_state.rda[cpu]; | 157 | rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu); |
158 | rnp = rdp->mynode; | 158 | rnp = rdp->mynode; |
159 | raw_spin_lock_irqsave(&rnp->lock, flags); | 159 | raw_spin_lock_irqsave(&rnp->lock, flags); |
160 | t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED; | 160 | t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED; |
@@ -771,7 +771,7 @@ static void rcu_preempt_send_cbs_to_orphanage(void) | |||
771 | */ | 771 | */ |
772 | static void __init __rcu_init_preempt(void) | 772 | static void __init __rcu_init_preempt(void) |
773 | { | 773 | { |
774 | RCU_INIT_FLAVOR(&rcu_preempt_state, rcu_preempt_data); | 774 | rcu_init_one(&rcu_preempt_state, &rcu_preempt_data); |
775 | } | 775 | } |
776 | 776 | ||
777 | /* | 777 | /* |
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 36c95b45738e..458e032a3a30 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c | |||
@@ -262,7 +262,7 @@ static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp) | |||
262 | struct rcu_data *rdp; | 262 | struct rcu_data *rdp; |
263 | 263 | ||
264 | for_each_possible_cpu(cpu) { | 264 | for_each_possible_cpu(cpu) { |
265 | rdp = rsp->rda[cpu]; | 265 | rdp = per_cpu_ptr(rsp->rda, cpu); |
266 | if (rdp->beenonline) | 266 | if (rdp->beenonline) |
267 | print_one_rcu_pending(m, rdp); | 267 | print_one_rcu_pending(m, rdp); |
268 | } | 268 | } |