diff options
author | Patrick McHardy <kaber@trash.net> | 2007-03-14 19:37:52 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:25:39 -0400 |
commit | b19caa0ca071dce76b0e81e957e7eb7c03d72cf5 (patch) | |
tree | baf307a4daa2c63ccc451d6dbcd47f55945aea9a /net | |
parent | 587aa64163bb14f70098f450abab9410787fce9d (diff) |
[NETFILTER]: nf_conntrack: switch protocol registration/unregistration to mutex
The protocol lookups done by nf_conntrack are already protected by RCU,
there is no need to keep taking nf_conntrack_lock for registration
and unregistration. Switch to a mutex.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_conntrack_proto.c | 52 |
1 files changed, 23 insertions, 29 deletions
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 456155f05c75..e2c4a58603a8 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -32,9 +32,9 @@ struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; | |||
32 | struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; | 32 | struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; |
33 | EXPORT_SYMBOL_GPL(nf_ct_l3protos); | 33 | EXPORT_SYMBOL_GPL(nf_ct_l3protos); |
34 | 34 | ||
35 | #ifdef CONFIG_SYSCTL | 35 | static DEFINE_MUTEX(nf_ct_proto_mutex); |
36 | static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex); | ||
37 | 36 | ||
37 | #ifdef CONFIG_SYSCTL | ||
38 | static int | 38 | static int |
39 | nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path, | 39 | nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path, |
40 | struct ctl_table *table, unsigned int *users) | 40 | struct ctl_table *table, unsigned int *users) |
@@ -164,13 +164,13 @@ static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) | |||
164 | int err = 0; | 164 | int err = 0; |
165 | 165 | ||
166 | #ifdef CONFIG_SYSCTL | 166 | #ifdef CONFIG_SYSCTL |
167 | mutex_lock(&nf_ct_proto_sysctl_mutex); | 167 | mutex_lock(&nf_ct_proto_mutex); |
168 | if (l3proto->ctl_table != NULL) { | 168 | if (l3proto->ctl_table != NULL) { |
169 | err = nf_ct_register_sysctl(&l3proto->ctl_table_header, | 169 | err = nf_ct_register_sysctl(&l3proto->ctl_table_header, |
170 | l3proto->ctl_table_path, | 170 | l3proto->ctl_table_path, |
171 | l3proto->ctl_table, NULL); | 171 | l3proto->ctl_table, NULL); |
172 | } | 172 | } |
173 | mutex_unlock(&nf_ct_proto_sysctl_mutex); | 173 | mutex_unlock(&nf_ct_proto_mutex); |
174 | #endif | 174 | #endif |
175 | return err; | 175 | return err; |
176 | } | 176 | } |
@@ -178,11 +178,11 @@ static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) | |||
178 | static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) | 178 | static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) |
179 | { | 179 | { |
180 | #ifdef CONFIG_SYSCTL | 180 | #ifdef CONFIG_SYSCTL |
181 | mutex_lock(&nf_ct_proto_sysctl_mutex); | 181 | mutex_lock(&nf_ct_proto_mutex); |
182 | if (l3proto->ctl_table_header != NULL) | 182 | if (l3proto->ctl_table_header != NULL) |
183 | nf_ct_unregister_sysctl(&l3proto->ctl_table_header, | 183 | nf_ct_unregister_sysctl(&l3proto->ctl_table_header, |
184 | l3proto->ctl_table, NULL); | 184 | l3proto->ctl_table, NULL); |
185 | mutex_unlock(&nf_ct_proto_sysctl_mutex); | 185 | mutex_unlock(&nf_ct_proto_mutex); |
186 | #endif | 186 | #endif |
187 | } | 187 | } |
188 | 188 | ||
@@ -195,13 +195,13 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | |||
195 | goto out; | 195 | goto out; |
196 | } | 196 | } |
197 | 197 | ||
198 | write_lock_bh(&nf_conntrack_lock); | 198 | mutex_lock(&nf_ct_proto_mutex); |
199 | if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { | 199 | if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { |
200 | ret = -EBUSY; | 200 | ret = -EBUSY; |
201 | goto out_unlock; | 201 | goto out_unlock; |
202 | } | 202 | } |
203 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); | 203 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); |
204 | write_unlock_bh(&nf_conntrack_lock); | 204 | mutex_unlock(&nf_ct_proto_mutex); |
205 | 205 | ||
206 | ret = nf_ct_l3proto_register_sysctl(proto); | 206 | ret = nf_ct_l3proto_register_sysctl(proto); |
207 | if (ret < 0) | 207 | if (ret < 0) |
@@ -209,7 +209,7 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | |||
209 | return ret; | 209 | return ret; |
210 | 210 | ||
211 | out_unlock: | 211 | out_unlock: |
212 | write_unlock_bh(&nf_conntrack_lock); | 212 | mutex_unlock(&nf_ct_proto_mutex); |
213 | out: | 213 | out: |
214 | return ret; | 214 | return ret; |
215 | } | 215 | } |
@@ -219,11 +219,11 @@ void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) | |||
219 | { | 219 | { |
220 | BUG_ON(proto->l3proto >= AF_MAX); | 220 | BUG_ON(proto->l3proto >= AF_MAX); |
221 | 221 | ||
222 | write_lock_bh(&nf_conntrack_lock); | 222 | mutex_lock(&nf_ct_proto_mutex); |
223 | BUG_ON(nf_ct_l3protos[proto->l3proto] != proto); | 223 | BUG_ON(nf_ct_l3protos[proto->l3proto] != proto); |
224 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], | 224 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], |
225 | &nf_conntrack_l3proto_generic); | 225 | &nf_conntrack_l3proto_generic); |
226 | write_unlock_bh(&nf_conntrack_lock); | 226 | mutex_unlock(&nf_ct_proto_mutex); |
227 | synchronize_rcu(); | 227 | synchronize_rcu(); |
228 | 228 | ||
229 | nf_ct_l3proto_unregister_sysctl(proto); | 229 | nf_ct_l3proto_unregister_sysctl(proto); |
@@ -238,7 +238,7 @@ static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) | |||
238 | int err = 0; | 238 | int err = 0; |
239 | 239 | ||
240 | #ifdef CONFIG_SYSCTL | 240 | #ifdef CONFIG_SYSCTL |
241 | mutex_lock(&nf_ct_proto_sysctl_mutex); | 241 | mutex_lock(&nf_ct_proto_mutex); |
242 | if (l4proto->ctl_table != NULL) { | 242 | if (l4proto->ctl_table != NULL) { |
243 | err = nf_ct_register_sysctl(l4proto->ctl_table_header, | 243 | err = nf_ct_register_sysctl(l4proto->ctl_table_header, |
244 | nf_net_netfilter_sysctl_path, | 244 | nf_net_netfilter_sysctl_path, |
@@ -260,7 +260,7 @@ static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) | |||
260 | } | 260 | } |
261 | #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ | 261 | #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ |
262 | out: | 262 | out: |
263 | mutex_unlock(&nf_ct_proto_sysctl_mutex); | 263 | mutex_unlock(&nf_ct_proto_mutex); |
264 | #endif /* CONFIG_SYSCTL */ | 264 | #endif /* CONFIG_SYSCTL */ |
265 | return err; | 265 | return err; |
266 | } | 266 | } |
@@ -268,7 +268,7 @@ out: | |||
268 | static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto) | 268 | static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto) |
269 | { | 269 | { |
270 | #ifdef CONFIG_SYSCTL | 270 | #ifdef CONFIG_SYSCTL |
271 | mutex_lock(&nf_ct_proto_sysctl_mutex); | 271 | mutex_lock(&nf_ct_proto_mutex); |
272 | if (l4proto->ctl_table_header != NULL && | 272 | if (l4proto->ctl_table_header != NULL && |
273 | *l4proto->ctl_table_header != NULL) | 273 | *l4proto->ctl_table_header != NULL) |
274 | nf_ct_unregister_sysctl(l4proto->ctl_table_header, | 274 | nf_ct_unregister_sysctl(l4proto->ctl_table_header, |
@@ -279,7 +279,7 @@ static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto | |||
279 | nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header, | 279 | nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header, |
280 | l4proto->ctl_compat_table, NULL); | 280 | l4proto->ctl_compat_table, NULL); |
281 | #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ | 281 | #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ |
282 | mutex_unlock(&nf_ct_proto_sysctl_mutex); | 282 | mutex_unlock(&nf_ct_proto_mutex); |
283 | #endif /* CONFIG_SYSCTL */ | 283 | #endif /* CONFIG_SYSCTL */ |
284 | } | 284 | } |
285 | 285 | ||
@@ -297,8 +297,8 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) | |||
297 | if (l4proto == &nf_conntrack_l4proto_generic) | 297 | if (l4proto == &nf_conntrack_l4proto_generic) |
298 | return nf_ct_l4proto_register_sysctl(l4proto); | 298 | return nf_ct_l4proto_register_sysctl(l4proto); |
299 | 299 | ||
300 | mutex_lock(&nf_ct_proto_mutex); | ||
300 | retry: | 301 | retry: |
301 | write_lock_bh(&nf_conntrack_lock); | ||
302 | if (nf_ct_protos[l4proto->l3proto]) { | 302 | if (nf_ct_protos[l4proto->l3proto]) { |
303 | if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] | 303 | if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] |
304 | != &nf_conntrack_l4proto_generic) { | 304 | != &nf_conntrack_l4proto_generic) { |
@@ -310,28 +310,22 @@ retry: | |||
310 | struct nf_conntrack_l4proto **proto_array; | 310 | struct nf_conntrack_l4proto **proto_array; |
311 | int i; | 311 | int i; |
312 | 312 | ||
313 | write_unlock_bh(&nf_conntrack_lock); | ||
314 | |||
315 | proto_array = (struct nf_conntrack_l4proto **) | 313 | proto_array = (struct nf_conntrack_l4proto **) |
316 | kmalloc(MAX_NF_CT_PROTO * | 314 | kmalloc(MAX_NF_CT_PROTO * |
317 | sizeof(struct nf_conntrack_l4proto *), | 315 | sizeof(struct nf_conntrack_l4proto *), |
318 | GFP_KERNEL); | 316 | GFP_KERNEL); |
319 | if (proto_array == NULL) { | 317 | if (proto_array == NULL) { |
320 | ret = -ENOMEM; | 318 | ret = -ENOMEM; |
321 | goto out; | 319 | goto out_unlock; |
322 | } | 320 | } |
323 | for (i = 0; i < MAX_NF_CT_PROTO; i++) | 321 | for (i = 0; i < MAX_NF_CT_PROTO; i++) |
324 | proto_array[i] = &nf_conntrack_l4proto_generic; | 322 | proto_array[i] = &nf_conntrack_l4proto_generic; |
325 | 323 | ||
326 | write_lock_bh(&nf_conntrack_lock); | 324 | if (nf_ct_protos[l4proto->l3proto]) |
327 | if (nf_ct_protos[l4proto->l3proto]) { | ||
328 | /* bad timing, but no problem */ | 325 | /* bad timing, but no problem */ |
329 | write_unlock_bh(&nf_conntrack_lock); | ||
330 | kfree(proto_array); | 326 | kfree(proto_array); |
331 | } else { | 327 | else |
332 | nf_ct_protos[l4proto->l3proto] = proto_array; | 328 | nf_ct_protos[l4proto->l3proto] = proto_array; |
333 | write_unlock_bh(&nf_conntrack_lock); | ||
334 | } | ||
335 | 329 | ||
336 | /* | 330 | /* |
337 | * Just once because array is never freed until unloading | 331 | * Just once because array is never freed until unloading |
@@ -341,7 +335,7 @@ retry: | |||
341 | } | 335 | } |
342 | 336 | ||
343 | rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], l4proto); | 337 | rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], l4proto); |
344 | write_unlock_bh(&nf_conntrack_lock); | 338 | mutex_unlock(&nf_ct_proto_mutex); |
345 | 339 | ||
346 | ret = nf_ct_l4proto_register_sysctl(l4proto); | 340 | ret = nf_ct_l4proto_register_sysctl(l4proto); |
347 | if (ret < 0) | 341 | if (ret < 0) |
@@ -349,7 +343,7 @@ retry: | |||
349 | return ret; | 343 | return ret; |
350 | 344 | ||
351 | out_unlock: | 345 | out_unlock: |
352 | write_unlock_bh(&nf_conntrack_lock); | 346 | mutex_unlock(&nf_ct_proto_mutex); |
353 | out: | 347 | out: |
354 | return ret; | 348 | return ret; |
355 | } | 349 | } |
@@ -364,11 +358,11 @@ void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto) | |||
364 | return; | 358 | return; |
365 | } | 359 | } |
366 | 360 | ||
367 | write_lock_bh(&nf_conntrack_lock); | 361 | mutex_lock(&nf_ct_proto_mutex); |
368 | BUG_ON(nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != l4proto); | 362 | BUG_ON(nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != l4proto); |
369 | rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], | 363 | rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], |
370 | &nf_conntrack_l4proto_generic); | 364 | &nf_conntrack_l4proto_generic); |
371 | write_unlock_bh(&nf_conntrack_lock); | 365 | mutex_unlock(&nf_ct_proto_mutex); |
372 | synchronize_rcu(); | 366 | synchronize_rcu(); |
373 | 367 | ||
374 | nf_ct_l4proto_unregister_sysctl(l4proto); | 368 | nf_ct_l4proto_unregister_sysctl(l4proto); |