diff options
| author | Johannes Berg <johannes@sipsolutions.net> | 2009-07-10 05:51:33 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-07-12 17:03:25 -0400 |
| commit | 11a28d373ed2539a110d56419457e2e7db221ac7 (patch) | |
| tree | d1460cb057299c89ff34b20821e30c8bfc7e589a /net | |
| parent | 6c04bb18ddd633b7feac2c8fe2ae0bf61d20ca7a (diff) | |
net: make namespace iteration possible under RCU
All we need to take care of is using proper RCU list
add/del primitives and inserting a synchronize_rcu()
at one place to make sure the exit notifiers are run
after everybody has stopped iterating the list.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
| -rw-r--r-- | net/core/net_namespace.c | 14 |
1 files changed, 11 insertions, 3 deletions
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); |
