net: devlink: convert port_list into xarray
authorJiri Pirko <jiri@nvidia.com>
Wed, 30 Nov 2022 08:52:50 +0000 (09:52 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 2 Dec 2022 10:37:03 +0000 (10:37 +0000)
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: Jiri Pirko <jiri@nvidia.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/devlink.c

index fca3ebee97b042f272c1574d87f75d3b123c0588..907df71241570245bb6322762fe775dd89bcabb8 100644 (file)
@@ -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;