diff options
Diffstat (limited to 'net/core/net_namespace.c')
-rw-r--r-- | net/core/net_namespace.c | 39 |
1 files changed, 26 insertions, 13 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 81384386f91b..e89b2b7abd36 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
@@ -41,6 +41,11 @@ struct net init_net = { | |||
41 | EXPORT_SYMBOL(init_net); | 41 | EXPORT_SYMBOL(init_net); |
42 | 42 | ||
43 | static bool init_net_initialized; | 43 | static bool init_net_initialized; |
44 | /* | ||
45 | * net_sem: protects: pernet_list, net_generic_ids, | ||
46 | * init_net_initialized and first_device pointer. | ||
47 | */ | ||
48 | DECLARE_RWSEM(net_sem); | ||
44 | 49 | ||
45 | #define MIN_PERNET_OPS_ID \ | 50 | #define MIN_PERNET_OPS_ID \ |
46 | ((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *)) | 51 | ((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *)) |
@@ -286,7 +291,7 @@ struct net *get_net_ns_by_id(struct net *net, int id) | |||
286 | */ | 291 | */ |
287 | static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) | 292 | static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) |
288 | { | 293 | { |
289 | /* Must be called with net_mutex held */ | 294 | /* Must be called with net_sem held */ |
290 | const struct pernet_operations *ops, *saved_ops; | 295 | const struct pernet_operations *ops, *saved_ops; |
291 | int error = 0; | 296 | int error = 0; |
292 | LIST_HEAD(net_exit_list); | 297 | LIST_HEAD(net_exit_list); |
@@ -418,12 +423,16 @@ struct net *copy_net_ns(unsigned long flags, | |||
418 | net->ucounts = ucounts; | 423 | net->ucounts = ucounts; |
419 | get_user_ns(user_ns); | 424 | get_user_ns(user_ns); |
420 | 425 | ||
421 | rv = mutex_lock_killable(&net_mutex); | 426 | rv = down_read_killable(&net_sem); |
422 | if (rv < 0) | 427 | if (rv < 0) |
423 | goto put_userns; | 428 | goto put_userns; |
424 | 429 | rv = mutex_lock_killable(&net_mutex); | |
430 | if (rv < 0) | ||
431 | goto up_read; | ||
425 | rv = setup_net(net, user_ns); | 432 | rv = setup_net(net, user_ns); |
426 | mutex_unlock(&net_mutex); | 433 | mutex_unlock(&net_mutex); |
434 | up_read: | ||
435 | up_read(&net_sem); | ||
427 | if (rv < 0) { | 436 | if (rv < 0) { |
428 | put_userns: | 437 | put_userns: |
429 | put_user_ns(user_ns); | 438 | put_user_ns(user_ns); |
@@ -477,6 +486,7 @@ static void cleanup_net(struct work_struct *work) | |||
477 | list_replace_init(&cleanup_list, &net_kill_list); | 486 | list_replace_init(&cleanup_list, &net_kill_list); |
478 | spin_unlock_irq(&cleanup_list_lock); | 487 | spin_unlock_irq(&cleanup_list_lock); |
479 | 488 | ||
489 | down_read(&net_sem); | ||
480 | mutex_lock(&net_mutex); | 490 | mutex_lock(&net_mutex); |
481 | 491 | ||
482 | /* Don't let anyone else find us. */ | 492 | /* Don't let anyone else find us. */ |
@@ -517,6 +527,7 @@ static void cleanup_net(struct work_struct *work) | |||
517 | ops_free_list(ops, &net_exit_list); | 527 | ops_free_list(ops, &net_exit_list); |
518 | 528 | ||
519 | mutex_unlock(&net_mutex); | 529 | mutex_unlock(&net_mutex); |
530 | up_read(&net_sem); | ||
520 | 531 | ||
521 | /* Ensure there are no outstanding rcu callbacks using this | 532 | /* Ensure there are no outstanding rcu callbacks using this |
522 | * network namespace. | 533 | * network namespace. |
@@ -543,8 +554,10 @@ static void cleanup_net(struct work_struct *work) | |||
543 | */ | 554 | */ |
544 | void net_ns_barrier(void) | 555 | void net_ns_barrier(void) |
545 | { | 556 | { |
557 | down_write(&net_sem); | ||
546 | mutex_lock(&net_mutex); | 558 | mutex_lock(&net_mutex); |
547 | mutex_unlock(&net_mutex); | 559 | mutex_unlock(&net_mutex); |
560 | up_write(&net_sem); | ||
548 | } | 561 | } |
549 | EXPORT_SYMBOL(net_ns_barrier); | 562 | EXPORT_SYMBOL(net_ns_barrier); |
550 | 563 | ||
@@ -871,12 +884,12 @@ static int __init net_ns_init(void) | |||
871 | 884 | ||
872 | rcu_assign_pointer(init_net.gen, ng); | 885 | rcu_assign_pointer(init_net.gen, ng); |
873 | 886 | ||
874 | mutex_lock(&net_mutex); | 887 | down_write(&net_sem); |
875 | if (setup_net(&init_net, &init_user_ns)) | 888 | if (setup_net(&init_net, &init_user_ns)) |
876 | panic("Could not setup the initial network namespace"); | 889 | panic("Could not setup the initial network namespace"); |
877 | 890 | ||
878 | init_net_initialized = true; | 891 | init_net_initialized = true; |
879 | mutex_unlock(&net_mutex); | 892 | up_write(&net_sem); |
880 | 893 | ||
881 | register_pernet_subsys(&net_ns_ops); | 894 | register_pernet_subsys(&net_ns_ops); |
882 | 895 | ||
@@ -1016,9 +1029,9 @@ static void unregister_pernet_operations(struct pernet_operations *ops) | |||
1016 | int register_pernet_subsys(struct pernet_operations *ops) | 1029 | int register_pernet_subsys(struct pernet_operations *ops) |
1017 | { | 1030 | { |
1018 | int error; | 1031 | int error; |
1019 | mutex_lock(&net_mutex); | 1032 | down_write(&net_sem); |
1020 | error = register_pernet_operations(first_device, ops); | 1033 | error = register_pernet_operations(first_device, ops); |
1021 | mutex_unlock(&net_mutex); | 1034 | up_write(&net_sem); |
1022 | return error; | 1035 | return error; |
1023 | } | 1036 | } |
1024 | EXPORT_SYMBOL_GPL(register_pernet_subsys); | 1037 | EXPORT_SYMBOL_GPL(register_pernet_subsys); |
@@ -1034,9 +1047,9 @@ EXPORT_SYMBOL_GPL(register_pernet_subsys); | |||
1034 | */ | 1047 | */ |
1035 | void unregister_pernet_subsys(struct pernet_operations *ops) | 1048 | void unregister_pernet_subsys(struct pernet_operations *ops) |
1036 | { | 1049 | { |
1037 | mutex_lock(&net_mutex); | 1050 | down_write(&net_sem); |
1038 | unregister_pernet_operations(ops); | 1051 | unregister_pernet_operations(ops); |
1039 | mutex_unlock(&net_mutex); | 1052 | up_write(&net_sem); |
1040 | } | 1053 | } |
1041 | EXPORT_SYMBOL_GPL(unregister_pernet_subsys); | 1054 | EXPORT_SYMBOL_GPL(unregister_pernet_subsys); |
1042 | 1055 | ||
@@ -1062,11 +1075,11 @@ EXPORT_SYMBOL_GPL(unregister_pernet_subsys); | |||
1062 | int register_pernet_device(struct pernet_operations *ops) | 1075 | int register_pernet_device(struct pernet_operations *ops) |
1063 | { | 1076 | { |
1064 | int error; | 1077 | int error; |
1065 | mutex_lock(&net_mutex); | 1078 | down_write(&net_sem); |
1066 | error = register_pernet_operations(&pernet_list, ops); | 1079 | error = register_pernet_operations(&pernet_list, ops); |
1067 | if (!error && (first_device == &pernet_list)) | 1080 | if (!error && (first_device == &pernet_list)) |
1068 | first_device = &ops->list; | 1081 | first_device = &ops->list; |
1069 | mutex_unlock(&net_mutex); | 1082 | up_write(&net_sem); |
1070 | return error; | 1083 | return error; |
1071 | } | 1084 | } |
1072 | EXPORT_SYMBOL_GPL(register_pernet_device); | 1085 | EXPORT_SYMBOL_GPL(register_pernet_device); |
@@ -1082,11 +1095,11 @@ EXPORT_SYMBOL_GPL(register_pernet_device); | |||
1082 | */ | 1095 | */ |
1083 | void unregister_pernet_device(struct pernet_operations *ops) | 1096 | void unregister_pernet_device(struct pernet_operations *ops) |
1084 | { | 1097 | { |
1085 | mutex_lock(&net_mutex); | 1098 | down_write(&net_sem); |
1086 | if (&ops->list == first_device) | 1099 | if (&ops->list == first_device) |
1087 | first_device = first_device->next; | 1100 | first_device = first_device->next; |
1088 | unregister_pernet_operations(ops); | 1101 | unregister_pernet_operations(ops); |
1089 | mutex_unlock(&net_mutex); | 1102 | up_write(&net_sem); |
1090 | } | 1103 | } |
1091 | EXPORT_SYMBOL_GPL(unregister_pernet_device); | 1104 | EXPORT_SYMBOL_GPL(unregister_pernet_device); |
1092 | 1105 | ||