Commit 47b438cc authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

net: devlink: convert port_list into xarray



Some devlink instances may contain thousands of ports. Storing them in
linked list and looking them up is not scalable. Convert the linked list
into xarray.

Signed-off-by: default avatarJiri Pirko <jiri@nvidia.com>
Acked-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3f5a4aa1
Loading
Loading
Loading
Loading
+27 −30
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ struct devlink_dev_stats {

struct devlink {
	u32 index;
	struct list_head port_list;
	struct xarray ports;
	struct list_head rate_list;
	struct list_head sb_list;
	struct list_head dpipe_table_list;
@@ -382,19 +382,7 @@ static struct devlink *devlink_get_from_attrs(struct net *net,
static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
						      unsigned int port_index)
{
	struct devlink_port *devlink_port;

	list_for_each_entry(devlink_port, &devlink->port_list, list) {
		if (devlink_port->index == port_index)
			return devlink_port;
	}
	return NULL;
}

static bool devlink_port_index_exists(struct devlink *devlink,
				      unsigned int port_index)
{
	return devlink_port_get_by_index(devlink, port_index);
	return xa_load(&devlink->ports, port_index);
}

static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
@@ -1565,14 +1553,14 @@ static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
{
	struct devlink *devlink;
	struct devlink_port *devlink_port;
	unsigned long index, port_index;
	int start = cb->args[0];
	unsigned long index;
	int idx = 0;
	int err;

	devlinks_xa_for_each_registered_get(sock_net(msg->sk), index, devlink) {
		devl_lock(devlink);
		list_for_each_entry(devlink_port, &devlink->port_list, list) {
		xa_for_each(&devlink->ports, port_index, devlink_port) {
			if (idx < start) {
				idx++;
				continue;
@@ -2886,10 +2874,11 @@ static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
{
	struct devlink_port *devlink_port;
	u16 pool_count = devlink_sb_pool_count(devlink_sb);
	unsigned long port_index;
	u16 pool_index;
	int err;

	list_for_each_entry(devlink_port, &devlink->port_list, list) {
	xa_for_each(&devlink->ports, port_index, devlink_port) {
		for (pool_index = 0; pool_index < pool_count; pool_index++) {
			if (*p_idx < start) {
				(*p_idx)++;
@@ -3107,10 +3096,11 @@ static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
					u32 portid, u32 seq)
{
	struct devlink_port *devlink_port;
	unsigned long port_index;
	u16 tc_index;
	int err;

	list_for_each_entry(devlink_port, &devlink->port_list, list) {
	xa_for_each(&devlink->ports, port_index, devlink_port) {
		for (tc_index = 0;
		     tc_index < devlink_sb->ingress_tc_count; tc_index++) {
			if (*p_idx < start) {
@@ -6207,6 +6197,7 @@ static int devlink_nl_cmd_region_get_devlink_dumpit(struct sk_buff *msg,
{
	struct devlink_region *region;
	struct devlink_port *port;
	unsigned long port_index;
	int err = 0;

	devl_lock(devlink);
@@ -6225,7 +6216,7 @@ static int devlink_nl_cmd_region_get_devlink_dumpit(struct sk_buff *msg,
		(*idx)++;
	}

	list_for_each_entry(port, &devlink->port_list, list) {
	xa_for_each(&devlink->ports, port_index, port) {
		err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, idx,
							    start);
		if (err)
@@ -8057,10 +8048,10 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
					  struct netlink_callback *cb)
{
	struct devlink_health_reporter *reporter;
	unsigned long index, port_index;
	struct devlink_port *port;
	struct devlink *devlink;
	int start = cb->args[0];
	unsigned long index;
	int idx = 0;
	int err;

@@ -8089,7 +8080,7 @@ devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,

	devlinks_xa_for_each_registered_get(sock_net(msg->sk), index, devlink) {
		devl_lock(devlink);
		list_for_each_entry(port, &devlink->port_list, list) {
		xa_for_each(&devlink->ports, port_index, port) {
			mutex_lock(&port->reporters_lock);
			list_for_each_entry(reporter, &port->reporter_list, list) {
				if (idx < start) {
@@ -9808,9 +9799,9 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,

	devlink->dev = dev;
	devlink->ops = ops;
	xa_init_flags(&devlink->ports, XA_FLAGS_ALLOC);
	xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
	write_pnet(&devlink->_net, net);
	INIT_LIST_HEAD(&devlink->port_list);
	INIT_LIST_HEAD(&devlink->rate_list);
	INIT_LIST_HEAD(&devlink->linecard_list);
	INIT_LIST_HEAD(&devlink->sb_list);
@@ -9862,12 +9853,13 @@ static void devlink_notify_register(struct devlink *devlink)
	struct devlink_linecard *linecard;
	struct devlink_rate *rate_node;
	struct devlink_region *region;
	unsigned long port_index;

	devlink_notify(devlink, DEVLINK_CMD_NEW);
	list_for_each_entry(linecard, &devlink->linecard_list, list)
		devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);

	list_for_each_entry(devlink_port, &devlink->port_list, list)
	xa_for_each(&devlink->ports, port_index, devlink_port)
		devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);

	list_for_each_entry(policer_item, &devlink->trap_policer_list, list)
@@ -9901,6 +9893,7 @@ static void devlink_notify_unregister(struct devlink *devlink)
	struct devlink_port *devlink_port;
	struct devlink_rate *rate_node;
	struct devlink_region *region;
	unsigned long port_index;

	list_for_each_entry_reverse(param_item, &devlink->param_list, list)
		devlink_param_notify(devlink, 0, param_item,
@@ -9923,7 +9916,7 @@ static void devlink_notify_unregister(struct devlink *devlink)
		devlink_trap_policer_notify(devlink, policer_item,
					    DEVLINK_CMD_TRAP_POLICER_DEL);

	list_for_each_entry_reverse(devlink_port, &devlink->port_list, list)
	xa_for_each(&devlink->ports, port_index, devlink_port)
		devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
	devlink_notify(devlink, DEVLINK_CMD_DEL);
}
@@ -9987,9 +9980,10 @@ void devlink_free(struct devlink *devlink)
	WARN_ON(!list_empty(&devlink->sb_list));
	WARN_ON(!list_empty(&devlink->rate_list));
	WARN_ON(!list_empty(&devlink->linecard_list));
	WARN_ON(!list_empty(&devlink->port_list));
	WARN_ON(!xa_empty(&devlink->ports));

	xa_destroy(&devlink->snapshot_ids);
	xa_destroy(&devlink->ports);

	WARN_ON_ONCE(unregister_netdevice_notifier_net(devlink_net(devlink),
						       &devlink->netdevice_nb));
@@ -10088,10 +10082,9 @@ int devl_port_register(struct devlink *devlink,
		       struct devlink_port *devlink_port,
		       unsigned int port_index)
{
	devl_assert_locked(devlink);
	int err;

	if (devlink_port_index_exists(devlink, port_index))
		return -EEXIST;
	devl_assert_locked(devlink);

	ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);

@@ -10101,7 +10094,11 @@ int devl_port_register(struct devlink *devlink,
	spin_lock_init(&devlink_port->type_lock);
	INIT_LIST_HEAD(&devlink_port->reporter_list);
	mutex_init(&devlink_port->reporters_lock);
	list_add_tail(&devlink_port->list, &devlink->port_list);
	err = xa_insert(&devlink->ports, port_index, devlink_port, GFP_KERNEL);
	if (err) {
		mutex_destroy(&devlink_port->reporters_lock);
		return err;
	}

	INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
	devlink_port_type_warn_schedule(devlink_port);
@@ -10150,7 +10147,7 @@ void devl_port_unregister(struct devlink_port *devlink_port)

	devlink_port_type_warn_cancel(devlink_port);
	devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
	list_del(&devlink_port->list);
	xa_erase(&devlink_port->devlink->ports, devlink_port->index);
	WARN_ON(!list_empty(&devlink_port->reporter_list));
	mutex_destroy(&devlink_port->reporters_lock);
	devlink_port->registered = false;