Skip to contentSkip to conversation

Devlink cleanup for delay event series

PATCH Applied Leon Romanovsky 4 participants 19 messages Aug 14, 2021 – Aug 20, 2021

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover Devlink cleanup for delay event series

From: Leon Romanovsky <[email protected]>

Hi,

Jakub's request to make sure that devlink events are delayed and not printed till they fully accessible [1] requires us to implement delayed event notification system in the devlink.

In order to do it, I moved some of my patches (xarray e.t.c) from the future series to be before "Move devlink_register to be near devlink_reload_enable" [2].

That allows us to rely on DEVLINK_REGISTERED xarray mark to decide if to print event or not.

Other patches are simple cleanup which is needed anyway.

[1] https://lore.kernel.org/lkml/20210811071817.4af5ab34@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com
[2] https://lore.kernel.org/lkml/[email protected]

Next in the queue:
* Delay event series
* Move devlink_register to be near devlink_reload_enable"
* Extension of devlink_ops to be set dynamically
* devlink_reload_* delete
* Devlink locks rework to user xarray and reference counting
* ????

Thanks

Leon Romanovsky (6):
devlink: Simplify devlink_pernet_pre_exit call
devlink: Remove check of always valid devlink pointer
devlink: Count struct devlink consumers
devlink: Use xarray to store devlink instances
devlink: Clear whole devlink_flash_notify struct
net: hns3: remove always exist devlink pointer check

 .../hisilicon/hns3/hns3pf/hclge_devlink.c     |   8 +-
 .../hisilicon/hns3/hns3vf/hclgevf_devlink.c   |   8 +-
 include/net/devlink.h                         |   4 +-
 net/core/devlink.c                            | 391 ++++++++++++------
 4 files changed, 273 insertions(+), 138 deletions(-)
Signature · 1 line
2.31.1
#1 lore raw

PATCH 1/6 devlink: Simplify devlink_pernet_pre_exit call

From: Leon Romanovsky <[email protected]>

The devlink_pernet_pre_exit() will be called if net namespace exits.

That routine is relevant for devlink instances that were assigned to that namespaces first. This assignment is possible only with the following
command: "devlink reload DEV netns ...", which already checks reload support.

---
 net/core/devlink.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
net/core/devlink.c +10 -10
index ee9787314cff..9e74a95b3322 100644
@@ -11392,16 +11392,16 @@ static void __net_exit devlink_pernet_pre_exit(struct net *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");
-		}
+		if (!net_eq(devlink_net(devlink), net))
+			continue;
+
+		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");
 	}
 	mutex_unlock(&devlink_mutex);
 }
Signature · 1 line
2.31.1
#2 lore raw

PATCH 2/6 devlink: Remove check of always valid devlink pointer

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Devlink objects are accessible only after they were registered and have valid devlink_*->devlink pointers.

Remove that check and simplify respective fill functions as an outcome of such change.

---
 net/core/devlink.c | 94 +++++++++++++++++++---------------------------
 1 file changed, 38 insertions(+), 56 deletions(-)
net/core/devlink.c +38 -56
index 9e74a95b3322..c8a8eecad1c5 100644
@@ -832,12 +832,11 @@ static int devlink_port_fn_hw_addr_fill(const struct devlink_ops *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);
@@ -959,12 +958,12 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por
 	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);
@@ -1025,53 +1024,47 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
 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->devlink)
-		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,
@@ -1096,9 +1089,7 @@ 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) {
@@ -1122,7 +1113,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;
 
@@ -1130,8 +1120,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) {
@@ -1208,7 +1197,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;
 
@@ -1216,8 +1204,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) {
@@ -1247,12 +1234,11 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
 				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);
 				goto out;
@@ -1488,9 +1474,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;
 
@@ -5071,7 +5056,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);
@@ -5080,8 +5064,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);
 }
 
 /**
@@ -6765,11 +6750,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;
 
@@ -6846,8 +6831,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;
@@ -7080,7 +7064,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);
@@ -7117,12 +7101,10 @@ 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);
 				goto out;
@@ -7143,11 +7125,11 @@ 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);
Signature · 1 line
2.31.1
#3 lore raw

PATCH 3/6 devlink: Count struct devlink consumers

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

The reference counting provides us a way to ensure that no new user space commands success to grab devlink instance which is going to be destroyed makes it is safe to access it without lock.

---
 include/net/devlink.h |   2 +
 net/core/devlink.c    | 205 ++++++++++++++++++++++++++++++++++--------
 2 files changed, 172 insertions(+), 35 deletions(-)
include/net/devlink.h +2 -0
index 1151497c0ec5..4c60d61d92da 100644
@@ -56,6 +56,8 @@ struct devlink {
 			    */
 	u8 reload_failed:1,
 	   reload_enabled:1;
+	refcount_t refcount;
+	struct completion comp;
 	char priv[0] __aligned(NETDEV_ALIGN);
 };
 
net/core/devlink.c +170 -35

561 lines not on this page · raw message

Signature · 1 line
2.31.1
maintainer
#4 lore raw

Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 10 lines · On Sat, 14 Aug 2021 12:57:28 +0300 Leon Romanovsky wrote:

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

Not a problem with this set but to state the obvious the global devlink lock also protects from concurrent execution of all the ops which don't take the instance lock (DEVLINK_NL_FLAG_NO_LOCK). You most likely know this but I thought I'd comment on an off chance it helps.

Quoted 3 lines

The reference counting provides us a way to ensure that no new user space commands success to grab devlink instance which is going to be destroyed makes it is safe to access it without lock.

#5 lore raw

Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 8 lines · Jakub Kicinski
Quoted 7 lines · On Sat, 14 Aug 2021 12:57:28 +0300 Leon Romanovsky wrote:

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

Quoted 8 lines
Quoted 3 lines

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

Not a problem with this set but to state the obvious the global devlink lock also protects from concurrent execution of all the ops which don't take the instance lock (DEVLINK_NL_FLAG_NO_LOCK). You most likely know this but I thought I'd comment on an off chance it helps.

The end goal will be something like that:
1. Delete devlink lock
2. Rely on xa_lock() while grabbing devlink instance (past devlink_try_get)
3. Convert devlink->lock to be read/write lock to make sure that we can run get query in parallel.
4. Open devlink netlink to parallel ops, ".parallel_ops = true".

Thanks

Quoted 5 lines
Quoted 4 lines

The reference counting provides us a way to ensure that no new user space commands success to grab devlink instance which is going to be destroyed makes it is safe to access it without lock.

maintainer
#6 lore raw

Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 18 lines · On Mon, 16 Aug 2021 18:53:45 +0300 Leon Romanovsky wrote:
Quoted 8 lines · Jakub Kicinski
Quoted 7 lines · On Sat, 14 Aug 2021 12:57:28 +0300 Leon Romanovsky wrote:

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

Quoted 8 lines
Quoted 3 lines

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

Not a problem with this set but to state the obvious the global devlink lock also protects from concurrent execution of all the ops which don't take the instance lock (DEVLINK_NL_FLAG_NO_LOCK). You most likely know this but I thought I'd comment on an off chance it helps.

Quoted 6 lines

The end goal will be something like that:
1. Delete devlink lock
2. Rely on xa_lock() while grabbing devlink instance (past devlink_try_get)
3. Convert devlink->lock to be read/write lock to make sure that we can run get query in parallel.
4. Open devlink netlink to parallel ops, ".parallel_ops = true".

IIUC that'd mean setting eswitch mode would hold write lock on the dl instance. What locks does e.g. registering a dl port take then?

#7 lore raw

RE: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 40 lines

-----Original Message-----
From: Jakub Kicinski <[email protected]>
Sent: Monday, August 16, 2021 9:07 AM
To: Leon Romanovsky <[email protected]>
Cc: David S . Miller <[email protected]>; Guangbin Huang <[email protected]>; Keller, Jacob E <[email protected]>; Jiri Pirko <[email protected]>; [email protected]; [email protected]; Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 18 lines · On Mon, 16 Aug 2021 18:53:45 +0300 Leon Romanovsky wrote:
Quoted 8 lines · Jakub Kicinski
Quoted 7 lines · On Sat, 14 Aug 2021 12:57:28 +0300 Leon Romanovsky wrote:

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

Quoted 8 lines
Quoted 3 lines

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

Not a problem with this set but to state the obvious the global devlink lock also protects from concurrent execution of all the ops which don't take the instance lock (DEVLINK_NL_FLAG_NO_LOCK). You most likely know this but I thought I'd comment on an off chance it helps.

Quoted 6 lines

The end goal will be something like that:
1. Delete devlink lock
2. Rely on xa_lock() while grabbing devlink instance (past devlink_try_get)
3. Convert devlink->lock to be read/write lock to make sure that we can run get query in parallel.
4. Open devlink netlink to parallel ops, ".parallel_ops = true".

Quoted 3 lines

IIUC that'd mean setting eswitch mode would hold write lock on the dl instance. What locks does e.g. registering a dl port take then?

Also that I think we have some cases where we want to allow the driver to allocate new devlink objects in response to adding a port, but still want to block other global operations from running?

#8 lore raw

Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 40 lines · Jacob E
Quoted 40 lines

-----Original Message-----
From: Jakub Kicinski <[email protected]>
Sent: Monday, August 16, 2021 9:07 AM
To: Leon Romanovsky <[email protected]>
Cc: David S . Miller <[email protected]>; Guangbin Huang <[email protected]>; Keller, Jacob E <[email protected]>; Jiri Pirko <[email protected]>; [email protected]; [email protected]; Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 24 lines · On Mon, 16 Aug 2021 18:53:45 +0300 Leon Romanovsky wrote:
Quoted 8 lines · Jakub Kicinski
Quoted 7 lines · On Sat, 14 Aug 2021 12:57:28 +0300 Leon Romanovsky wrote:

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

Quoted 8 lines
Quoted 3 lines

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

Not a problem with this set but to state the obvious the global devlink lock also protects from concurrent execution of all the ops which don't take the instance lock (DEVLINK_NL_FLAG_NO_LOCK). You most likely know this but I thought I'd comment on an off chance it helps.

The end goal will be something like that:
1. Delete devlink lock
2. Rely on xa_lock() while grabbing devlink instance (past devlink_try_get)
3. Convert devlink->lock to be read/write lock to make sure that we can run get query in parallel.
4. Open devlink netlink to parallel ops, ".parallel_ops = true".

Quoted 5 lines
Quoted 3 lines

IIUC that'd mean setting eswitch mode would hold write lock on the dl instance. What locks does e.g. registering a dl port take then?

Also that I think we have some cases where we want to allow the driver to allocate new devlink objects in response to adding a port, but still want to block other global operations from running?

I don't see the flow where operations on devlink_A should block devlink_B. Only in such flows we will need global lock like we have now - devlink->lock. In all other flows, write lock of devlink instance will protect from parallel execution.

Thanks

#9 lore raw

RE: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 65 lines

-----Original Message-----
From: Leon Romanovsky <[email protected]>
Sent: Wednesday, August 18, 2021 1:12 AM
To: Keller, Jacob E <[email protected]>
Cc: Jakub Kicinski <[email protected]>; David S . Miller <[email protected]>; Guangbin Huang <[email protected]>; Jiri Pirko <[email protected]>; [email protected]; [email protected]; Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 8 lines · Jacob E
Quoted 8 lines

-----Original Message-----
From: Jakub Kicinski <[email protected]>
Sent: Monday, August 16, 2021 9:07 AM
To: Leon Romanovsky <[email protected]>
Cc: David S . Miller <[email protected]>; Guangbin Huang <[email protected]>; Keller, Jacob E <[email protected]>;

Jiri

Quoted 1 line
Quoted 1 line

Pirko <[email protected]>; [email protected];

[email protected];

Quoted 15 lines
Quoted 15 lines

Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 9 lines · On Mon, 16 Aug 2021 18:53:45 +0300 Leon Romanovsky wrote:
Quoted 8 lines · Jakub Kicinski
Quoted 7 lines · On Sat, 14 Aug 2021 12:57:28 +0300 Leon Romanovsky wrote:

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

Not a problem with this set but to state the obvious the global devlink lock also protects from concurrent execution of all the ops which don't take the instance lock (DEVLINK_NL_FLAG_NO_LOCK). You most likely

know

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Quoted 1 line

this but I thought I'd comment on an off chance it helps.

The end goal will be something like that:
1. Delete devlink lock
2. Rely on xa_lock() while grabbing devlink instance (past devlink_try_get)
3. Convert devlink->lock to be read/write lock to make sure that we can run get query in parallel.
4. Open devlink netlink to parallel ops, ".parallel_ops = true".

Quoted 5 lines
Quoted 3 lines

IIUC that'd mean setting eswitch mode would hold write lock on the dl instance. What locks does e.g. registering a dl port take then?

Also that I think we have some cases where we want to allow the driver to

allocate new devlink objects in response to adding a port, but still want to block other global operations from running?

Quoted 6 lines

I don't see the flow where operations on devlink_A should block devlink_B. Only in such flows we will need global lock like we have now - devlink->lock. In all other flows, write lock of devlink instance will protect from parallel execution.

Thanks

But how do we handle what is essentially recursion?

If we add a port on the devlink A:

userspace sends PORT_ADD for devlink A
driver responds by creating a port
adding a port causes driver to add a region, or other devlink object

In the current design, if I understand correctly, we hold the global lock but *not* the instance lock. We can't hold the instance lock while adding port without breaking a bunch of drivers that add many devlink objects in response to port creation.. because they'll deadlock when going to add the sub objects.

But if we don't hold the global lock, then in theory another userspace program could attempt to do something inbetween PORT_ADD starting and finishing which might not be desirable. (Remember, we had to drop the instance lock otherwise drivers get stuck when trying to add many subobjects)

Thanks,
Jake

#10 lore raw

Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 70 lines · Jacob E
Quoted 70 lines

-----Original Message-----
From: Leon Romanovsky <[email protected]>
Sent: Wednesday, August 18, 2021 1:12 AM
To: Keller, Jacob E <[email protected]>
Cc: Jakub Kicinski <[email protected]>; David S . Miller <[email protected]>; Guangbin Huang <[email protected]>; Jiri Pirko <[email protected]>; [email protected]; [email protected]; Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 8 lines · Jacob E
Quoted 8 lines

-----Original Message-----
From: Jakub Kicinski <[email protected]>
Sent: Monday, August 16, 2021 9:07 AM
To: Leon Romanovsky <[email protected]>
Cc: David S . Miller <[email protected]>; Guangbin Huang <[email protected]>; Keller, Jacob E <[email protected]>;

Jiri

Quoted 1 line
Quoted 1 line

Pirko <[email protected]>; [email protected];

[email protected];

Quoted 15 lines
Quoted 15 lines

Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 9 lines · On Mon, 16 Aug 2021 18:53:45 +0300 Leon Romanovsky wrote:
Quoted 8 lines · Jakub Kicinski
Quoted 7 lines · On Sat, 14 Aug 2021 12:57:28 +0300 Leon Romanovsky wrote:

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

Not a problem with this set but to state the obvious the global devlink lock also protects from concurrent execution of all the ops which don't take the instance lock (DEVLINK_NL_FLAG_NO_LOCK). You most likely

know

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Quoted 1 line

this but I thought I'd comment on an off chance it helps.

The end goal will be something like that:
1. Delete devlink lock
2. Rely on xa_lock() while grabbing devlink instance (past devlink_try_get)
3. Convert devlink->lock to be read/write lock to make sure that we can run get query in parallel.
4. Open devlink netlink to parallel ops, ".parallel_ops = true".

Quoted 5 lines
Quoted 3 lines

IIUC that'd mean setting eswitch mode would hold write lock on the dl instance. What locks does e.g. registering a dl port take then?

Also that I think we have some cases where we want to allow the driver to

allocate new devlink objects in response to adding a port, but still want to block other global operations from running?

I don't see the flow where operations on devlink_A should block devlink_B. Only in such flows we will need global lock like we have now - devlink->lock. In all other flows, write lock of devlink instance will protect from parallel execution.

Quoted 4 lines
Quoted 1 line

Thanks

But how do we handle what is essentially recursion?

Let's wait till implementation, I promise it will be covered :).

Quoted 10 lines

If we add a port on the devlink A:

userspace sends PORT_ADD for devlink A
driver responds by creating a port
adding a port causes driver to add a region, or other devlink object

In the current design, if I understand correctly, we hold the global lock but *not* the instance lock. We can't hold the instance lock while adding port without breaking a bunch of drivers that add many devlink objects in response to port creation.. because they'll deadlock when going to add the sub objects.

But if we don't hold the global lock, then in theory another userspace program could attempt to do something inbetween PORT_ADD starting and finishing which might not be desirable. (Remember, we had to drop the instance lock otherwise drivers get stuck when trying to add many subobjects)

You just surfaced my main issue with the current devlink implementation - the purpose of devlink_lock. Over the years devlink code lost clear separation between user space flows and kernel flows.

Thanks

Quoted 3 lines

Thanks,
Jake

#11 lore raw

RE: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 91 lines

-----Original Message-----
From: Leon Romanovsky <[email protected]>
Sent: Friday, August 20, 2021 6:07 AM
To: Keller, Jacob E <[email protected]>
Cc: Jakub Kicinski <[email protected]>; David S . Miller <[email protected]>; Guangbin Huang <[email protected]>; Jiri Pirko <[email protected]>; [email protected]; [email protected]; Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 7 lines · Jacob E
Quoted 7 lines

-----Original Message-----
From: Leon Romanovsky <[email protected]>
Sent: Wednesday, August 18, 2021 1:12 AM
To: Keller, Jacob E <[email protected]>
Cc: Jakub Kicinski <[email protected]>; David S . Miller

<[email protected]>;

Quoted 1 line
Quoted 1 line

Guangbin Huang <[email protected]>; Jiri Pirko

<[email protected]>;

Quoted 8 lines
Quoted 8 lines

[email protected]; [email protected]; Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 2 lines · Jacob E
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

-----Original Message-----
From: Jakub Kicinski <[email protected]>
Sent: Monday, August 16, 2021 9:07 AM
To: Leon Romanovsky <[email protected]>
Cc: David S . Miller <[email protected]>; Guangbin Huang <[email protected]>; Keller, Jacob E

<[email protected]>;

Quoted 5 lines
Quoted 5 lines

Jiri

Quoted 1 line
Quoted 1 line

Pirko <[email protected]>; [email protected];

[email protected];

Quoted 2 lines
Quoted 2 lines

Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>;

Yufeng

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
Quoted 20 lines

Mo <[email protected]>
Subject: Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

Quoted 16 lines · On Mon, 16 Aug 2021 18:53:45 +0300 Leon Romanovsky wrote:
Quoted 15 lines · Jakub Kicinski
Quoted 10 lines · On Sat, 14 Aug 2021 12:57:28 +0300 Leon Romanovsky wrote:

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

Not a problem with this set but to state the obvious the global devlink lock also protects from concurrent execution of all the ops which don't take the instance lock (DEVLINK_NL_FLAG_NO_LOCK). You most likely

Quoted 6 lines
Quoted 6 lines

know

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line

this but I thought I'd comment on an off chance it helps.

The end goal will be something like that:
1. Delete devlink lock
2. Rely on xa_lock() while grabbing devlink instance (past

devlink_try_get)

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

3. Convert devlink->lock to be read/write lock to make sure that we can

run

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

get query in parallel.
4. Open devlink netlink to parallel ops, ".parallel_ops = true".

IIUC that'd mean setting eswitch mode would hold write lock on the dl instance. What locks does e.g. registering a dl port take then?

Also that I think we have some cases where we want to allow the driver to

allocate new devlink objects in response to adding a port, but still want to

block

Quoted 7 lines
Quoted 7 lines

other global operations from running?

I don't see the flow where operations on devlink_A should block devlink_B. Only in such flows we will need global lock like we have now - devlink->lock. In all other flows, write lock of devlink instance will protect from parallel execution.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

Thanks

But how do we handle what is essentially recursion?

Let's wait till implementation, I promise it will be covered :).

Sure. It's certainly easier to talk about a proposed implementation once we have it.

Quoted 17 lines
Quoted 8 lines

If we add a port on the devlink A:

userspace sends PORT_ADD for devlink A
driver responds by creating a port
adding a port causes driver to add a region, or other devlink object

In the current design, if I understand correctly, we hold the global lock but

*not* the instance lock. We can't hold the instance lock while adding port without breaking a bunch of drivers that add many devlink objects in response to port creation.. because they'll deadlock when going to add the sub objects.

Quoted 2 lines

But if we don't hold the global lock, then in theory another userspace program

could attempt to do something inbetween PORT_ADD starting and finishing which might not be desirable. (Remember, we had to drop the instance lock otherwise drivers get stuck when trying to add many subobjects)

Quoted 6 lines

You just surfaced my main issue with the current devlink implementation - the purpose of devlink_lock. Over the years devlink code lost clear separation between user space flows and kernel flows.

Thanks

Yep. It's definitely complex.

Quoted 3 lines
Quoted 3 lines

Thanks,
Jake

#12 lore raw

Re: [PATCH net-next 3/6] devlink: Count struct devlink consumers

In reply to Jakub Kicinski
Quoted 26 lines · Jakub Kicinski
Quoted 18 lines · On Mon, 16 Aug 2021 18:53:45 +0300 Leon Romanovsky wrote:
Quoted 8 lines · Jakub Kicinski
Quoted 7 lines · On Sat, 14 Aug 2021 12:57:28 +0300 Leon Romanovsky wrote:

From: Leon Romanovsky <[email protected]>

The struct devlink itself is protected by internal lock and doesn't need global lock during operation. That global lock is used to protect addition/removal new devlink instances from the global list in use by all devlink consumers in the system.

Quoted 8 lines
Quoted 3 lines

The future conversion of linked list to be xarray will allow us to actually delete that lock, but first we need to count all struct devlink users.

Not a problem with this set but to state the obvious the global devlink lock also protects from concurrent execution of all the ops which don't take the instance lock (DEVLINK_NL_FLAG_NO_LOCK). You most likely know this but I thought I'd comment on an off chance it helps.

Quoted 6 lines

The end goal will be something like that:
1. Delete devlink lock
2. Rely on xa_lock() while grabbing devlink instance (past devlink_try_get)
3. Convert devlink->lock to be read/write lock to make sure that we can run get query in parallel.
4. Open devlink netlink to parallel ops, ".parallel_ops = true".

Quoted 3 lines

IIUC that'd mean setting eswitch mode would hold write lock on the dl instance. What locks does e.g. registering a dl port take then?

write lock, because we are adding port to devlink->port_list.
9099 int devlink_port_register(struct devlink *devlink,
9100 struct devlink_port *devlink_port,
9101 unsigned int port_index)
9102 {
...
9115 list_add_tail(&devlink_port->list, &devlink->port_list);

#13 lore raw

PATCH 4/6 devlink: Use xarray to store devlink instances

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

We can use xarray instead of linearly organized linked lists for the devlink instances. This will let us revise the locking scheme in favour of internal xarray locking that protects database.

---
 include/net/devlink.h |  2 +-
 net/core/devlink.c    | 70 ++++++++++++++++++++++++++++++-------------
 2 files changed, 50 insertions(+), 22 deletions(-)
include/net/devlink.h +1 -1
index 4c60d61d92da..154cf0dbca37 100644
@@ -32,7 +32,7 @@ struct devlink_dev_stats {
 struct devlink_ops;
 
 struct devlink {
-	struct list_head list;
+	u32 index;
 	struct list_head port_list;
 	struct list_head rate_list;
 	struct list_head sb_list;
net/core/devlink.c +49 -21

286 lines not on this page · raw message

Signature · 1 line
2.31.1
Reviewed-by on v1 4/6
#14 lore raw

RE: [PATCH net-next 4/6] devlink: Use xarray to store devlink instances

Quoted 14 lines

-----Original Message-----
From: Leon Romanovsky <[email protected]>
Sent: Saturday, August 14, 2021 2:57 AM
To: David S . Miller <[email protected]>; Jakub Kicinski <[email protected]>
Cc: Leon Romanovsky <[email protected]>; Guangbin Huang <[email protected]>; Keller, Jacob E <[email protected]>; Jiri Pirko <[email protected]>; [email protected]; [email protected]; Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: [PATCH net-next 4/6] devlink: Use xarray to store devlink instances

Quoted 6 lines

From: Leon Romanovsky <[email protected]>

We can use xarray instead of linearly organized linked lists for the devlink instances. This will let us revise the locking scheme in favour of internal xarray locking that protects database.

Nice. Seems like an xarray makes quite a bit of sense here vs a linked list, and it's resizable. Plus we can use marks to loop over the registered devlinks. Ok.

The conversions to xa interfaces look correct to me.

Thanks,
Jake

Quoted 358 lines
---
 include/net/devlink.h |  2 +-
 net/core/devlink.c    | 70 ++++++++++++++++++++++++++++++-------------
 2 files changed, 50 insertions(+), 22 deletions(-)
include/net/devlink.h +1 -1
index 4c60d61d92da..154cf0dbca37 100644
@@ -32,7 +32,7 @@ struct devlink_dev_stats {
 struct devlink_ops;
 
 struct devlink {
-	struct list_head list;
+	u32 index;
 	struct list_head port_list;
 	struct list_head rate_list;
 	struct list_head sb_list;
net/core/devlink.c +0 -0
index 76f459da6e05..d218f57ad8cf 100644
@@ -92,7 +92,8 @@ static const struct nla_policy

devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_

net/core/devlink.c +3 -1
 				 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
  *
@@ -123,6 +124,7 @@ static struct devlink *devlink_get_from_attrs(struct net
 *net,
 					      struct nlattr **attrs)
 {
 	struct devlink *devlink;
+	unsigned long index;
 	bool found = false;
 	char *busname;
net/core/devlink.c +1 -1
 	char *devname;
@@ -135,7 +137,7 @@ 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/core/devlink.c +33 -16
 		    net_eq(devlink_net(devlink), net)) {
@@ -1087,11 +1089,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -1189,11 +1192,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -1251,11 +1255,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -1916,11 +1921,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -2067,11 +2073,12 @@ 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;
@@ -2287,11 +2294,12 @@ 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;
@@ -2535,11 +2543,12 @@ 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;
@@ -4611,11 +4620,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -4886,11 +4896,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -5462,11 +5473,12 @@ 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 = 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;
@@ -5995,11 +6007,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -7176,11 +7189,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -7210,7 +7224,7 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct
 sk_buff *msg,
 		devlink_put(devlink);
 	}
 
-	list_for_each_entry(devlink, &devlink_list, list) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -7771,11 +7785,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -7997,11 +8012,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -8310,11 +8326,12 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
@@ -8899,6 +8916,8 @@ struct devlink *devlink_alloc_ns(const struct
 devlink_ops *ops,
 				 struct device *dev)
 {
 	struct devlink *devlink;
+	static u32 last_id;
+	int ret;
 
 	WARN_ON(!ops || !dev);
net/core/devlink.c +7 -0
 	if (!devlink_reload_actions_valid(ops))
@@ -8908,6 +8927,13 @@ struct devlink *devlink_alloc_ns(const struct
 devlink_ops *ops,
 	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;
net/core/devlink.c +5 -4
 	xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
@@ -8940,7 +8966,7 @@ EXPORT_SYMBOL_GPL(devlink_alloc_ns);
 int devlink_register(struct devlink *devlink)
 {
 	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;
@@ -8961,7 +8987,7 @@ void devlink_unregister(struct devlink *devlink)
 	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);
@@ -9023,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);
 }
@@ -11497,13 +11524,14 @@ 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) {
+	xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) {
 		if (!devlink_try_get(devlink))
 			continue;
 
--

2.31.1

#15 lore raw

PATCH 5/6 devlink: Clear whole devlink_flash_notify struct

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

The { 0 } doesn't clear all fields in the struct, but tells to the compiler to set all fields to zero and doesn't touch any sub-fields if they exists.

The {} is an empty initialiser that instructs to fully initialize whole struct including sub-fields, which is error-prone for future devlink_flash_notify extensions.

Fixes 6700acc5f1fe ("devlink: collect flash notify params into a struct")
---
 net/core/devlink.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/core/devlink.c +2 -2
index d218f57ad8cf..a856ae401ea5 100644
@@ -4169,7 +4169,7 @@ static void __devlink_flash_update_notify(struct devlink *devlink,
 
 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,
@@ -4178,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,
Signature · 1 line
2.31.1
Reviewed-by on v1 5/6
#16 lore raw

RE: [PATCH net-next 5/6] devlink: Clear whole devlink_flash_notify struct

Quoted 20 lines

-----Original Message-----
From: Leon Romanovsky <[email protected]>
Sent: Saturday, August 14, 2021 2:58 AM
To: David S . Miller <[email protected]>; Jakub Kicinski <[email protected]>
Cc: Leon Romanovsky <[email protected]>; Guangbin Huang <[email protected]>; Keller, Jacob E <[email protected]>; Jiri Pirko <[email protected]>; [email protected]; [email protected]; Salil Mehta <[email protected]>; Shannon Nelson <[email protected]>; Yisen Zhuang <[email protected]>; Yufeng Mo <[email protected]>
Subject: [PATCH net-next 5/6] devlink: Clear whole devlink_flash_notify struct

From: Leon Romanovsky <[email protected]>

The { 0 } doesn't clear all fields in the struct, but tells to the compiler to set all fields to zero and doesn't touch any sub-fields if they exists.

Quoted 6 lines

The {} is an empty initialiser that instructs to fully initialize whole struct including sub-fields, which is error-prone for future devlink_flash_notify extensions.

Fixes 6700acc5f1fe ("devlink: collect flash notify params into a struct")

Yep, we should have used {} before. Are there any other misses where I used { 0 }.... Nope, I just double checked. Ok great!

Quoted 30 lines
---
 net/core/devlink.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/core/devlink.c +1 -1
index d218f57ad8cf..a856ae401ea5 100644
@@ -4169,7 +4169,7 @@ static void __devlink_flash_update_notify(struct
 devlink *devlink,
 
 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,
net/core/devlink.c +1 -1
 				      DEVLINK_CMD_FLASH_UPDATE,
@@ -4178,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,
--
2.31.1

#17 lore raw

PATCH 6/6 net: hns3: remove always exist devlink pointer check

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

The devlink pointer always exists after hclge_devlink_init() succeed. Remove that check together with NULL setting after release and ensure that devlink_register is last command prior to call to devlink_reload_enable().

Fixes b741269b2759 ("net: hns3: add support for registering devlink for PF")
---
 .../net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c    | 8 +-------
 .../net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c  | 8 +-------
 2 files changed, 2 insertions(+), 14 deletions(-)
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c +1 -7
index 448f29aa4e6b..e4aad695abcc 100644
@@ -118,6 +118,7 @@ int hclge_devlink_init(struct hclge_dev *hdev)
 
 	priv = devlink_priv(devlink);
 	priv->hdev = hdev;
+	hdev->devlink = devlink;
 
 	ret = devlink_register(devlink);
 	if (ret) {
@@ -126,8 +127,6 @@ int hclge_devlink_init(struct hclge_dev *hdev)
 		goto out_reg_fail;
 	}
 
-	hdev->devlink = devlink;
-
 	devlink_reload_enable(devlink);
 
 	return 0;
@@ -141,14 +140,9 @@ void hclge_devlink_uninit(struct hclge_dev *hdev)
 {
 	struct devlink *devlink = hdev->devlink;
 
-	if (!devlink)
-		return;
-
 	devlink_reload_disable(devlink);
 
 	devlink_unregister(devlink);
 
 	devlink_free(devlink);
-
-	hdev->devlink = NULL;
 }
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_devlink.c +1 -7
index 1e6061fb8ed4..f478770299c6 100644
@@ -120,6 +120,7 @@ int hclgevf_devlink_init(struct hclgevf_dev *hdev)
 
 	priv = devlink_priv(devlink);
 	priv->hdev = hdev;
+	hdev->devlink = devlink;
 
 	ret = devlink_register(devlink);
 	if (ret) {
@@ -128,8 +129,6 @@ int hclgevf_devlink_init(struct hclgevf_dev *hdev)
 		goto out_reg_fail;
 	}
 
-	hdev->devlink = devlink;
-
 	devlink_reload_enable(devlink);
 
 	return 0;
@@ -143,14 +142,9 @@ void hclgevf_devlink_uninit(struct hclgevf_dev *hdev)
 {
 	struct devlink *devlink = hdev->devlink;
 
-	if (!devlink)
-		return;
-
 	devlink_reload_disable(devlink);
 
 	devlink_unregister(devlink);
 
 	devlink_free(devlink);
-
-	hdev->devlink = NULL;
 }
Signature · 1 line
2.31.1
#18 lore raw
In reply to Leon Romanovsky
This series was applied to netdev/net-next.git (refs/heads/master):

Hello:

This series was applied to netdev/net-next.git (refs/heads/master):

Quoted 9 lines · On Sat, 14 Aug 2021 12:57:25 +0300 you wrote:

From: Leon Romanovsky <[email protected]>

Hi,

Jakub's request to make sure that devlink events are delayed and not printed till they fully accessible [1] requires us to implement delayed event notification system in the devlink.

[...]

Here is the summary with links:
- [net-next,1/6] devlink: Simplify devlink_pernet_pre_exit call

    https://git.kernel.org/netdev/net-next/c/cbf6ab672eb4
  - [net-next,2/6] devlink: Remove check of always valid devlink pointer
    https://git.kernel.org/netdev/net-next/c/7ca973dc9fe5
  - [net-next,3/6] devlink: Count struct devlink consumers
    https://git.kernel.org/netdev/net-next/c/437ebfd90a25
  - [net-next,4/6] devlink: Use xarray to store devlink instances
    https://git.kernel.org/netdev/net-next/c/11a861d767cd
  - [net-next,5/6] devlink: Clear whole devlink_flash_notify struct
    https://git.kernel.org/netdev/net-next/c/ed43fbac7178
  - [net-next,6/6] net: hns3: remove always exist devlink pointer check
    https://git.kernel.org/netdev/net-next/c/a1fcb106ae97

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html