]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/igmp.c
net: use the macros defined for the members of flowi
[net-next-2.6.git] / net / ipv4 / igmp.c
index 2a4bb76f2132957da25326ce98653b249d9ccaaf..afb1e82a59f9acea63d1037f0ca5414cb8df58bf 100644 (file)
@@ -149,21 +149,37 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc);
 static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
                         int sfcount, __be32 *psfsrc, int delta);
 
+
+static void ip_mc_list_reclaim(struct rcu_head *head)
+{
+       kfree(container_of(head, struct ip_mc_list, rcu));
+}
+
 static void ip_ma_put(struct ip_mc_list *im)
 {
        if (atomic_dec_and_test(&im->refcnt)) {
                in_dev_put(im->interface);
-               kfree(im);
+               call_rcu(&im->rcu, ip_mc_list_reclaim);
        }
 }
 
+#define for_each_pmc_rcu(in_dev, pmc)                          \
+       for (pmc = rcu_dereference(in_dev->mc_list);            \
+            pmc != NULL;                                       \
+            pmc = rcu_dereference(pmc->next_rcu))
+
+#define for_each_pmc_rtnl(in_dev, pmc)                         \
+       for (pmc = rtnl_dereference(in_dev->mc_list);           \
+            pmc != NULL;                                       \
+            pmc = rtnl_dereference(pmc->next_rcu))
+
 #ifdef CONFIG_IP_MULTICAST
 
 /*
  *     Timer management
  */
 
-static __inline__ void igmp_stop_timer(struct ip_mc_list *im)
+static void igmp_stop_timer(struct ip_mc_list *im)
 {
        spin_lock_bh(&im->lock);
        if (del_timer(&im->timer))
@@ -298,8 +314,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
 
        {
                struct flowi fl = { .oif = dev->ifindex,
-                                   .nl_u = { .ip4_u = {
-                                   .daddr = IGMPV3_ALL_MCR } },
+                                   .fl4_dst = IGMPV3_ALL_MCR,
                                    .proto = IPPROTO_IGMP };
                if (ip_route_output_key(net, &rt, &fl)) {
                        kfree_skb(skb);
@@ -502,8 +517,8 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc)
        int type;
 
        if (!pmc) {
-               read_lock(&in_dev->mc_list_lock);
-               for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
+               rcu_read_lock();
+               for_each_pmc_rcu(in_dev, pmc) {
                        if (pmc->multiaddr == IGMP_ALL_HOSTS)
                                continue;
                        spin_lock_bh(&pmc->lock);
@@ -514,7 +529,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc)
                        skb = add_grec(skb, pmc, type, 0, 0);
                        spin_unlock_bh(&pmc->lock);
                }
-               read_unlock(&in_dev->mc_list_lock);
+               rcu_read_unlock();
        } else {
                spin_lock_bh(&pmc->lock);
                if (pmc->sfcount[MCAST_EXCLUDE])
@@ -556,7 +571,7 @@ static void igmpv3_send_cr(struct in_device *in_dev)
        struct sk_buff *skb = NULL;
        int type, dtype;
 
-       read_lock(&in_dev->mc_list_lock);
+       rcu_read_lock();
        spin_lock_bh(&in_dev->mc_tomb_lock);
 
        /* deleted MCA's */
@@ -593,7 +608,7 @@ static void igmpv3_send_cr(struct in_device *in_dev)
        spin_unlock_bh(&in_dev->mc_tomb_lock);
 
        /* change recs */
-       for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
+       for_each_pmc_rcu(in_dev, pmc) {
                spin_lock_bh(&pmc->lock);
                if (pmc->sfcount[MCAST_EXCLUDE]) {
                        type = IGMPV3_BLOCK_OLD_SOURCES;
@@ -616,7 +631,7 @@ static void igmpv3_send_cr(struct in_device *in_dev)
                }
                spin_unlock_bh(&pmc->lock);
        }
-       read_unlock(&in_dev->mc_list_lock);
+       rcu_read_unlock();
 
        if (!skb)
                return;
@@ -644,7 +659,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
 
        {
                struct flowi fl = { .oif = dev->ifindex,
-                                   .nl_u = { .ip4_u = { .daddr = dst } },
+                                   .fl4_dst = dst,
                                    .proto = IPPROTO_IGMP };
                if (ip_route_output_key(net, &rt, &fl))
                        return -1;
@@ -813,14 +828,14 @@ static void igmp_heard_report(struct in_device *in_dev, __be32 group)
        if (group == IGMP_ALL_HOSTS)
                return;
 
-       read_lock(&in_dev->mc_list_lock);
-       for (im=in_dev->mc_list; im!=NULL; im=im->next) {
+       rcu_read_lock();
+       for_each_pmc_rcu(in_dev, im) {
                if (im->multiaddr == group) {
                        igmp_stop_timer(im);
                        break;
                }
        }
-       read_unlock(&in_dev->mc_list_lock);
+       rcu_read_unlock();
 }
 
 static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
@@ -906,8 +921,8 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
         * - Use the igmp->igmp_code field as the maximum
         *   delay possible
         */
-       read_lock(&in_dev->mc_list_lock);
-       for (im=in_dev->mc_list; im!=NULL; im=im->next) {
+       rcu_read_lock();
+       for_each_pmc_rcu(in_dev, im) {
                int changed;
 
                if (group && group != im->multiaddr)
@@ -925,7 +940,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
                if (changed)
                        igmp_mod_timer(im, max_delay);
        }
-       read_unlock(&in_dev->mc_list_lock);
+       rcu_read_unlock();
 }
 
 /* called in rcu_read_lock() section */
@@ -961,7 +976,7 @@ int igmp_rcv(struct sk_buff *skb)
        case IGMP_HOST_MEMBERSHIP_REPORT:
        case IGMPV2_HOST_MEMBERSHIP_REPORT:
                /* Is it our report looped back? */
-               if (skb_rtable(skb)->fl.iif == 0)
+               if (rt_is_output_route(skb_rtable(skb)))
                        break;
                /* don't rely on MC router hearing unicast reports */
                if (skb->pkt_type == PACKET_MULTICAST ||
@@ -1110,8 +1125,8 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
                kfree(pmc);
        }
        /* clear dead sources, too */
-       read_lock(&in_dev->mc_list_lock);
-       for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
+       rcu_read_lock();
+       for_each_pmc_rcu(in_dev, pmc) {
                struct ip_sf_list *psf, *psf_next;
 
                spin_lock_bh(&pmc->lock);
@@ -1123,7 +1138,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
                        kfree(psf);
                }
        }
-       read_unlock(&in_dev->mc_list_lock);
+       rcu_read_unlock();
 }
 #endif
 
@@ -1209,7 +1224,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
 
        ASSERT_RTNL();
 
-       for (im=in_dev->mc_list; im; im=im->next) {
+       for_each_pmc_rtnl(in_dev, im) {
                if (im->multiaddr == addr) {
                        im->users++;
                        ip_mc_add_src(in_dev, &addr, MCAST_EXCLUDE, 0, NULL, 0);
@@ -1217,7 +1232,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
                }
        }
 
-       im = kmalloc(sizeof(*im), GFP_KERNEL);
+       im = kzalloc(sizeof(*im), GFP_KERNEL);
        if (!im)
                goto out;
 
@@ -1227,26 +1242,18 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
        im->multiaddr = addr;
        /* initial mode is (EX, empty) */
        im->sfmode = MCAST_EXCLUDE;
-       im->sfcount[MCAST_INCLUDE] = 0;
        im->sfcount[MCAST_EXCLUDE] = 1;
-       im->sources = NULL;
-       im->tomb = NULL;
-       im->crcount = 0;
        atomic_set(&im->refcnt, 1);
        spin_lock_init(&im->lock);
 #ifdef CONFIG_IP_MULTICAST
-       im->tm_running = 0;
        setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im);
        im->unsolicit_count = IGMP_Unsolicited_Report_Count;
-       im->reporter = 0;
-       im->gsquery = 0;
 #endif
-       im->loaded = 0;
-       write_lock_bh(&in_dev->mc_list_lock);
-       im->next = in_dev->mc_list;
-       in_dev->mc_list = im;
+
+       im->next_rcu = in_dev->mc_list;
        in_dev->mc_count++;
-       write_unlock_bh(&in_dev->mc_list_lock);
+       rcu_assign_pointer(in_dev->mc_list, im);
+
 #ifdef CONFIG_IP_MULTICAST
        igmpv3_del_delrec(in_dev, im->multiaddr);
 #endif
@@ -1269,14 +1276,14 @@ void ip_mc_rejoin_group(struct ip_mc_list *im)
        if (im->multiaddr == IGMP_ALL_HOSTS)
                return;
 
-       if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
-               igmp_mod_timer(im, IGMP_Initial_Report_Delay);
-               return;
-       }
-       /* else, v3 */
-       im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-               IGMP_Unsolicited_Report_Count;
-       igmp_ifc_event(in_dev);
+       /* a failover is happening and switches
+        * must be notified immediately */
+       if (IGMP_V1_SEEN(in_dev))
+               igmp_send_report(in_dev, im, IGMP_HOST_MEMBERSHIP_REPORT);
+       else if (IGMP_V2_SEEN(in_dev))
+               igmp_send_report(in_dev, im, IGMPV2_HOST_MEMBERSHIP_REPORT);
+       else
+               igmp_send_report(in_dev, im, IGMPV3_HOST_MEMBERSHIP_REPORT);
 #endif
 }
 EXPORT_SYMBOL(ip_mc_rejoin_group);
@@ -1287,17 +1294,18 @@ EXPORT_SYMBOL(ip_mc_rejoin_group);
 
 void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
 {
-       struct ip_mc_list *i, **ip;
+       struct ip_mc_list *i;
+       struct ip_mc_list __rcu **ip;
 
        ASSERT_RTNL();
 
-       for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
+       for (ip = &in_dev->mc_list;
+            (i = rtnl_dereference(*ip)) != NULL;
+            ip = &i->next_rcu) {
                if (i->multiaddr == addr) {
                        if (--i->users == 0) {
-                               write_lock_bh(&in_dev->mc_list_lock);
-                               *ip = i->next;
+                               *ip = i->next_rcu;
                                in_dev->mc_count--;
-                               write_unlock_bh(&in_dev->mc_list_lock);
                                igmp_group_dropped(i);
 
                                if (!in_dev->dead)
@@ -1316,34 +1324,34 @@ EXPORT_SYMBOL(ip_mc_dec_group);
 
 void ip_mc_unmap(struct in_device *in_dev)
 {
-       struct ip_mc_list *i;
+       struct ip_mc_list *pmc;
 
        ASSERT_RTNL();
 
-       for (i = in_dev->mc_list; i; i = i->next)
-               igmp_group_dropped(i);
+       for_each_pmc_rtnl(in_dev, pmc)
+               igmp_group_dropped(pmc);
 }
 
 void ip_mc_remap(struct in_device *in_dev)
 {
-       struct ip_mc_list *i;
+       struct ip_mc_list *pmc;
 
        ASSERT_RTNL();
 
-       for (i = in_dev->mc_list; i; i = i->next)
-               igmp_group_added(i);
+       for_each_pmc_rtnl(in_dev, pmc)
+               igmp_group_added(pmc);
 }
 
 /* Device going down */
 
 void ip_mc_down(struct in_device *in_dev)
 {
-       struct ip_mc_list *i;
+       struct ip_mc_list *pmc;
 
        ASSERT_RTNL();
 
-       for (i=in_dev->mc_list; i; i=i->next)
-               igmp_group_dropped(i);
+       for_each_pmc_rtnl(in_dev, pmc)
+               igmp_group_dropped(pmc);
 
 #ifdef CONFIG_IP_MULTICAST
        in_dev->mr_ifc_count = 0;
@@ -1374,7 +1382,6 @@ void ip_mc_init_dev(struct in_device *in_dev)
        in_dev->mr_qrv = IGMP_Unsolicited_Report_Count;
 #endif
 
-       rwlock_init(&in_dev->mc_list_lock);
        spin_lock_init(&in_dev->mc_tomb_lock);
 }
 
@@ -1382,14 +1389,14 @@ void ip_mc_init_dev(struct in_device *in_dev)
 
 void ip_mc_up(struct in_device *in_dev)
 {
-       struct ip_mc_list *i;
+       struct ip_mc_list *pmc;
 
        ASSERT_RTNL();
 
        ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
 
-       for (i=in_dev->mc_list; i; i=i->next)
-               igmp_group_added(i);
+       for_each_pmc_rtnl(in_dev, pmc)
+               igmp_group_added(pmc);
 }
 
 /*
@@ -1405,38 +1412,31 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
        /* Deactivate timers */
        ip_mc_down(in_dev);
 
-       write_lock_bh(&in_dev->mc_list_lock);
-       while ((i = in_dev->mc_list) != NULL) {
-               in_dev->mc_list = i->next;
+       while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) {
+               in_dev->mc_list = i->next_rcu;
                in_dev->mc_count--;
-               write_unlock_bh(&in_dev->mc_list_lock);
+
                igmp_group_dropped(i);
                ip_ma_put(i);
-
-               write_lock_bh(&in_dev->mc_list_lock);
        }
-       write_unlock_bh(&in_dev->mc_list_lock);
 }
 
+/* RTNL is locked */
 static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
 {
-       struct flowi fl = { .nl_u = { .ip4_u =
-                                     { .daddr = imr->imr_multiaddr.s_addr } } };
+       struct flowi fl = { .fl4_dst = imr->imr_multiaddr.s_addr };
        struct rtable *rt;
        struct net_device *dev = NULL;
        struct in_device *idev = NULL;
 
        if (imr->imr_ifindex) {
                idev = inetdev_by_index(net, imr->imr_ifindex);
-               if (idev)
-                       __in_dev_put(idev);
                return idev;
        }
        if (imr->imr_address.s_addr) {
-               dev = ip_dev_find(net, imr->imr_address.s_addr);
+               dev = __ip_dev_find(net, imr->imr_address.s_addr, false);
                if (!dev)
                        return NULL;
-               dev_put(dev);
        }
 
        if (!dev && !ip_route_output_key(net, &rt, &fl)) {
@@ -1515,18 +1515,18 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
 
        if (!in_dev)
                return -ENODEV;
-       read_lock(&in_dev->mc_list_lock);
-       for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
+       rcu_read_lock();
+       for_each_pmc_rcu(in_dev, pmc) {
                if (*pmca == pmc->multiaddr)
                        break;
        }
        if (!pmc) {
                /* MCA not found?? bug */
-               read_unlock(&in_dev->mc_list_lock);
+               rcu_read_unlock();
                return -ESRCH;
        }
        spin_lock_bh(&pmc->lock);
-       read_unlock(&in_dev->mc_list_lock);
+       rcu_read_unlock();
 #ifdef CONFIG_IP_MULTICAST
        sf_markstate(pmc);
 #endif
@@ -1687,18 +1687,18 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
 
        if (!in_dev)
                return -ENODEV;
-       read_lock(&in_dev->mc_list_lock);
-       for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
+       rcu_read_lock();
+       for_each_pmc_rcu(in_dev, pmc) {
                if (*pmca == pmc->multiaddr)
                        break;
        }
        if (!pmc) {
                /* MCA not found?? bug */
-               read_unlock(&in_dev->mc_list_lock);
+               rcu_read_unlock();
                return -ESRCH;
        }
        spin_lock_bh(&pmc->lock);
-       read_unlock(&in_dev->mc_list_lock);
+       rcu_read_unlock();
 
 #ifdef CONFIG_IP_MULTICAST
        sf_markstate(pmc);
@@ -1795,7 +1795,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
 
        err = -EADDRINUSE;
        ifindex = imr->imr_ifindex;
-       for (i = inet->mc_list; i; i = i->next) {
+       for_each_pmc_rtnl(inet, i) {
                if (i->multi.imr_multiaddr.s_addr == addr &&
                    i->multi.imr_ifindex == ifindex)
                        goto done;
@@ -1809,7 +1809,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
                goto done;
 
        memcpy(&iml->multi, imr, sizeof(*imr));
-       iml->next = inet->mc_list;
+       iml->next_rcu = inet->mc_list;
        iml->sflist = NULL;
        iml->sfmode = MCAST_EXCLUDE;
        rcu_assign_pointer(inet->mc_list, iml);
@@ -1823,17 +1823,14 @@ EXPORT_SYMBOL(ip_mc_join_group);
 
 static void ip_sf_socklist_reclaim(struct rcu_head *rp)
 {
-       struct ip_sf_socklist *psf;
-
-       psf = container_of(rp, struct ip_sf_socklist, rcu);
+       kfree(container_of(rp, struct ip_sf_socklist, rcu));
        /* sk_omem_alloc should have been decreased by the caller*/
-       kfree(psf);
 }
 
 static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
                           struct in_device *in_dev)
 {
-       struct ip_sf_socklist *psf = iml->sflist;
+       struct ip_sf_socklist *psf = rtnl_dereference(iml->sflist);
        int err;
 
        if (psf == NULL) {
@@ -1853,11 +1850,8 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
 
 static void ip_mc_socklist_reclaim(struct rcu_head *rp)
 {
-       struct ip_mc_socklist *iml;
-
-       iml = container_of(rp, struct ip_mc_socklist, rcu);
+       kfree(container_of(rp, struct ip_mc_socklist, rcu));
        /* sk_omem_alloc should have been decreased by the caller*/
-       kfree(iml);
 }
 
 
@@ -1868,7 +1862,8 @@ static void ip_mc_socklist_reclaim(struct rcu_head *rp)
 int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
 {
        struct inet_sock *inet = inet_sk(sk);
-       struct ip_mc_socklist *iml, **imlp;
+       struct ip_mc_socklist *iml;
+       struct ip_mc_socklist __rcu **imlp;
        struct in_device *in_dev;
        struct net *net = sock_net(sk);
        __be32 group = imr->imr_multiaddr.s_addr;
@@ -1878,7 +1873,9 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
        rtnl_lock();
        in_dev = ip_mc_find_dev(net, imr);
        ifindex = imr->imr_ifindex;
-       for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {
+       for (imlp = &inet->mc_list;
+            (iml = rtnl_dereference(*imlp)) != NULL;
+            imlp = &iml->next_rcu) {
                if (iml->multi.imr_multiaddr.s_addr != group)
                        continue;
                if (ifindex) {
@@ -1890,7 +1887,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
 
                (void) ip_mc_leave_src(sk, iml, in_dev);
 
-               rcu_assign_pointer(*imlp, iml->next);
+               *imlp = iml->next_rcu;
 
                if (in_dev)
                        ip_mc_dec_group(in_dev, group);
@@ -1936,7 +1933,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
        }
        err = -EADDRNOTAVAIL;
 
-       for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
+       for_each_pmc_rtnl(inet, pmc) {
                if ((pmc->multi.imr_multiaddr.s_addr ==
                     imr.imr_multiaddr.s_addr) &&
                    (pmc->multi.imr_ifindex == imr.imr_ifindex))
@@ -1960,7 +1957,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
                pmc->sfmode = omode;
        }
 
-       psl = pmc->sflist;
+       psl = rtnl_dereference(pmc->sflist);
        if (!add) {
                if (!psl)
                        goto done;      /* err = -EADDRNOTAVAIL */
@@ -2079,7 +2076,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
                goto done;
        }
 
-       for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
+       for_each_pmc_rtnl(inet, pmc) {
                if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&
                    pmc->multi.imr_ifindex == imr.imr_ifindex)
                        break;
@@ -2109,7 +2106,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
                (void) ip_mc_add_src(in_dev, &msf->imsf_multiaddr,
                                     msf->imsf_fmode, 0, NULL, 0);
        }
-       psl = pmc->sflist;
+       psl = rtnl_dereference(pmc->sflist);
        if (psl) {
                (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
                        psl->sl_count, psl->sl_addr, 0);
@@ -2157,7 +2154,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
        }
        err = -EADDRNOTAVAIL;
 
-       for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
+       for_each_pmc_rtnl(inet, pmc) {
                if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&
                    pmc->multi.imr_ifindex == imr.imr_ifindex)
                        break;
@@ -2165,7 +2162,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
        if (!pmc)               /* must have a prior join */
                goto done;
        msf->imsf_fmode = pmc->sfmode;
-       psl = pmc->sflist;
+       psl = rtnl_dereference(pmc->sflist);
        rtnl_unlock();
        if (!psl) {
                len = 0;
@@ -2210,7 +2207,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
 
        err = -EADDRNOTAVAIL;
 
-       for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
+       for_each_pmc_rtnl(inet, pmc) {
                if (pmc->multi.imr_multiaddr.s_addr == addr &&
                    pmc->multi.imr_ifindex == gsf->gf_interface)
                        break;
@@ -2218,7 +2215,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
        if (!pmc)               /* must have a prior join */
                goto done;
        gsf->gf_fmode = pmc->sfmode;
-       psl = pmc->sflist;
+       psl = rtnl_dereference(pmc->sflist);
        rtnl_unlock();
        count = psl ? psl->sl_count : 0;
        copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
@@ -2259,7 +2256,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif)
                goto out;
 
        rcu_read_lock();
-       for (pmc=rcu_dereference(inet->mc_list); pmc; pmc=rcu_dereference(pmc->next)) {
+       for_each_pmc_rcu(inet, pmc) {
                if (pmc->multi.imr_multiaddr.s_addr == loc_addr &&
                    pmc->multi.imr_ifindex == dif)
                        break;
@@ -2267,7 +2264,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif)
        ret = inet->mc_all;
        if (!pmc)
                goto unlock;
-       psl = pmc->sflist;
+       psl = rcu_dereference(pmc->sflist);
        ret = (pmc->sfmode == MCAST_EXCLUDE);
        if (!psl)
                goto unlock;
@@ -2302,16 +2299,14 @@ void ip_mc_drop_socket(struct sock *sk)
                return;
 
        rtnl_lock();
-       while ((iml = inet->mc_list) != NULL) {
+       while ((iml = rtnl_dereference(inet->mc_list)) != NULL) {
                struct in_device *in_dev;
-               rcu_assign_pointer(inet->mc_list, iml->next);
 
+               inet->mc_list = iml->next_rcu;
                in_dev = inetdev_by_index(net, iml->multi.imr_ifindex);
                (void) ip_mc_leave_src(sk, iml, in_dev);
-               if (in_dev != NULL) {
+               if (in_dev != NULL)
                        ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
-                       in_dev_put(in_dev);
-               }
                /* decrease mem now to avoid the memleak warning */
                atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
                call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
@@ -2325,8 +2320,8 @@ int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 p
        struct ip_sf_list *psf;
        int rv = 0;
 
-       read_lock(&in_dev->mc_list_lock);
-       for (im=in_dev->mc_list; im; im=im->next) {
+       rcu_read_lock();
+       for_each_pmc_rcu(in_dev, im) {
                if (im->multiaddr == mc_addr)
                        break;
        }
@@ -2347,7 +2342,7 @@ int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 p
                } else
                        rv = 1; /* unspecified source; tentatively allow */
        }
-       read_unlock(&in_dev->mc_list_lock);
+       rcu_read_unlock();
        return rv;
 }
 
@@ -2373,13 +2368,11 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
                in_dev = __in_dev_get_rcu(state->dev);
                if (!in_dev)
                        continue;
-               read_lock(&in_dev->mc_list_lock);
-               im = in_dev->mc_list;
+               im = rcu_dereference(in_dev->mc_list);
                if (im) {
                        state->in_dev = in_dev;
                        break;
                }
-               read_unlock(&in_dev->mc_list_lock);
        }
        return im;
 }
@@ -2387,11 +2380,9 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
 static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im)
 {
        struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
-       im = im->next;
-       while (!im) {
-               if (likely(state->in_dev != NULL))
-                       read_unlock(&state->in_dev->mc_list_lock);
 
+       im = rcu_dereference(im->next_rcu);
+       while (!im) {
                state->dev = next_net_device_rcu(state->dev);
                if (!state->dev) {
                        state->in_dev = NULL;
@@ -2400,8 +2391,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li
                state->in_dev = __in_dev_get_rcu(state->dev);
                if (!state->in_dev)
                        continue;
-               read_lock(&state->in_dev->mc_list_lock);
-               im = state->in_dev->mc_list;
+               im = rcu_dereference(state->in_dev->mc_list);
        }
        return im;
 }
@@ -2437,10 +2427,8 @@ static void igmp_mc_seq_stop(struct seq_file *seq, void *v)
        __releases(rcu)
 {
        struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
-       if (likely(state->in_dev != NULL)) {
-               read_unlock(&state->in_dev->mc_list_lock);
-               state->in_dev = NULL;
-       }
+
+       state->in_dev = NULL;
        state->dev = NULL;
        rcu_read_unlock();
 }
@@ -2462,7 +2450,7 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
                querier = "NONE";
 #endif
 
-               if (state->in_dev->mc_list == im) {
+               if (rcu_dereference(state->in_dev->mc_list) == im) {
                        seq_printf(seq, "%d\t%-10s: %5d %7s\n",
                                   state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier);
                }
@@ -2521,8 +2509,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
                idev = __in_dev_get_rcu(state->dev);
                if (unlikely(idev == NULL))
                        continue;
-               read_lock(&idev->mc_list_lock);
-               im = idev->mc_list;
+               im = rcu_dereference(idev->mc_list);
                if (likely(im != NULL)) {
                        spin_lock_bh(&im->lock);
                        psf = im->sources;
@@ -2533,7 +2520,6 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
                        }
                        spin_unlock_bh(&im->lock);
                }
-               read_unlock(&idev->mc_list_lock);
        }
        return psf;
 }
@@ -2547,9 +2533,6 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l
                spin_unlock_bh(&state->im->lock);
                state->im = state->im->next;
                while (!state->im) {
-                       if (likely(state->idev != NULL))
-                               read_unlock(&state->idev->mc_list_lock);
-
                        state->dev = next_net_device_rcu(state->dev);
                        if (!state->dev) {
                                state->idev = NULL;
@@ -2558,8 +2541,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l
                        state->idev = __in_dev_get_rcu(state->dev);
                        if (!state->idev)
                                continue;
-                       read_lock(&state->idev->mc_list_lock);
-                       state->im = state->idev->mc_list;
+                       state->im = rcu_dereference(state->idev->mc_list);
                }
                if (!state->im)
                        break;
@@ -2605,10 +2587,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v)
                spin_unlock_bh(&state->im->lock);
                state->im = NULL;
        }
-       if (likely(state->idev != NULL)) {
-               read_unlock(&state->idev->mc_list_lock);
-               state->idev = NULL;
-       }
+       state->idev = NULL;
        state->dev = NULL;
        rcu_read_unlock();
 }