diff options
| -rw-r--r-- | include/net/net_namespace.h | 3 | ||||
| -rw-r--r-- | net/core/net_namespace.c | 14 |
2 files changed, 14 insertions, 3 deletions
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index ded434b032a4..b34a6ee73754 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h | |||
| @@ -208,6 +208,9 @@ static inline struct net *read_pnet(struct net * const *pnet) | |||
| 208 | #define for_each_net(VAR) \ | 208 | #define for_each_net(VAR) \ |
| 209 | list_for_each_entry(VAR, &net_namespace_list, list) | 209 | list_for_each_entry(VAR, &net_namespace_list, list) |
| 210 | 210 | ||
| 211 | #define for_each_net_rcu(VAR) \ | ||
| 212 | list_for_each_entry_rcu(VAR, &net_namespace_list, list) | ||
| 213 | |||
| 211 | #ifdef CONFIG_NET_NS | 214 | #ifdef CONFIG_NET_NS |
| 212 | #define __net_init | 215 | #define __net_init |
| 213 | #define __net_exit | 216 | #define __net_exit |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index b7292a2719dc..5cd0b22e649d 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <linux/delay.h> | 6 | #include <linux/delay.h> |
| 7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
| 8 | #include <linux/idr.h> | 8 | #include <linux/idr.h> |
| 9 | #include <linux/rculist.h> | ||
| 9 | #include <net/net_namespace.h> | 10 | #include <net/net_namespace.h> |
| 10 | #include <net/netns/generic.h> | 11 | #include <net/netns/generic.h> |
| 11 | 12 | ||
| @@ -127,7 +128,7 @@ static struct net *net_create(void) | |||
| 127 | rv = setup_net(net); | 128 | rv = setup_net(net); |
| 128 | if (rv == 0) { | 129 | if (rv == 0) { |
| 129 | rtnl_lock(); | 130 | rtnl_lock(); |
| 130 | list_add_tail(&net->list, &net_namespace_list); | 131 | list_add_tail_rcu(&net->list, &net_namespace_list); |
| 131 | rtnl_unlock(); | 132 | rtnl_unlock(); |
| 132 | } | 133 | } |
| 133 | mutex_unlock(&net_mutex); | 134 | mutex_unlock(&net_mutex); |
| @@ -156,9 +157,16 @@ static void cleanup_net(struct work_struct *work) | |||
| 156 | 157 | ||
| 157 | /* Don't let anyone else find us. */ | 158 | /* Don't let anyone else find us. */ |
| 158 | rtnl_lock(); | 159 | rtnl_lock(); |
| 159 | list_del(&net->list); | 160 | list_del_rcu(&net->list); |
| 160 | rtnl_unlock(); | 161 | rtnl_unlock(); |
| 161 | 162 | ||
| 163 | /* | ||
| 164 | * Another CPU might be rcu-iterating the list, wait for it. | ||
| 165 | * This needs to be before calling the exit() notifiers, so | ||
| 166 | * the rcu_barrier() below isn't sufficient alone. | ||
| 167 | */ | ||
| 168 | synchronize_rcu(); | ||
| 169 | |||
| 162 | /* Run all of the network namespace exit methods */ | 170 | /* Run all of the network namespace exit methods */ |
| 163 | list_for_each_entry_reverse(ops, &pernet_list, list) { | 171 | list_for_each_entry_reverse(ops, &pernet_list, list) { |
| 164 | if (ops->exit) | 172 | if (ops->exit) |
| @@ -219,7 +227,7 @@ static int __init net_ns_init(void) | |||
| 219 | panic("Could not setup the initial network namespace"); | 227 | panic("Could not setup the initial network namespace"); |
| 220 | 228 | ||
| 221 | rtnl_lock(); | 229 | rtnl_lock(); |
| 222 | list_add_tail(&init_net.list, &net_namespace_list); | 230 | list_add_tail_rcu(&init_net.list, &net_namespace_list); |
| 223 | rtnl_unlock(); | 231 | rtnl_unlock(); |
| 224 | 232 | ||
| 225 | mutex_unlock(&net_mutex); | 233 | mutex_unlock(&net_mutex); |
