DORMANTno replies

[PATCH net-next 1/8] mld: convert ifmcaddr6 to list macros

From: Taehee Yoo <ap420073@gmail.com>
Date: 2021-02-08 17:56:23
Subsystem: batman advanced, networking drivers, networking [general], networking [ipv4/ipv6], s390 architecture, s390 network drivers, the rest · Maintainers: Marek Lindner, Simon Wunderlich, Antonio Quartulli, Sven Eckelmann, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Heiko Carstens, Vasily Gorbik, Alexander Gordeev, Alexandra Winter, Aswin Karuvally, Linus Torvalds

Currently, struct ifmcaddr6 doesn't use list API so that code shape is
a little bit different from others.
So it converts ifmcaddr6 to use list API so it would improve readability.

Signed-off-by: Taehee Yoo <ap420073@gmail.com>
---
 drivers/s390/net/qeth_l3_main.c |   2 +-
 include/net/if_inet6.h          |   9 +-
 net/batman-adv/multicast.c      |   2 +-
 net/ipv6/addrconf.c             |   7 +-
 net/ipv6/addrconf_core.c        |   3 +-
 net/ipv6/mcast.c                | 999 ++++++++++++++++----------------
 6 files changed, 523 insertions(+), 499 deletions(-)
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index dd441eaec66e..e49abdeff69c 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1099,7 +1099,7 @@ static int qeth_l3_add_mcast_rtnl(struct net_device *dev, int vid, void *arg)
 	tmp.is_multicast = 1;
 
 	read_lock_bh(&in6_dev->lock);
-	for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
+	list_for_each_entry(im6, in6_dev->mc_list, list) {
 		tmp.u.a6.addr = im6->mca_addr;
 
 		ipm = qeth_l3_find_addr_by_ip(card, &tmp);
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 8bf5906073bc..1262ccd5221e 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -114,7 +114,7 @@ struct ip6_sf_list {
 struct ifmcaddr6 {
 	struct in6_addr		mca_addr;
 	struct inet6_dev	*idev;
-	struct ifmcaddr6	*next;
+	struct list_head	list;
 	struct ip6_sf_list	*mca_sources;
 	struct ip6_sf_list	*mca_tomb;
 	unsigned int		mca_sfmode;
@@ -164,10 +164,9 @@ struct inet6_dev {
 	struct net_device	*dev;
 
 	struct list_head	addr_list;
-
-	struct ifmcaddr6	*mc_list;
-	struct ifmcaddr6	*mc_tomb;
-	spinlock_t		mc_lock;
+	struct list_head	mc_list;
+	struct list_head	mc_tomb_list;
+	spinlock_t		mc_tomb_lock;
 
 	unsigned char		mc_qrv;		/* Query Robustness Variable */
 	unsigned char		mc_gq_running;
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 854e5ff28a3f..1a9ad5a9257b 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -455,7 +455,7 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
 	}
 
 	read_lock_bh(&in6_dev->lock);
-	for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) {
+	list_for_each_entry(pmc6, &in6_dev->mc_list, list) {
 		if (IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) <
 		    IPV6_ADDR_SCOPE_LINKLOCAL)
 			continue;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f2337fb756ac..e9fe0eee5768 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5110,13 +5110,14 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
 		fillargs->event = RTM_GETMULTICAST;
 
 		/* multicast address */
-		for (ifmca = idev->mc_list; ifmca;
-		     ifmca = ifmca->next, ip_idx++) {
+		list_for_each_entry(ifmca, &idev->mc_list, list) {
 			if (ip_idx < s_ip_idx)
-				continue;
+				goto next2;
 			err = inet6_fill_ifmcaddr(skb, ifmca, fillargs);
 			if (err < 0)
 				break;
+next2:
+			ip_idx++;
 		}
 		break;
 	case ANYCAST_ADDR:
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
index c70c192bc91b..b55f85dcfd74 100644
--- a/net/ipv6/addrconf_core.c
+++ b/net/ipv6/addrconf_core.c
@@ -250,7 +250,8 @@ 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(!list_empty(&idev->mc_list));
+	WARN_ON(!list_empty(&idev->mc_tomb_list));
 	WARN_ON(timer_pending(&idev->rs_timer));
 
 #ifdef NET_REFCNT_DEBUG
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 6c8604390266..508c007df84f 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -69,24 +69,19 @@ static int __mld2_query_bugs[] __attribute__((__unused__)) = {
 
 static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT;
 
-static void igmp6_join_group(struct ifmcaddr6 *ma);
-static void igmp6_leave_group(struct ifmcaddr6 *ma);
+static void igmp6_join_group(struct ifmcaddr6 *mc);
+static void igmp6_leave_group(struct ifmcaddr6 *mc);
 static void igmp6_timer_handler(struct timer_list *t);
 
-static void mld_gq_timer_expire(struct timer_list *t);
-static void mld_ifc_timer_expire(struct timer_list *t);
 static void mld_ifc_event(struct inet6_dev *idev);
-static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
-static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
-static void mld_clear_delrec(struct inet6_dev *idev);
 static bool mld_in_v1_mode(const struct inet6_dev *idev);
-static int sf_setstate(struct ifmcaddr6 *pmc);
-static void sf_markstate(struct ifmcaddr6 *pmc);
-static void ip6_mc_clear_src(struct ifmcaddr6 *pmc);
-static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+static int sf_setstate(struct ifmcaddr6 *mc);
+static void sf_markstate(struct ifmcaddr6 *mc);
+static void ip6_mc_clear_src(struct ifmcaddr6 *mc);
+static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *mca,
 			  int sfmode, int sfcount, const struct in6_addr *psfsrc,
 			  int delta);
-static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *mca,
 			  int sfmode, int sfcount, const struct in6_addr *psfsrc,
 			  int delta);
 static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
@@ -113,10 +108,23 @@ int sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT;
  *	socket join on multicast group
  */
 
-#define for_each_pmc_rcu(np, pmc)				\
-	for (pmc = rcu_dereference(np->ipv6_mc_list);		\
-	     pmc != NULL;					\
-	     pmc = rcu_dereference(pmc->next))
+#define for_each_mc_rcu(np, mc)				\
+	for (mc = rcu_dereference((np)->ipv6_mc_list);	\
+	     mc;					\
+	     mc = rcu_dereference(mc->next))
+
+static void mca_get(struct ifmcaddr6 *mc)
+{
+	refcount_inc(&mc->mca_refcnt);
+}
+
+static void mca_put(struct ifmcaddr6 *mc)
+{
+	if (refcount_dec_and_test(&mc->mca_refcnt)) {
+		in6_dev_put(mc->idev);
+		kfree(mc);
+	}
+}
 
 static int unsolicited_report_interval(struct inet6_dev *idev)
 {
@@ -145,7 +153,7 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
 		return -EINVAL;
 
 	rcu_read_lock();
-	for_each_pmc_rcu(np, mc_lst) {
+	for_each_mc_rcu(np, mc_lst) {
 		if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&
 		    ipv6_addr_equal(&mc_lst->addr, addr)) {
 			rcu_read_unlock();
@@ -328,15 +336,15 @@ void ipv6_sock_mc_close(struct sock *sk)
 int ip6_mc_source(int add, int omode, struct sock *sk,
 	struct group_source_req *pgsr)
 {
-	struct in6_addr *source, *group;
-	struct ipv6_mc_socklist *pmc;
-	struct inet6_dev *idev;
 	struct ipv6_pinfo *inet6 = inet6_sk(sk);
-	struct ip6_sf_socklist *psl;
+	struct in6_addr *source, *group;
 	struct net *net = sock_net(sk);
-	int i, j, rv;
+	struct ipv6_mc_socklist *mc;
+	struct ip6_sf_socklist *psl;
+	struct inet6_dev *idev;
 	int leavegroup = 0;
-	int pmclocked = 0;
+	int mclocked = 0;
+	int i, j, rv;
 	int err;
 
 	source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr;
@@ -354,33 +362,33 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
 
 	err = -EADDRNOTAVAIL;
 
-	for_each_pmc_rcu(inet6, pmc) {
-		if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface)
+	for_each_mc_rcu(inet6, mc) {
+		if (pgsr->gsr_interface && mc->ifindex != pgsr->gsr_interface)
 			continue;
-		if (ipv6_addr_equal(&pmc->addr, group))
+		if (ipv6_addr_equal(&mc->addr, group))
 			break;
 	}
-	if (!pmc) {		/* must have a prior join */
+	if (!mc) {		/* must have a prior join */
 		err = -EINVAL;
 		goto done;
 	}
 	/* if a source filter was set, must be the same mode as before */
-	if (pmc->sflist) {
-		if (pmc->sfmode != omode) {
+	if (mc->sflist) {
+		if (mc->sfmode != omode) {
 			err = -EINVAL;
 			goto done;
 		}
-	} else if (pmc->sfmode != omode) {
+	} else if (mc->sfmode != omode) {
 		/* allow mode switches for empty-set filters */
 		ip6_mc_add_src(idev, group, omode, 0, NULL, 0);
-		ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
-		pmc->sfmode = omode;
+		ip6_mc_del_src(idev, group, mc->sfmode, 0, NULL, 0);
+		mc->sfmode = omode;
 	}
 
-	write_lock(&pmc->sflock);
-	pmclocked = 1;
+	write_lock(&mc->sflock);
+	mclocked = 1;
 
-	psl = pmc->sflist;
+	psl = mc->sflist;
 	if (!add) {
 		if (!psl)
 			goto done;	/* err = -EADDRNOTAVAIL */
@@ -432,7 +440,8 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
 				newpsl->sl_addr[i] = psl->sl_addr[i];
 			sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
 		}
-		pmc->sflist = psl = newpsl;
+		psl = newpsl;
+		mc->sflist = psl;
 	}
 	rv = 1;	/* > 0 for insert logic below if sl_count is 0 */
 	for (i = 0; i < psl->sl_count; i++) {
@@ -448,8 +457,8 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
 	/* update the interface list */
 	ip6_mc_add_src(idev, group, omode, 1, source, 1);
 done:
-	if (pmclocked)
-		write_unlock(&pmc->sflock);
+	if (mclocked)
+		write_unlock(&mc->sflock);
 	read_unlock_bh(&idev->lock);
 	rcu_read_unlock();
 	if (leavegroup)
@@ -460,12 +469,12 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
 int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
 		    struct sockaddr_storage *list)
 {
-	const struct in6_addr *group;
-	struct ipv6_mc_socklist *pmc;
-	struct inet6_dev *idev;
 	struct ipv6_pinfo *inet6 = inet6_sk(sk);
 	struct ip6_sf_socklist *newpsl, *psl;
 	struct net *net = sock_net(sk);
+	const struct in6_addr *group;
+	struct ipv6_mc_socklist *mc;
+	struct inet6_dev *idev;
 	int leavegroup = 0;
 	int i, err;
 
@@ -492,13 +501,13 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
 		goto done;
 	}
 
-	for_each_pmc_rcu(inet6, pmc) {
-		if (pmc->ifindex != gsf->gf_interface)
+	for_each_mc_rcu(inet6, mc) {
+		if (mc->ifindex != gsf->gf_interface)
 			continue;
-		if (ipv6_addr_equal(&pmc->addr, group))
+		if (ipv6_addr_equal(&mc->addr, group))
 			break;
 	}
-	if (!pmc) {		/* must have a prior join */
+	if (!mc) {		/* must have a prior join */
 		err = -EINVAL;
 		goto done;
 	}
@@ -524,20 +533,20 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf,
 		}
 	} else {
 		newpsl = NULL;
-		(void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
+		ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
 	}
 
-	write_lock(&pmc->sflock);
-	psl = pmc->sflist;
+	write_lock(&mc->sflock);
+	psl = mc->sflist;
 	if (psl) {
-		(void) ip6_mc_del_src(idev, group, pmc->sfmode,
-			psl->sl_count, psl->sl_addr, 0);
+		ip6_mc_del_src(idev, group, mc->sfmode,
+			       psl->sl_count, psl->sl_addr, 0);
 		sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
 	} else
-		(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
-	pmc->sflist = newpsl;
-	pmc->sfmode = gsf->gf_fmode;
-	write_unlock(&pmc->sflock);
+		ip6_mc_del_src(idev, group, mc->sfmode, 0, NULL, 0);
+	mc->sflist = newpsl;
+	mc->sfmode = gsf->gf_fmode;
+	write_unlock(&mc->sflock);
 	err = 0;
 done:
 	read_unlock_bh(&idev->lock);
@@ -552,7 +561,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
 {
 	int err, i, count, copycount;
 	const struct in6_addr *group;
-	struct ipv6_mc_socklist *pmc;
+	struct ipv6_mc_socklist *mc;
 	struct inet6_dev *idev;
 	struct ipv6_pinfo *inet6 = inet6_sk(sk);
 	struct ip6_sf_socklist *psl;
@@ -577,16 +586,16 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
 	 * so reading the list is safe.
 	 */
 
-	for_each_pmc_rcu(inet6, pmc) {
-		if (pmc->ifindex != gsf->gf_interface)
+	for_each_mc_rcu(inet6, mc) {
+		if (mc->ifindex != gsf->gf_interface)
 			continue;
-		if (ipv6_addr_equal(group, &pmc->addr))
+		if (ipv6_addr_equal(group, &mc->addr))
 			break;
 	}
-	if (!pmc)		/* must have a prior join */
+	if (!mc)		/* must have a prior join */
 		goto done;
-	gsf->gf_fmode = pmc->sfmode;
-	psl = pmc->sflist;
+	gsf->gf_fmode = mc->sfmode;
+	psl = mc->sflist;
 	count = psl ? psl->sl_count : 0;
 	read_unlock_bh(&idev->lock);
 	rcu_read_unlock();
@@ -594,7 +603,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
 	copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
 	gsf->gf_numsrc = count;
 	/* changes to psl require the socket lock, and a write lock
-	 * on pmc->sflock. We have the socket lock so reading here is safe.
+	 * on mc->sflock. We have the socket lock so reading here is safe.
 	 */
 	for (i = 0; i < copycount; i++, p++) {
 		struct sockaddr_in6 *psin6;
@@ -623,7 +632,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
 	bool rv = true;
 
 	rcu_read_lock();
-	for_each_pmc_rcu(np, mc) {
+	for_each_mc_rcu(np, mc) {
 		if (ipv6_addr_equal(&mc->addr, mc_addr))
 			break;
 	}
@@ -723,7 +732,7 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc)
  */
 static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
 {
-	struct ifmcaddr6 *pmc;
+	struct ifmcaddr6 *mc;
 
 	/* this is an "ifmcaddr6" for convenience; only the fields below
 	 * are actually used. In particular, the refcnt and users are not
@@ -731,98 +740,91 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
 	 * for deleted items allows change reports to use common code with
 	 * non-deleted or query-response MCA's.
 	 */
-	pmc = kzalloc(sizeof(*pmc), GFP_ATOMIC);
-	if (!pmc)
+	mc = kzalloc(sizeof(*mc), GFP_ATOMIC);
+	if (!mc)
 		return;
 
 	spin_lock_bh(&im->mca_lock);
-	spin_lock_init(&pmc->mca_lock);
-	pmc->idev = im->idev;
+	spin_lock_init(&mc->mca_lock);
+	INIT_LIST_HEAD(&mc->list);
+	mc->idev = im->idev;
 	in6_dev_hold(idev);
-	pmc->mca_addr = im->mca_addr;
-	pmc->mca_crcount = idev->mc_qrv;
-	pmc->mca_sfmode = im->mca_sfmode;
-	if (pmc->mca_sfmode == MCAST_INCLUDE) {
+	mc->mca_addr = im->mca_addr;
+	mc->mca_crcount = idev->mc_qrv;
+	mc->mca_sfmode = im->mca_sfmode;
+	if (mc->mca_sfmode == MCAST_INCLUDE) {
 		struct ip6_sf_list *psf;
 
-		pmc->mca_tomb = im->mca_tomb;
-		pmc->mca_sources = im->mca_sources;
+		mc->mca_tomb = im->mca_tomb;
+		mc->mca_sources = im->mca_sources;
 		im->mca_tomb = im->mca_sources = NULL;
-		for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
-			psf->sf_crcount = pmc->mca_crcount;
+		for (psf = mc->mca_sources; psf; psf = psf->sf_next)
+			psf->sf_crcount = mc->mca_crcount;
 	}
 	spin_unlock_bh(&im->mca_lock);
 
-	spin_lock_bh(&idev->mc_lock);
-	pmc->next = idev->mc_tomb;
-	idev->mc_tomb = pmc;
-	spin_unlock_bh(&idev->mc_lock);
+	spin_lock_bh(&idev->mc_tomb_lock);
+	list_add(&mc->list, &idev->mc_tomb_list);
+	spin_unlock_bh(&idev->mc_tomb_lock);
 }
 
 static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
 {
-	struct ifmcaddr6 *pmc, *pmc_prev;
+	struct ifmcaddr6 *mc = NULL, *tmp = NULL;
+	struct in6_addr *mca = &im->mca_addr;
 	struct ip6_sf_list *psf;
-	struct in6_addr *pmca = &im->mca_addr;
+	bool found = false;
 
-	spin_lock_bh(&idev->mc_lock);
-	pmc_prev = NULL;
-	for (pmc = idev->mc_tomb; pmc; pmc = pmc->next) {
-		if (ipv6_addr_equal(&pmc->mca_addr, pmca))
+	spin_lock_bh(&idev->mc_tomb_lock);
+	list_for_each_entry_safe(mc, tmp, &idev->mc_tomb_list, list) {
+		if (ipv6_addr_equal(&mc->mca_addr, mca)) {
+			list_del(&mc->list);
+			found = true;
 			break;
-		pmc_prev = pmc;
-	}
-	if (pmc) {
-		if (pmc_prev)
-			pmc_prev->next = pmc->next;
-		else
-			idev->mc_tomb = pmc->next;
+		}
 	}
-	spin_unlock_bh(&idev->mc_lock);
+	spin_unlock_bh(&idev->mc_tomb_lock);
 
 	spin_lock_bh(&im->mca_lock);
-	if (pmc) {
-		im->idev = pmc->idev;
+	if (found) {
+		im->idev = mc->idev;
 		if (im->mca_sfmode == MCAST_INCLUDE) {
-			swap(im->mca_tomb, pmc->mca_tomb);
-			swap(im->mca_sources, pmc->mca_sources);
+			swap(im->mca_tomb, mc->mca_tomb);
+			swap(im->mca_sources, mc->mca_sources);
 			for (psf = im->mca_sources; psf; psf = psf->sf_next)
 				psf->sf_crcount = idev->mc_qrv;
 		} else {
 			im->mca_crcount = idev->mc_qrv;
 		}
-		in6_dev_put(pmc->idev);
-		ip6_mc_clear_src(pmc);
-		kfree(pmc);
+		in6_dev_put(mc->idev);
+		ip6_mc_clear_src(mc);
+		kfree(mc);
 	}
 	spin_unlock_bh(&im->mca_lock);
 }
 
 static void mld_clear_delrec(struct inet6_dev *idev)
 {
-	struct ifmcaddr6 *pmc, *nextpmc;
+	struct ifmcaddr6 *mc, *tmp;
 
-	spin_lock_bh(&idev->mc_lock);
-	pmc = idev->mc_tomb;
-	idev->mc_tomb = NULL;
-	spin_unlock_bh(&idev->mc_lock);
-
-	for (; pmc; pmc = nextpmc) {
-		nextpmc = pmc->next;
-		ip6_mc_clear_src(pmc);
-		in6_dev_put(pmc->idev);
-		kfree(pmc);
+	spin_lock_bh(&idev->mc_tomb_lock);
+	list_for_each_entry_safe(mc, tmp, &idev->mc_tomb_list, list) {
+		list_del(&mc->list);
+		ip6_mc_clear_src(mc);
+		in6_dev_put(mc->idev);
+		kfree(mc);
 	}
+	spin_unlock_bh(&idev->mc_tomb_lock);
 
 	/* clear dead sources, too */
 	read_lock_bh(&idev->lock);
-	for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
+	list_for_each_entry_safe(mc, tmp, &idev->mc_list, list) {
 		struct ip6_sf_list *psf, *psf_next;
 
-		spin_lock_bh(&pmc->mca_lock);
-		psf = pmc->mca_tomb;
-		pmc->mca_tomb = NULL;
-		spin_unlock_bh(&pmc->mca_lock);
+		spin_lock_bh(&mc->mca_lock);
+		psf = mc->mca_tomb;
+		mc->mca_tomb = NULL;
+		spin_unlock_bh(&mc->mca_lock);
 		for (; psf; psf = psf_next) {
 			psf_next = psf->sf_next;
 			kfree(psf);
@@ -831,19 +833,6 @@ static void mld_clear_delrec(struct inet6_dev *idev)
 	read_unlock_bh(&idev->lock);
 }
 
-static void mca_get(struct ifmcaddr6 *mc)
-{
-	refcount_inc(&mc->mca_refcnt);
-}
-
-static void ma_put(struct ifmcaddr6 *mc)
-{
-	if (refcount_dec_and_test(&mc->mca_refcnt)) {
-		in6_dev_put(mc->idev);
-		kfree(mc);
-	}
-}
-
 static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev,
 				   const struct in6_addr *addr,
 				   unsigned int mode)
@@ -858,6 +847,7 @@ static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev,
 
 	mc->mca_addr = *addr;
 	mc->idev = idev; /* reference taken by caller */
+	INIT_LIST_HEAD(&mc->list);
 	mc->mca_users = 1;
 	/* mca_stamp should be updated upon changes */
 	mc->mca_cstamp = mc->mca_tstamp = jiffies;
@@ -880,14 +870,13 @@ static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev,
 static int __ipv6_dev_mc_inc(struct net_device *dev,
 			     const struct in6_addr *addr, unsigned int mode)
 {
-	struct ifmcaddr6 *mc;
 	struct inet6_dev *idev;
+	struct ifmcaddr6 *mc;
 
 	ASSERT_RTNL();
 
 	/* we need to take a reference on idev */
 	idev = in6_dev_get(dev);
-
 	if (!idev)
 		return -EINVAL;
 
@@ -898,7 +887,7 @@ static int __ipv6_dev_mc_inc(struct net_device *dev,
 		return -ENODEV;
 	}
 
-	for (mc = idev->mc_list; mc; mc = mc->next) {
+	list_for_each_entry(mc, &idev->mc_list, list) {
 		if (ipv6_addr_equal(&mc->mca_addr, addr)) {
 			mc->mca_users++;
 			write_unlock_bh(&idev->lock);
@@ -915,8 +904,7 @@ static int __ipv6_dev_mc_inc(struct net_device *dev,
 		return -ENOMEM;
 	}
 
-	mc->next = idev->mc_list;
-	idev->mc_list = mc;
+	list_add(&mc->list, &idev->mc_list);
 
 	/* Hold this for the code below before we unlock,
 	 * it is already exposed via idev->mc_list.
@@ -926,7 +914,7 @@ static int __ipv6_dev_mc_inc(struct net_device *dev,
 
 	mld_del_delrec(idev, mc);
 	igmp6_group_added(mc);
-	ma_put(mc);
+	mca_put(mc);
 	return 0;
 }
 
@@ -941,29 +929,28 @@ EXPORT_SYMBOL(ipv6_dev_mc_inc);
  */
 int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
 {
-	struct ifmcaddr6 *ma, **map;
+	struct ifmcaddr6 *mc, *tmp;
 
 	ASSERT_RTNL();
 
 	write_lock_bh(&idev->lock);
-	for (map = &idev->mc_list; (ma = *map) != NULL; map = &ma->next) {
-		if (ipv6_addr_equal(&ma->mca_addr, addr)) {
-			if (--ma->mca_users == 0) {
-				*map = ma->next;
+	list_for_each_entry_safe(mc, tmp, &idev->mc_list, list) {
+		if (ipv6_addr_equal(&mc->mca_addr, addr)) {
+			if (--mc->mca_users == 0) {
+				list_del(&mc->list);
 				write_unlock_bh(&idev->lock);
-
-				igmp6_group_dropped(ma);
-				ip6_mc_clear_src(ma);
-
-				ma_put(ma);
+				igmp6_group_dropped(mc);
+				ip6_mc_clear_src(mc);
+				mca_put(mc);
 				return 0;
 			}
+
 			write_unlock_bh(&idev->lock);
 			return 0;
 		}
 	}
-	write_unlock_bh(&idev->lock);
 
+	write_unlock_bh(&idev->lock);
 	return -ENOENT;
 }
 
@@ -990,19 +977,22 @@ EXPORT_SYMBOL(ipv6_dev_mc_dec);
 bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
 			 const struct in6_addr *src_addr)
 {
+	bool rv = false, found = false;
 	struct inet6_dev *idev;
 	struct ifmcaddr6 *mc;
-	bool rv = false;
 
 	rcu_read_lock();
 	idev = __in6_dev_get(dev);
 	if (idev) {
 		read_lock_bh(&idev->lock);
-		for (mc = idev->mc_list; mc; mc = mc->next) {
-			if (ipv6_addr_equal(&mc->mca_addr, group))
+		list_for_each_entry(mc, &idev->mc_list, list) {
+			if (ipv6_addr_equal(&mc->mca_addr, group)) {
+				found = true;
 				break;
+			}
 		}
-		if (mc) {
+
+		if (found) {
 			if (src_addr && !ipv6_addr_any(src_addr)) {
 				struct ip6_sf_list *psf;
 
@@ -1076,44 +1066,44 @@ static void mld_dad_stop_timer(struct inet6_dev *idev)
  *	IGMP handling (alias multicast ICMPv6 messages)
  */
 
-static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
+static void igmp6_group_queried(struct ifmcaddr6 *mc, unsigned long resptime)
 {
 	unsigned long delay = resptime;
 
 	/* Do not start timer for these addresses */
-	if (ipv6_addr_is_ll_all_nodes(&ma->mca_addr) ||
-	    IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL)
+	if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) ||
+	    IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL)
 		return;
 
-	if (del_timer(&ma->mca_timer)) {
-		refcount_dec(&ma->mca_refcnt);
-		delay = ma->mca_timer.expires - jiffies;
+	if (del_timer(&mc->mca_timer)) {
+		refcount_dec(&mc->mca_refcnt);
+		delay = mc->mca_timer.expires - jiffies;
 	}
 
 	if (delay >= resptime)
 		delay = prandom_u32() % resptime;
 
-	ma->mca_timer.expires = jiffies + delay;
-	if (!mod_timer(&ma->mca_timer, jiffies + delay))
-		refcount_inc(&ma->mca_refcnt);
-	ma->mca_flags |= MAF_TIMER_RUNNING;
+	mc->mca_timer.expires = jiffies + delay;
+	if (!mod_timer(&mc->mca_timer, jiffies + delay))
+		refcount_inc(&mc->mca_refcnt);
+	mc->mca_flags |= MAF_TIMER_RUNNING;
 }
 
 /* mark EXCLUDE-mode sources */
-static bool mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
+static bool mld_xmarksources(struct ifmcaddr6 *mc, int nsrcs,
 			     const struct in6_addr *srcs)
 {
 	struct ip6_sf_list *psf;
 	int i, scount;
 
 	scount = 0;
-	for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
+	for (psf = mc->mca_sources; psf; psf = psf->sf_next) {
 		if (scount == nsrcs)
 			break;
 		for (i = 0; i < nsrcs; i++) {
 			/* skip inactive filters */
 			if (psf->sf_count[MCAST_INCLUDE] ||
-			    pmc->mca_sfcount[MCAST_EXCLUDE] !=
+			    mc->mca_sfcount[MCAST_EXCLUDE] !=
 			    psf->sf_count[MCAST_EXCLUDE])
 				break;
 			if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) {
@@ -1122,25 +1112,25 @@ static bool mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
 			}
 		}
 	}
-	pmc->mca_flags &= ~MAF_GSQUERY;
+	mc->mca_flags &= ~MAF_GSQUERY;
 	if (scount == nsrcs)	/* all sources excluded */
 		return false;
 	return true;
 }
 
-static bool mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
+static bool mld_marksources(struct ifmcaddr6 *mc, int nsrcs,
 			    const struct in6_addr *srcs)
 {
 	struct ip6_sf_list *psf;
 	int i, scount;
 
-	if (pmc->mca_sfmode == MCAST_EXCLUDE)
-		return mld_xmarksources(pmc, nsrcs, srcs);
+	if (mc->mca_sfmode == MCAST_EXCLUDE)
+		return mld_xmarksources(mc, nsrcs, srcs);
 
 	/* mark INCLUDE-mode sources */
 
 	scount = 0;
-	for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
+	for (psf = mc->mca_sources; psf; psf = psf->sf_next) {
 		if (scount == nsrcs)
 			break;
 		for (i = 0; i < nsrcs; i++) {
@@ -1152,10 +1142,10 @@ static bool mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
 		}
 	}
 	if (!scount) {
-		pmc->mca_flags &= ~MAF_GSQUERY;
+		mc->mca_flags &= ~MAF_GSQUERY;
 		return false;
 	}
-	pmc->mca_flags |= MAF_GSQUERY;
+	mc->mca_flags |= MAF_GSQUERY;
 	return true;
 }
 
@@ -1333,10 +1323,10 @@ static int mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld,
 int igmp6_event_query(struct sk_buff *skb)
 {
 	struct mld2_query *mlh2 = NULL;
-	struct ifmcaddr6 *ma;
 	const struct in6_addr *group;
 	unsigned long max_delay;
 	struct inet6_dev *idev;
+	struct ifmcaddr6 *mc;
 	struct mld_msg *mld;
 	int group_type;
 	int mark = 0;
@@ -1416,31 +1406,31 @@ int igmp6_event_query(struct sk_buff *skb)
 
 	read_lock_bh(&idev->lock);
 	if (group_type == IPV6_ADDR_ANY) {
-		for (ma = idev->mc_list; ma; ma = ma->next) {
-			spin_lock_bh(&ma->mca_lock);
-			igmp6_group_queried(ma, max_delay);
-			spin_unlock_bh(&ma->mca_lock);
+		list_for_each_entry(mc, &idev->mc_list, list) {
+			spin_lock_bh(&mc->mca_lock);
+			igmp6_group_queried(mc, max_delay);
+			spin_unlock_bh(&mc->mca_lock);
 		}
 	} else {
-		for (ma = idev->mc_list; ma; ma = ma->next) {
-			if (!ipv6_addr_equal(group, &ma->mca_addr))
+		list_for_each_entry(mc, &idev->mc_list, list) {
+			if (!ipv6_addr_equal(group, &mc->mca_addr))
 				continue;
-			spin_lock_bh(&ma->mca_lock);
-			if (ma->mca_flags & MAF_TIMER_RUNNING) {
+			spin_lock_bh(&mc->mca_lock);
+			if (mc->mca_flags & MAF_TIMER_RUNNING) {
 				/* gsquery <- gsquery && mark */
 				if (!mark)
-					ma->mca_flags &= ~MAF_GSQUERY;
+					mc->mca_flags &= ~MAF_GSQUERY;
 			} else {
 				/* gsquery <- mark */
 				if (mark)
-					ma->mca_flags |= MAF_GSQUERY;
+					mc->mca_flags |= MAF_GSQUERY;
 				else
-					ma->mca_flags &= ~MAF_GSQUERY;
+					mc->mca_flags &= ~MAF_GSQUERY;
 			}
-			if (!(ma->mca_flags & MAF_GSQUERY) ||
-			    mld_marksources(ma, ntohs(mlh2->mld2q_nsrcs), mlh2->mld2q_srcs))
-				igmp6_group_queried(ma, max_delay);
-			spin_unlock_bh(&ma->mca_lock);
+			if (!(mc->mca_flags & MAF_GSQUERY) ||
+			    mld_marksources(mc, ntohs(mlh2->mld2q_nsrcs), mlh2->mld2q_srcs))
+				igmp6_group_queried(mc, max_delay);
+			spin_unlock_bh(&mc->mca_lock);
 			break;
 		}
 	}
@@ -1452,8 +1442,8 @@ int igmp6_event_query(struct sk_buff *skb)
 /* called with rcu_read_lock() */
 int igmp6_event_report(struct sk_buff *skb)
 {
-	struct ifmcaddr6 *ma;
 	struct inet6_dev *idev;
+	struct ifmcaddr6 *mc;
 	struct mld_msg *mld;
 	int addr_type;
 
@@ -1486,13 +1476,13 @@ int igmp6_event_report(struct sk_buff *skb)
 	 */
 
 	read_lock_bh(&idev->lock);
-	for (ma = idev->mc_list; ma; ma = ma->next) {
-		if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) {
-			spin_lock(&ma->mca_lock);
-			if (del_timer(&ma->mca_timer))
-				refcount_dec(&ma->mca_refcnt);
-			ma->mca_flags &= ~(MAF_LAST_REPORTER|MAF_TIMER_RUNNING);
-			spin_unlock(&ma->mca_lock);
+	list_for_each_entry(mc, &idev->mc_list, list) {
+		if (ipv6_addr_equal(&mc->mca_addr, &mld->mld_mca)) {
+			spin_lock(&mc->mca_lock);
+			if (del_timer(&mc->mca_timer))
+				refcount_dec(&mc->mca_refcnt);
+			mc->mca_flags &= ~(MAF_LAST_REPORTER | MAF_TIMER_RUNNING);
+			spin_unlock(&mc->mca_lock);
 			break;
 		}
 	}
@@ -1500,7 +1490,7 @@ int igmp6_event_report(struct sk_buff *skb)
 	return 0;
 }
 
-static bool is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type,
+static bool is_in(struct ifmcaddr6 *mc, struct ip6_sf_list *psf, int type,
 		  int gdeleted, int sdeleted)
 {
 	switch (type) {
@@ -1508,15 +1498,15 @@ static bool is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type,
 	case MLD2_MODE_IS_EXCLUDE:
 		if (gdeleted || sdeleted)
 			return false;
-		if (!((pmc->mca_flags & MAF_GSQUERY) && !psf->sf_gsresp)) {
-			if (pmc->mca_sfmode == MCAST_INCLUDE)
+		if (!((mc->mca_flags & MAF_GSQUERY) && !psf->sf_gsresp)) {
+			if (mc->mca_sfmode == MCAST_INCLUDE)
 				return true;
 			/* don't include if this source is excluded
 			 * in all filters
 			 */
 			if (psf->sf_count[MCAST_INCLUDE])
 				return type == MLD2_MODE_IS_INCLUDE;
-			return pmc->mca_sfcount[MCAST_EXCLUDE] ==
+			return mc->mca_sfcount[MCAST_EXCLUDE] ==
 				psf->sf_count[MCAST_EXCLUDE];
 		}
 		return false;
@@ -1527,31 +1517,31 @@ static bool is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type,
 	case MLD2_CHANGE_TO_EXCLUDE:
 		if (gdeleted || sdeleted)
 			return false;
-		if (pmc->mca_sfcount[MCAST_EXCLUDE] == 0 ||
+		if (mc->mca_sfcount[MCAST_EXCLUDE] == 0 ||
 		    psf->sf_count[MCAST_INCLUDE])
 			return false;
-		return pmc->mca_sfcount[MCAST_EXCLUDE] ==
+		return mc->mca_sfcount[MCAST_EXCLUDE] ==
 			psf->sf_count[MCAST_EXCLUDE];
 	case MLD2_ALLOW_NEW_SOURCES:
 		if (gdeleted || !psf->sf_crcount)
 			return false;
-		return (pmc->mca_sfmode == MCAST_INCLUDE) ^ sdeleted;
+		return (mc->mca_sfmode == MCAST_INCLUDE) ^ sdeleted;
 	case MLD2_BLOCK_OLD_SOURCES:
-		if (pmc->mca_sfmode == MCAST_INCLUDE)
+		if (mc->mca_sfmode == MCAST_INCLUDE)
 			return gdeleted || (psf->sf_crcount && sdeleted);
 		return psf->sf_crcount && !gdeleted && !sdeleted;
 	}
 	return false;
 }
 
-static int
-mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted)
+static int mld_scount(struct ifmcaddr6 *mc, int type, int gdeleted,
+		      int sdeleted)
 {
 	struct ip6_sf_list *psf;
 	int scount = 0;
 
-	for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
-		if (!is_in(pmc, psf, type, gdeleted, sdeleted))
+	for (psf = mc->mca_sources; psf; psf = psf->sf_next) {
+		if (!is_in(mc, psf, type, gdeleted, sdeleted))
 			continue;
 		scount++;
 	}
@@ -1585,21 +1575,23 @@ static void ip6_mc_hdr(struct sock *sk, struct sk_buff *skb,
 
 static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu)
 {
+	u8 ra[8] = { IPPROTO_ICMPV6, 0,
+		     IPV6_TLV_ROUTERALERT, 2,
+		     0, 0, IPV6_TLV_PADN, 0 };
 	struct net_device *dev = idev->dev;
-	struct net *net = dev_net(dev);
-	struct sock *sk = net->ipv6.igmp_sk;
-	struct sk_buff *skb;
-	struct mld2_report *pmr;
-	struct in6_addr addr_buf;
-	const struct in6_addr *saddr;
 	int hlen = LL_RESERVED_SPACE(dev);
 	int tlen = dev->needed_tailroom;
-	unsigned int size = mtu + hlen + tlen;
+	struct net *net = dev_net(dev);
+	const struct in6_addr *saddr;
+	struct in6_addr addr_buf;
+	struct mld2_report *pmr;
+	struct sk_buff *skb;
+	unsigned int size;
+	struct sock *sk;
 	int err;
-	u8 ra[8] = { IPPROTO_ICMPV6, 0,
-		     IPV6_TLV_ROUTERALERT, 2, 0, 0,
-		     IPV6_TLV_PADN, 0 };
 
+	size = mtu + hlen + tlen;
+	sk = net->ipv6.igmp_sk;
 	/* we assume size > sizeof(ra) here */
 	/* limit our allocations to order-0 page */
 	size = min_t(int, size, SKB_MAX_ORDER(0, 0));
@@ -1639,21 +1631,22 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu)
 static void mld_sendpack(struct sk_buff *skb)
 {
 	struct ipv6hdr *pip6 = ipv6_hdr(skb);
-	struct mld2_report *pmr =
-			      (struct mld2_report *)skb_transport_header(skb);
+	struct net *net = dev_net(skb->dev);
 	int payload_len, mldlen;
+	struct mld2_report *pmr;
 	struct inet6_dev *idev;
-	struct net *net = dev_net(skb->dev);
-	int err;
-	struct flowi6 fl6;
 	struct dst_entry *dst;
+	struct flowi6 fl6;
+	int err;
+
+	pmr = (struct mld2_report *)skb_transport_header(skb);
 
 	rcu_read_lock();
 	idev = __in6_dev_get(skb->dev);
 	IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
 
 	payload_len = (skb_tail_pointer(skb) - skb_network_header(skb)) -
-		sizeof(*pip6);
+		      sizeof(*pip6);
 	mldlen = skb_tail_pointer(skb) - skb_transport_header(skb);
 	pip6->payload_len = htons(payload_len);
 
@@ -1695,19 +1688,20 @@ static void mld_sendpack(struct sk_buff *skb)
 	goto out;
 }
 
-static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel)
+static int grec_size(struct ifmcaddr6 *mc, int type, int gdel, int sdel)
 {
-	return sizeof(struct mld2_grec) + 16 * mld_scount(pmc,type,gdel,sdel);
+	return sizeof(struct mld2_grec) + 16 * mld_scount(mc, type, gdel, sdel);
 }
 
-static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
-	int type, struct mld2_grec **ppgr, unsigned int mtu)
+static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *mc,
+				  int type, struct mld2_grec **ppgr,
+				  unsigned int mtu)
 {
 	struct mld2_report *pmr;
 	struct mld2_grec *pgr;
 
 	if (!skb) {
-		skb = mld_newpack(pmc->idev, mtu);
+		skb = mld_newpack(mc->idev, mtu);
 		if (!skb)
 			return NULL;
 	}
@@ -1715,7 +1709,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 	pgr->grec_type = type;
 	pgr->grec_auxwords = 0;
 	pgr->grec_nsrcs = 0;
-	pgr->grec_mca = pmc->mca_addr;	/* structure copy */
+	pgr->grec_mca = mc->mca_addr;	/* structure copy */
 	pmr = (struct mld2_report *)skb_transport_header(skb);
 	pmr->mld2r_ngrec = htons(ntohs(pmr->mld2r_ngrec)+1);
 	*ppgr = pgr;
@@ -1724,18 +1718,20 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 
 #define AVAILABLE(skb)	((skb) ? skb_availroom(skb) : 0)
 
-static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
-	int type, int gdeleted, int sdeleted, int crsend)
+static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *mc,
+				int type, int gdeleted, int sdeleted,
+				int crsend)
 {
-	struct inet6_dev *idev = pmc->idev;
-	struct net_device *dev = idev->dev;
-	struct mld2_report *pmr;
-	struct mld2_grec *pgr = NULL;
 	struct ip6_sf_list *psf, *psf_next, *psf_prev, **psf_list;
 	int scount, stotal, first, isquery, truncate;
+	struct inet6_dev *idev = mc->idev;
+	struct mld2_grec *pgr = NULL;
+	struct mld2_report *pmr;
+	struct net_device *dev;
 	unsigned int mtu;
 
-	if (pmc->mca_flags & MAF_NOREPORT)
+	dev = idev->dev;
+	if (mc->mca_flags & MAF_NOREPORT)
 		return skb;
 
 	mtu = READ_ONCE(dev->mtu);
@@ -1749,7 +1745,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 
 	stotal = scount = 0;
 
-	psf_list = sdeleted ? &pmc->mca_tomb : &pmc->mca_sources;
+	psf_list = sdeleted ? &mc->mca_tomb : &mc->mca_sources;
 
 	if (!*psf_list)
 		goto empty_source;
@@ -1759,7 +1755,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 	/* EX and TO_EX get a fresh packet, if needed */
 	if (truncate) {
 		if (pmr && pmr->mld2r_ngrec &&
-		    AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) {
+		    AVAILABLE(skb) < grec_size(mc, type, gdeleted, sdeleted)) {
 			if (skb)
 				mld_sendpack(skb);
 			skb = mld_newpack(idev, mtu);
@@ -1772,7 +1768,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 
 		psf_next = psf->sf_next;
 
-		if (!is_in(pmc, psf, type, gdeleted, sdeleted) && !crsend) {
+		if (!is_in(mc, psf, type, gdeleted, sdeleted) && !crsend) {
 			psf_prev = psf;
 			continue;
 		}
@@ -1780,8 +1776,8 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 		/* Based on RFC3810 6.1. Should not send source-list change
 		 * records when there is a filter mode change.
 		 */
-		if (((gdeleted && pmc->mca_sfmode == MCAST_EXCLUDE) ||
-		     (!gdeleted && pmc->mca_crcount)) &&
+		if (((gdeleted && mc->mca_sfmode == MCAST_EXCLUDE) ||
+		     (!gdeleted && mc->mca_crcount)) &&
 		    (type == MLD2_ALLOW_NEW_SOURCES ||
 		     type == MLD2_BLOCK_OLD_SOURCES) && psf->sf_crcount)
 			goto decrease_sf_crcount;
@@ -1803,7 +1799,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 			scount = 0;
 		}
 		if (first) {
-			skb = add_grhead(skb, pmc, type, &pgr, mtu);
+			skb = add_grhead(skb, mc, type, &pgr, mtu);
 			first = 0;
 		}
 		if (!skb)
@@ -1832,49 +1828,49 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 		if (type == MLD2_ALLOW_NEW_SOURCES ||
 		    type == MLD2_BLOCK_OLD_SOURCES)
 			return skb;
-		if (pmc->mca_crcount || isquery || crsend) {
+		if (mc->mca_crcount || isquery || crsend) {
 			/* make sure we have room for group header */
 			if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) {
 				mld_sendpack(skb);
 				skb = NULL; /* add_grhead will get a new one */
 			}
-			skb = add_grhead(skb, pmc, type, &pgr, mtu);
+			skb = add_grhead(skb, mc, type, &pgr, mtu);
 		}
 	}
 	if (pgr)
 		pgr->grec_nsrcs = htons(scount);
 
 	if (isquery)
-		pmc->mca_flags &= ~MAF_GSQUERY;	/* clear query state */
+		mc->mca_flags &= ~MAF_GSQUERY;	/* clear query state */
 	return skb;
 }
 
-static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)
+static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *mc)
 {
 	struct sk_buff *skb = NULL;
 	int type;
 
 	read_lock_bh(&idev->lock);
-	if (!pmc) {
-		for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
-			if (pmc->mca_flags & MAF_NOREPORT)
+	if (!mc) {
+		list_for_each_entry(mc, &idev->mc_list, list) {
+			if (mc->mca_flags & MAF_NOREPORT)
 				continue;
-			spin_lock_bh(&pmc->mca_lock);
-			if (pmc->mca_sfcount[MCAST_EXCLUDE])
+			spin_lock_bh(&mc->mca_lock);
+			if (mc->mca_sfcount[MCAST_EXCLUDE])
 				type = MLD2_MODE_IS_EXCLUDE;
 			else
 				type = MLD2_MODE_IS_INCLUDE;
-			skb = add_grec(skb, pmc, type, 0, 0, 0);
-			spin_unlock_bh(&pmc->mca_lock);
+			skb = add_grec(skb, mc, type, 0, 0, 0);
+			spin_unlock_bh(&mc->mca_lock);
 		}
 	} else {
-		spin_lock_bh(&pmc->mca_lock);
-		if (pmc->mca_sfcount[MCAST_EXCLUDE])
+		spin_lock_bh(&mc->mca_lock);
+		if (mc->mca_sfcount[MCAST_EXCLUDE])
 			type = MLD2_MODE_IS_EXCLUDE;
 		else
 			type = MLD2_MODE_IS_INCLUDE;
-		skb = add_grec(skb, pmc, type, 0, 0, 0);
-		spin_unlock_bh(&pmc->mca_lock);
+		skb = add_grec(skb, mc, type, 0, 0, 0);
+		spin_unlock_bh(&mc->mca_lock);
 	}
 	read_unlock_bh(&idev->lock);
 	if (skb)
@@ -1904,94 +1900,90 @@ static void mld_clear_zeros(struct ip6_sf_list **ppsf)
 
 static void mld_send_cr(struct inet6_dev *idev)
 {
-	struct ifmcaddr6 *pmc, *pmc_prev, *pmc_next;
 	struct sk_buff *skb = NULL;
+	struct ifmcaddr6 *mc, *tmp;
 	int type, dtype;
 
 	read_lock_bh(&idev->lock);
-	spin_lock(&idev->mc_lock);
+	spin_lock(&idev->mc_tomb_lock);
 
 	/* deleted MCA's */
-	pmc_prev = NULL;
-	for (pmc = idev->mc_tomb; pmc; pmc = pmc_next) {
-		pmc_next = pmc->next;
-		if (pmc->mca_sfmode == MCAST_INCLUDE) {
+	list_for_each_entry_safe(mc, tmp, &idev->mc_tomb_list, list) {
+		if (mc->mca_sfmode == MCAST_INCLUDE) {
 			type = MLD2_BLOCK_OLD_SOURCES;
 			dtype = MLD2_BLOCK_OLD_SOURCES;
-			skb = add_grec(skb, pmc, type, 1, 0, 0);
-			skb = add_grec(skb, pmc, dtype, 1, 1, 0);
+			skb = add_grec(skb, mc, type, 1, 0, 0);
+			skb = add_grec(skb, mc, dtype, 1, 1, 0);
 		}
-		if (pmc->mca_crcount) {
-			if (pmc->mca_sfmode == MCAST_EXCLUDE) {
+		if (mc->mca_crcount) {
+			if (mc->mca_sfmode == MCAST_EXCLUDE) {
 				type = MLD2_CHANGE_TO_INCLUDE;
-				skb = add_grec(skb, pmc, type, 1, 0, 0);
+				skb = add_grec(skb, mc, type, 1, 0, 0);
 			}
-			pmc->mca_crcount--;
-			if (pmc->mca_crcount == 0) {
-				mld_clear_zeros(&pmc->mca_tomb);
-				mld_clear_zeros(&pmc->mca_sources);
+			mc->mca_crcount--;
+			if (mc->mca_crcount == 0) {
+				mld_clear_zeros(&mc->mca_tomb);
+				mld_clear_zeros(&mc->mca_sources);
 			}
 		}
-		if (pmc->mca_crcount == 0 && !pmc->mca_tomb &&
-		    !pmc->mca_sources) {
-			if (pmc_prev)
-				pmc_prev->next = pmc_next;
-			else
-				idev->mc_tomb = pmc_next;
-			in6_dev_put(pmc->idev);
-			kfree(pmc);
-		} else
-			pmc_prev = pmc;
+		if (mc->mca_crcount == 0 && !mc->mca_tomb &&
+		    !mc->mca_sources) {
+			list_del(&mc->list);
+			in6_dev_put(mc->idev);
+			kfree(mc);
+		}
 	}
-	spin_unlock(&idev->mc_lock);
+	spin_unlock(&idev->mc_tomb_lock);
 
 	/* change recs */
-	for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
-		spin_lock_bh(&pmc->mca_lock);
-		if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
+	list_for_each_entry(mc, &idev->mc_list, list) {
+		spin_lock_bh(&mc->mca_lock);
+		if (mc->mca_sfcount[MCAST_EXCLUDE]) {
 			type = MLD2_BLOCK_OLD_SOURCES;
 			dtype = MLD2_ALLOW_NEW_SOURCES;
 		} else {
 			type = MLD2_ALLOW_NEW_SOURCES;
 			dtype = MLD2_BLOCK_OLD_SOURCES;
 		}
-		skb = add_grec(skb, pmc, type, 0, 0, 0);
-		skb = add_grec(skb, pmc, dtype, 0, 1, 0);	/* deleted sources */
+		skb = add_grec(skb, mc, type, 0, 0, 0);
+		skb = add_grec(skb, mc, dtype, 0, 1, 0);	/* deleted sources */
 
 		/* filter mode changes */
-		if (pmc->mca_crcount) {
-			if (pmc->mca_sfmode == MCAST_EXCLUDE)
+		if (mc->mca_crcount) {
+			if (mc->mca_sfmode == MCAST_EXCLUDE)
 				type = MLD2_CHANGE_TO_EXCLUDE;
 			else
 				type = MLD2_CHANGE_TO_INCLUDE;
-			skb = add_grec(skb, pmc, type, 0, 0, 0);
-			pmc->mca_crcount--;
+			skb = add_grec(skb, mc, type, 0, 0, 0);
+			mc->mca_crcount--;
 		}
-		spin_unlock_bh(&pmc->mca_lock);
+		spin_unlock_bh(&mc->mca_lock);
 	}
 	read_unlock_bh(&idev->lock);
 	if (!skb)
 		return;
-	(void) mld_sendpack(skb);
+	mld_sendpack(skb);
 }
 
 static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 {
+	u8 ra[8] = { IPPROTO_ICMPV6, 0,
+		     IPV6_TLV_ROUTERALERT,
+		     2, 0, 0, IPV6_TLV_PADN, 0 };
+	const struct in6_addr *snd_addr, *saddr;
+	int err, len, payload_len, full_len;
+	int hlen = LL_RESERVED_SPACE(dev);
+	int tlen = dev->needed_tailroom;
 	struct net *net = dev_net(dev);
-	struct sock *sk = net->ipv6.igmp_sk;
+	struct in6_addr addr_buf;
 	struct inet6_dev *idev;
+	struct dst_entry *dst;
 	struct sk_buff *skb;
 	struct mld_msg *hdr;
-	const struct in6_addr *snd_addr, *saddr;
-	struct in6_addr addr_buf;
-	int hlen = LL_RESERVED_SPACE(dev);
-	int tlen = dev->needed_tailroom;
-	int err, len, payload_len, full_len;
-	u8 ra[8] = { IPPROTO_ICMPV6, 0,
-		     IPV6_TLV_ROUTERALERT, 2, 0, 0,
-		     IPV6_TLV_PADN, 0 };
 	struct flowi6 fl6;
-	struct dst_entry *dst;
+	struct sock *sk;
+
+	sk = net->ipv6.igmp_sk;
 
 	if (type == ICMPV6_MGM_REDUCTION)
 		snd_addr = &in6addr_linklocal_allrouters;
@@ -2074,7 +2066,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 static void mld_send_initial_cr(struct inet6_dev *idev)
 {
 	struct sk_buff *skb;
-	struct ifmcaddr6 *pmc;
+	struct ifmcaddr6 *mc;
 	int type;
 
 	if (mld_in_v1_mode(idev))
@@ -2082,14 +2074,14 @@ static void mld_send_initial_cr(struct inet6_dev *idev)
 
 	skb = NULL;
 	read_lock_bh(&idev->lock);
-	for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
-		spin_lock_bh(&pmc->mca_lock);
-		if (pmc->mca_sfcount[MCAST_EXCLUDE])
+	list_for_each_entry(mc, &idev->mc_list, list) {
+		spin_lock_bh(&mc->mca_lock);
+		if (mc->mca_sfcount[MCAST_EXCLUDE])
 			type = MLD2_CHANGE_TO_EXCLUDE;
 		else
 			type = MLD2_ALLOW_NEW_SOURCES;
-		skb = add_grec(skb, pmc, type, 0, 0, 1);
-		spin_unlock_bh(&pmc->mca_lock);
+		skb = add_grec(skb, mc, type, 0, 0, 1);
+		spin_unlock_bh(&mc->mca_lock);
 	}
 	read_unlock_bh(&idev->lock);
 	if (skb)
@@ -2122,14 +2114,14 @@ static void mld_dad_timer_expire(struct timer_list *t)
 	in6_dev_put(idev);
 }
 
-static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
-	const struct in6_addr *psfsrc)
+static int ip6_mc_del1_src(struct ifmcaddr6 *mc, int sfmode,
+			   const struct in6_addr *psfsrc)
 {
 	struct ip6_sf_list *psf, *psf_prev;
 	int rv = 0;
 
 	psf_prev = NULL;
-	for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
+	for (psf = mc->mca_sources; psf; psf = psf->sf_next) {
 		if (ipv6_addr_equal(&psf->sf_addr, psfsrc))
 			break;
 		psf_prev = psf;
@@ -2140,78 +2132,83 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
 	}
 	psf->sf_count[sfmode]--;
 	if (!psf->sf_count[MCAST_INCLUDE] && !psf->sf_count[MCAST_EXCLUDE]) {
-		struct inet6_dev *idev = pmc->idev;
+		struct inet6_dev *idev = mc->idev;
 
 		/* no more filters for this source */
 		if (psf_prev)
 			psf_prev->sf_next = psf->sf_next;
 		else
-			pmc->mca_sources = psf->sf_next;
-		if (psf->sf_oldin && !(pmc->mca_flags & MAF_NOREPORT) &&
+			mc->mca_sources = psf->sf_next;
+		if (psf->sf_oldin && !(mc->mca_flags & MAF_NOREPORT) &&
 		    !mld_in_v1_mode(idev)) {
 			psf->sf_crcount = idev->mc_qrv;
-			psf->sf_next = pmc->mca_tomb;
-			pmc->mca_tomb = psf;
+			psf->sf_next = mc->mca_tomb;
+			mc->mca_tomb = psf;
 			rv = 1;
-		} else
+		} else {
 			kfree(psf);
+		}
 	}
 	return rv;
 }
 
-static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *mca,
 			  int sfmode, int sfcount, const struct in6_addr *psfsrc,
 			  int delta)
 {
-	struct ifmcaddr6 *pmc;
-	int	changerec = 0;
-	int	i, err;
+	struct ifmcaddr6 *mc;
+	bool found = false;
+	int changerec = 0;
+	int i, err;
 
 	if (!idev)
 		return -ENODEV;
 	read_lock_bh(&idev->lock);
-	for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
-		if (ipv6_addr_equal(pmca, &pmc->mca_addr))
+	list_for_each_entry(mc, &idev->mc_list, list) {
+		if (ipv6_addr_equal(mca, &mc->mca_addr)) {
+			found = true;
 			break;
+		}
 	}
-	if (!pmc) {
+	if (!found) {
 		/* MCA not found?? bug */
 		read_unlock_bh(&idev->lock);
 		return -ESRCH;
 	}
-	spin_lock_bh(&pmc->mca_lock);
-	sf_markstate(pmc);
+	spin_lock_bh(&mc->mca_lock);
+	sf_markstate(mc);
 	if (!delta) {
-		if (!pmc->mca_sfcount[sfmode]) {
-			spin_unlock_bh(&pmc->mca_lock);
+		if (!mc->mca_sfcount[sfmode]) {
+			spin_unlock_bh(&mc->mca_lock);
 			read_unlock_bh(&idev->lock);
 			return -EINVAL;
 		}
-		pmc->mca_sfcount[sfmode]--;
+		mc->mca_sfcount[sfmode]--;
 	}
 	err = 0;
 	for (i = 0; i < sfcount; i++) {
-		int rv = ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
+		int rv = ip6_mc_del1_src(mc, sfmode, &psfsrc[i]);
 
 		changerec |= rv > 0;
 		if (!err && rv < 0)
 			err = rv;
 	}
-	if (pmc->mca_sfmode == MCAST_EXCLUDE &&
-	    pmc->mca_sfcount[MCAST_EXCLUDE] == 0 &&
-	    pmc->mca_sfcount[MCAST_INCLUDE]) {
+	if (mc->mca_sfmode == MCAST_EXCLUDE &&
+	    mc->mca_sfcount[MCAST_EXCLUDE] == 0 &&
+	    mc->mca_sfcount[MCAST_INCLUDE]) {
 		struct ip6_sf_list *psf;
 
 		/* filter mode change */
-		pmc->mca_sfmode = MCAST_INCLUDE;
-		pmc->mca_crcount = idev->mc_qrv;
-		idev->mc_ifc_count = pmc->mca_crcount;
-		for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
+		mc->mca_sfmode = MCAST_INCLUDE;
+		mc->mca_crcount = idev->mc_qrv;
+		idev->mc_ifc_count = mc->mca_crcount;
+		for (psf = mc->mca_sources; psf; psf = psf->sf_next)
 			psf->sf_crcount = 0;
-		mld_ifc_event(pmc->idev);
-	} else if (sf_setstate(pmc) || changerec)
-		mld_ifc_event(pmc->idev);
-	spin_unlock_bh(&pmc->mca_lock);
+		mld_ifc_event(mc->idev);
+	} else if (sf_setstate(mc) || changerec) {
+		mld_ifc_event(mc->idev);
+	}
+	spin_unlock_bh(&mc->mca_lock);
 	read_unlock_bh(&idev->lock);
 	return err;
 }
@@ -2219,13 +2216,13 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
 /*
  * Add multicast single-source filter to the interface list
  */
-static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
-	const struct in6_addr *psfsrc)
+static int ip6_mc_add1_src(struct ifmcaddr6 *mc, int sfmode,
+			   const struct in6_addr *psfsrc)
 {
 	struct ip6_sf_list *psf, *psf_prev;
 
 	psf_prev = NULL;
-	for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
+	for (psf = mc->mca_sources; psf; psf = psf->sf_next) {
 		if (ipv6_addr_equal(&psf->sf_addr, psfsrc))
 			break;
 		psf_prev = psf;
@@ -2239,36 +2236,37 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
 		if (psf_prev) {
 			psf_prev->sf_next = psf;
 		} else
-			pmc->mca_sources = psf;
+			mc->mca_sources = psf;
 	}
 	psf->sf_count[sfmode]++;
 	return 0;
 }
 
-static void sf_markstate(struct ifmcaddr6 *pmc)
+static void sf_markstate(struct ifmcaddr6 *mc)
 {
+	int mca_xcount = mc->mca_sfcount[MCAST_EXCLUDE];
 	struct ip6_sf_list *psf;
-	int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];
 
-	for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
-		if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
+	for (psf = mc->mca_sources; psf; psf = psf->sf_next) {
+		if (mc->mca_sfcount[MCAST_EXCLUDE]) {
 			psf->sf_oldin = mca_xcount ==
 				psf->sf_count[MCAST_EXCLUDE] &&
 				!psf->sf_count[MCAST_INCLUDE];
 		} else
 			psf->sf_oldin = psf->sf_count[MCAST_INCLUDE] != 0;
+	}
 }
 
-static int sf_setstate(struct ifmcaddr6 *pmc)
+static int sf_setstate(struct ifmcaddr6 *mc)
 {
+	int mca_xcount = mc->mca_sfcount[MCAST_EXCLUDE];
 	struct ip6_sf_list *psf, *dpsf;
-	int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];
-	int qrv = pmc->idev->mc_qrv;
+	int qrv = mc->idev->mc_qrv;
 	int new_in, rv;
 
 	rv = 0;
-	for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
-		if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
+	for (psf = mc->mca_sources; psf; psf = psf->sf_next) {
+		if (mc->mca_sfcount[MCAST_EXCLUDE]) {
 			new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] &&
 				!psf->sf_count[MCAST_INCLUDE];
 		} else
@@ -2277,7 +2275,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
 			if (!psf->sf_oldin) {
 				struct ip6_sf_list *prev = NULL;
 
-				for (dpsf = pmc->mca_tomb; dpsf;
+				for (dpsf = mc->mca_tomb; dpsf;
 				     dpsf = dpsf->sf_next) {
 					if (ipv6_addr_equal(&dpsf->sf_addr,
 					    &psf->sf_addr))
@@ -2288,7 +2286,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
 					if (prev)
 						prev->sf_next = dpsf->sf_next;
 					else
-						pmc->mca_tomb = dpsf->sf_next;
+						mc->mca_tomb = dpsf->sf_next;
 					kfree(dpsf);
 				}
 				psf->sf_crcount = qrv;
@@ -2300,7 +2298,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
 			 * add or update "delete" records if an active filter
 			 * is now inactive
 			 */
-			for (dpsf = pmc->mca_tomb; dpsf; dpsf = dpsf->sf_next)
+			for (dpsf = mc->mca_tomb; dpsf; dpsf = dpsf->sf_next)
 				if (ipv6_addr_equal(&dpsf->sf_addr,
 				    &psf->sf_addr))
 					break;
@@ -2309,9 +2307,9 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
 				if (!dpsf)
 					continue;
 				*dpsf = *psf;
-				/* pmc->mca_lock held by callers */
-				dpsf->sf_next = pmc->mca_tomb;
-				pmc->mca_tomb = dpsf;
+				/* mc->mca_lock held by callers */
+				dpsf->sf_next = mc->mca_tomb;
+				mc->mca_tomb = dpsf;
 			}
 			dpsf->sf_crcount = qrv;
 			rv++;
@@ -2323,35 +2321,39 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
 /*
  * Add multicast source filter list to the interface list
  */
-static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *mca,
 			  int sfmode, int sfcount, const struct in6_addr *psfsrc,
 			  int delta)
 {
-	struct ifmcaddr6 *pmc;
-	int	isexclude;
-	int	i, err;
+	struct ifmcaddr6 *mc;
+	bool found = false;
+	int isexclude;
+	int i, err;
 
 	if (!idev)
 		return -ENODEV;
+
 	read_lock_bh(&idev->lock);
-	for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
-		if (ipv6_addr_equal(pmca, &pmc->mca_addr))
+	list_for_each_entry(mc, &idev->mc_list, list) {
+		if (ipv6_addr_equal(mca, &mc->mca_addr)) {
+			found = true;
 			break;
+		}
 	}
-	if (!pmc) {
+	if (!found) {
 		/* MCA not found?? bug */
 		read_unlock_bh(&idev->lock);
 		return -ESRCH;
 	}
-	spin_lock_bh(&pmc->mca_lock);
+	spin_lock_bh(&mc->mca_lock);
 
-	sf_markstate(pmc);
-	isexclude = pmc->mca_sfmode == MCAST_EXCLUDE;
+	sf_markstate(mc);
+	isexclude = mc->mca_sfmode == MCAST_EXCLUDE;
 	if (!delta)
-		pmc->mca_sfcount[sfmode]++;
+		mc->mca_sfcount[sfmode]++;
 	err = 0;
 	for (i = 0; i < sfcount; i++) {
-		err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i]);
+		err = ip6_mc_add1_src(mc, sfmode, &psfsrc[i]);
 		if (err)
 			break;
 	}
@@ -2359,72 +2361,72 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
 		int j;
 
 		if (!delta)
-			pmc->mca_sfcount[sfmode]--;
+			mc->mca_sfcount[sfmode]--;
 		for (j = 0; j < i; j++)
-			ip6_mc_del1_src(pmc, sfmode, &psfsrc[j]);
-	} else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
+			ip6_mc_del1_src(mc, sfmode, &psfsrc[j]);
+	} else if (isexclude != (mc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
 		struct ip6_sf_list *psf;
 
 		/* filter mode change */
-		if (pmc->mca_sfcount[MCAST_EXCLUDE])
-			pmc->mca_sfmode = MCAST_EXCLUDE;
-		else if (pmc->mca_sfcount[MCAST_INCLUDE])
-			pmc->mca_sfmode = MCAST_INCLUDE;
+		if (mc->mca_sfcount[MCAST_EXCLUDE])
+			mc->mca_sfmode = MCAST_EXCLUDE;
+		else if (mc->mca_sfcount[MCAST_INCLUDE])
+			mc->mca_sfmode = MCAST_INCLUDE;
 		/* else no filters; keep old mode for reports */
 
-		pmc->mca_crcount = idev->mc_qrv;
-		idev->mc_ifc_count = pmc->mca_crcount;
-		for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
+		mc->mca_crcount = idev->mc_qrv;
+		idev->mc_ifc_count = mc->mca_crcount;
+		for (psf = mc->mca_sources; psf; psf = psf->sf_next)
 			psf->sf_crcount = 0;
 		mld_ifc_event(idev);
-	} else if (sf_setstate(pmc))
+	} else if (sf_setstate(mc))
 		mld_ifc_event(idev);
-	spin_unlock_bh(&pmc->mca_lock);
+	spin_unlock_bh(&mc->mca_lock);
 	read_unlock_bh(&idev->lock);
 	return err;
 }
 
-static void ip6_mc_clear_src(struct ifmcaddr6 *pmc)
+static void ip6_mc_clear_src(struct ifmcaddr6 *mc)
 {
 	struct ip6_sf_list *psf, *nextpsf;
 
-	for (psf = pmc->mca_tomb; psf; psf = nextpsf) {
+	for (psf = mc->mca_tomb; psf; psf = nextpsf) {
 		nextpsf = psf->sf_next;
 		kfree(psf);
 	}
-	pmc->mca_tomb = NULL;
-	for (psf = pmc->mca_sources; psf; psf = nextpsf) {
+	mc->mca_tomb = NULL;
+	for (psf = mc->mca_sources; psf; psf = nextpsf) {
 		nextpsf = psf->sf_next;
 		kfree(psf);
 	}
-	pmc->mca_sources = NULL;
-	pmc->mca_sfmode = MCAST_EXCLUDE;
-	pmc->mca_sfcount[MCAST_INCLUDE] = 0;
-	pmc->mca_sfcount[MCAST_EXCLUDE] = 1;
+	mc->mca_sources = NULL;
+	mc->mca_sfmode = MCAST_EXCLUDE;
+	mc->mca_sfcount[MCAST_INCLUDE] = 0;
+	mc->mca_sfcount[MCAST_EXCLUDE] = 1;
 }
 
 
-static void igmp6_join_group(struct ifmcaddr6 *ma)
+static void igmp6_join_group(struct ifmcaddr6 *mc)
 {
 	unsigned long delay;
 
-	if (ma->mca_flags & MAF_NOREPORT)
+	if (mc->mca_flags & MAF_NOREPORT)
 		return;
 
-	igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
+	igmp6_send(&mc->mca_addr, mc->idev->dev, ICMPV6_MGM_REPORT);
 
-	delay = prandom_u32() % unsolicited_report_interval(ma->idev);
+	delay = prandom_u32() % unsolicited_report_interval(mc->idev);
 
-	spin_lock_bh(&ma->mca_lock);
-	if (del_timer(&ma->mca_timer)) {
-		refcount_dec(&ma->mca_refcnt);
-		delay = ma->mca_timer.expires - jiffies;
+	spin_lock_bh(&mc->mca_lock);
+	if (del_timer(&mc->mca_timer)) {
+		refcount_dec(&mc->mca_refcnt);
+		delay = mc->mca_timer.expires - jiffies;
 	}
 
-	if (!mod_timer(&ma->mca_timer, jiffies + delay))
-		refcount_inc(&ma->mca_refcnt);
-	ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;
-	spin_unlock_bh(&ma->mca_lock);
+	if (!mod_timer(&mc->mca_timer, jiffies + delay))
+		refcount_inc(&mc->mca_refcnt);
+	mc->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;
+	spin_unlock_bh(&mc->mca_lock);
 }
 
 static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
@@ -2446,15 +2448,15 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
 	return err;
 }
 
-static void igmp6_leave_group(struct ifmcaddr6 *ma)
+static void igmp6_leave_group(struct ifmcaddr6 *mc)
 {
-	if (mld_in_v1_mode(ma->idev)) {
-		if (ma->mca_flags & MAF_LAST_REPORTER)
-			igmp6_send(&ma->mca_addr, ma->idev->dev,
-				ICMPV6_MGM_REDUCTION);
+	if (mld_in_v1_mode(mc->idev)) {
+		if (mc->mca_flags & MAF_LAST_REPORTER)
+			igmp6_send(&mc->mca_addr, mc->idev->dev,
+				   ICMPV6_MGM_REDUCTION);
 	} else {
-		mld_add_delrec(ma->idev, ma);
-		mld_ifc_event(ma->idev);
+		mld_add_delrec(mc->idev, mc);
+		mld_ifc_event(mc->idev);
 	}
 }
 
@@ -2491,31 +2493,31 @@ static void mld_ifc_event(struct inet6_dev *idev)
 
 static void igmp6_timer_handler(struct timer_list *t)
 {
-	struct ifmcaddr6 *ma = from_timer(ma, t, mca_timer);
+	struct ifmcaddr6 *mc = from_timer(mc, t, mca_timer);
 
-	if (mld_in_v1_mode(ma->idev))
-		igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
+	if (mld_in_v1_mode(mc->idev))
+		igmp6_send(&mc->mca_addr, mc->idev->dev, ICMPV6_MGM_REPORT);
 	else
-		mld_send_report(ma->idev, ma);
+		mld_send_report(mc->idev, mc);
 
-	spin_lock(&ma->mca_lock);
-	ma->mca_flags |=  MAF_LAST_REPORTER;
-	ma->mca_flags &= ~MAF_TIMER_RUNNING;
-	spin_unlock(&ma->mca_lock);
-	ma_put(ma);
+	spin_lock(&mc->mca_lock);
+	mc->mca_flags |=  MAF_LAST_REPORTER;
+	mc->mca_flags &= ~MAF_TIMER_RUNNING;
+	spin_unlock(&mc->mca_lock);
+	mca_put(mc);
 }
 
 /* Device changing type */
 
 void ipv6_mc_unmap(struct inet6_dev *idev)
 {
-	struct ifmcaddr6 *i;
+	struct ifmcaddr6 *mc, *tmp;
 
 	/* Install multicast list, except for all-nodes (already installed) */
 
 	read_lock_bh(&idev->lock);
-	for (i = idev->mc_list; i; i = i->next)
-		igmp6_group_dropped(i);
+	list_for_each_entry_safe(mc, tmp, &idev->mc_list, list)
+		igmp6_group_dropped(mc);
 	read_unlock_bh(&idev->lock);
 }
 
@@ -2528,14 +2530,14 @@ void ipv6_mc_remap(struct inet6_dev *idev)
 
 void ipv6_mc_down(struct inet6_dev *idev)
 {
-	struct ifmcaddr6 *i;
+	struct ifmcaddr6 *mc, *tmp;
 
 	/* Withdraw multicast list */
 
 	read_lock_bh(&idev->lock);
 
-	for (i = idev->mc_list; i; i = i->next)
-		igmp6_group_dropped(i);
+	list_for_each_entry_safe(mc, tmp, &idev->mc_list, list)
+		igmp6_group_dropped(mc);
 
 	/* Should stop timer after group drop. or we will
 	 * start timer again in mld_ifc_event()
@@ -2559,15 +2561,15 @@ static void ipv6_mc_reset(struct inet6_dev *idev)
 
 void ipv6_mc_up(struct inet6_dev *idev)
 {
-	struct ifmcaddr6 *i;
+	struct ifmcaddr6 *mc, *tmp;
 
 	/* Install multicast list, except for all-nodes (already installed) */
 
 	read_lock_bh(&idev->lock);
 	ipv6_mc_reset(idev);
-	for (i = idev->mc_list; i; i = i->next) {
-		mld_del_delrec(idev, i);
-		igmp6_group_added(i);
+	list_for_each_entry_safe(mc, tmp, &idev->mc_list, list) {
+		mld_del_delrec(idev, mc);
+		igmp6_group_added(mc);
 	}
 	read_unlock_bh(&idev->lock);
 }
@@ -2577,10 +2579,11 @@ void ipv6_mc_up(struct inet6_dev *idev)
 void ipv6_mc_init_dev(struct inet6_dev *idev)
 {
 	write_lock_bh(&idev->lock);
-	spin_lock_init(&idev->mc_lock);
+	spin_lock_init(&idev->mc_tomb_lock);
 	idev->mc_gq_running = 0;
 	timer_setup(&idev->mc_gq_timer, mld_gq_timer_expire, 0);
-	idev->mc_tomb = NULL;
+	INIT_LIST_HEAD(&idev->mc_tomb_list);
+	INIT_LIST_HEAD(&idev->mc_list);
 	idev->mc_ifc_count = 0;
 	timer_setup(&idev->mc_ifc_timer, mld_ifc_timer_expire, 0);
 	timer_setup(&idev->mc_dad_timer, mld_dad_timer_expire, 0);
@@ -2594,7 +2597,7 @@ void ipv6_mc_init_dev(struct inet6_dev *idev)
 
 void ipv6_mc_destroy_dev(struct inet6_dev *idev)
 {
-	struct ifmcaddr6 *i;
+	struct ifmcaddr6 *mc, *tmp;
 
 	/* Deactivate timers */
 	ipv6_mc_down(idev);
@@ -2611,12 +2614,11 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
 		__ipv6_dev_mc_dec(idev, &in6addr_linklocal_allrouters);
 
 	write_lock_bh(&idev->lock);
-	while ((i = idev->mc_list) != NULL) {
-		idev->mc_list = i->next;
-
+	list_for_each_entry_safe(mc, tmp, &idev->mc_list, list) {
+		list_del(&mc->list);
 		write_unlock_bh(&idev->lock);
-		ip6_mc_clear_src(i);
-		ma_put(i);
+		ip6_mc_clear_src(mc);
+		mca_put(mc);
 		write_lock_bh(&idev->lock);
 	}
 	write_unlock_bh(&idev->lock);
@@ -2624,14 +2626,14 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
 
 static void ipv6_mc_rejoin_groups(struct inet6_dev *idev)
 {
-	struct ifmcaddr6 *pmc;
+	struct ifmcaddr6 *mc;
 
 	ASSERT_RTNL();
 
 	if (mld_in_v1_mode(idev)) {
 		read_lock_bh(&idev->lock);
-		for (pmc = idev->mc_list; pmc; pmc = pmc->next)
-			igmp6_join_group(pmc);
+		list_for_each_entry(mc, &idev->mc_list, list)
+			igmp6_join_group(mc);
 		read_unlock_bh(&idev->lock);
 	} else
 		mld_send_report(idev, NULL);
@@ -2671,57 +2673,64 @@ struct igmp6_mc_iter_state {
 
 static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
 {
-	struct ifmcaddr6 *im = NULL;
 	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
 	struct net *net = seq_file_net(seq);
+	struct ifmcaddr6 *mc;
 
 	state->idev = NULL;
 	for_each_netdev_rcu(net, state->dev) {
 		struct inet6_dev *idev;
+
 		idev = __in6_dev_get(state->dev);
 		if (!idev)
 			continue;
+
 		read_lock_bh(&idev->lock);
-		im = idev->mc_list;
-		if (im) {
+		list_for_each_entry(mc, &idev->mc_list, list) {
 			state->idev = idev;
-			break;
+			return mc;
 		}
 		read_unlock_bh(&idev->lock);
 	}
-	return im;
+	return NULL;
 }
 
-static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr6 *im)
+static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr6 *mc)
 {
 	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
 
-	im = im->next;
-	while (!im) {
-		if (likely(state->idev))
+	list_for_each_entry_continue(mc, &state->idev->mc_list, list)
+		return mc;
+
+	mc = NULL;
+
+	while (!mc) {
+		if (state->idev)
 			read_unlock_bh(&state->idev->lock);
 
 		state->dev = next_net_device_rcu(state->dev);
 		if (!state->dev) {
 			state->idev = NULL;
-			break;
+			return NULL;
 		}
 		state->idev = __in6_dev_get(state->dev);
 		if (!state->idev)
 			continue;
 		read_lock_bh(&state->idev->lock);
-		im = state->idev->mc_list;
+		mc = list_first_entry_or_null(&state->idev->mc_list,
+					      struct ifmcaddr6, list);
 	}
-	return im;
+	return mc;
 }
 
 static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos)
 {
-	struct ifmcaddr6 *im = igmp6_mc_get_first(seq);
-	if (im)
-		while (pos && (im = igmp6_mc_get_next(seq, im)) != NULL)
+	struct ifmcaddr6 *mc = igmp6_mc_get_first(seq);
+
+	if (mc)
+		while (pos && (mc = igmp6_mc_get_next(seq, mc)) != NULL)
 			--pos;
-	return pos ? NULL : im;
+	return pos ? NULL : mc;
 }
 
 static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -2733,10 +2742,10 @@ static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos)
 
 static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-	struct ifmcaddr6 *im = igmp6_mc_get_next(seq, v);
+	struct ifmcaddr6 *mc = igmp6_mc_get_next(seq, v);
 
 	++*pos;
-	return im;
+	return mc;
 }
 
 static void igmp6_mc_seq_stop(struct seq_file *seq, void *v)
@@ -2754,16 +2763,16 @@ static void igmp6_mc_seq_stop(struct seq_file *seq, void *v)
 
 static int igmp6_mc_seq_show(struct seq_file *seq, void *v)
 {
-	struct ifmcaddr6 *im = (struct ifmcaddr6 *)v;
+	struct ifmcaddr6 *mc = (struct ifmcaddr6 *)v;
 	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
 
 	seq_printf(seq,
 		   "%-4d %-15s %pi6 %5d %08X %ld\n",
 		   state->dev->ifindex, state->dev->name,
-		   &im->mca_addr,
-		   im->mca_users, im->mca_flags,
-		   (im->mca_flags&MAF_TIMER_RUNNING) ?
-		   jiffies_to_clock_t(im->mca_timer.expires-jiffies) : 0);
+		   &mc->mca_addr,
+		   mc->mca_users, mc->mca_flags,
+		   (mc->mca_flags & MAF_TIMER_RUNNING) ?
+		   jiffies_to_clock_t(mc->mca_timer.expires - jiffies) : 0);
 	return 0;
 }
 
@@ -2778,51 +2787,61 @@ struct igmp6_mcf_iter_state {
 	struct seq_net_private p;
 	struct net_device *dev;
 	struct inet6_dev *idev;
-	struct ifmcaddr6 *im;
+	struct ifmcaddr6 *mc;
 };
 
 #define igmp6_mcf_seq_private(seq)	((struct igmp6_mcf_iter_state *)(seq)->private)
 
 static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
 {
-	struct ip6_sf_list *psf = NULL;
-	struct ifmcaddr6 *im = NULL;
 	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
 	struct net *net = seq_file_net(seq);
+	struct ip6_sf_list *psf = NULL;
+	struct ifmcaddr6 *mc = NULL;
 
 	state->idev = NULL;
-	state->im = NULL;
+	state->mc = NULL;
 	for_each_netdev_rcu(net, state->dev) {
 		struct inet6_dev *idev;
+
 		idev = __in6_dev_get(state->dev);
 		if (unlikely(idev == NULL))
 			continue;
 		read_lock_bh(&idev->lock);
-		im = idev->mc_list;
-		if (likely(im)) {
-			spin_lock_bh(&im->mca_lock);
-			psf = im->mca_sources;
+		mc = list_first_entry_or_null(&idev->mc_list,
+					      struct ifmcaddr6, list);
+		if (likely(mc)) {
+			spin_lock_bh(&mc->mca_lock);
+			psf = mc->mca_sources;
 			if (likely(psf)) {
-				state->im = im;
+				state->mc = mc;
 				state->idev = idev;
 				break;
 			}
-			spin_unlock_bh(&im->mca_lock);
+			spin_unlock_bh(&mc->mca_lock);
 		}
 		read_unlock_bh(&idev->lock);
 	}
 	return psf;
 }
 
-static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_sf_list *psf)
+static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq,
+					      struct ip6_sf_list *psf)
 {
 	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
 
 	psf = psf->sf_next;
 	while (!psf) {
-		spin_unlock_bh(&state->im->mca_lock);
-		state->im = state->im->next;
-		while (!state->im) {
+		spin_unlock_bh(&state->mc->mca_lock);
+		list_for_each_entry_continue(state->mc, &state->idev->mc_list, list) {
+			spin_lock_bh(&state->mc->mca_lock);
+			psf = state->mc->mca_sources;
+			goto out;
+		}
+
+		state->mc = NULL;
+
+		while (!state->mc) {
 			if (likely(state->idev))
 				read_unlock_bh(&state->idev->lock);
 
@@ -2835,12 +2854,13 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s
 			if (!state->idev)
 				continue;
 			read_lock_bh(&state->idev->lock);
-			state->im = state->idev->mc_list;
+			state->mc = list_first_entry_or_null(&state->idev->mc_list,
+							     struct ifmcaddr6, list);
 		}
-		if (!state->im)
+		if (!state->mc)
 			break;
-		spin_lock_bh(&state->im->mca_lock);
-		psf = state->im->mca_sources;
+		spin_lock_bh(&state->mc->mca_lock);
+		psf = state->mc->mca_sources;
 	}
 out:
 	return psf;
@@ -2849,6 +2869,7 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s
 static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos)
 {
 	struct ip6_sf_list *psf = igmp6_mcf_get_first(seq);
+
 	if (psf)
 		while (pos && (psf = igmp6_mcf_get_next(seq, psf)) != NULL)
 			--pos;
@@ -2865,6 +2886,7 @@ static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos)
 static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct ip6_sf_list *psf;
+
 	if (v == SEQ_START_TOKEN)
 		psf = igmp6_mcf_get_first(seq);
 	else
@@ -2877,9 +2899,10 @@ static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v)
 	__releases(RCU)
 {
 	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
-	if (likely(state->im)) {
-		spin_unlock_bh(&state->im->mca_lock);
-		state->im = NULL;
+
+	if (likely(state->mc)) {
+		spin_unlock_bh(&state->mc->mca_lock);
+		state->mc = NULL;
 	}
 	if (likely(state->idev)) {
 		read_unlock_bh(&state->idev->lock);
@@ -2900,7 +2923,7 @@ static int igmp6_mcf_seq_show(struct seq_file *seq, void *v)
 		seq_printf(seq,
 			   "%3d %6.6s %pi6 %pi6 %6lu %6lu\n",
 			   state->dev->ifindex, state->dev->name,
-			   &state->im->mca_addr,
+			   &state->mc->mca_addr,
 			   &psf->sf_addr,
 			   psf->sf_count[MCAST_INCLUDE],
 			   psf->sf_count[MCAST_EXCLUDE]);
-- 
2.17.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help