Commit 88e2ca30 authored by Taehee Yoo's avatar Taehee Yoo Committed by David S. Miller
Browse files

mld: convert ifmcaddr6 to RCU



The ifmcaddr6 has been protected by inet6_dev->lock(rwlock) so that
the critical section is atomic context. In order to switch this context,
changing locking is needed. The ifmcaddr6 actually already protected by
RTNL So if it's converted to use RCU, its control path context can be
switched to sleepable.

Suggested-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarTaehee Yoo <ap420073@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4b200e39
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -1098,8 +1098,9 @@ static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg)
	tmp.disp_flag = QETH_DISP_ADDR_ADD;
	tmp.is_multicast = 1;

	read_lock_bh(&in6_dev->lock);
	for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
	for (im6 = rtnl_dereference(in6_dev->mc_list);
	     im6;
	     im6 = rtnl_dereference(im6->next)) {
		tmp.u.a6.addr = im6->mca_addr;

		ipm = qeth_l3_find_addr_by_ip(card, &tmp);
@@ -1117,7 +1118,6 @@ static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg)
			 qeth_l3_ipaddr_hash(ipm));

	}
	read_unlock_bh(&in6_dev->lock);

out:
	return 0;
+4 −3
Original line number Diff line number Diff line
@@ -115,7 +115,7 @@ struct ip6_sf_list {
struct ifmcaddr6 {
	struct in6_addr		mca_addr;
	struct inet6_dev	*idev;
	struct ifmcaddr6	*next;
	struct ifmcaddr6	__rcu *next;
	struct ip6_sf_list	__rcu *mca_sources;
	struct ip6_sf_list	__rcu *mca_tomb;
	unsigned int		mca_sfmode;
@@ -128,6 +128,7 @@ struct ifmcaddr6 {
	spinlock_t		mca_lock;
	unsigned long		mca_cstamp;
	unsigned long		mca_tstamp;
	struct rcu_head		rcu;
};

/* Anycast stuff */
@@ -166,8 +167,8 @@ struct inet6_dev {

	struct list_head	addr_list;

	struct ifmcaddr6	*mc_list;
	struct ifmcaddr6	*mc_tomb;
	struct ifmcaddr6	__rcu *mc_list;
	struct ifmcaddr6	__rcu *mc_tomb;

	unsigned char		mc_qrv;		/* Query Robustness Variable */
	unsigned char		mc_gq_running;
+3 −3
Original line number Diff line number Diff line
@@ -454,8 +454,9 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
		return 0;
	}

	read_lock_bh(&in6_dev->lock);
	for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) {
	for (pmc6 = rcu_dereference(in6_dev->mc_list);
	     pmc6;
	     pmc6 = rcu_dereference(pmc6->next)) {
		if (IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) <
		    IPV6_ADDR_SCOPE_LINKLOCAL)
			continue;
@@ -484,7 +485,6 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
		hlist_add_head(&new->list, mcast_list);
		ret++;
	}
	read_unlock_bh(&in6_dev->lock);
	rcu_read_unlock();

	return ret;
+5 −4
Original line number Diff line number Diff line
@@ -5107,17 +5107,20 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
		break;
	}
	case MULTICAST_ADDR:
		read_unlock_bh(&idev->lock);
		fillargs->event = RTM_GETMULTICAST;

		/* multicast address */
		for (ifmca = idev->mc_list; ifmca;
		     ifmca = ifmca->next, ip_idx++) {
		for (ifmca = rcu_dereference(idev->mc_list);
		     ifmca;
		     ifmca = rcu_dereference(ifmca->next), ip_idx++) {
			if (ip_idx < s_ip_idx)
				continue;
			err = inet6_fill_ifmcaddr(skb, ifmca, fillargs);
			if (err < 0)
				break;
		}
		read_lock_bh(&idev->lock);
		break;
	case ANYCAST_ADDR:
		fillargs->event = RTM_GETANYCAST;
@@ -6093,10 +6096,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)

static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
	rcu_read_lock_bh();
	if (likely(ifp->idev->dead == 0))
		__ipv6_ifa_notify(event, ifp);
	rcu_read_unlock_bh();
}

#ifdef CONFIG_SYSCTL
+1 −1
Original line number Diff line number Diff line
@@ -250,7 +250,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
	struct net_device *dev = idev->dev;

	WARN_ON(!list_empty(&idev->addr_list));
	WARN_ON(idev->mc_list);
	WARN_ON(rcu_access_pointer(idev->mc_list));
	WARN_ON(timer_pending(&idev->rs_timer));

#ifdef NET_REFCNT_DEBUG
Loading