forked from mirrors/linux
		
	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
					
				
					 1 changed files with 7 additions and 41 deletions
				
			
		|  | @ -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 a new issue
	
	 Eric Dumazet
						Eric Dumazet