mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 06:10:56 +00:00
netns: protect netns ID lookups with RCU
commit 2dce224f46
upstream.
__peernet2id() can be protected by RCU as it only calls idr_for_each(),
which is RCU-safe, and never modifies the nsid table.
rtnl_net_dumpid() can also do lockless lookups. It does two nested
idr_for_each() calls on nsid tables (one direct call and one indirect
call because of rtnl_net_dumpid_one() calling __peernet2id()). The
netnsid tables are never updated. Therefore it is safe to not take the
nsid_lock and run within an RCU-critical section instead.
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Håkon Bugge <haakon.bugge@oracle.com>
This commit is contained in:
parent
38e5963135
commit
73b10060f6
1 changed files with 10 additions and 8 deletions
|
@ -181,9 +181,9 @@ static int net_eq_idr(int id, void *net, void *peer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Should be called with nsid_lock held. If a new id is assigned, the bool alloc
|
||||
* is set to true, thus the caller knows that the new id must be notified via
|
||||
* rtnl.
|
||||
/* Must be called from RCU-critical section or with nsid_lock held. If
|
||||
* a new id is assigned, the bool alloc is set to true, thus the
|
||||
* caller knows that the new id must be notified via rtnl.
|
||||
*/
|
||||
static int __peernet2id_alloc(struct net *net, struct net *peer, bool *alloc)
|
||||
{
|
||||
|
@ -207,7 +207,7 @@ static int __peernet2id_alloc(struct net *net, struct net *peer, bool *alloc)
|
|||
return NETNSA_NSID_NOT_ASSIGNED;
|
||||
}
|
||||
|
||||
/* should be called with nsid_lock held */
|
||||
/* Must be called from RCU-critical section or with nsid_lock held */
|
||||
static int __peernet2id(struct net *net, struct net *peer)
|
||||
{
|
||||
bool no = false;
|
||||
|
@ -240,9 +240,10 @@ int peernet2id(struct net *net, struct net *peer)
|
|||
{
|
||||
int id;
|
||||
|
||||
spin_lock_bh(&net->nsid_lock);
|
||||
rcu_read_lock();
|
||||
id = __peernet2id(net, peer);
|
||||
spin_unlock_bh(&net->nsid_lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
return id;
|
||||
}
|
||||
EXPORT_SYMBOL(peernet2id);
|
||||
|
@ -761,6 +762,7 @@ struct rtnl_net_dump_cb {
|
|||
int s_idx;
|
||||
};
|
||||
|
||||
/* Runs in RCU-critical section. */
|
||||
static int rtnl_net_dumpid_one(int id, void *peer, void *data)
|
||||
{
|
||||
struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data;
|
||||
|
@ -791,9 +793,9 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
.s_idx = cb->args[0],
|
||||
};
|
||||
|
||||
spin_lock_bh(&net->nsid_lock);
|
||||
rcu_read_lock();
|
||||
idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb);
|
||||
spin_unlock_bh(&net->nsid_lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
cb->args[0] = net_cb.idx;
|
||||
return skb->len;
|
||||
|
|
Loading…
Reference in a new issue