diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/net_namespace.c | 35 |
1 files changed, 20 insertions, 15 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 989434f36f96..f61c0e02a413 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
| @@ -215,13 +215,14 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id); | |||
| 215 | */ | 215 | */ |
| 216 | int peernet2id_alloc(struct net *net, struct net *peer) | 216 | int peernet2id_alloc(struct net *net, struct net *peer) |
| 217 | { | 217 | { |
| 218 | unsigned long flags; | ||
| 218 | bool alloc; | 219 | bool alloc; |
| 219 | int id; | 220 | int id; |
| 220 | 221 | ||
| 221 | spin_lock_bh(&net->nsid_lock); | 222 | spin_lock_irqsave(&net->nsid_lock, flags); |
| 222 | alloc = atomic_read(&peer->count) == 0 ? false : true; | 223 | alloc = atomic_read(&peer->count) == 0 ? false : true; |
| 223 | id = __peernet2id_alloc(net, peer, &alloc); | 224 | id = __peernet2id_alloc(net, peer, &alloc); |
| 224 | spin_unlock_bh(&net->nsid_lock); | 225 | spin_unlock_irqrestore(&net->nsid_lock, flags); |
| 225 | if (alloc && id >= 0) | 226 | if (alloc && id >= 0) |
| 226 | rtnl_net_notifyid(net, RTM_NEWNSID, id); | 227 | rtnl_net_notifyid(net, RTM_NEWNSID, id); |
| 227 | return id; | 228 | return id; |
| @@ -230,11 +231,12 @@ int peernet2id_alloc(struct net *net, struct net *peer) | |||
| 230 | /* This function returns, if assigned, the id of a peer netns. */ | 231 | /* This function returns, if assigned, the id of a peer netns. */ |
| 231 | int peernet2id(struct net *net, struct net *peer) | 232 | int peernet2id(struct net *net, struct net *peer) |
| 232 | { | 233 | { |
| 234 | unsigned long flags; | ||
| 233 | int id; | 235 | int id; |
| 234 | 236 | ||
| 235 | spin_lock_bh(&net->nsid_lock); | 237 | spin_lock_irqsave(&net->nsid_lock, flags); |
| 236 | id = __peernet2id(net, peer); | 238 | id = __peernet2id(net, peer); |
| 237 | spin_unlock_bh(&net->nsid_lock); | 239 | spin_unlock_irqrestore(&net->nsid_lock, flags); |
| 238 | return id; | 240 | return id; |
| 239 | } | 241 | } |
| 240 | EXPORT_SYMBOL(peernet2id); | 242 | EXPORT_SYMBOL(peernet2id); |
| @@ -249,17 +251,18 @@ bool peernet_has_id(struct net *net, struct net *peer) | |||
| 249 | 251 | ||
| 250 | struct net *get_net_ns_by_id(struct net *net, int id) | 252 | struct net *get_net_ns_by_id(struct net *net, int id) |
| 251 | { | 253 | { |
| 254 | unsigned long flags; | ||
| 252 | struct net *peer; | 255 | struct net *peer; |
| 253 | 256 | ||
| 254 | if (id < 0) | 257 | if (id < 0) |
| 255 | return NULL; | 258 | return NULL; |
| 256 | 259 | ||
| 257 | rcu_read_lock(); | 260 | rcu_read_lock(); |
| 258 | spin_lock_bh(&net->nsid_lock); | 261 | spin_lock_irqsave(&net->nsid_lock, flags); |
| 259 | peer = idr_find(&net->netns_ids, id); | 262 | peer = idr_find(&net->netns_ids, id); |
| 260 | if (peer) | 263 | if (peer) |
| 261 | get_net(peer); | 264 | get_net(peer); |
| 262 | spin_unlock_bh(&net->nsid_lock); | 265 | spin_unlock_irqrestore(&net->nsid_lock, flags); |
| 263 | rcu_read_unlock(); | 266 | rcu_read_unlock(); |
| 264 | 267 | ||
| 265 | return peer; | 268 | return peer; |
| @@ -422,17 +425,17 @@ static void cleanup_net(struct work_struct *work) | |||
| 422 | for_each_net(tmp) { | 425 | for_each_net(tmp) { |
| 423 | int id; | 426 | int id; |
| 424 | 427 | ||
| 425 | spin_lock_bh(&tmp->nsid_lock); | 428 | spin_lock_irq(&tmp->nsid_lock); |
| 426 | id = __peernet2id(tmp, net); | 429 | id = __peernet2id(tmp, net); |
| 427 | if (id >= 0) | 430 | if (id >= 0) |
| 428 | idr_remove(&tmp->netns_ids, id); | 431 | idr_remove(&tmp->netns_ids, id); |
| 429 | spin_unlock_bh(&tmp->nsid_lock); | 432 | spin_unlock_irq(&tmp->nsid_lock); |
| 430 | if (id >= 0) | 433 | if (id >= 0) |
| 431 | rtnl_net_notifyid(tmp, RTM_DELNSID, id); | 434 | rtnl_net_notifyid(tmp, RTM_DELNSID, id); |
| 432 | } | 435 | } |
| 433 | spin_lock_bh(&net->nsid_lock); | 436 | spin_lock_irq(&net->nsid_lock); |
| 434 | idr_destroy(&net->netns_ids); | 437 | idr_destroy(&net->netns_ids); |
| 435 | spin_unlock_bh(&net->nsid_lock); | 438 | spin_unlock_irq(&net->nsid_lock); |
| 436 | 439 | ||
| 437 | } | 440 | } |
| 438 | rtnl_unlock(); | 441 | rtnl_unlock(); |
| @@ -561,6 +564,7 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 561 | { | 564 | { |
| 562 | struct net *net = sock_net(skb->sk); | 565 | struct net *net = sock_net(skb->sk); |
| 563 | struct nlattr *tb[NETNSA_MAX + 1]; | 566 | struct nlattr *tb[NETNSA_MAX + 1]; |
| 567 | unsigned long flags; | ||
| 564 | struct net *peer; | 568 | struct net *peer; |
| 565 | int nsid, err; | 569 | int nsid, err; |
| 566 | 570 | ||
| @@ -581,15 +585,15 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 581 | if (IS_ERR(peer)) | 585 | if (IS_ERR(peer)) |
| 582 | return PTR_ERR(peer); | 586 | return PTR_ERR(peer); |
| 583 | 587 | ||
| 584 | spin_lock_bh(&net->nsid_lock); | 588 | spin_lock_irqsave(&net->nsid_lock, flags); |
| 585 | if (__peernet2id(net, peer) >= 0) { | 589 | if (__peernet2id(net, peer) >= 0) { |
| 586 | spin_unlock_bh(&net->nsid_lock); | 590 | spin_unlock_irqrestore(&net->nsid_lock, flags); |
| 587 | err = -EEXIST; | 591 | err = -EEXIST; |
| 588 | goto out; | 592 | goto out; |
| 589 | } | 593 | } |
| 590 | 594 | ||
| 591 | err = alloc_netid(net, peer, nsid); | 595 | err = alloc_netid(net, peer, nsid); |
| 592 | spin_unlock_bh(&net->nsid_lock); | 596 | spin_unlock_irqrestore(&net->nsid_lock, flags); |
| 593 | if (err >= 0) { | 597 | if (err >= 0) { |
| 594 | rtnl_net_notifyid(net, RTM_NEWNSID, err); | 598 | rtnl_net_notifyid(net, RTM_NEWNSID, err); |
| 595 | err = 0; | 599 | err = 0; |
| @@ -711,10 +715,11 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 711 | .idx = 0, | 715 | .idx = 0, |
| 712 | .s_idx = cb->args[0], | 716 | .s_idx = cb->args[0], |
| 713 | }; | 717 | }; |
| 718 | unsigned long flags; | ||
| 714 | 719 | ||
| 715 | spin_lock_bh(&net->nsid_lock); | 720 | spin_lock_irqsave(&net->nsid_lock, flags); |
| 716 | idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb); | 721 | idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb); |
| 717 | spin_unlock_bh(&net->nsid_lock); | 722 | spin_unlock_irqrestore(&net->nsid_lock, flags); |
| 718 | 723 | ||
| 719 | cb->args[0] = net_cb.idx; | 724 | cb->args[0] = net_cb.idx; |
| 720 | return skb->len; | 725 | return skb->len; |
