aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/net_namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/net_namespace.c')
-rw-r--r--net/core/net_namespace.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index b5796d17a302..7fdf321d4997 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -33,6 +33,10 @@ static struct list_head *first_device = &pernet_list;
33LIST_HEAD(net_namespace_list); 33LIST_HEAD(net_namespace_list);
34EXPORT_SYMBOL_GPL(net_namespace_list); 34EXPORT_SYMBOL_GPL(net_namespace_list);
35 35
36/* Protects net_namespace_list. Nests iside rtnl_lock() */
37DECLARE_RWSEM(net_rwsem);
38EXPORT_SYMBOL_GPL(net_rwsem);
39
36struct net init_net = { 40struct net init_net = {
37 .count = REFCOUNT_INIT(1), 41 .count = REFCOUNT_INIT(1),
38 .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head), 42 .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head),
@@ -309,9 +313,9 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
309 if (error < 0) 313 if (error < 0)
310 goto out_undo; 314 goto out_undo;
311 } 315 }
312 rtnl_lock(); 316 down_write(&net_rwsem);
313 list_add_tail_rcu(&net->list, &net_namespace_list); 317 list_add_tail_rcu(&net->list, &net_namespace_list);
314 rtnl_unlock(); 318 up_write(&net_rwsem);
315out: 319out:
316 return error; 320 return error;
317 321
@@ -450,7 +454,7 @@ static void unhash_nsid(struct net *net, struct net *last)
450 * and this work is the only process, that may delete 454 * and this work is the only process, that may delete
451 * a net from net_namespace_list. So, when the below 455 * a net from net_namespace_list. So, when the below
452 * is executing, the list may only grow. Thus, we do not 456 * is executing, the list may only grow. Thus, we do not
453 * use for_each_net_rcu() or rtnl_lock(). 457 * use for_each_net_rcu() or net_rwsem.
454 */ 458 */
455 for_each_net(tmp) { 459 for_each_net(tmp) {
456 int id; 460 int id;
@@ -485,7 +489,7 @@ static void cleanup_net(struct work_struct *work)
485 down_read(&pernet_ops_rwsem); 489 down_read(&pernet_ops_rwsem);
486 490
487 /* Don't let anyone else find us. */ 491 /* Don't let anyone else find us. */
488 rtnl_lock(); 492 down_write(&net_rwsem);
489 llist_for_each_entry(net, net_kill_list, cleanup_list) 493 llist_for_each_entry(net, net_kill_list, cleanup_list)
490 list_del_rcu(&net->list); 494 list_del_rcu(&net->list);
491 /* Cache last net. After we unlock rtnl, no one new net 495 /* Cache last net. After we unlock rtnl, no one new net
@@ -499,7 +503,7 @@ static void cleanup_net(struct work_struct *work)
499 * useless anyway, as netns_ids are destroyed there. 503 * useless anyway, as netns_ids are destroyed there.
500 */ 504 */
501 last = list_last_entry(&net_namespace_list, struct net, list); 505 last = list_last_entry(&net_namespace_list, struct net, list);
502 rtnl_unlock(); 506 up_write(&net_rwsem);
503 507
504 llist_for_each_entry(net, net_kill_list, cleanup_list) { 508 llist_for_each_entry(net, net_kill_list, cleanup_list) {
505 unhash_nsid(net, last); 509 unhash_nsid(net, last);
@@ -900,6 +904,9 @@ static int __register_pernet_operations(struct list_head *list,
900 904
901 list_add_tail(&ops->list, list); 905 list_add_tail(&ops->list, list);
902 if (ops->init || (ops->id && ops->size)) { 906 if (ops->init || (ops->id && ops->size)) {
907 /* We held write locked pernet_ops_rwsem, and parallel
908 * setup_net() and cleanup_net() are not possible.
909 */
903 for_each_net(net) { 910 for_each_net(net) {
904 error = ops_init(ops, net); 911 error = ops_init(ops, net);
905 if (error) 912 if (error)
@@ -923,6 +930,7 @@ static void __unregister_pernet_operations(struct pernet_operations *ops)
923 LIST_HEAD(net_exit_list); 930 LIST_HEAD(net_exit_list);
924 931
925 list_del(&ops->list); 932 list_del(&ops->list);
933 /* See comment in __register_pernet_operations() */
926 for_each_net(net) 934 for_each_net(net)
927 list_add_tail(&net->exit_list, &net_exit_list); 935 list_add_tail(&net->exit_list, &net_exit_list);
928 ops_exit_list(ops, &net_exit_list); 936 ops_exit_list(ops, &net_exit_list);