diff options
-rw-r--r-- | include/linux/rtnetlink.h | 2 | ||||
-rw-r--r-- | include/net/net_namespace.h | 12 | ||||
-rw-r--r-- | net/core/net_namespace.c | 40 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 4 |
4 files changed, 30 insertions, 28 deletions
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 562a175c35a9..c7d1e4689325 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h | |||
@@ -36,7 +36,7 @@ extern int rtnl_is_locked(void); | |||
36 | extern int rtnl_lock_killable(void); | 36 | extern int rtnl_lock_killable(void); |
37 | 37 | ||
38 | extern wait_queue_head_t netdev_unregistering_wq; | 38 | extern wait_queue_head_t netdev_unregistering_wq; |
39 | extern struct rw_semaphore net_sem; | 39 | extern struct rw_semaphore pernet_ops_rwsem; |
40 | 40 | ||
41 | #ifdef CONFIG_PROVE_LOCKING | 41 | #ifdef CONFIG_PROVE_LOCKING |
42 | extern bool lockdep_rtnl_is_held(void); | 42 | extern bool lockdep_rtnl_is_held(void); |
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 37bcf8382b61..922e8b6fb422 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h | |||
@@ -60,9 +60,10 @@ struct net { | |||
60 | 60 | ||
61 | struct list_head list; /* list of network namespaces */ | 61 | struct list_head list; /* list of network namespaces */ |
62 | struct list_head exit_list; /* To linked to call pernet exit | 62 | struct list_head exit_list; /* To linked to call pernet exit |
63 | * methods on dead net (net_sem | 63 | * methods on dead net ( |
64 | * read locked), or to unregister | 64 | * pernet_ops_rwsem read locked), |
65 | * pernet ops (net_sem wr locked). | 65 | * or to unregister pernet ops |
66 | * (pernet_ops_rwsem write locked). | ||
66 | */ | 67 | */ |
67 | struct llist_node cleanup_list; /* namespaces on death row */ | 68 | struct llist_node cleanup_list; /* namespaces on death row */ |
68 | 69 | ||
@@ -95,8 +96,9 @@ struct net { | |||
95 | /* core fib_rules */ | 96 | /* core fib_rules */ |
96 | struct list_head rules_ops; | 97 | struct list_head rules_ops; |
97 | 98 | ||
98 | struct list_head fib_notifier_ops; /* protected by net_sem */ | 99 | struct list_head fib_notifier_ops; /* Populated by |
99 | 100 | * register_pernet_subsys() | |
101 | */ | ||
100 | struct net_device *loopback_dev; /* The loopback */ | 102 | struct net_device *loopback_dev; /* The loopback */ |
101 | struct netns_core core; | 103 | struct netns_core core; |
102 | struct netns_mib mib; | 104 | struct netns_mib mib; |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index eef17ad29dea..9e8ee4640451 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
@@ -41,10 +41,10 @@ EXPORT_SYMBOL(init_net); | |||
41 | 41 | ||
42 | static bool init_net_initialized; | 42 | static bool init_net_initialized; |
43 | /* | 43 | /* |
44 | * net_sem: protects: pernet_list, net_generic_ids, | 44 | * pernet_ops_rwsem: protects: pernet_list, net_generic_ids, |
45 | * init_net_initialized and first_device pointer. | 45 | * init_net_initialized and first_device pointer. |
46 | */ | 46 | */ |
47 | DECLARE_RWSEM(net_sem); | 47 | DECLARE_RWSEM(pernet_ops_rwsem); |
48 | 48 | ||
49 | #define MIN_PERNET_OPS_ID \ | 49 | #define MIN_PERNET_OPS_ID \ |
50 | ((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *)) | 50 | ((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *)) |
@@ -72,7 +72,7 @@ static int net_assign_generic(struct net *net, unsigned int id, void *data) | |||
72 | BUG_ON(id < MIN_PERNET_OPS_ID); | 72 | BUG_ON(id < MIN_PERNET_OPS_ID); |
73 | 73 | ||
74 | old_ng = rcu_dereference_protected(net->gen, | 74 | old_ng = rcu_dereference_protected(net->gen, |
75 | lockdep_is_held(&net_sem)); | 75 | lockdep_is_held(&pernet_ops_rwsem)); |
76 | if (old_ng->s.len > id) { | 76 | if (old_ng->s.len > id) { |
77 | old_ng->ptr[id] = data; | 77 | old_ng->ptr[id] = data; |
78 | return 0; | 78 | return 0; |
@@ -289,7 +289,7 @@ struct net *get_net_ns_by_id(struct net *net, int id) | |||
289 | */ | 289 | */ |
290 | static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) | 290 | static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) |
291 | { | 291 | { |
292 | /* Must be called with net_sem held */ | 292 | /* Must be called with pernet_ops_rwsem held */ |
293 | const struct pernet_operations *ops, *saved_ops; | 293 | const struct pernet_operations *ops, *saved_ops; |
294 | int error = 0; | 294 | int error = 0; |
295 | LIST_HEAD(net_exit_list); | 295 | LIST_HEAD(net_exit_list); |
@@ -422,13 +422,13 @@ struct net *copy_net_ns(unsigned long flags, | |||
422 | net->ucounts = ucounts; | 422 | net->ucounts = ucounts; |
423 | get_user_ns(user_ns); | 423 | get_user_ns(user_ns); |
424 | 424 | ||
425 | rv = down_read_killable(&net_sem); | 425 | rv = down_read_killable(&pernet_ops_rwsem); |
426 | if (rv < 0) | 426 | if (rv < 0) |
427 | goto put_userns; | 427 | goto put_userns; |
428 | 428 | ||
429 | rv = setup_net(net, user_ns); | 429 | rv = setup_net(net, user_ns); |
430 | 430 | ||
431 | up_read(&net_sem); | 431 | up_read(&pernet_ops_rwsem); |
432 | 432 | ||
433 | if (rv < 0) { | 433 | if (rv < 0) { |
434 | put_userns: | 434 | put_userns: |
@@ -480,7 +480,7 @@ static void cleanup_net(struct work_struct *work) | |||
480 | /* Atomically snapshot the list of namespaces to cleanup */ | 480 | /* Atomically snapshot the list of namespaces to cleanup */ |
481 | net_kill_list = llist_del_all(&cleanup_list); | 481 | net_kill_list = llist_del_all(&cleanup_list); |
482 | 482 | ||
483 | down_read(&net_sem); | 483 | down_read(&pernet_ops_rwsem); |
484 | 484 | ||
485 | /* Don't let anyone else find us. */ | 485 | /* Don't let anyone else find us. */ |
486 | rtnl_lock(); | 486 | rtnl_lock(); |
@@ -519,7 +519,7 @@ static void cleanup_net(struct work_struct *work) | |||
519 | list_for_each_entry_reverse(ops, &pernet_list, list) | 519 | list_for_each_entry_reverse(ops, &pernet_list, list) |
520 | ops_free_list(ops, &net_exit_list); | 520 | ops_free_list(ops, &net_exit_list); |
521 | 521 | ||
522 | up_read(&net_sem); | 522 | up_read(&pernet_ops_rwsem); |
523 | 523 | ||
524 | /* Ensure there are no outstanding rcu callbacks using this | 524 | /* Ensure there are no outstanding rcu callbacks using this |
525 | * network namespace. | 525 | * network namespace. |
@@ -546,8 +546,8 @@ static void cleanup_net(struct work_struct *work) | |||
546 | */ | 546 | */ |
547 | void net_ns_barrier(void) | 547 | void net_ns_barrier(void) |
548 | { | 548 | { |
549 | down_write(&net_sem); | 549 | down_write(&pernet_ops_rwsem); |
550 | up_write(&net_sem); | 550 | up_write(&pernet_ops_rwsem); |
551 | } | 551 | } |
552 | EXPORT_SYMBOL(net_ns_barrier); | 552 | EXPORT_SYMBOL(net_ns_barrier); |
553 | 553 | ||
@@ -869,12 +869,12 @@ static int __init net_ns_init(void) | |||
869 | 869 | ||
870 | rcu_assign_pointer(init_net.gen, ng); | 870 | rcu_assign_pointer(init_net.gen, ng); |
871 | 871 | ||
872 | down_write(&net_sem); | 872 | down_write(&pernet_ops_rwsem); |
873 | if (setup_net(&init_net, &init_user_ns)) | 873 | if (setup_net(&init_net, &init_user_ns)) |
874 | panic("Could not setup the initial network namespace"); | 874 | panic("Could not setup the initial network namespace"); |
875 | 875 | ||
876 | init_net_initialized = true; | 876 | init_net_initialized = true; |
877 | up_write(&net_sem); | 877 | up_write(&pernet_ops_rwsem); |
878 | 878 | ||
879 | register_pernet_subsys(&net_ns_ops); | 879 | register_pernet_subsys(&net_ns_ops); |
880 | 880 | ||
@@ -1013,9 +1013,9 @@ static void unregister_pernet_operations(struct pernet_operations *ops) | |||
1013 | int register_pernet_subsys(struct pernet_operations *ops) | 1013 | int register_pernet_subsys(struct pernet_operations *ops) |
1014 | { | 1014 | { |
1015 | int error; | 1015 | int error; |
1016 | down_write(&net_sem); | 1016 | down_write(&pernet_ops_rwsem); |
1017 | error = register_pernet_operations(first_device, ops); | 1017 | error = register_pernet_operations(first_device, ops); |
1018 | up_write(&net_sem); | 1018 | up_write(&pernet_ops_rwsem); |
1019 | return error; | 1019 | return error; |
1020 | } | 1020 | } |
1021 | EXPORT_SYMBOL_GPL(register_pernet_subsys); | 1021 | EXPORT_SYMBOL_GPL(register_pernet_subsys); |
@@ -1031,9 +1031,9 @@ EXPORT_SYMBOL_GPL(register_pernet_subsys); | |||
1031 | */ | 1031 | */ |
1032 | void unregister_pernet_subsys(struct pernet_operations *ops) | 1032 | void unregister_pernet_subsys(struct pernet_operations *ops) |
1033 | { | 1033 | { |
1034 | down_write(&net_sem); | 1034 | down_write(&pernet_ops_rwsem); |
1035 | unregister_pernet_operations(ops); | 1035 | unregister_pernet_operations(ops); |
1036 | up_write(&net_sem); | 1036 | up_write(&pernet_ops_rwsem); |
1037 | } | 1037 | } |
1038 | EXPORT_SYMBOL_GPL(unregister_pernet_subsys); | 1038 | EXPORT_SYMBOL_GPL(unregister_pernet_subsys); |
1039 | 1039 | ||
@@ -1059,11 +1059,11 @@ EXPORT_SYMBOL_GPL(unregister_pernet_subsys); | |||
1059 | int register_pernet_device(struct pernet_operations *ops) | 1059 | int register_pernet_device(struct pernet_operations *ops) |
1060 | { | 1060 | { |
1061 | int error; | 1061 | int error; |
1062 | down_write(&net_sem); | 1062 | down_write(&pernet_ops_rwsem); |
1063 | error = register_pernet_operations(&pernet_list, ops); | 1063 | error = register_pernet_operations(&pernet_list, ops); |
1064 | if (!error && (first_device == &pernet_list)) | 1064 | if (!error && (first_device == &pernet_list)) |
1065 | first_device = &ops->list; | 1065 | first_device = &ops->list; |
1066 | up_write(&net_sem); | 1066 | up_write(&pernet_ops_rwsem); |
1067 | return error; | 1067 | return error; |
1068 | } | 1068 | } |
1069 | EXPORT_SYMBOL_GPL(register_pernet_device); | 1069 | EXPORT_SYMBOL_GPL(register_pernet_device); |
@@ -1079,11 +1079,11 @@ EXPORT_SYMBOL_GPL(register_pernet_device); | |||
1079 | */ | 1079 | */ |
1080 | void unregister_pernet_device(struct pernet_operations *ops) | 1080 | void unregister_pernet_device(struct pernet_operations *ops) |
1081 | { | 1081 | { |
1082 | down_write(&net_sem); | 1082 | down_write(&pernet_ops_rwsem); |
1083 | if (&ops->list == first_device) | 1083 | if (&ops->list == first_device) |
1084 | first_device = first_device->next; | 1084 | first_device = first_device->next; |
1085 | unregister_pernet_operations(ops); | 1085 | unregister_pernet_operations(ops); |
1086 | up_write(&net_sem); | 1086 | up_write(&pernet_ops_rwsem); |
1087 | } | 1087 | } |
1088 | EXPORT_SYMBOL_GPL(unregister_pernet_device); | 1088 | EXPORT_SYMBOL_GPL(unregister_pernet_device); |
1089 | 1089 | ||
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 31438b63d4b4..73011a60434c 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -460,11 +460,11 @@ static void rtnl_lock_unregistering_all(void) | |||
460 | void rtnl_link_unregister(struct rtnl_link_ops *ops) | 460 | void rtnl_link_unregister(struct rtnl_link_ops *ops) |
461 | { | 461 | { |
462 | /* Close the race with cleanup_net() */ | 462 | /* Close the race with cleanup_net() */ |
463 | down_write(&net_sem); | 463 | down_write(&pernet_ops_rwsem); |
464 | rtnl_lock_unregistering_all(); | 464 | rtnl_lock_unregistering_all(); |
465 | __rtnl_link_unregister(ops); | 465 | __rtnl_link_unregister(ops); |
466 | rtnl_unlock(); | 466 | rtnl_unlock(); |
467 | up_write(&net_sem); | 467 | up_write(&pernet_ops_rwsem); |
468 | } | 468 | } |
469 | EXPORT_SYMBOL_GPL(rtnl_link_unregister); | 469 | EXPORT_SYMBOL_GPL(rtnl_link_unregister); |
470 | 470 | ||