diff options
Diffstat (limited to 'net/core/devlink.c')
| -rw-r--r-- | net/core/devlink.c | 70 | 
1 files changed, 49 insertions, 21 deletions
| diff --git a/net/core/devlink.c b/net/core/devlink.c index a932d95be798..8c5ddffd707d 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -517,7 +517,7 @@ devlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_l  	return test_bit(limit, &devlink->ops->reload_limits);  } -static int devlink_reload_stat_put(struct sk_buff *msg, enum devlink_reload_action action, +static int devlink_reload_stat_put(struct sk_buff *msg,  				   enum devlink_reload_limit limit, u32 value)  {  	struct nlattr *reload_stats_entry; @@ -526,8 +526,7 @@ static int devlink_reload_stat_put(struct sk_buff *msg, enum devlink_reload_acti  	if (!reload_stats_entry)  		return -EMSGSIZE; -	if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, action) || -	    nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) || +	if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) ||  	    nla_put_u32(msg, DEVLINK_ATTR_RELOAD_STATS_VALUE, value))  		goto nla_put_failure;  	nla_nest_end(msg, reload_stats_entry); @@ -540,7 +539,7 @@ nla_put_failure:  static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink, bool is_remote)  { -	struct nlattr *reload_stats_attr; +	struct nlattr *reload_stats_attr, *act_info, *act_stats;  	int i, j, stat_idx;  	u32 value; @@ -552,17 +551,29 @@ static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink  	if (!reload_stats_attr)  		return -EMSGSIZE; -	for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) { -		/* Remote stats are shown even if not locally supported. Stats -		 * of actions with unspecified limit are shown though drivers -		 * don't need to register unspecified limit. -		 */ -		if (!is_remote && j != DEVLINK_RELOAD_LIMIT_UNSPEC && -		    !devlink_reload_limit_is_supported(devlink, j)) +	for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) { +		if ((!is_remote && +		     !devlink_reload_action_is_supported(devlink, i)) || +		    i == DEVLINK_RELOAD_ACTION_UNSPEC)  			continue; -		for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) { -			if ((!is_remote && !devlink_reload_action_is_supported(devlink, i)) || -			    i == DEVLINK_RELOAD_ACTION_UNSPEC || +		act_info = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_INFO); +		if (!act_info) +			goto nla_put_failure; + +		if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, i)) +			goto action_info_nest_cancel; +		act_stats = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_STATS); +		if (!act_stats) +			goto action_info_nest_cancel; + +		for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) { +			/* Remote stats are shown even if not locally supported. +			 * Stats of actions with unspecified limit are shown +			 * though drivers don't need to register unspecified +			 * limit. +			 */ +			if ((!is_remote && j != DEVLINK_RELOAD_LIMIT_UNSPEC && +			     !devlink_reload_limit_is_supported(devlink, j)) ||  			    devlink_reload_combination_is_invalid(i, j))  				continue; @@ -571,13 +582,19 @@ static int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink  				value = devlink->stats.reload_stats[stat_idx];  			else  				value = devlink->stats.remote_reload_stats[stat_idx]; -			if (devlink_reload_stat_put(msg, i, j, value)) -				goto nla_put_failure; +			if (devlink_reload_stat_put(msg, j, value)) +				goto action_stats_nest_cancel;  		} +		nla_nest_end(msg, act_stats); +		nla_nest_end(msg, act_info);  	}  	nla_nest_end(msg, reload_stats_attr);  	return 0; +action_stats_nest_cancel: +	nla_nest_cancel(msg, act_stats); +action_info_nest_cancel: +	nla_nest_cancel(msg, act_info);  nla_put_failure:  	nla_nest_cancel(msg, reload_stats_attr);  	return -EMSGSIZE; @@ -755,6 +772,8 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,  	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))  		goto nla_put_failure; +	/* Hold rtnl lock while accessing port's netdev attributes. */ +	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; @@ -763,9 +782,10 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,  			devlink_port->desired_type))  		goto nla_put_failure_type_locked;  	if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) { +		struct net *net = devlink_net(devlink_port->devlink);  		struct net_device *netdev = devlink_port->type_dev; -		if (netdev && +		if (netdev && net_eq(net, dev_net(netdev)) &&  		    (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,  				 netdev->ifindex) ||  		     nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME, @@ -781,6 +801,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,  			goto nla_put_failure_type_locked;  	}  	spin_unlock_bh(&devlink_port->type_lock); +	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)) @@ -791,6 +812,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,  nla_put_failure_type_locked:  	spin_unlock_bh(&devlink_port->type_lock); +	rtnl_unlock();  nla_put_failure:  	genlmsg_cancel(msg, hdr);  	return -EMSGSIZE; @@ -1448,7 +1470,7 @@ static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,  		err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,  						pool_index, &cur, &max);  		if (err && err != -EOPNOTSUPP) -			return err; +			goto sb_occ_get_failure;  		if (!err) {  			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))  				goto nla_put_failure; @@ -1461,8 +1483,10 @@ static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,  	return 0;  nla_put_failure: +	err = -EMSGSIZE; +sb_occ_get_failure:  	genlmsg_cancel(msg, hdr); -	return -EMSGSIZE; +	return err;  }  static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb, @@ -8254,8 +8278,6 @@ static int __devlink_port_attrs_set(struct devlink_port *devlink_port,  {  	struct devlink_port_attrs *attrs = &devlink_port->attrs; -	if (WARN_ON(devlink_port->registered)) -		return -EEXIST;  	devlink_port->attrs_set = true;  	attrs->flavour = flavour;  	if (attrs->switch_id.id_len) { @@ -8279,6 +8301,8 @@ void devlink_port_attrs_set(struct devlink_port *devlink_port,  {  	int ret; +	if (WARN_ON(devlink_port->registered)) +		return;  	devlink_port->attrs = *attrs;  	ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);  	if (ret) @@ -8301,6 +8325,8 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro  	struct devlink_port_attrs *attrs = &devlink_port->attrs;  	int ret; +	if (WARN_ON(devlink_port->registered)) +		return;  	ret = __devlink_port_attrs_set(devlink_port,  				       DEVLINK_PORT_FLAVOUR_PCI_PF);  	if (ret) @@ -8326,6 +8352,8 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro  	struct devlink_port_attrs *attrs = &devlink_port->attrs;  	int ret; +	if (WARN_ON(devlink_port->registered)) +		return;  	ret = __devlink_port_attrs_set(devlink_port,  				       DEVLINK_PORT_FLAVOUR_PCI_VF);  	if (ret) | 
