devlink: call peernet2id_alloc() with net pointer under RCU read lock
authorJiri Pirko <jiri@nvidia.com>
Fri, 13 Oct 2023 12:10:24 +0000 (14:10 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 18 Oct 2023 08:23:01 +0000 (09:23 +0100)
peernet2id_alloc() allows to be called lockless with peer net pointer
obtained in RCU critical section and makes sure to return ns ID if net
namespaces is not being removed concurrently. Benefit from
read_pnet_rcu() helper addition, use it to obtain net pointer under RCU
read lock and pass it to peernet2id_alloc() to get ns ID.

Fixes: c137743bce02 ("devlink: introduce object and nested devlink relationship infra")
Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/devlink/netlink.c

index 499304d9de497da36bf0b1654b182bcc8a195f14..809bfc3ba8c4d4ac05951a6c7d45b8f7d08598f1 100644 (file)
@@ -86,18 +86,24 @@ int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
                                 struct devlink *devlink, int attrtype)
 {
        struct nlattr *nested_attr;
+       struct net *devl_net;
 
        nested_attr = nla_nest_start(msg, attrtype);
        if (!nested_attr)
                return -EMSGSIZE;
        if (devlink_nl_put_handle(msg, devlink))
                goto nla_put_failure;
-       if (!net_eq(net, devlink_net(devlink))) {
-               int id = peernet2id_alloc(net, devlink_net(devlink),
-                                         GFP_KERNEL);
 
+       rcu_read_lock();
+       devl_net = read_pnet_rcu(&devlink->_net);
+       if (!net_eq(net, devl_net)) {
+               int id = peernet2id_alloc(net, devl_net, GFP_ATOMIC);
+
+               rcu_read_unlock();
                if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id))
                        return -EMSGSIZE;
+       } else {
+               rcu_read_unlock();
        }
 
        nla_nest_end(msg, nested_attr);