ipv6: use RCU to walk list of network devices
No longer need read_lock(&dev_base_lock), use RCU instead. We also can avoid taking references on inet6_dev structs. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committato da
David S. Miller

parent
bee7ca9ec0
commit
ce81b76a39
@@ -431,9 +431,9 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
|
||||
struct net *net = seq_file_net(seq);
|
||||
|
||||
state->idev = NULL;
|
||||
for_each_netdev(net, state->dev) {
|
||||
for_each_netdev_rcu(net, state->dev) {
|
||||
struct inet6_dev *idev;
|
||||
idev = in6_dev_get(state->dev);
|
||||
idev = __in6_dev_get(state->dev);
|
||||
if (!idev)
|
||||
continue;
|
||||
read_lock_bh(&idev->lock);
|
||||
@@ -443,7 +443,6 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
|
||||
break;
|
||||
}
|
||||
read_unlock_bh(&idev->lock);
|
||||
in6_dev_put(idev);
|
||||
}
|
||||
return im;
|
||||
}
|
||||
@@ -454,16 +453,15 @@ static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im
|
||||
|
||||
im = im->aca_next;
|
||||
while (!im) {
|
||||
if (likely(state->idev != NULL)) {
|
||||
if (likely(state->idev != NULL))
|
||||
read_unlock_bh(&state->idev->lock);
|
||||
in6_dev_put(state->idev);
|
||||
}
|
||||
state->dev = next_net_device(state->dev);
|
||||
|
||||
state->dev = next_net_device_rcu(state->dev);
|
||||
if (!state->dev) {
|
||||
state->idev = NULL;
|
||||
break;
|
||||
}
|
||||
state->idev = in6_dev_get(state->dev);
|
||||
state->idev = __in6_dev_get(state->dev);
|
||||
if (!state->idev)
|
||||
continue;
|
||||
read_lock_bh(&state->idev->lock);
|
||||
@@ -482,29 +480,30 @@ static struct ifacaddr6 *ac6_get_idx(struct seq_file *seq, loff_t pos)
|
||||
}
|
||||
|
||||
static void *ac6_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
__acquires(dev_base_lock)
|
||||
__acquires(RCU)
|
||||
{
|
||||
read_lock(&dev_base_lock);
|
||||
rcu_read_lock();
|
||||
return ac6_get_idx(seq, *pos);
|
||||
}
|
||||
|
||||
static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
struct ifacaddr6 *im;
|
||||
im = ac6_get_next(seq, v);
|
||||
struct ifacaddr6 *im = ac6_get_next(seq, v);
|
||||
|
||||
++*pos;
|
||||
return im;
|
||||
}
|
||||
|
||||
static void ac6_seq_stop(struct seq_file *seq, void *v)
|
||||
__releases(dev_base_lock)
|
||||
__releases(RCU)
|
||||
{
|
||||
struct ac6_iter_state *state = ac6_seq_private(seq);
|
||||
|
||||
if (likely(state->idev != NULL)) {
|
||||
read_unlock_bh(&state->idev->lock);
|
||||
in6_dev_put(state->idev);
|
||||
state->idev = NULL;
|
||||
}
|
||||
read_unlock(&dev_base_lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int ac6_seq_show(struct seq_file *seq, void *v)
|
||||
|
Fai riferimento in un nuovo problema
Block a user