diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2008-10-31 02:55:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-10-31 02:55:16 -0400 |
commit | 485ac57bc1238719b1508f91b0f9eeda4a3c84bb (patch) | |
tree | daa4c6fde9255c7d3a2a1add5c8c78b418d5e81e | |
parent | ad1d967c88e349c7e822ad75dd3247a2a50d2ea3 (diff) |
netns: add register_pernet_gen_subsys/unregister_pernet_gen_subsys
netns ops which are registered with register_pernet_gen_device() are
shutdown strictly before those which are registered with
register_pernet_subsys(). Sometimes this leads to opposite (read: buggy)
shutdown ordering between two modules.
Add register_pernet_gen_subsys()/unregister_pernet_gen_subsys() for modules
which aren't elite enough for entry in struct net, and which can't use
register_pernet_gen_device(). PPTP conntracking module is such one.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/net_namespace.h | 2 | ||||
-rw-r--r-- | net/core/net_namespace.c | 32 |
2 files changed, 34 insertions, 0 deletions
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 708009be88b6..700c53a3c6fa 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h | |||
@@ -214,6 +214,8 @@ struct pernet_operations { | |||
214 | 214 | ||
215 | extern int register_pernet_subsys(struct pernet_operations *); | 215 | extern int register_pernet_subsys(struct pernet_operations *); |
216 | extern void unregister_pernet_subsys(struct pernet_operations *); | 216 | extern void unregister_pernet_subsys(struct pernet_operations *); |
217 | extern int register_pernet_gen_subsys(int *id, struct pernet_operations *); | ||
218 | extern void unregister_pernet_gen_subsys(int id, struct pernet_operations *); | ||
217 | extern int register_pernet_device(struct pernet_operations *); | 219 | extern int register_pernet_device(struct pernet_operations *); |
218 | extern void unregister_pernet_device(struct pernet_operations *); | 220 | extern void unregister_pernet_device(struct pernet_operations *); |
219 | extern int register_pernet_gen_device(int *id, struct pernet_operations *); | 221 | extern int register_pernet_gen_device(int *id, struct pernet_operations *); |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index f1d07b5c1e17..1895a4ca9c4f 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
@@ -325,6 +325,38 @@ void unregister_pernet_subsys(struct pernet_operations *module) | |||
325 | } | 325 | } |
326 | EXPORT_SYMBOL_GPL(unregister_pernet_subsys); | 326 | EXPORT_SYMBOL_GPL(unregister_pernet_subsys); |
327 | 327 | ||
328 | int register_pernet_gen_subsys(int *id, struct pernet_operations *ops) | ||
329 | { | ||
330 | int rv; | ||
331 | |||
332 | mutex_lock(&net_mutex); | ||
333 | again: | ||
334 | rv = ida_get_new_above(&net_generic_ids, 1, id); | ||
335 | if (rv < 0) { | ||
336 | if (rv == -EAGAIN) { | ||
337 | ida_pre_get(&net_generic_ids, GFP_KERNEL); | ||
338 | goto again; | ||
339 | } | ||
340 | goto out; | ||
341 | } | ||
342 | rv = register_pernet_operations(first_device, ops); | ||
343 | if (rv < 0) | ||
344 | ida_remove(&net_generic_ids, *id); | ||
345 | mutex_unlock(&net_mutex); | ||
346 | out: | ||
347 | return rv; | ||
348 | } | ||
349 | EXPORT_SYMBOL_GPL(register_pernet_gen_subsys); | ||
350 | |||
351 | void unregister_pernet_gen_subsys(int id, struct pernet_operations *ops) | ||
352 | { | ||
353 | mutex_lock(&net_mutex); | ||
354 | unregister_pernet_operations(ops); | ||
355 | ida_remove(&net_generic_ids, id); | ||
356 | mutex_unlock(&net_mutex); | ||
357 | } | ||
358 | EXPORT_SYMBOL_GPL(unregister_pernet_gen_subsys); | ||
359 | |||
328 | /** | 360 | /** |
329 | * register_pernet_device - register a network namespace device | 361 | * register_pernet_device - register a network namespace device |
330 | * @ops: pernet operations structure for the subsystem | 362 | * @ops: pernet operations structure for the subsystem |