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

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
Loading
Loading
Loading
Loading
+31 −15
Original line number Diff line number Diff line
@@ -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,
				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,6 +1294,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg,
		goto nla_put_failure;

	/* Hold rtnl lock while accessing port's netdev attributes. */
	if (!rtnl_held)
		rtnl_lock();
	spin_lock_bh(&devlink_port->type_lock);
	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,
			goto nla_put_failure_type_locked;
	}
	spin_unlock_bh(&devlink_port->type_lock);
	if (!rtnl_held)
		rtnl_unlock();
	if (devlink_nl_port_attrs_put(msg, devlink_port))
		goto nla_put_failure;
@@ -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);
	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);