From f383ced24d6ae6c1989394d052d3109b9d645f11 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 11 Feb 2024 21:44:03 +0000 Subject: [PATCH] vlan: use xarray iterator to implement /proc/net/vlan/config Adopt net->dev_by_index as I did in commit 0e0939c0adf9 ("net-procfs: use xarray iterator to implement /proc/net/dev") Not only this removes quadratic behavior, it also makes sure an existing vlan device is always visible in the dump, regardless of concurrent net->dev_base_head changes. Signed-off-by: Eric Dumazet Reviewed-by: Jakub Kicinski Reviewed-by: Ido Schimmel Link: https://lore.kernel.org/r/20240211214404.1882191-2-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/8021q/vlanproc.c | 46 +++++++++++++++----------------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 7825c129742a..87b959da00cd 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -163,48 +163,34 @@ void vlan_proc_rem_dev(struct net_device *vlandev) * The following few functions build the content of /proc/net/vlan/config */ -/* start read of /proc/net/vlan/config */ +static void *vlan_seq_from_index(struct seq_file *seq, loff_t *pos) +{ + unsigned long ifindex = *pos; + struct net_device *dev; + + for_each_netdev_dump(seq_file_net(seq), dev, ifindex) { + if (!is_vlan_dev(dev)) + continue; + *pos = dev->ifindex; + return dev; + } + return NULL; +} + static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) __acquires(rcu) { - struct net_device *dev; - struct net *net = seq_file_net(seq); - loff_t i = 1; - rcu_read_lock(); if (*pos == 0) return SEQ_START_TOKEN; - for_each_netdev_rcu(net, dev) { - if (!is_vlan_dev(dev)) - continue; - - if (i++ == *pos) - return dev; - } - - return NULL; + return vlan_seq_from_index(seq, pos); } static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct net_device *dev; - struct net *net = seq_file_net(seq); - ++*pos; - - dev = v; - if (v == SEQ_START_TOKEN) - dev = net_device_entry(&net->dev_base_head); - - for_each_netdev_continue_rcu(net, dev) { - if (!is_vlan_dev(dev)) - continue; - - return dev; - } - - return NULL; + return vlan_seq_from_index(seq, pos); } static void vlan_seq_stop(struct seq_file *seq, void *v)