diff options
Diffstat (limited to 'net/core/net_namespace.c')
-rw-r--r-- | net/core/net_namespace.c | 18 |
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; | |||
33 | LIST_HEAD(net_namespace_list); | 33 | LIST_HEAD(net_namespace_list); |
34 | EXPORT_SYMBOL_GPL(net_namespace_list); | 34 | EXPORT_SYMBOL_GPL(net_namespace_list); |
35 | 35 | ||
36 | /* Protects net_namespace_list. Nests iside rtnl_lock() */ | ||
37 | DECLARE_RWSEM(net_rwsem); | ||
38 | EXPORT_SYMBOL_GPL(net_rwsem); | ||
39 | |||
36 | struct net init_net = { | 40 | struct 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); |
315 | out: | 319 | out: |
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); |