]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
net: devlink: take RTNL in port_fill() function only if it is not held
authorJiri Pirko <jiri@nvidia.com>
Wed, 2 Nov 2022 16:02:02 +0000 (17:02 +0100)
committerJakub Kicinski <kuba@kernel.org>
Fri, 4 Nov 2022 03:48:33 +0000 (20:48 -0700)
Follow-up patch is going to introduce a netdevice notifier event
processing which is called with RTNL mutex held. Processing of this will
eventually lead to call to port_notity() and port_fill() which currently
takes RTNL mutex internally. So as a temporary solution, propagate a
bool indicating if the mutex is already held. This will go away in one
of the follow-up patches.

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/devlink.c

index ff81a5a5087cfcdeea23f0675e49aabe4fd60f25..3387dfbb80c5a3eee6fd857f063d4c710fcaf79e 100644 (file)
@@ -1278,7 +1278,8 @@ out:
 static int devlink_nl_port_fill(struct sk_buff *msg,
                                struct devlink_port *devlink_port,
                                enum devlink_command cmd, u32 portid, u32 seq,
-                               int flags, struct netlink_ext_ack *extack)
+                               int flags, struct netlink_ext_ack *extack,
+                               bool rtnl_held)
 {
        struct devlink *devlink = devlink_port->devlink;
        void *hdr;
@@ -1293,7 +1294,8 @@ static int devlink_nl_port_fill(struct sk_buff *msg,
                goto nla_put_failure;
 
        /* Hold rtnl lock while accessing port's netdev attributes. */
-       rtnl_lock();
+       if (!rtnl_held)
+               rtnl_lock();
        spin_lock_bh(&devlink_port->type_lock);
        if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
                goto nla_put_failure_type_locked;
@@ -1321,7 +1323,8 @@ static int devlink_nl_port_fill(struct sk_buff *msg,
                        goto nla_put_failure_type_locked;
        }
        spin_unlock_bh(&devlink_port->type_lock);
-       rtnl_unlock();
+       if (!rtnl_held)
+               rtnl_unlock();
        if (devlink_nl_port_attrs_put(msg, devlink_port))
                goto nla_put_failure;
        if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
@@ -1336,14 +1339,15 @@ static int devlink_nl_port_fill(struct sk_buff *msg,
 
 nla_put_failure_type_locked:
        spin_unlock_bh(&devlink_port->type_lock);
-       rtnl_unlock();
+       if (!rtnl_held)
+               rtnl_unlock();
 nla_put_failure:
        genlmsg_cancel(msg, hdr);
        return -EMSGSIZE;
 }
 
-static void devlink_port_notify(struct devlink_port *devlink_port,
-                               enum devlink_command cmd)
+static void __devlink_port_notify(struct devlink_port *devlink_port,
+                                 enum devlink_command cmd, bool rtnl_held)
 {
        struct devlink *devlink = devlink_port->devlink;
        struct sk_buff *msg;
@@ -1358,7 +1362,8 @@ static void devlink_port_notify(struct devlink_port *devlink_port,
        if (!msg)
                return;
 
-       err = devlink_nl_port_fill(msg, devlink_port, cmd, 0, 0, 0, NULL);
+       err = devlink_nl_port_fill(msg, devlink_port, cmd, 0, 0, 0, NULL,
+                                  rtnl_held);
        if (err) {
                nlmsg_free(msg);
                return;
@@ -1368,6 +1373,12 @@ static void devlink_port_notify(struct devlink_port *devlink_port,
                                0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
 }
 
+static void devlink_port_notify(struct devlink_port *devlink_port,
+                               enum devlink_command cmd)
+{
+       __devlink_port_notify(devlink_port, cmd, false);
+}
+
 static void devlink_rate_notify(struct devlink_rate *devlink_rate,
                                enum devlink_command cmd)
 {
@@ -1531,7 +1542,7 @@ static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
 
        err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_PORT_NEW,
                                   info->snd_portid, info->snd_seq, 0,
-                                  info->extack);
+                                  info->extack, false);
        if (err) {
                nlmsg_free(msg);
                return err;
@@ -1561,7 +1572,8 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
                                                   DEVLINK_CMD_NEW,
                                                   NETLINK_CB(cb->skb).portid,
                                                   cb->nlh->nlmsg_seq,
-                                                  NLM_F_MULTI, cb->extack);
+                                                  NLM_F_MULTI, cb->extack,
+                                                  false);
                        if (err) {
                                devl_unlock(devlink);
                                devlink_put(devlink);
@@ -1773,7 +1785,8 @@ static int devlink_port_new_notify(struct devlink *devlink,
        }
 
        err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_NEW,
-                                  info->snd_portid, info->snd_seq, 0, NULL);
+                                  info->snd_portid, info->snd_seq, 0, NULL,
+                                  false);
        if (err)
                goto out;
 
@@ -10033,7 +10046,7 @@ static void devlink_port_type_netdev_checks(struct devlink_port *devlink_port,
 
 static void __devlink_port_type_set(struct devlink_port *devlink_port,
                                    enum devlink_port_type type,
-                                   void *type_dev)
+                                   void *type_dev, bool rtnl_held)
 {
        struct net_device *netdev = type_dev;
 
@@ -10060,7 +10073,7 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port,
                break;
        }
        spin_unlock_bh(&devlink_port->type_lock);
-       devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
+       __devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW, rtnl_held);
 }
 
 /**
@@ -10077,7 +10090,8 @@ void devlink_port_type_eth_set(struct devlink_port *devlink_port,
                         "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
                         devlink_port->index);
 
-       __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
+       __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev,
+                               false);
 }
 EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
 
@@ -10090,7 +10104,8 @@ EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
 void devlink_port_type_ib_set(struct devlink_port *devlink_port,
                              struct ib_device *ibdev)
 {
-       __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
+       __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev,
+                               false);
 }
 EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
 
@@ -10101,7 +10116,8 @@ EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
  */
 void devlink_port_type_clear(struct devlink_port *devlink_port)
 {
-       __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
+       __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL,
+                               false);
 }
 EXPORT_SYMBOL_GPL(devlink_port_type_clear);