On Mon, Feb 8, 2021 at 9:19 AM Antoine Tenart <aten...@kernel.org> wrote: > > Most of the xps_cpus_show and xps_rxqs_show functions share the same > logic. Having it in two different functions does not help maintenance. > This patch moves their common logic into a new function, xps_queue_show, > to improve this. > > Signed-off-by: Antoine Tenart <aten...@kernel.org> > --- > net/core/net-sysfs.c | 98 ++++++++++++++------------------------------ > 1 file changed, 31 insertions(+), 67 deletions(-) > > diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c > index 6ce5772e799e..984c15248483 100644 > --- a/net/core/net-sysfs.c > +++ b/net/core/net-sysfs.c > @@ -1314,35 +1314,31 @@ static const struct attribute_group dql_group = { > #endif /* CONFIG_BQL */ > > #ifdef CONFIG_XPS > -static ssize_t xps_cpus_show(struct netdev_queue *queue, > - char *buf) > +static ssize_t xps_queue_show(struct net_device *dev, unsigned int index, > + char *buf, enum xps_map_type type) > { > - struct net_device *dev = queue->dev; > struct xps_dev_maps *dev_maps; > - unsigned int index, nr_ids; > - int j, len, ret, tc = 0; > unsigned long *mask; > - > - if (!netif_is_multiqueue(dev)) > - return -ENOENT; > - > - index = get_netdev_queue_index(queue); > - > - /* If queue belongs to subordinate dev use its map */ > - dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev; > + unsigned int nr_ids; > + int j, len, tc = 0; > > tc = netdev_txq_to_tc(dev, index); > if (tc < 0) > return -EINVAL; > > rcu_read_lock(); > - dev_maps = rcu_dereference(dev->xps_maps[XPS_CPUS]); > - nr_ids = dev_maps ? dev_maps->nr_ids : nr_cpu_ids; > + dev_maps = rcu_dereference(dev->xps_maps[type]); > + > + /* Default to nr_cpu_ids/dev->num_rx_queues and do not just return 0 > + * when dev_maps hasn't been allocated yet, to be backward compatible. > + */ > + nr_ids = dev_maps ? dev_maps->nr_ids : > + (type == XPS_CPUS ? nr_cpu_ids : dev->num_rx_queues); > > mask = bitmap_zalloc(nr_ids, GFP_KERNEL); > if (!mask) { > - ret = -ENOMEM; > - goto err_rcu_unlock; > + rcu_read_unlock(); > + return -ENOMEM; > } > > if (!dev_maps || tc >= dev_maps->num_tc) > @@ -1368,11 +1364,24 @@ static ssize_t xps_cpus_show(struct netdev_queue > *queue, > > len = bitmap_print_to_pagebuf(false, buf, mask, nr_ids); > bitmap_free(mask); > + > return len < PAGE_SIZE ? len : -EINVAL; > +} > > -err_rcu_unlock: > - rcu_read_unlock(); > - return ret; > +static ssize_t xps_cpus_show(struct netdev_queue *queue, char *buf) > +{ > + struct net_device *dev = queue->dev; > + unsigned int index; > + > + if (!netif_is_multiqueue(dev)) > + return -ENOENT; > + > + index = get_netdev_queue_index(queue); > + > + /* If queue belongs to subordinate dev use its map */ > + dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev; > + > + return xps_queue_show(dev, index, buf, XPS_CPUS); > } > > static ssize_t xps_cpus_store(struct netdev_queue *queue,
So this patch has the same issue as the one that was removing the rtnl_lock. Basically the sb_dev needs to still be protected by the rtnl_lock. We might need to take the rtnl_lock and maybe make use of the get_device/put_device logic to make certain the device cannot be freed while you are passing it to xps_queue_show.