Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce81b76a authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bee7ca9e
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1114,6 +1114,16 @@ static inline struct net_device *next_net_device(struct net_device *dev)
	return lh == &net->dev_base_head ? NULL : net_device_entry(lh);
}

static inline struct net_device *next_net_device_rcu(struct net_device *dev)
{
	struct list_head *lh;
	struct net *net;

	net = dev_net(dev);
	lh = rcu_dereference(dev->dev_list.next);
	return lh == &net->dev_base_head ? NULL : net_device_entry(lh);
}

static inline struct net_device *first_net_device(struct net *net)
{
	return list_empty(&net->dev_base_head) ? NULL :
+14 −15
Original line number Diff line number Diff line
@@ -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)
+23 −28
Original line number Diff line number Diff line
@@ -2375,9 +2375,9 @@ static inline struct ifmcaddr6 *igmp6_mc_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);
@@ -2387,7 +2387,6 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
			break;
		}
		read_unlock_bh(&idev->lock);
		in6_dev_put(idev);
	}
	return im;
}
@@ -2398,16 +2397,15 @@ static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr

	im = im->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);
@@ -2426,31 +2424,31 @@ static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos)
}

static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos)
	__acquires(dev_base_lock)
	__acquires(RCU)
{
	read_lock(&dev_base_lock);
	rcu_read_lock();
	return igmp6_mc_get_idx(seq, *pos);
}

static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
	struct ifmcaddr6 *im;
	im = igmp6_mc_get_next(seq, v);
	struct ifmcaddr6 *im = igmp6_mc_get_next(seq, v);

	++*pos;
	return im;
}

static void igmp6_mc_seq_stop(struct seq_file *seq, void *v)
	__releases(dev_base_lock)
	__releases(RCU)
{
	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);

	if (likely(state->idev != NULL)) {
		read_unlock_bh(&state->idev->lock);
		in6_dev_put(state->idev);
		state->idev = NULL;
	}
	state->dev = NULL;
	read_unlock(&dev_base_lock);
	rcu_read_unlock();
}

static int igmp6_mc_seq_show(struct seq_file *seq, void *v)
@@ -2507,9 +2505,9 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)

	state->idev = NULL;
	state->im = 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 (unlikely(idev == NULL))
			continue;
		read_lock_bh(&idev->lock);
@@ -2525,7 +2523,6 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
			spin_unlock_bh(&im->mca_lock);
		}
		read_unlock_bh(&idev->lock);
		in6_dev_put(idev);
	}
	return psf;
}
@@ -2539,16 +2536,15 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s
		spin_unlock_bh(&state->im->mca_lock);
		state->im = state->im->next;
		while (!state->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;
				goto out;
			}
			state->idev = in6_dev_get(state->dev);
			state->idev = __in6_dev_get(state->dev);
			if (!state->idev)
				continue;
			read_lock_bh(&state->idev->lock);
@@ -2573,9 +2569,9 @@ static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos)
}

static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos)
	__acquires(dev_base_lock)
	__acquires(RCU)
{
	read_lock(&dev_base_lock);
	rcu_read_lock();
	return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
}

@@ -2591,7 +2587,7 @@ static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}

static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v)
	__releases(dev_base_lock)
	__releases(RCU)
{
	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
	if (likely(state->im != NULL)) {
@@ -2600,11 +2596,10 @@ static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v)
	}
	if (likely(state->idev != NULL)) {
		read_unlock_bh(&state->idev->lock);
		in6_dev_put(state->idev);
		state->idev = NULL;
	}
	state->dev = NULL;
	read_unlock(&dev_base_lock);
	rcu_read_unlock();
}

static int igmp6_mcf_seq_show(struct seq_file *seq, void *v)