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>

authored by Alexey Dobriyan and committed by David S. Miller 485ac57b ad1d967c

+34
+2
include/net/net_namespace.h
··· 214 214 215 215 extern int register_pernet_subsys(struct pernet_operations *); 216 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 219 extern int register_pernet_device(struct pernet_operations *); 218 220 extern void unregister_pernet_device(struct pernet_operations *); 219 221 extern int register_pernet_gen_device(int *id, struct pernet_operations *);
+32
net/core/net_namespace.c
··· 325 325 } 326 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 361 * register_pernet_device - register a network namespace device 330 362 * @ops: pernet operations structure for the subsystem