Commit d41c9dbd authored by Jiri Pirko's avatar Jiri Pirko Committed by Jakub Kicinski

net: devlink: take RTNL in port_fill() function only if it is not held

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: default avatarJiri Pirko <jiri@nvidia.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 45791e0d
...@@ -1278,7 +1278,8 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por ...@@ -1278,7 +1278,8 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por
static int devlink_nl_port_fill(struct sk_buff *msg, static int devlink_nl_port_fill(struct sk_buff *msg,
struct devlink_port *devlink_port, struct devlink_port *devlink_port,
enum devlink_command cmd, u32 portid, u32 seq, 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; struct devlink *devlink = devlink_port->devlink;
void *hdr; void *hdr;
...@@ -1293,6 +1294,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, ...@@ -1293,6 +1294,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg,
goto nla_put_failure; goto nla_put_failure;
/* Hold rtnl lock while accessing port's netdev attributes. */ /* Hold rtnl lock while accessing port's netdev attributes. */
if (!rtnl_held)
rtnl_lock(); rtnl_lock();
spin_lock_bh(&devlink_port->type_lock); spin_lock_bh(&devlink_port->type_lock);
if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type)) if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
...@@ -1321,6 +1323,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, ...@@ -1321,6 +1323,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg,
goto nla_put_failure_type_locked; goto nla_put_failure_type_locked;
} }
spin_unlock_bh(&devlink_port->type_lock); spin_unlock_bh(&devlink_port->type_lock);
if (!rtnl_held)
rtnl_unlock(); rtnl_unlock();
if (devlink_nl_port_attrs_put(msg, devlink_port)) if (devlink_nl_port_attrs_put(msg, devlink_port))
goto nla_put_failure; goto nla_put_failure;
...@@ -1336,14 +1339,15 @@ static int devlink_nl_port_fill(struct sk_buff *msg, ...@@ -1336,14 +1339,15 @@ static int devlink_nl_port_fill(struct sk_buff *msg,
nla_put_failure_type_locked: nla_put_failure_type_locked:
spin_unlock_bh(&devlink_port->type_lock); spin_unlock_bh(&devlink_port->type_lock);
if (!rtnl_held)
rtnl_unlock(); rtnl_unlock();
nla_put_failure: nla_put_failure:
genlmsg_cancel(msg, hdr); genlmsg_cancel(msg, hdr);
return -EMSGSIZE; return -EMSGSIZE;
} }
static void devlink_port_notify(struct devlink_port *devlink_port, static void __devlink_port_notify(struct devlink_port *devlink_port,
enum devlink_command cmd) enum devlink_command cmd, bool rtnl_held)
{ {
struct devlink *devlink = devlink_port->devlink; struct devlink *devlink = devlink_port->devlink;
struct sk_buff *msg; struct sk_buff *msg;
...@@ -1358,7 +1362,8 @@ static void devlink_port_notify(struct devlink_port *devlink_port, ...@@ -1358,7 +1362,8 @@ static void devlink_port_notify(struct devlink_port *devlink_port,
if (!msg) if (!msg)
return; 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) { if (err) {
nlmsg_free(msg); nlmsg_free(msg);
return; return;
...@@ -1368,6 +1373,12 @@ static void devlink_port_notify(struct devlink_port *devlink_port, ...@@ -1368,6 +1373,12 @@ static void devlink_port_notify(struct devlink_port *devlink_port,
0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 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, static void devlink_rate_notify(struct devlink_rate *devlink_rate,
enum devlink_command cmd) enum devlink_command cmd)
{ {
...@@ -1531,7 +1542,7 @@ static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb, ...@@ -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, err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_PORT_NEW,
info->snd_portid, info->snd_seq, 0, info->snd_portid, info->snd_seq, 0,
info->extack); info->extack, false);
if (err) { if (err) {
nlmsg_free(msg); nlmsg_free(msg);
return err; return err;
...@@ -1561,7 +1572,8 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg, ...@@ -1561,7 +1572,8 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
DEVLINK_CMD_NEW, DEVLINK_CMD_NEW,
NETLINK_CB(cb->skb).portid, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
NLM_F_MULTI, cb->extack); NLM_F_MULTI, cb->extack,
false);
if (err) { if (err) {
devl_unlock(devlink); devl_unlock(devlink);
devlink_put(devlink); devlink_put(devlink);
...@@ -1773,7 +1785,8 @@ static int devlink_port_new_notify(struct devlink *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, 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) if (err)
goto out; goto out;
...@@ -10033,7 +10046,7 @@ static void devlink_port_type_netdev_checks(struct devlink_port *devlink_port, ...@@ -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, static void __devlink_port_type_set(struct devlink_port *devlink_port,
enum devlink_port_type type, enum devlink_port_type type,
void *type_dev) void *type_dev, bool rtnl_held)
{ {
struct net_device *netdev = type_dev; struct net_device *netdev = type_dev;
...@@ -10060,7 +10073,7 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port, ...@@ -10060,7 +10073,7 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port,
break; break;
} }
spin_unlock_bh(&devlink_port->type_lock); 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, ...@@ -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 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->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); EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
...@@ -10090,7 +10104,8 @@ 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, void devlink_port_type_ib_set(struct devlink_port *devlink_port,
struct ib_device *ibdev) 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); EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
...@@ -10101,7 +10116,8 @@ 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) 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); EXPORT_SYMBOL_GPL(devlink_port_type_clear);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment