netns: Remove __peernet2id_alloc()
__peernet2id_alloc() was used for both plain lookups and for netns ID allocations (depending the value of '*alloc'). Let's separate lookups from allocations instead. That is, integrate the lookup code into __peernet2id() and make peernet2id_alloc() responsible for allocating new netns IDs when necessary. This makes it clear that __peernet2id() doesn't modify the idr and prepares the code for lockless lookups. Also, mark the 'net' argument of __peernet2id() as 'const', since we're modifying this line. Signed-off-by: Guillaume Nault <gnault@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
621400366b
commit
4905294162
@ -211,16 +211,10 @@ static int net_eq_idr(int id, void *net, void *peer)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Should be called with nsid_lock held. If a new id is assigned, the bool alloc
|
/* Should be called with nsid_lock held. */
|
||||||
* is set to true, thus the caller knows that the new id must be notified via
|
static int __peernet2id(const struct net *net, struct net *peer)
|
||||||
* rtnl.
|
|
||||||
*/
|
|
||||||
static int __peernet2id_alloc(struct net *net, struct net *peer, bool *alloc)
|
|
||||||
{
|
{
|
||||||
int id = idr_for_each(&net->netns_ids, net_eq_idr, peer);
|
int id = idr_for_each(&net->netns_ids, net_eq_idr, peer);
|
||||||
bool alloc_it = *alloc;
|
|
||||||
|
|
||||||
*alloc = false;
|
|
||||||
|
|
||||||
/* Magic value for id 0. */
|
/* Magic value for id 0. */
|
||||||
if (id == NET_ID_ZERO)
|
if (id == NET_ID_ZERO)
|
||||||
@ -228,23 +222,9 @@ static int __peernet2id_alloc(struct net *net, struct net *peer, bool *alloc)
|
|||||||
if (id > 0)
|
if (id > 0)
|
||||||
return id;
|
return id;
|
||||||
|
|
||||||
if (alloc_it) {
|
|
||||||
id = alloc_netid(net, peer, -1);
|
|
||||||
*alloc = true;
|
|
||||||
return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NETNSA_NSID_NOT_ASSIGNED;
|
return NETNSA_NSID_NOT_ASSIGNED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* should be called with nsid_lock held */
|
|
||||||
static int __peernet2id(struct net *net, struct net *peer)
|
|
||||||
{
|
|
||||||
bool no = false;
|
|
||||||
|
|
||||||
return __peernet2id_alloc(net, peer, &no);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,
|
static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,
|
||||||
struct nlmsghdr *nlh, gfp_t gfp);
|
struct nlmsghdr *nlh, gfp_t gfp);
|
||||||
/* This function returns the id of a peer netns. If no id is assigned, one will
|
/* This function returns the id of a peer netns. If no id is assigned, one will
|
||||||
@ -252,26 +232,37 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,
|
|||||||
*/
|
*/
|
||||||
int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp)
|
int peernet2id_alloc(struct net *net, struct net *peer, gfp_t gfp)
|
||||||
{
|
{
|
||||||
bool alloc = false, alive = false;
|
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
if (refcount_read(&net->count) == 0)
|
if (refcount_read(&net->count) == 0)
|
||||||
return NETNSA_NSID_NOT_ASSIGNED;
|
return NETNSA_NSID_NOT_ASSIGNED;
|
||||||
|
|
||||||
spin_lock_bh(&net->nsid_lock);
|
spin_lock_bh(&net->nsid_lock);
|
||||||
/*
|
id = __peernet2id(net, peer);
|
||||||
* When peer is obtained from RCU lists, we may race with
|
if (id >= 0) {
|
||||||
|
spin_unlock_bh(&net->nsid_lock);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When peer is obtained from RCU lists, we may race with
|
||||||
* its cleanup. Check whether it's alive, and this guarantees
|
* its cleanup. Check whether it's alive, and this guarantees
|
||||||
* we never hash a peer back to net->netns_ids, after it has
|
* we never hash a peer back to net->netns_ids, after it has
|
||||||
* just been idr_remove()'d from there in cleanup_net().
|
* just been idr_remove()'d from there in cleanup_net().
|
||||||
*/
|
*/
|
||||||
if (maybe_get_net(peer))
|
if (!maybe_get_net(peer)) {
|
||||||
alive = alloc = true;
|
spin_unlock_bh(&net->nsid_lock);
|
||||||
id = __peernet2id_alloc(net, peer, &alloc);
|
return NETNSA_NSID_NOT_ASSIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = alloc_netid(net, peer, -1);
|
||||||
spin_unlock_bh(&net->nsid_lock);
|
spin_unlock_bh(&net->nsid_lock);
|
||||||
if (alloc && id >= 0)
|
|
||||||
rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL, gfp);
|
put_net(peer);
|
||||||
if (alive)
|
if (id < 0)
|
||||||
put_net(peer);
|
return NETNSA_NSID_NOT_ASSIGNED;
|
||||||
|
|
||||||
|
rtnl_net_notifyid(net, RTM_NEWNSID, id, 0, NULL, gfp);
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(peernet2id_alloc);
|
EXPORT_SYMBOL_GPL(peernet2id_alloc);
|
||||||
|
Loading…
Reference in New Issue
Block a user