diff options
author | Julian Anastasov <ja@ssi.bg> | 2013-03-22 05:46:46 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-04-01 18:23:53 -0400 |
commit | 1acb7f6761626f4834ea5ce16d8a4dd2a5dd1949 (patch) | |
tree | 0eb9257cb29c7892a4a7f8c98da8366f86c2e79f /net/netfilter | |
parent | 9be52aba7a7fdaaad82d88b2e66b0d215877a1fd (diff) |
ipvs: convert sh scheduler to rcu
Use the 3 new methods to reassign dests.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/ipvs/ip_vs_sh.c | 81 |
1 files changed, 45 insertions, 36 deletions
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c index e33126994628..55e76d8db711 100644 --- a/net/netfilter/ipvs/ip_vs_sh.c +++ b/net/netfilter/ipvs/ip_vs_sh.c | |||
@@ -53,7 +53,7 @@ | |||
53 | * IPVS SH bucket | 53 | * IPVS SH bucket |
54 | */ | 54 | */ |
55 | struct ip_vs_sh_bucket { | 55 | struct ip_vs_sh_bucket { |
56 | struct ip_vs_dest *dest; /* real server (cache) */ | 56 | struct ip_vs_dest __rcu *dest; /* real server (cache) */ |
57 | }; | 57 | }; |
58 | 58 | ||
59 | /* | 59 | /* |
@@ -66,6 +66,10 @@ struct ip_vs_sh_bucket { | |||
66 | #define IP_VS_SH_TAB_SIZE (1 << IP_VS_SH_TAB_BITS) | 66 | #define IP_VS_SH_TAB_SIZE (1 << IP_VS_SH_TAB_BITS) |
67 | #define IP_VS_SH_TAB_MASK (IP_VS_SH_TAB_SIZE - 1) | 67 | #define IP_VS_SH_TAB_MASK (IP_VS_SH_TAB_SIZE - 1) |
68 | 68 | ||
69 | struct ip_vs_sh_state { | ||
70 | struct ip_vs_sh_bucket buckets[IP_VS_SH_TAB_SIZE]; | ||
71 | struct rcu_head rcu_head; | ||
72 | }; | ||
69 | 73 | ||
70 | /* | 74 | /* |
71 | * Returns hash value for IPVS SH entry | 75 | * Returns hash value for IPVS SH entry |
@@ -87,10 +91,9 @@ static inline unsigned int ip_vs_sh_hashkey(int af, const union nf_inet_addr *ad | |||
87 | * Get ip_vs_dest associated with supplied parameters. | 91 | * Get ip_vs_dest associated with supplied parameters. |
88 | */ | 92 | */ |
89 | static inline struct ip_vs_dest * | 93 | static inline struct ip_vs_dest * |
90 | ip_vs_sh_get(int af, struct ip_vs_sh_bucket *tbl, | 94 | ip_vs_sh_get(int af, struct ip_vs_sh_state *s, const union nf_inet_addr *addr) |
91 | const union nf_inet_addr *addr) | ||
92 | { | 95 | { |
93 | return (tbl[ip_vs_sh_hashkey(af, addr)]).dest; | 96 | return rcu_dereference(s->buckets[ip_vs_sh_hashkey(af, addr)].dest); |
94 | } | 97 | } |
95 | 98 | ||
96 | 99 | ||
@@ -98,27 +101,32 @@ ip_vs_sh_get(int af, struct ip_vs_sh_bucket *tbl, | |||
98 | * Assign all the hash buckets of the specified table with the service. | 101 | * Assign all the hash buckets of the specified table with the service. |
99 | */ | 102 | */ |
100 | static int | 103 | static int |
101 | ip_vs_sh_assign(struct ip_vs_sh_bucket *tbl, struct ip_vs_service *svc) | 104 | ip_vs_sh_reassign(struct ip_vs_sh_state *s, struct ip_vs_service *svc) |
102 | { | 105 | { |
103 | int i; | 106 | int i; |
104 | struct ip_vs_sh_bucket *b; | 107 | struct ip_vs_sh_bucket *b; |
105 | struct list_head *p; | 108 | struct list_head *p; |
106 | struct ip_vs_dest *dest; | 109 | struct ip_vs_dest *dest; |
107 | int d_count; | 110 | int d_count; |
111 | bool empty; | ||
108 | 112 | ||
109 | b = tbl; | 113 | b = &s->buckets[0]; |
110 | p = &svc->destinations; | 114 | p = &svc->destinations; |
115 | empty = list_empty(p); | ||
111 | d_count = 0; | 116 | d_count = 0; |
112 | for (i=0; i<IP_VS_SH_TAB_SIZE; i++) { | 117 | for (i=0; i<IP_VS_SH_TAB_SIZE; i++) { |
113 | if (list_empty(p)) { | 118 | dest = rcu_dereference_protected(b->dest, 1); |
114 | b->dest = NULL; | 119 | if (dest) |
115 | } else { | 120 | ip_vs_dest_put(dest); |
121 | if (empty) | ||
122 | RCU_INIT_POINTER(b->dest, NULL); | ||
123 | else { | ||
116 | if (p == &svc->destinations) | 124 | if (p == &svc->destinations) |
117 | p = p->next; | 125 | p = p->next; |
118 | 126 | ||
119 | dest = list_entry(p, struct ip_vs_dest, n_list); | 127 | dest = list_entry(p, struct ip_vs_dest, n_list); |
120 | atomic_inc(&dest->refcnt); | 128 | ip_vs_dest_hold(dest); |
121 | b->dest = dest; | 129 | RCU_INIT_POINTER(b->dest, dest); |
122 | 130 | ||
123 | IP_VS_DBG_BUF(6, "assigned i: %d dest: %s weight: %d\n", | 131 | IP_VS_DBG_BUF(6, "assigned i: %d dest: %s weight: %d\n", |
124 | i, IP_VS_DBG_ADDR(svc->af, &dest->addr), | 132 | i, IP_VS_DBG_ADDR(svc->af, &dest->addr), |
@@ -140,16 +148,18 @@ ip_vs_sh_assign(struct ip_vs_sh_bucket *tbl, struct ip_vs_service *svc) | |||
140 | /* | 148 | /* |
141 | * Flush all the hash buckets of the specified table. | 149 | * Flush all the hash buckets of the specified table. |
142 | */ | 150 | */ |
143 | static void ip_vs_sh_flush(struct ip_vs_sh_bucket *tbl) | 151 | static void ip_vs_sh_flush(struct ip_vs_sh_state *s) |
144 | { | 152 | { |
145 | int i; | 153 | int i; |
146 | struct ip_vs_sh_bucket *b; | 154 | struct ip_vs_sh_bucket *b; |
155 | struct ip_vs_dest *dest; | ||
147 | 156 | ||
148 | b = tbl; | 157 | b = &s->buckets[0]; |
149 | for (i=0; i<IP_VS_SH_TAB_SIZE; i++) { | 158 | for (i=0; i<IP_VS_SH_TAB_SIZE; i++) { |
150 | if (b->dest) { | 159 | dest = rcu_dereference_protected(b->dest, 1); |
151 | atomic_dec(&b->dest->refcnt); | 160 | if (dest) { |
152 | b->dest = NULL; | 161 | ip_vs_dest_put(dest); |
162 | RCU_INIT_POINTER(b->dest, NULL); | ||
153 | } | 163 | } |
154 | b++; | 164 | b++; |
155 | } | 165 | } |
@@ -158,21 +168,20 @@ static void ip_vs_sh_flush(struct ip_vs_sh_bucket *tbl) | |||
158 | 168 | ||
159 | static int ip_vs_sh_init_svc(struct ip_vs_service *svc) | 169 | static int ip_vs_sh_init_svc(struct ip_vs_service *svc) |
160 | { | 170 | { |
161 | struct ip_vs_sh_bucket *tbl; | 171 | struct ip_vs_sh_state *s; |
162 | 172 | ||
163 | /* allocate the SH table for this service */ | 173 | /* allocate the SH table for this service */ |
164 | tbl = kmalloc(sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE, | 174 | s = kzalloc(sizeof(struct ip_vs_sh_state), GFP_KERNEL); |
165 | GFP_KERNEL); | 175 | if (s == NULL) |
166 | if (tbl == NULL) | ||
167 | return -ENOMEM; | 176 | return -ENOMEM; |
168 | 177 | ||
169 | svc->sched_data = tbl; | 178 | svc->sched_data = s; |
170 | IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) allocated for " | 179 | IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) allocated for " |
171 | "current service\n", | 180 | "current service\n", |
172 | sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE); | 181 | sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE); |
173 | 182 | ||
174 | /* assign the hash buckets with the updated service */ | 183 | /* assign the hash buckets with current dests */ |
175 | ip_vs_sh_assign(tbl, svc); | 184 | ip_vs_sh_reassign(s, svc); |
176 | 185 | ||
177 | return 0; | 186 | return 0; |
178 | } | 187 | } |
@@ -180,13 +189,13 @@ static int ip_vs_sh_init_svc(struct ip_vs_service *svc) | |||
180 | 189 | ||
181 | static int ip_vs_sh_done_svc(struct ip_vs_service *svc) | 190 | static int ip_vs_sh_done_svc(struct ip_vs_service *svc) |
182 | { | 191 | { |
183 | struct ip_vs_sh_bucket *tbl = svc->sched_data; | 192 | struct ip_vs_sh_state *s = svc->sched_data; |
184 | 193 | ||
185 | /* got to clean up hash buckets here */ | 194 | /* got to clean up hash buckets here */ |
186 | ip_vs_sh_flush(tbl); | 195 | ip_vs_sh_flush(s); |
187 | 196 | ||
188 | /* release the table itself */ | 197 | /* release the table itself */ |
189 | kfree(svc->sched_data); | 198 | kfree_rcu(s, rcu_head); |
190 | IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) released\n", | 199 | IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) released\n", |
191 | sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE); | 200 | sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE); |
192 | 201 | ||
@@ -194,15 +203,13 @@ static int ip_vs_sh_done_svc(struct ip_vs_service *svc) | |||
194 | } | 203 | } |
195 | 204 | ||
196 | 205 | ||
197 | static int ip_vs_sh_update_svc(struct ip_vs_service *svc) | 206 | static int ip_vs_sh_dest_changed(struct ip_vs_service *svc, |
207 | struct ip_vs_dest *dest) | ||
198 | { | 208 | { |
199 | struct ip_vs_sh_bucket *tbl = svc->sched_data; | 209 | struct ip_vs_sh_state *s = svc->sched_data; |
200 | |||
201 | /* got to clean up hash buckets here */ | ||
202 | ip_vs_sh_flush(tbl); | ||
203 | 210 | ||
204 | /* assign the hash buckets with the updated service */ | 211 | /* assign the hash buckets with the updated service */ |
205 | ip_vs_sh_assign(tbl, svc); | 212 | ip_vs_sh_reassign(s, svc); |
206 | 213 | ||
207 | return 0; | 214 | return 0; |
208 | } | 215 | } |
@@ -225,15 +232,15 @@ static struct ip_vs_dest * | |||
225 | ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) | 232 | ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) |
226 | { | 233 | { |
227 | struct ip_vs_dest *dest; | 234 | struct ip_vs_dest *dest; |
228 | struct ip_vs_sh_bucket *tbl; | 235 | struct ip_vs_sh_state *s; |
229 | struct ip_vs_iphdr iph; | 236 | struct ip_vs_iphdr iph; |
230 | 237 | ||
231 | ip_vs_fill_iph_addr_only(svc->af, skb, &iph); | 238 | ip_vs_fill_iph_addr_only(svc->af, skb, &iph); |
232 | 239 | ||
233 | IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n"); | 240 | IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n"); |
234 | 241 | ||
235 | tbl = (struct ip_vs_sh_bucket *)svc->sched_data; | 242 | s = (struct ip_vs_sh_state *) svc->sched_data; |
236 | dest = ip_vs_sh_get(svc->af, tbl, &iph.saddr); | 243 | dest = ip_vs_sh_get(svc->af, s, &iph.saddr); |
237 | if (!dest | 244 | if (!dest |
238 | || !(dest->flags & IP_VS_DEST_F_AVAILABLE) | 245 | || !(dest->flags & IP_VS_DEST_F_AVAILABLE) |
239 | || atomic_read(&dest->weight) <= 0 | 246 | || atomic_read(&dest->weight) <= 0 |
@@ -262,7 +269,9 @@ static struct ip_vs_scheduler ip_vs_sh_scheduler = | |||
262 | .n_list = LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list), | 269 | .n_list = LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list), |
263 | .init_service = ip_vs_sh_init_svc, | 270 | .init_service = ip_vs_sh_init_svc, |
264 | .done_service = ip_vs_sh_done_svc, | 271 | .done_service = ip_vs_sh_done_svc, |
265 | .update_service = ip_vs_sh_update_svc, | 272 | .add_dest = ip_vs_sh_dest_changed, |
273 | .del_dest = ip_vs_sh_dest_changed, | ||
274 | .upd_dest = ip_vs_sh_dest_changed, | ||
266 | .schedule = ip_vs_sh_schedule, | 275 | .schedule = ip_vs_sh_schedule, |
267 | }; | 276 | }; |
268 | 277 | ||