aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/core/dev.c84
1 files changed, 69 insertions, 15 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 40d439524f49..ad5d7027c545 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4093,6 +4093,60 @@ static int dev_ifconf(struct net *net, char __user *arg)
4093} 4093}
4094 4094
4095#ifdef CONFIG_PROC_FS 4095#ifdef CONFIG_PROC_FS
4096
4097#define BUCKET_SPACE (32 - NETDEV_HASHBITS)
4098
4099struct dev_iter_state {
4100 struct seq_net_private p;
4101 unsigned int pos; /* bucket << BUCKET_SPACE + offset */
4102};
4103
4104#define get_bucket(x) ((x) >> BUCKET_SPACE)
4105#define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
4106#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
4107
4108static inline struct net_device *dev_from_same_bucket(struct seq_file *seq)
4109{
4110 struct dev_iter_state *state = seq->private;
4111 struct net *net = seq_file_net(seq);
4112 struct net_device *dev;
4113 struct hlist_node *p;
4114 struct hlist_head *h;
4115 unsigned int count, bucket, offset;
4116
4117 bucket = get_bucket(state->pos);
4118 offset = get_offset(state->pos);
4119 h = &net->dev_name_head[bucket];
4120 count = 0;
4121 hlist_for_each_entry_rcu(dev, p, h, name_hlist) {
4122 if (count++ == offset) {
4123 state->pos = set_bucket_offset(bucket, count);
4124 return dev;
4125 }
4126 }
4127
4128 return NULL;
4129}
4130
4131static inline struct net_device *dev_from_new_bucket(struct seq_file *seq)
4132{
4133 struct dev_iter_state *state = seq->private;
4134 struct net_device *dev;
4135 unsigned int bucket;
4136
4137 bucket = get_bucket(state->pos);
4138 do {
4139 dev = dev_from_same_bucket(seq);
4140 if (dev)
4141 return dev;
4142
4143 bucket++;
4144 state->pos = set_bucket_offset(bucket, 0);
4145 } while (bucket < NETDEV_HASHENTRIES);
4146
4147 return NULL;
4148}
4149
4096/* 4150/*
4097 * This is invoked by the /proc filesystem handler to display a device 4151 * This is invoked by the /proc filesystem handler to display a device
4098 * in detail. 4152 * in detail.
@@ -4100,33 +4154,33 @@ static int dev_ifconf(struct net *net, char __user *arg)
4100void *dev_seq_start(struct seq_file *seq, loff_t *pos) 4154void *dev_seq_start(struct seq_file *seq, loff_t *pos)
4101 __acquires(RCU) 4155 __acquires(RCU)
4102{ 4156{
4103 struct net *net = seq_file_net(seq); 4157 struct dev_iter_state *state = seq->private;
4104 loff_t off;
4105 struct net_device *dev;
4106 4158
4107 rcu_read_lock(); 4159 rcu_read_lock();
4108 if (!*pos) 4160 if (!*pos)
4109 return SEQ_START_TOKEN; 4161 return SEQ_START_TOKEN;
4110 4162
4111 off = 1; 4163 /* check for end of the hash */
4112 for_each_netdev_rcu(net, dev) 4164 if (state->pos == 0 && *pos > 1)
4113 if (off++ == *pos) 4165 return NULL;
4114 return dev;
4115 4166
4116 return NULL; 4167 return dev_from_new_bucket(seq);
4117} 4168}
4118 4169
4119void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 4170void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
4120{ 4171{
4121 struct net_device *dev = v; 4172 struct net_device *dev;
4173
4174 ++*pos;
4122 4175
4123 if (v == SEQ_START_TOKEN) 4176 if (v == SEQ_START_TOKEN)
4124 dev = first_net_device_rcu(seq_file_net(seq)); 4177 return dev_from_new_bucket(seq);
4125 else
4126 dev = next_net_device_rcu(dev);
4127 4178
4128 ++*pos; 4179 dev = dev_from_same_bucket(seq);
4129 return dev; 4180 if (dev)
4181 return dev;
4182
4183 return dev_from_new_bucket(seq);
4130} 4184}
4131 4185
4132void dev_seq_stop(struct seq_file *seq, void *v) 4186void dev_seq_stop(struct seq_file *seq, void *v)
@@ -4225,7 +4279,7 @@ static const struct seq_operations dev_seq_ops = {
4225static int dev_seq_open(struct inode *inode, struct file *file) 4279static int dev_seq_open(struct inode *inode, struct file *file)
4226{ 4280{
4227 return seq_open_net(inode, file, &dev_seq_ops, 4281 return seq_open_net(inode, file, &dev_seq_ops,
4228 sizeof(struct seq_net_private)); 4282 sizeof(struct dev_iter_state));
4229} 4283}
4230 4284
4231static const struct file_operations dev_seq_fops = { 4285static const struct file_operations dev_seq_fops = {