mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-01 10:43:43 +00:00
net-procfs: use xarray iterator to implement /proc/net/dev
In commit 759ab1edb5
("net: store netdevs in an xarray")
Jakub added net->dev_by_index to map ifindex to netdevices.
We can get rid of the old hash table (net->dev_index_head),
one patch at a time, if performance is acceptable.
This patch removes unpleasant code to something more readable.
As a bonus, /proc/net/dev gets netdevices sorted by their ifindex.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/20240207165318.3814525-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
6fb5dfee27
commit
0e0939c0ad
@ -6,49 +6,18 @@
|
||||
|
||||
#include "dev.h"
|
||||
|
||||
#define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1)
|
||||
|
||||
#define get_bucket(x) ((x) >> BUCKET_SPACE)
|
||||
#define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
|
||||
#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
|
||||
|
||||
static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos)
|
||||
static void *dev_seq_from_index(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
struct net *net = seq_file_net(seq);
|
||||
unsigned long ifindex = *pos;
|
||||
struct net_device *dev;
|
||||
struct hlist_head *h;
|
||||
unsigned int count = 0, offset = get_offset(*pos);
|
||||
|
||||
h = &net->dev_index_head[get_bucket(*pos)];
|
||||
hlist_for_each_entry_rcu(dev, h, index_hlist) {
|
||||
if (++count == offset)
|
||||
return dev;
|
||||
for_each_netdev_dump(seq_file_net(seq), dev, ifindex) {
|
||||
*pos = dev->ifindex;
|
||||
return dev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
struct net_device *dev;
|
||||
unsigned int bucket;
|
||||
|
||||
do {
|
||||
dev = dev_from_same_bucket(seq, pos);
|
||||
if (dev)
|
||||
return dev;
|
||||
|
||||
bucket = get_bucket(*pos) + 1;
|
||||
*pos = set_bucket_offset(bucket, 1);
|
||||
} while (bucket < NETDEV_HASHENTRIES);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is invoked by the /proc filesystem handler to display a device
|
||||
* in detail.
|
||||
*/
|
||||
static void *dev_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
__acquires(RCU)
|
||||
{
|
||||
@ -56,16 +25,13 @@ static void *dev_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
if (!*pos)
|
||||
return SEQ_START_TOKEN;
|
||||
|
||||
if (get_bucket(*pos) >= NETDEV_HASHENTRIES)
|
||||
return NULL;
|
||||
|
||||
return dev_from_bucket(seq, pos);
|
||||
return dev_seq_from_index(seq, pos);
|
||||
}
|
||||
|
||||
static void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
++*pos;
|
||||
return dev_from_bucket(seq, pos);
|
||||
return dev_seq_from_index(seq, pos);
|
||||
}
|
||||
|
||||
static void dev_seq_stop(struct seq_file *seq, void *v)
|
||||
|
Loading…
Reference in New Issue
Block a user