diff options
author | Oleg Nesterov <oleg@redhat.com> | 2015-08-21 13:42:47 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2015-10-06 14:25:10 -0400 |
commit | 82e8c565be8a72957570d7da8dd9b441db7bb648 (patch) | |
tree | 340d7f93cecbb93a2f6517e369b675195282ba7f | |
parent | cc44ca848f5e517aeca9f5eabbe13609a3f71450 (diff) |
rcu_sync: Simplify rcu_sync using new rcu_sync_ops structure
This commit adds the new struct rcu_sync_ops which holds sync/call
methods, and turns the function pointers in rcu_sync_struct into an array
of struct rcu_sync_ops. This simplifies the "init" helpers by collapsing
a switch statement and explicit multiple definitions into a simple
assignment and a helper macro, respectively.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
-rw-r--r-- | include/linux/rcu_sync.h | 60 | ||||
-rw-r--r-- | kernel/rcu/sync.c | 42 |
2 files changed, 45 insertions, 57 deletions
diff --git a/include/linux/rcu_sync.h b/include/linux/rcu_sync.h index cb044df2e21c..c6d2272c4459 100644 --- a/include/linux/rcu_sync.h +++ b/include/linux/rcu_sync.h | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/wait.h> | 26 | #include <linux/wait.h> |
27 | #include <linux/rcupdate.h> | 27 | #include <linux/rcupdate.h> |
28 | 28 | ||
29 | enum rcu_sync_type { RCU_SYNC, RCU_SCHED_SYNC, RCU_BH_SYNC }; | ||
30 | |||
29 | /* Structure to mediate between updaters and fastpath-using readers. */ | 31 | /* Structure to mediate between updaters and fastpath-using readers. */ |
30 | struct rcu_sync { | 32 | struct rcu_sync { |
31 | int gp_state; | 33 | int gp_state; |
@@ -35,43 +37,9 @@ struct rcu_sync { | |||
35 | int cb_state; | 37 | int cb_state; |
36 | struct rcu_head cb_head; | 38 | struct rcu_head cb_head; |
37 | 39 | ||
38 | void (*sync)(void); | 40 | enum rcu_sync_type gp_type; |
39 | void (*call)(struct rcu_head *, void (*)(struct rcu_head *)); | ||
40 | }; | 41 | }; |
41 | 42 | ||
42 | #define ___RCU_SYNC_INIT(name) \ | ||
43 | .gp_state = 0, \ | ||
44 | .gp_count = 0, \ | ||
45 | .gp_wait = __WAIT_QUEUE_HEAD_INITIALIZER(name.gp_wait), \ | ||
46 | .cb_state = 0 | ||
47 | |||
48 | #define __RCU_SCHED_SYNC_INIT(name) { \ | ||
49 | ___RCU_SYNC_INIT(name), \ | ||
50 | .sync = synchronize_sched, \ | ||
51 | .call = call_rcu_sched, \ | ||
52 | } | ||
53 | |||
54 | #define __RCU_BH_SYNC_INIT(name) { \ | ||
55 | ___RCU_SYNC_INIT(name), \ | ||
56 | .sync = synchronize_rcu_bh, \ | ||
57 | .call = call_rcu_bh, \ | ||
58 | } | ||
59 | |||
60 | #define __RCU_SYNC_INIT(name) { \ | ||
61 | ___RCU_SYNC_INIT(name), \ | ||
62 | .sync = synchronize_rcu, \ | ||
63 | .call = call_rcu, \ | ||
64 | } | ||
65 | |||
66 | #define DEFINE_RCU_SCHED_SYNC(name) \ | ||
67 | struct rcu_sync name = __RCU_SCHED_SYNC_INIT(name) | ||
68 | |||
69 | #define DEFINE_RCU_BH_SYNC(name) \ | ||
70 | struct rcu_sync name = __RCU_BH_SYNC_INIT(name) | ||
71 | |||
72 | #define DEFINE_RCU_SYNC(name) \ | ||
73 | struct rcu_sync name = __RCU_SYNC_INIT(name) | ||
74 | |||
75 | /** | 43 | /** |
76 | * rcu_sync_is_idle() - Are readers permitted to use their fastpaths? | 44 | * rcu_sync_is_idle() - Are readers permitted to use their fastpaths? |
77 | * @rsp: Pointer to rcu_sync structure to use for synchronization | 45 | * @rsp: Pointer to rcu_sync structure to use for synchronization |
@@ -85,10 +53,28 @@ static inline bool rcu_sync_is_idle(struct rcu_sync *rsp) | |||
85 | return !rsp->gp_state; /* GP_IDLE */ | 53 | return !rsp->gp_state; /* GP_IDLE */ |
86 | } | 54 | } |
87 | 55 | ||
88 | enum rcu_sync_type { RCU_SYNC, RCU_SCHED_SYNC, RCU_BH_SYNC }; | ||
89 | |||
90 | extern void rcu_sync_init(struct rcu_sync *, enum rcu_sync_type); | 56 | extern void rcu_sync_init(struct rcu_sync *, enum rcu_sync_type); |
91 | extern void rcu_sync_enter(struct rcu_sync *); | 57 | extern void rcu_sync_enter(struct rcu_sync *); |
92 | extern void rcu_sync_exit(struct rcu_sync *); | 58 | extern void rcu_sync_exit(struct rcu_sync *); |
93 | 59 | ||
60 | #define __RCU_SYNC_INITIALIZER(name, type) { \ | ||
61 | .gp_state = 0, \ | ||
62 | .gp_count = 0, \ | ||
63 | .gp_wait = __WAIT_QUEUE_HEAD_INITIALIZER(name.gp_wait), \ | ||
64 | .cb_state = 0, \ | ||
65 | .gp_type = type, \ | ||
66 | } | ||
67 | |||
68 | #define __DEFINE_RCU_SYNC(name, type) \ | ||
69 | struct rcu_sync_struct name = __RCU_SYNC_INITIALIZER(name, type) | ||
70 | |||
71 | #define DEFINE_RCU_SYNC(name) \ | ||
72 | __DEFINE_RCU_SYNC(name, RCU_SYNC) | ||
73 | |||
74 | #define DEFINE_RCU_SCHED_SYNC(name) \ | ||
75 | __DEFINE_RCU_SYNC(name, RCU_SCHED_SYNC) | ||
76 | |||
77 | #define DEFINE_RCU_BH_SYNC(name) \ | ||
78 | __DEFINE_RCU_SYNC(name, RCU_BH_SYNC) | ||
79 | |||
94 | #endif /* _LINUX_RCU_SYNC_H_ */ | 80 | #endif /* _LINUX_RCU_SYNC_H_ */ |
diff --git a/kernel/rcu/sync.c b/kernel/rcu/sync.c index 0a11df43be23..5a9aa4c394f1 100644 --- a/kernel/rcu/sync.c +++ b/kernel/rcu/sync.c | |||
@@ -23,6 +23,24 @@ | |||
23 | #include <linux/rcu_sync.h> | 23 | #include <linux/rcu_sync.h> |
24 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
25 | 25 | ||
26 | static const struct { | ||
27 | void (*sync)(void); | ||
28 | void (*call)(struct rcu_head *, void (*)(struct rcu_head *)); | ||
29 | } gp_ops[] = { | ||
30 | [RCU_SYNC] = { | ||
31 | .sync = synchronize_rcu, | ||
32 | .call = call_rcu, | ||
33 | }, | ||
34 | [RCU_SCHED_SYNC] = { | ||
35 | .sync = synchronize_sched, | ||
36 | .call = call_rcu_sched, | ||
37 | }, | ||
38 | [RCU_BH_SYNC] = { | ||
39 | .sync = synchronize_rcu_bh, | ||
40 | .call = call_rcu_bh, | ||
41 | }, | ||
42 | }; | ||
43 | |||
26 | enum { GP_IDLE = 0, GP_PENDING, GP_PASSED }; | 44 | enum { GP_IDLE = 0, GP_PENDING, GP_PASSED }; |
27 | enum { CB_IDLE = 0, CB_PENDING, CB_REPLAY }; | 45 | enum { CB_IDLE = 0, CB_PENDING, CB_REPLAY }; |
28 | 46 | ||
@@ -37,23 +55,7 @@ void rcu_sync_init(struct rcu_sync *rsp, enum rcu_sync_type type) | |||
37 | { | 55 | { |
38 | memset(rsp, 0, sizeof(*rsp)); | 56 | memset(rsp, 0, sizeof(*rsp)); |
39 | init_waitqueue_head(&rsp->gp_wait); | 57 | init_waitqueue_head(&rsp->gp_wait); |
40 | 58 | rsp->gp_type = type; | |
41 | switch (type) { | ||
42 | case RCU_SYNC: | ||
43 | rsp->sync = synchronize_rcu; | ||
44 | rsp->call = call_rcu; | ||
45 | break; | ||
46 | |||
47 | case RCU_SCHED_SYNC: | ||
48 | rsp->sync = synchronize_sched; | ||
49 | rsp->call = call_rcu_sched; | ||
50 | break; | ||
51 | |||
52 | case RCU_BH_SYNC: | ||
53 | rsp->sync = synchronize_rcu_bh; | ||
54 | rsp->call = call_rcu_bh; | ||
55 | break; | ||
56 | } | ||
57 | } | 59 | } |
58 | 60 | ||
59 | /** | 61 | /** |
@@ -85,7 +87,7 @@ void rcu_sync_enter(struct rcu_sync *rsp) | |||
85 | BUG_ON(need_wait && need_sync); | 87 | BUG_ON(need_wait && need_sync); |
86 | 88 | ||
87 | if (need_sync) { | 89 | if (need_sync) { |
88 | rsp->sync(); | 90 | gp_ops[rsp->gp_type].sync(); |
89 | rsp->gp_state = GP_PASSED; | 91 | rsp->gp_state = GP_PASSED; |
90 | wake_up_all(&rsp->gp_wait); | 92 | wake_up_all(&rsp->gp_wait); |
91 | } else if (need_wait) { | 93 | } else if (need_wait) { |
@@ -138,7 +140,7 @@ static void rcu_sync_func(struct rcu_head *rcu) | |||
138 | * to catch a later GP. | 140 | * to catch a later GP. |
139 | */ | 141 | */ |
140 | rsp->cb_state = CB_PENDING; | 142 | rsp->cb_state = CB_PENDING; |
141 | rsp->call(&rsp->cb_head, rcu_sync_func); | 143 | gp_ops[rsp->gp_type].call(&rsp->cb_head, rcu_sync_func); |
142 | } else { | 144 | } else { |
143 | /* | 145 | /* |
144 | * We're at least a GP after rcu_sync_exit(); eveybody will now | 146 | * We're at least a GP after rcu_sync_exit(); eveybody will now |
@@ -166,7 +168,7 @@ void rcu_sync_exit(struct rcu_sync *rsp) | |||
166 | if (!--rsp->gp_count) { | 168 | if (!--rsp->gp_count) { |
167 | if (rsp->cb_state == CB_IDLE) { | 169 | if (rsp->cb_state == CB_IDLE) { |
168 | rsp->cb_state = CB_PENDING; | 170 | rsp->cb_state = CB_PENDING; |
169 | rsp->call(&rsp->cb_head, rcu_sync_func); | 171 | gp_ops[rsp->gp_type].call(&rsp->cb_head, rcu_sync_func); |
170 | } else if (rsp->cb_state == CB_PENDING) { | 172 | } else if (rsp->cb_state == CB_PENDING) { |
171 | rsp->cb_state = CB_REPLAY; | 173 | rsp->cb_state = CB_REPLAY; |
172 | } | 174 | } |