diff options
Diffstat (limited to 'net/core/devlink.c')
| -rw-r--r-- | net/core/devlink.c | 680 | 
1 files changed, 467 insertions, 213 deletions
diff --git a/net/core/devlink.c b/net/core/devlink.c index 85032626de24..a856ae401ea5 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -92,7 +92,8 @@ static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_  				 DEVLINK_PORT_FN_STATE_ACTIVE),  }; -static LIST_HEAD(devlink_list); +static DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC); +#define DEVLINK_REGISTERED XA_MARK_1  /* devlink_mutex   * @@ -108,23 +109,23 @@ struct net *devlink_net(const struct devlink *devlink)  }  EXPORT_SYMBOL_GPL(devlink_net); -static void __devlink_net_set(struct devlink *devlink, struct net *net) +static void devlink_put(struct devlink *devlink)  { -	write_pnet(&devlink->_net, net); +	if (refcount_dec_and_test(&devlink->refcount)) +		complete(&devlink->comp);  } -void devlink_net_set(struct devlink *devlink, struct net *net) +static bool __must_check devlink_try_get(struct devlink *devlink)  { -	if (WARN_ON(devlink->registered)) -		return; -	__devlink_net_set(devlink, net); +	return refcount_inc_not_zero(&devlink->refcount);  } -EXPORT_SYMBOL_GPL(devlink_net_set);  static struct devlink *devlink_get_from_attrs(struct net *net,  					      struct nlattr **attrs)  {  	struct devlink *devlink; +	unsigned long index; +	bool found = false;  	char *busname;  	char *devname; @@ -136,19 +137,19 @@ static struct devlink *devlink_get_from_attrs(struct net *net,  	lockdep_assert_held(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {  		if (strcmp(devlink->dev->bus->name, busname) == 0 &&  		    strcmp(dev_name(devlink->dev), devname) == 0 && -		    net_eq(devlink_net(devlink), net)) -			return devlink; +		    net_eq(devlink_net(devlink), net)) { +			found = true; +			break; +		}  	} -	return ERR_PTR(-ENODEV); -} +	if (!found || !devlink_try_get(devlink)) +		devlink = ERR_PTR(-ENODEV); -static struct devlink *devlink_get_from_info(struct genl_info *info) -{ -	return devlink_get_from_attrs(genl_info_net(info), info->attrs); +	return devlink;  }  static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink, @@ -499,7 +500,7 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,  	int err;  	mutex_lock(&devlink_mutex); -	devlink = devlink_get_from_info(info); +	devlink = devlink_get_from_attrs(genl_info_net(info), info->attrs);  	if (IS_ERR(devlink)) {  		mutex_unlock(&devlink_mutex);  		return PTR_ERR(devlink); @@ -542,6 +543,7 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,  unlock:  	if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)  		mutex_unlock(&devlink->lock); +	devlink_put(devlink);  	mutex_unlock(&devlink_mutex);  	return err;  } @@ -554,6 +556,7 @@ static void devlink_nl_post_doit(const struct genl_ops *ops,  	devlink = info->user_ptr[0];  	if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)  		mutex_unlock(&devlink->lock); +	devlink_put(devlink);  	mutex_unlock(&devlink_mutex);  } @@ -817,10 +820,11 @@ static int devlink_nl_port_attrs_put(struct sk_buff *msg,  	return 0;  } -static int -devlink_port_fn_hw_addr_fill(struct devlink *devlink, const struct devlink_ops *ops, -			     struct devlink_port *port, struct sk_buff *msg, -			     struct netlink_ext_ack *extack, bool *msg_updated) +static int devlink_port_fn_hw_addr_fill(const struct devlink_ops *ops, +					struct devlink_port *port, +					struct sk_buff *msg, +					struct netlink_ext_ack *extack, +					bool *msg_updated)  {  	u8 hw_addr[MAX_ADDR_LEN];  	int hw_addr_len; @@ -829,7 +833,8 @@ devlink_port_fn_hw_addr_fill(struct devlink *devlink, const struct devlink_ops *  	if (!ops->port_function_hw_addr_get)  		return 0; -	err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack); +	err = ops->port_function_hw_addr_get(port, hw_addr, &hw_addr_len, +					     extack);  	if (err) {  		if (err == -EOPNOTSUPP)  			return 0; @@ -843,12 +848,11 @@ devlink_port_fn_hw_addr_fill(struct devlink *devlink, const struct devlink_ops *  }  static int devlink_nl_rate_fill(struct sk_buff *msg, -				struct devlink *devlink,  				struct devlink_rate *devlink_rate, -				enum devlink_command cmd, u32 portid, -				u32 seq, int flags, -				struct netlink_ext_ack *extack) +				enum devlink_command cmd, u32 portid, u32 seq, +				int flags, struct netlink_ext_ack *extack)  { +	struct devlink *devlink = devlink_rate->devlink;  	void *hdr;  	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); @@ -906,12 +910,11 @@ devlink_port_fn_opstate_valid(enum devlink_port_fn_opstate opstate)  	       opstate == DEVLINK_PORT_FN_OPSTATE_ATTACHED;  } -static int -devlink_port_fn_state_fill(struct devlink *devlink, -			   const struct devlink_ops *ops, -			   struct devlink_port *port, struct sk_buff *msg, -			   struct netlink_ext_ack *extack, -			   bool *msg_updated) +static int devlink_port_fn_state_fill(const struct devlink_ops *ops, +				      struct devlink_port *port, +				      struct sk_buff *msg, +				      struct netlink_ext_ack *extack, +				      bool *msg_updated)  {  	enum devlink_port_fn_opstate opstate;  	enum devlink_port_fn_state state; @@ -920,7 +923,7 @@ devlink_port_fn_state_fill(struct devlink *devlink,  	if (!ops->port_fn_state_get)  		return 0; -	err = ops->port_fn_state_get(devlink, port, &state, &opstate, extack); +	err = ops->port_fn_state_get(port, &state, &opstate, extack);  	if (err) {  		if (err == -EOPNOTSUPP)  			return 0; @@ -948,7 +951,6 @@ static int  devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,  				   struct netlink_ext_ack *extack)  { -	struct devlink *devlink = port->devlink;  	const struct devlink_ops *ops;  	struct nlattr *function_attr;  	bool msg_updated = false; @@ -958,13 +960,12 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por  	if (!function_attr)  		return -EMSGSIZE; -	ops = devlink->ops; -	err = devlink_port_fn_hw_addr_fill(devlink, ops, port, msg, -					   extack, &msg_updated); +	ops = port->devlink->ops; +	err = devlink_port_fn_hw_addr_fill(ops, port, msg, extack, +					   &msg_updated);  	if (err)  		goto out; -	err = devlink_port_fn_state_fill(devlink, ops, port, msg, extack, -					 &msg_updated); +	err = devlink_port_fn_state_fill(ops, port, msg, extack, &msg_updated);  out:  	if (err || !msg_updated)  		nla_nest_cancel(msg, function_attr); @@ -973,12 +974,12 @@ out:  	return err;  } -static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink, +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) +				enum devlink_command cmd, u32 portid, u32 seq, +				int flags, struct netlink_ext_ack *extack)  { +	struct devlink *devlink = devlink_port->devlink;  	void *hdr;  	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); @@ -1039,53 +1040,47 @@ nla_put_failure:  static void devlink_port_notify(struct devlink_port *devlink_port,  				enum devlink_command cmd)  { -	struct devlink *devlink = devlink_port->devlink;  	struct sk_buff *msg;  	int err; -	if (!devlink_port->registered) -		return; -  	WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);  	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);  	if (!msg)  		return; -	err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0, -				   NULL); +	err = devlink_nl_port_fill(msg, devlink_port, cmd, 0, 0, 0, NULL);  	if (err) {  		nlmsg_free(msg);  		return;  	} -	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), -				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); +	genlmsg_multicast_netns(&devlink_nl_family, +				devlink_net(devlink_port->devlink), msg, 0, +				DEVLINK_MCGRP_CONFIG, GFP_KERNEL);  }  static void devlink_rate_notify(struct devlink_rate *devlink_rate,  				enum devlink_command cmd)  { -	struct devlink *devlink = devlink_rate->devlink;  	struct sk_buff *msg;  	int err; -	WARN_ON(cmd != DEVLINK_CMD_RATE_NEW && -		cmd != DEVLINK_CMD_RATE_DEL); +	WARN_ON(cmd != DEVLINK_CMD_RATE_NEW && cmd != DEVLINK_CMD_RATE_DEL);  	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);  	if (!msg)  		return; -	err = devlink_nl_rate_fill(msg, devlink, devlink_rate, -				   cmd, 0, 0, 0, NULL); +	err = devlink_nl_rate_fill(msg, devlink_rate, cmd, 0, 0, 0, NULL);  	if (err) {  		nlmsg_free(msg);  		return;  	} -	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), -				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); +	genlmsg_multicast_netns(&devlink_nl_family, +				devlink_net(devlink_rate->devlink), msg, 0, +				DEVLINK_MCGRP_CONFIG, GFP_KERNEL);  }  static int devlink_nl_cmd_rate_get_dumpit(struct sk_buff *msg, @@ -1094,13 +1089,18 @@ static int devlink_nl_cmd_rate_get_dumpit(struct sk_buff *msg,  	struct devlink_rate *devlink_rate;  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err = 0;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(devlink_rate, &devlink->rate_list, list) {  			enum devlink_command cmd = DEVLINK_CMD_RATE_NEW; @@ -1110,18 +1110,19 @@ static int devlink_nl_cmd_rate_get_dumpit(struct sk_buff *msg,  				idx++;  				continue;  			} -			err = devlink_nl_rate_fill(msg, devlink, -						   devlink_rate, -						   cmd, id, +			err = devlink_nl_rate_fill(msg, devlink_rate, cmd, id,  						   cb->nlh->nlmsg_seq,  						   NLM_F_MULTI, NULL);  			if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  			idx++;  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -1136,7 +1137,6 @@ static int devlink_nl_cmd_rate_get_doit(struct sk_buff *skb,  					struct genl_info *info)  {  	struct devlink_rate *devlink_rate = info->user_ptr[1]; -	struct devlink *devlink = devlink_rate->devlink;  	struct sk_buff *msg;  	int err; @@ -1144,8 +1144,7 @@ static int devlink_nl_cmd_rate_get_doit(struct sk_buff *skb,  	if (!msg)  		return -ENOMEM; -	err = devlink_nl_rate_fill(msg, devlink, devlink_rate, -				   DEVLINK_CMD_RATE_NEW, +	err = devlink_nl_rate_fill(msg, devlink_rate, DEVLINK_CMD_RATE_NEW,  				   info->snd_portid, info->snd_seq, 0,  				   info->extack);  	if (err) { @@ -1193,20 +1192,30 @@ static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,  {  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) { +			devlink_put(devlink); +			continue; +		} +  		if (idx < start) {  			idx++; +			devlink_put(devlink);  			continue;  		} +  		err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,  				      NETLINK_CB(cb->skb).portid,  				      cb->nlh->nlmsg_seq, NLM_F_MULTI); +		devlink_put(devlink);  		if (err)  			goto out;  		idx++; @@ -1222,7 +1231,6 @@ static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,  					struct genl_info *info)  {  	struct devlink_port *devlink_port = info->user_ptr[1]; -	struct devlink *devlink = devlink_port->devlink;  	struct sk_buff *msg;  	int err; @@ -1230,8 +1238,7 @@ static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,  	if (!msg)  		return -ENOMEM; -	err = devlink_nl_port_fill(msg, devlink, 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->extack);  	if (err) { @@ -1248,32 +1255,39 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,  	struct devlink *devlink;  	struct devlink_port *devlink_port;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(devlink_port, &devlink->port_list, list) {  			if (idx < start) {  				idx++;  				continue;  			} -			err = devlink_nl_port_fill(msg, devlink, devlink_port, +			err = devlink_nl_port_fill(msg, devlink_port,  						   DEVLINK_CMD_NEW,  						   NETLINK_CB(cb->skb).portid,  						   cb->nlh->nlmsg_seq, -						   NLM_F_MULTI, -						   cb->extack); +						   NLM_F_MULTI, cb->extack);  			if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  			idx++;  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -1282,31 +1296,33 @@ out:  	return msg->len;  } -static int devlink_port_type_set(struct devlink *devlink, -				 struct devlink_port *devlink_port, +static int devlink_port_type_set(struct devlink_port *devlink_port,  				 enum devlink_port_type port_type)  {  	int err; -	if (devlink->ops->port_type_set) { -		if (port_type == devlink_port->type) -			return 0; -		err = devlink->ops->port_type_set(devlink_port, port_type); -		if (err) -			return err; -		devlink_port->desired_type = port_type; -		devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); +	if (!devlink_port->devlink->ops->port_type_set) +		return -EOPNOTSUPP; + +	if (port_type == devlink_port->type)  		return 0; -	} -	return -EOPNOTSUPP; + +	err = devlink_port->devlink->ops->port_type_set(devlink_port, +							port_type); +	if (err) +		return err; + +	devlink_port->desired_type = port_type; +	devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); +	return 0;  } -static int -devlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port, -				  const struct nlattr *attr, struct netlink_ext_ack *extack) +static int devlink_port_function_hw_addr_set(struct devlink_port *port, +					     const struct nlattr *attr, +					     struct netlink_ext_ack *extack)  { -	const struct devlink_ops *ops; +	const struct devlink_ops *ops = port->devlink->ops;  	const u8 *hw_addr;  	int hw_addr_len; @@ -1327,17 +1343,16 @@ devlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *  		}  	} -	ops = devlink->ops;  	if (!ops->port_function_hw_addr_set) {  		NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes");  		return -EOPNOTSUPP;  	} -	return ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack); +	return ops->port_function_hw_addr_set(port, hw_addr, hw_addr_len, +					      extack);  } -static int devlink_port_fn_state_set(struct devlink *devlink, -				     struct devlink_port *port, +static int devlink_port_fn_state_set(struct devlink_port *port,  				     const struct nlattr *attr,  				     struct netlink_ext_ack *extack)  { @@ -1345,18 +1360,18 @@ static int devlink_port_fn_state_set(struct devlink *devlink,  	const struct devlink_ops *ops;  	state = nla_get_u8(attr); -	ops = devlink->ops; +	ops = port->devlink->ops;  	if (!ops->port_fn_state_set) {  		NL_SET_ERR_MSG_MOD(extack,  				   "Function does not support state setting");  		return -EOPNOTSUPP;  	} -	return ops->port_fn_state_set(devlink, port, state, extack); +	return ops->port_fn_state_set(port, state, extack);  } -static int -devlink_port_function_set(struct devlink *devlink, struct devlink_port *port, -			  const struct nlattr *attr, struct netlink_ext_ack *extack) +static int devlink_port_function_set(struct devlink_port *port, +				     const struct nlattr *attr, +				     struct netlink_ext_ack *extack)  {  	struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];  	int err; @@ -1370,7 +1385,7 @@ devlink_port_function_set(struct devlink *devlink, struct devlink_port *port,  	attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];  	if (attr) { -		err = devlink_port_function_hw_addr_set(devlink, port, attr, extack); +		err = devlink_port_function_hw_addr_set(port, attr, extack);  		if (err)  			return err;  	} @@ -1380,7 +1395,7 @@ devlink_port_function_set(struct devlink *devlink, struct devlink_port *port,  	 */  	attr = tb[DEVLINK_PORT_FN_ATTR_STATE];  	if (attr) -		err = devlink_port_fn_state_set(devlink, port, attr, extack); +		err = devlink_port_fn_state_set(port, attr, extack);  	if (!err)  		devlink_port_notify(port, DEVLINK_CMD_PORT_NEW); @@ -1391,14 +1406,13 @@ static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,  					struct genl_info *info)  {  	struct devlink_port *devlink_port = info->user_ptr[1]; -	struct devlink *devlink = devlink_port->devlink;  	int err;  	if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {  		enum devlink_port_type port_type;  		port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]); -		err = devlink_port_type_set(devlink, devlink_port, port_type); +		err = devlink_port_type_set(devlink_port, port_type);  		if (err)  			return err;  	} @@ -1407,7 +1421,7 @@ static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,  		struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];  		struct netlink_ext_ack *extack = info->extack; -		err = devlink_port_function_set(devlink, devlink_port, attr, extack); +		err = devlink_port_function_set(devlink_port, attr, extack);  		if (err)  			return err;  	} @@ -1502,9 +1516,8 @@ static int devlink_port_new_notifiy(struct devlink *devlink,  		goto out;  	} -	err = devlink_nl_port_fill(msg, devlink, devlink_port, -				   DEVLINK_CMD_NEW, info->snd_portid, -				   info->snd_seq, 0, NULL); +	err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_NEW, +				   info->snd_portid, info->snd_seq, 0, NULL);  	if (err)  		goto out; @@ -1908,13 +1921,18 @@ static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,  	struct devlink *devlink;  	struct devlink_sb *devlink_sb;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(devlink_sb, &devlink->sb_list, list) {  			if (idx < start) { @@ -1928,11 +1946,14 @@ static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,  						 NLM_F_MULTI);  			if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  			idx++;  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -2052,14 +2073,19 @@ static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,  	struct devlink *devlink;  	struct devlink_sb *devlink_sb;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err = 0;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink)) +			continue; +  		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||  		    !devlink->ops->sb_pool_get) -			continue; +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(devlink_sb, &devlink->sb_list, list) {  			err = __sb_pool_get_dumpit(msg, start, &idx, devlink, @@ -2070,10 +2096,13 @@ static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,  				err = 0;  			} else if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -2265,14 +2294,19 @@ static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,  	struct devlink *devlink;  	struct devlink_sb *devlink_sb;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err = 0;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink)) +			continue; +  		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||  		    !devlink->ops->sb_port_pool_get) -			continue; +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(devlink_sb, &devlink->sb_list, list) {  			err = __sb_port_pool_get_dumpit(msg, start, &idx, @@ -2283,10 +2317,13 @@ static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,  				err = 0;  			} else if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -2506,14 +2543,18 @@ devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,  	struct devlink *devlink;  	struct devlink_sb *devlink_sb;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err = 0;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink)) +			continue; +  		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||  		    !devlink->ops->sb_tc_pool_bind_get) -			continue; +			goto retry;  		mutex_lock(&devlink->lock);  		list_for_each_entry(devlink_sb, &devlink->sb_list, list) { @@ -2526,10 +2567,13 @@ devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,  				err = 0;  			} else if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -3801,10 +3845,12 @@ static void devlink_param_notify(struct devlink *devlink,  				 struct devlink_param_item *param_item,  				 enum devlink_command cmd); -static void devlink_reload_netns_change(struct devlink *devlink, -					struct net *dest_net) +static void devlink_ns_change_notify(struct devlink *devlink, +				     struct net *dest_net, struct net *curr_net, +				     bool new)  {  	struct devlink_param_item *param_item; +	enum devlink_command cmd;  	/* Userspace needs to be notified about devlink objects  	 * removed from original and entering new network namespace. @@ -3812,17 +3858,18 @@ static void devlink_reload_netns_change(struct devlink *devlink,  	 * reload process so the notifications are generated separatelly.  	 */ -	list_for_each_entry(param_item, &devlink->param_list, list) -		devlink_param_notify(devlink, 0, param_item, -				     DEVLINK_CMD_PARAM_DEL); -	devlink_notify(devlink, DEVLINK_CMD_DEL); +	if (!dest_net || net_eq(dest_net, curr_net)) +		return; -	__devlink_net_set(devlink, dest_net); +	if (new) +		devlink_notify(devlink, DEVLINK_CMD_NEW); -	devlink_notify(devlink, DEVLINK_CMD_NEW); +	cmd = new ? DEVLINK_CMD_PARAM_NEW : DEVLINK_CMD_PARAM_DEL;  	list_for_each_entry(param_item, &devlink->param_list, list) -		devlink_param_notify(devlink, 0, param_item, -				     DEVLINK_CMD_PARAM_NEW); +		devlink_param_notify(devlink, 0, param_item, cmd); + +	if (!new) +		devlink_notify(devlink, DEVLINK_CMD_DEL);  }  static bool devlink_reload_supported(const struct devlink_ops *ops) @@ -3902,6 +3949,7 @@ static int devlink_reload(struct devlink *devlink, struct net *dest_net,  			  u32 *actions_performed, struct netlink_ext_ack *extack)  {  	u32 remote_reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE]; +	struct net *curr_net;  	int err;  	if (!devlink->reload_enabled) @@ -3909,18 +3957,22 @@ static int devlink_reload(struct devlink *devlink, struct net *dest_net,  	memcpy(remote_reload_stats, devlink->stats.remote_reload_stats,  	       sizeof(remote_reload_stats)); + +	curr_net = devlink_net(devlink); +	devlink_ns_change_notify(devlink, dest_net, curr_net, false);  	err = devlink->ops->reload_down(devlink, !!dest_net, action, limit, extack);  	if (err)  		return err; -	if (dest_net && !net_eq(dest_net, devlink_net(devlink))) -		devlink_reload_netns_change(devlink, dest_net); +	if (dest_net && !net_eq(dest_net, curr_net)) +		write_pnet(&devlink->_net, dest_net);  	err = devlink->ops->reload_up(devlink, action, limit, actions_performed, extack);  	devlink_reload_failed_set(devlink, !!err);  	if (err)  		return err; +	devlink_ns_change_notify(devlink, dest_net, curr_net, true);  	WARN_ON(!(*actions_performed & BIT(action)));  	/* Catch driver on updating the remote action within devlink reload */  	WARN_ON(memcmp(remote_reload_stats, devlink->stats.remote_reload_stats, @@ -4117,7 +4169,7 @@ out_free_msg:  static void devlink_flash_update_begin_notify(struct devlink *devlink)  { -	struct devlink_flash_notify params = { 0 }; +	struct devlink_flash_notify params = {};  	__devlink_flash_update_notify(devlink,  				      DEVLINK_CMD_FLASH_UPDATE, @@ -4126,7 +4178,7 @@ static void devlink_flash_update_begin_notify(struct devlink *devlink)  static void devlink_flash_update_end_notify(struct devlink *devlink)  { -	struct devlink_flash_notify params = { 0 }; +	struct devlink_flash_notify params = {};  	__devlink_flash_update_notify(devlink,  				      DEVLINK_CMD_FLASH_UPDATE_END, @@ -4283,6 +4335,21 @@ static const struct devlink_param devlink_param_generic[] = {  		.name = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_NAME,  		.type = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_TYPE,  	}, +	{ +		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH, +		.name = DEVLINK_PARAM_GENERIC_ENABLE_ETH_NAME, +		.type = DEVLINK_PARAM_GENERIC_ENABLE_ETH_TYPE, +	}, +	{ +		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA, +		.name = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_NAME, +		.type = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_TYPE, +	}, +	{ +		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET, +		.name = DEVLINK_PARAM_GENERIC_ENABLE_VNET_NAME, +		.type = DEVLINK_PARAM_GENERIC_ENABLE_VNET_TYPE, +	},  };  static int devlink_param_generic_verify(const struct devlink_param *param) @@ -4553,13 +4620,18 @@ static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,  	struct devlink_param_item *param_item;  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err = 0;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(param_item, &devlink->param_list, list) {  			if (idx < start) { @@ -4575,11 +4647,14 @@ static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,  				err = 0;  			} else if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  			idx++;  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -4821,13 +4896,18 @@ static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,  	struct devlink_port *devlink_port;  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err = 0;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(devlink_port, &devlink->port_list, list) {  			list_for_each_entry(param_item, @@ -4847,12 +4927,15 @@ static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,  					err = 0;  				} else if (err) {  					mutex_unlock(&devlink->lock); +					devlink_put(devlink);  					goto out;  				}  				idx++;  			}  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -5062,7 +5145,6 @@ static void devlink_nl_region_notify(struct devlink_region *region,  				     struct devlink_snapshot *snapshot,  				     enum devlink_command cmd)  { -	struct devlink *devlink = region->devlink;  	struct sk_buff *msg;  	WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL); @@ -5071,8 +5153,9 @@ static void devlink_nl_region_notify(struct devlink_region *region,  	if (IS_ERR(msg))  		return; -	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), -				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); +	genlmsg_multicast_netns(&devlink_nl_family, +				devlink_net(region->devlink), msg, 0, +				DEVLINK_MCGRP_CONFIG, GFP_KERNEL);  }  /** @@ -5390,15 +5473,22 @@ static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,  {  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0; -	int err; +	int err = 0;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; +  		err = devlink_nl_cmd_region_get_devlink_dumpit(msg, cb, devlink,  							       &idx, start); +retry: +		devlink_put(devlink);  		if (err)  			goto out;  	} @@ -5761,6 +5851,7 @@ static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,  	nla_nest_end(skb, chunks_attr);  	genlmsg_end(skb, hdr);  	mutex_unlock(&devlink->lock); +	devlink_put(devlink);  	mutex_unlock(&devlink_mutex);  	return skb->len; @@ -5769,6 +5860,7 @@ nla_put_failure:  	genlmsg_cancel(skb, hdr);  out_unlock:  	mutex_unlock(&devlink->lock); +	devlink_put(devlink);  out_dev:  	mutex_unlock(&devlink_mutex);  	return err; @@ -5915,22 +6007,20 @@ static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,  {  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err = 0;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; -		if (idx < start) { -			idx++; -			continue; -		} -		if (!devlink->ops->info_get) { -			idx++; -			continue; -		} +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; + +		if (idx < start || !devlink->ops->info_get) +			goto inc;  		mutex_lock(&devlink->lock);  		err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET, @@ -5940,9 +6030,14 @@ static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,  		mutex_unlock(&devlink->lock);  		if (err == -EOPNOTSUPP)  			err = 0; -		else if (err) +		else if (err) { +			devlink_put(devlink);  			break; +		} +inc:  		idx++; +retry: +		devlink_put(devlink);  	}  	mutex_unlock(&devlink_mutex); @@ -6756,11 +6851,11 @@ EXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy);  static int  devlink_nl_health_reporter_fill(struct sk_buff *msg, -				struct devlink *devlink,  				struct devlink_health_reporter *reporter,  				enum devlink_command cmd, u32 portid,  				u32 seq, int flags)  { +	struct devlink *devlink = reporter->devlink;  	struct nlattr *reporter_attr;  	void *hdr; @@ -6837,8 +6932,7 @@ static void devlink_recover_notify(struct devlink_health_reporter *reporter,  	if (!msg)  		return; -	err = devlink_nl_health_reporter_fill(msg, reporter->devlink, -					      reporter, cmd, 0, 0, 0); +	err = devlink_nl_health_reporter_fill(msg, reporter, cmd, 0, 0, 0);  	if (err) {  		nlmsg_free(msg);  		return; @@ -7028,6 +7122,7 @@ devlink_health_reporter_get_from_cb(struct netlink_callback *cb)  		goto unlock;  	reporter = devlink_health_reporter_get_from_attrs(devlink, attrs); +	devlink_put(devlink);  	mutex_unlock(&devlink_mutex);  	return reporter;  unlock: @@ -7071,7 +7166,7 @@ static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,  		goto out;  	} -	err = devlink_nl_health_reporter_fill(msg, devlink, reporter, +	err = devlink_nl_health_reporter_fill(msg, reporter,  					      DEVLINK_CMD_HEALTH_REPORTER_GET,  					      info->snd_portid, info->snd_seq,  					      0); @@ -7094,13 +7189,18 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,  	struct devlink_port *port;  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry_rep; +  		mutex_lock(&devlink->reporters_lock);  		list_for_each_entry(reporter, &devlink->reporter_list,  				    list) { @@ -7108,24 +7208,29 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,  				idx++;  				continue;  			} -			err = devlink_nl_health_reporter_fill(msg, devlink, -							      reporter, -							      DEVLINK_CMD_HEALTH_REPORTER_GET, -							      NETLINK_CB(cb->skb).portid, -							      cb->nlh->nlmsg_seq, -							      NLM_F_MULTI); +			err = devlink_nl_health_reporter_fill( +				msg, reporter, DEVLINK_CMD_HEALTH_REPORTER_GET, +				NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, +				NLM_F_MULTI);  			if (err) {  				mutex_unlock(&devlink->reporters_lock); +				devlink_put(devlink);  				goto out;  			}  			idx++;  		}  		mutex_unlock(&devlink->reporters_lock); +retry_rep: +		devlink_put(devlink);  	} -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry_port; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(port, &devlink->port_list, list) {  			mutex_lock(&port->reporters_lock); @@ -7134,14 +7239,15 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,  					idx++;  					continue;  				} -				err = devlink_nl_health_reporter_fill(msg, devlink, reporter, -								      DEVLINK_CMD_HEALTH_REPORTER_GET, -								      NETLINK_CB(cb->skb).portid, -								      cb->nlh->nlmsg_seq, -								      NLM_F_MULTI); +				err = devlink_nl_health_reporter_fill( +					msg, reporter, +					DEVLINK_CMD_HEALTH_REPORTER_GET, +					NETLINK_CB(cb->skb).portid, +					cb->nlh->nlmsg_seq, NLM_F_MULTI);  				if (err) {  					mutex_unlock(&port->reporters_lock);  					mutex_unlock(&devlink->lock); +					devlink_put(devlink);  					goto out;  				}  				idx++; @@ -7149,6 +7255,8 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,  			mutex_unlock(&port->reporters_lock);  		}  		mutex_unlock(&devlink->lock); +retry_port: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -7677,13 +7785,18 @@ static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,  	struct devlink_trap_item *trap_item;  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(trap_item, &devlink->trap_list, list) {  			if (idx < start) { @@ -7697,11 +7810,14 @@ static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,  						   NLM_F_MULTI);  			if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  			idx++;  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -7896,13 +8012,18 @@ static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,  	u32 portid = NETLINK_CB(cb->skb).portid;  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(group_item, &devlink->trap_group_list,  				    list) { @@ -7917,11 +8038,14 @@ static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,  							 NLM_F_MULTI);  			if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  			idx++;  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -8202,13 +8326,18 @@ static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,  	u32 portid = NETLINK_CB(cb->skb).portid;  	struct devlink *devlink;  	int start = cb->args[0]; +	unsigned long index;  	int idx = 0;  	int err;  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink))  			continue; + +		if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) +			goto retry; +  		mutex_lock(&devlink->lock);  		list_for_each_entry(policer_item, &devlink->trap_policer_list,  				    list) { @@ -8223,11 +8352,14 @@ static int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,  							   NLM_F_MULTI);  			if (err) {  				mutex_unlock(&devlink->lock); +				devlink_put(devlink);  				goto out;  			}  			idx++;  		}  		mutex_unlock(&devlink->lock); +retry: +		devlink_put(devlink);  	}  out:  	mutex_unlock(&devlink_mutex); @@ -8768,30 +8900,44 @@ static bool devlink_reload_actions_valid(const struct devlink_ops *ops)  }  /** - *	devlink_alloc - Allocate new devlink instance resources + *	devlink_alloc_ns - Allocate new devlink instance resources + *	in specific namespace   *   *	@ops: ops   *	@priv_size: size of user private data + *	@net: net namespace + *	@dev: parent device   *   *	Allocate new devlink instance resources, including devlink index   *	and name.   */ -struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size) +struct devlink *devlink_alloc_ns(const struct devlink_ops *ops, +				 size_t priv_size, struct net *net, +				 struct device *dev)  {  	struct devlink *devlink; +	static u32 last_id; +	int ret; -	if (WARN_ON(!ops)) -		return NULL; - +	WARN_ON(!ops || !dev);  	if (!devlink_reload_actions_valid(ops))  		return NULL;  	devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);  	if (!devlink)  		return NULL; + +	ret = xa_alloc_cyclic(&devlinks, &devlink->index, devlink, xa_limit_31b, +			      &last_id, GFP_KERNEL); +	if (ret < 0) { +		kfree(devlink); +		return NULL; +	} + +	devlink->dev = dev;  	devlink->ops = ops;  	xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC); -	__devlink_net_set(devlink, &init_net); +	write_pnet(&devlink->_net, net);  	INIT_LIST_HEAD(&devlink->port_list);  	INIT_LIST_HEAD(&devlink->rate_list);  	INIT_LIST_HEAD(&devlink->sb_list); @@ -8805,22 +8951,22 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)  	INIT_LIST_HEAD(&devlink->trap_policer_list);  	mutex_init(&devlink->lock);  	mutex_init(&devlink->reporters_lock); +	refcount_set(&devlink->refcount, 1); +	init_completion(&devlink->comp); +  	return devlink;  } -EXPORT_SYMBOL_GPL(devlink_alloc); +EXPORT_SYMBOL_GPL(devlink_alloc_ns);  /**   *	devlink_register - Register devlink instance   *   *	@devlink: devlink - *	@dev: parent device   */ -int devlink_register(struct devlink *devlink, struct device *dev) +int devlink_register(struct devlink *devlink)  { -	devlink->dev = dev; -	devlink->registered = true;  	mutex_lock(&devlink_mutex); -	list_add_tail(&devlink->list, &devlink_list); +	xa_set_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);  	devlink_notify(devlink, DEVLINK_CMD_NEW);  	mutex_unlock(&devlink_mutex);  	return 0; @@ -8834,11 +8980,14 @@ EXPORT_SYMBOL_GPL(devlink_register);   */  void devlink_unregister(struct devlink *devlink)  { +	devlink_put(devlink); +	wait_for_completion(&devlink->comp); +  	mutex_lock(&devlink_mutex);  	WARN_ON(devlink_reload_supported(devlink->ops) &&  		devlink->reload_enabled);  	devlink_notify(devlink, DEVLINK_CMD_DEL); -	list_del(&devlink->list); +	xa_clear_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);  	mutex_unlock(&devlink_mutex);  }  EXPORT_SYMBOL_GPL(devlink_unregister); @@ -8900,6 +9049,7 @@ void devlink_free(struct devlink *devlink)  	WARN_ON(!list_empty(&devlink->port_list));  	xa_destroy(&devlink->snapshot_ids); +	xa_erase(&devlinks, devlink->index);  	kfree(devlink);  } @@ -8960,9 +9110,10 @@ int devlink_port_register(struct devlink *devlink,  		mutex_unlock(&devlink->lock);  		return -EEXIST;  	} + +	WARN_ON(devlink_port->devlink);  	devlink_port->devlink = devlink;  	devlink_port->index = port_index; -	devlink_port->registered = true;  	spin_lock_init(&devlink_port->type_lock);  	INIT_LIST_HEAD(&devlink_port->reporter_list);  	mutex_init(&devlink_port->reporters_lock); @@ -9001,7 +9152,7 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port,  				    enum devlink_port_type type,  				    void *type_dev)  { -	if (WARN_ON(!devlink_port->registered)) +	if (WARN_ON(!devlink_port->devlink))  		return;  	devlink_port_type_warn_cancel(devlink_port);  	spin_lock_bh(&devlink_port->type_lock); @@ -9121,7 +9272,7 @@ void devlink_port_attrs_set(struct devlink_port *devlink_port,  {  	int ret; -	if (WARN_ON(devlink_port->registered)) +	if (WARN_ON(devlink_port->devlink))  		return;  	devlink_port->attrs = *attrs;  	ret = __devlink_port_attrs_set(devlink_port, attrs->flavour); @@ -9145,7 +9296,7 @@ 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)) +	if (WARN_ON(devlink_port->devlink))  		return;  	ret = __devlink_port_attrs_set(devlink_port,  				       DEVLINK_PORT_FLAVOUR_PCI_PF); @@ -9172,7 +9323,7 @@ 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)) +	if (WARN_ON(devlink_port->devlink))  		return;  	ret = __devlink_port_attrs_set(devlink_port,  				       DEVLINK_PORT_FLAVOUR_PCI_VF); @@ -9200,7 +9351,7 @@ void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 contro  	struct devlink_port_attrs *attrs = &devlink_port->attrs;  	int ret; -	if (WARN_ON(devlink_port->registered)) +	if (WARN_ON(devlink_port->devlink))  		return;  	ret = __devlink_port_attrs_set(devlink_port,  				       DEVLINK_PORT_FLAVOUR_PCI_SF); @@ -9788,6 +9939,22 @@ static int devlink_param_verify(const struct devlink_param *param)  		return devlink_param_driver_verify(param);  } +static int __devlink_param_register_one(struct devlink *devlink, +					unsigned int port_index, +					struct list_head *param_list, +					const struct devlink_param *param, +					enum devlink_command reg_cmd) +{ +	int err; + +	err = devlink_param_verify(param); +	if (err) +		return err; + +	return devlink_param_register_one(devlink, port_index, +					  param_list, param, reg_cmd); +} +  static int __devlink_params_register(struct devlink *devlink,  				     unsigned int port_index,  				     struct list_head *param_list, @@ -9802,12 +9969,8 @@ static int __devlink_params_register(struct devlink *devlink,  	mutex_lock(&devlink->lock);  	for (i = 0; i < params_count; i++, param++) { -		err = devlink_param_verify(param); -		if (err) -			goto rollback; - -		err = devlink_param_register_one(devlink, port_index, -						 param_list, param, reg_cmd); +		err = __devlink_param_register_one(devlink, port_index, +						   param_list, param, reg_cmd);  		if (err)  			goto rollback;  	} @@ -9880,6 +10043,43 @@ void devlink_params_unregister(struct devlink *devlink,  EXPORT_SYMBOL_GPL(devlink_params_unregister);  /** + * devlink_param_register - register one configuration parameter + * + * @devlink: devlink + * @param: one configuration parameter + * + * Register the configuration parameter supported by the driver. + * Return: returns 0 on successful registration or error code otherwise. + */ +int devlink_param_register(struct devlink *devlink, +			   const struct devlink_param *param) +{ +	int err; + +	mutex_lock(&devlink->lock); +	err = __devlink_param_register_one(devlink, 0, &devlink->param_list, +					   param, DEVLINK_CMD_PARAM_NEW); +	mutex_unlock(&devlink->lock); +	return err; +} +EXPORT_SYMBOL_GPL(devlink_param_register); + +/** + * devlink_param_unregister - unregister one configuration parameter + * @devlink: devlink + * @param: configuration parameter to unregister + */ +void devlink_param_unregister(struct devlink *devlink, +			      const struct devlink_param *param) +{ +	mutex_lock(&devlink->lock); +	devlink_param_unregister_one(devlink, 0, &devlink->param_list, param, +				     DEVLINK_CMD_PARAM_DEL); +	mutex_unlock(&devlink->lock); +} +EXPORT_SYMBOL_GPL(devlink_param_unregister); + +/**   *	devlink_params_publish - publish configuration parameters   *   *	@devlink: devlink @@ -9922,6 +10122,54 @@ void devlink_params_unpublish(struct devlink *devlink)  EXPORT_SYMBOL_GPL(devlink_params_unpublish);  /** + * devlink_param_publish - publish one configuration parameter + * + * @devlink: devlink + * @param: one configuration parameter + * + * Publish previously registered configuration parameter. + */ +void devlink_param_publish(struct devlink *devlink, +			   const struct devlink_param *param) +{ +	struct devlink_param_item *param_item; + +	list_for_each_entry(param_item, &devlink->param_list, list) { +		if (param_item->param != param || param_item->published) +			continue; +		param_item->published = true; +		devlink_param_notify(devlink, 0, param_item, +				     DEVLINK_CMD_PARAM_NEW); +		break; +	} +} +EXPORT_SYMBOL_GPL(devlink_param_publish); + +/** + * devlink_param_unpublish - unpublish one configuration parameter + * + * @devlink: devlink + * @param: one configuration parameter + * + * Unpublish previously registered configuration parameter. + */ +void devlink_param_unpublish(struct devlink *devlink, +			     const struct devlink_param *param) +{ +	struct devlink_param_item *param_item; + +	list_for_each_entry(param_item, &devlink->param_list, list) { +		if (param_item->param != param || !param_item->published) +			continue; +		param_item->published = false; +		devlink_param_notify(devlink, 0, param_item, +				     DEVLINK_CMD_PARAM_DEL); +		break; +	} +} +EXPORT_SYMBOL_GPL(devlink_param_unpublish); + +/**   *	devlink_port_params_register - register port configuration parameters   *   *	@devlink_port: devlink port @@ -11276,23 +11524,29 @@ static void __net_exit devlink_pernet_pre_exit(struct net *net)  {  	struct devlink *devlink;  	u32 actions_performed; +	unsigned long index;  	int err;  	/* In case network namespace is getting destroyed, reload  	 * all devlink instances from this namespace into init_net.  	 */  	mutex_lock(&devlink_mutex); -	list_for_each_entry(devlink, &devlink_list, list) { -		if (net_eq(devlink_net(devlink), net)) { -			if (WARN_ON(!devlink_reload_supported(devlink->ops))) -				continue; -			err = devlink_reload(devlink, &init_net, -					     DEVLINK_RELOAD_ACTION_DRIVER_REINIT, -					     DEVLINK_RELOAD_LIMIT_UNSPEC, -					     &actions_performed, NULL); -			if (err && err != -EOPNOTSUPP) -				pr_warn("Failed to reload devlink instance into init_net\n"); -		} +	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { +		if (!devlink_try_get(devlink)) +			continue; + +		if (!net_eq(devlink_net(devlink), net)) +			goto retry; + +		WARN_ON(!devlink_reload_supported(devlink->ops)); +		err = devlink_reload(devlink, &init_net, +				     DEVLINK_RELOAD_ACTION_DRIVER_REINIT, +				     DEVLINK_RELOAD_LIMIT_UNSPEC, +				     &actions_performed, NULL); +		if (err && err != -EOPNOTSUPP) +			pr_warn("Failed to reload devlink instance into init_net\n"); +retry: +		devlink_put(devlink);  	}  	mutex_unlock(&devlink_mutex);  }  | 
