nfsd4: consistent session flag setting
[safe/jmp/linux-2.6] / net / ipv6 / mcast.c
index a1d588d..bcd9719 100644 (file)
@@ -303,20 +303,23 @@ static struct inet6_dev *ip6_mc_find_dev(struct net *net,
                dev = dev_get_by_index(net, ifindex);
 
        if (!dev)
-               return NULL;
+               goto nodev;
        idev = in6_dev_get(dev);
-       if (!idev) {
-               dev_put(dev);
-               return NULL;
-       }
+       if (!idev)
+               goto release;
        read_lock_bh(&idev->lock);
-       if (idev->dead) {
-               read_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
-               dev_put(dev);
-               return NULL;
-       }
+       if (idev->dead)
+               goto unlock_release;
+
        return idev;
+
+unlock_release:
+       read_unlock_bh(&idev->lock);
+       in6_dev_put(idev);
+release:
+       dev_put(dev);
+nodev:
+       return NULL;
 }
 
 void ipv6_sock_mc_close(struct sock *sk)
@@ -790,10 +793,10 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
        }
        spin_unlock_bh(&im->mca_lock);
 
-       write_lock_bh(&idev->mc_lock);
+       spin_lock_bh(&idev->mc_lock);
        pmc->next = idev->mc_tomb;
        idev->mc_tomb = pmc;
-       write_unlock_bh(&idev->mc_lock);
+       spin_unlock_bh(&idev->mc_lock);
 }
 
 static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca)
@@ -801,7 +804,7 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca)
        struct ifmcaddr6 *pmc, *pmc_prev;
        struct ip6_sf_list *psf, *psf_next;
 
-       write_lock_bh(&idev->mc_lock);
+       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))
@@ -814,7 +817,8 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca)
                else
                        idev->mc_tomb = pmc->next;
        }
-       write_unlock_bh(&idev->mc_lock);
+       spin_unlock_bh(&idev->mc_lock);
+
        if (pmc) {
                for (psf=pmc->mca_tomb; psf; psf=psf_next) {
                        psf_next = psf->sf_next;
@@ -829,10 +833,10 @@ static void mld_clear_delrec(struct inet6_dev *idev)
 {
        struct ifmcaddr6 *pmc, *nextpmc;
 
-       write_lock_bh(&idev->mc_lock);
+       spin_lock_bh(&idev->mc_lock);
        pmc = idev->mc_tomb;
        idev->mc_tomb = NULL;
-       write_unlock_bh(&idev->mc_lock);
+       spin_unlock_bh(&idev->mc_lock);
 
        for (; pmc; pmc = nextpmc) {
                nextpmc = pmc->next;
@@ -1445,8 +1449,10 @@ static void mld_sendpack(struct sk_buff *skb)
        struct net *net = dev_net(skb->dev);
        int err;
        struct flowi fl;
+       struct dst_entry *dst;
+
+       IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
 
-       IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS);
        payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
        mldlen = skb->tail - skb->transport_header;
        pip6->payload_len = htons(payload_len);
@@ -1455,9 +1461,9 @@ static void mld_sendpack(struct sk_buff *skb)
                IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb),
                                             mldlen, 0));
 
-       skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
+       dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
 
-       if (!skb->dst) {
+       if (!dst) {
                err = -ENOMEM;
                goto err_out;
        }
@@ -1466,19 +1472,22 @@ static void mld_sendpack(struct sk_buff *skb)
                         &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
                         skb->dev->ifindex);
 
-       err = xfrm_lookup(&skb->dst, &fl, NULL, 0);
+       err = xfrm_lookup(net, &dst, &fl, NULL, 0);
+       skb_dst_set(skb, dst);
        if (err)
                goto err_out;
 
+       payload_len = skb->len;
+
        err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
                      dst_output);
 out:
        if (!err) {
-               ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT);
-               ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
-               IP6_INC_STATS_BH(idev, IPSTATS_MIB_OUTMCASTPKTS);
+               ICMP6MSGOUT_INC_STATS_BH(net, idev, ICMPV6_MLD2_REPORT);
+               ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
+               IP6_UPD_PO_STATS_BH(net, idev, IPSTATS_MIB_OUTMCAST, payload_len);
        } else
-               IP6_INC_STATS_BH(idev, IPSTATS_MIB_OUTDISCARDS);
+               IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS);
 
        if (likely(idev != NULL))
                in6_dev_put(idev);
@@ -1688,7 +1697,7 @@ static void mld_send_cr(struct inet6_dev *idev)
        int type, dtype;
 
        read_lock_bh(&idev->lock);
-       write_lock_bh(&idev->mc_lock);
+       spin_lock(&idev->mc_lock);
 
        /* deleted MCA's */
        pmc_prev = NULL;
@@ -1722,7 +1731,7 @@ static void mld_send_cr(struct inet6_dev *idev)
                } else
                        pmc_prev = pmc;
        }
-       write_unlock_bh(&idev->mc_lock);
+       spin_unlock(&idev->mc_lock);
 
        /* change recs */
        for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
@@ -1769,11 +1778,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                     IPV6_TLV_ROUTERALERT, 2, 0, 0,
                     IPV6_TLV_PADN, 0 };
        struct flowi fl;
+       struct dst_entry *dst;
 
-       rcu_read_lock();
-       IP6_INC_STATS(net, __in6_dev_get(dev),
-                     IPSTATS_MIB_OUTREQUESTS);
-       rcu_read_unlock();
        if (type == ICMPV6_MGM_REDUCTION)
                snd_addr = &in6addr_linklocal_allrouters;
        else
@@ -1783,6 +1789,11 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
        payload_len = len + sizeof(ra);
        full_len = sizeof(struct ipv6hdr) + payload_len;
 
+       rcu_read_lock();
+       IP6_UPD_PO_STATS(net, __in6_dev_get(dev),
+                     IPSTATS_MIB_OUT, full_len);
+       rcu_read_unlock();
+
        skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + full_len, 1, &err);
 
        if (skb == NULL) {
@@ -1817,12 +1828,12 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 
        hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len,
                                           IPPROTO_ICMPV6,
-                                          csum_partial((__u8 *) hdr, len, 0));
+                                          csum_partial(hdr, len, 0));
 
        idev = in6_dev_get(skb->dev);
 
-       skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
-       if (!skb->dst) {
+       dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
+       if (!dst) {
                err = -ENOMEM;
                goto err_out;
        }
@@ -1831,17 +1842,18 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                         &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
                         skb->dev->ifindex);
 
-       err = xfrm_lookup(&skb->dst, &fl, NULL, 0);
+       err = xfrm_lookup(net, &dst, &fl, NULL, 0);
        if (err)
                goto err_out;
 
+       skb_dst_set(skb, dst);
        err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
                      dst_output);
 out:
        if (!err) {
-               ICMP6MSGOUT_INC_STATS(idev, type);
-               ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
-               IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTMCASTPKTS);
+               ICMP6MSGOUT_INC_STATS(net, idev, type);
+               ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
+               IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, full_len);
        } else
                IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
 
@@ -2096,7 +2108,6 @@ static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
                for (j=0; j<i; j++)
                        (void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
        } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
-               struct inet6_dev *idev = pmc->idev;
                struct ip6_sf_list *psf;
 
                /* filter mode change */
@@ -2239,6 +2250,25 @@ static void igmp6_timer_handler(unsigned long data)
        ma_put(ma);
 }
 
+/* Device changing type */
+
+void ipv6_mc_unmap(struct inet6_dev *idev)
+{
+       struct ifmcaddr6 *i;
+
+       /* 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);
+       read_unlock_bh(&idev->lock);
+}
+
+void ipv6_mc_remap(struct inet6_dev *idev)
+{
+       ipv6_mc_up(idev);
+}
+
 /* Device going down */
 
 void ipv6_mc_down(struct inet6_dev *idev)
@@ -2282,7 +2312,7 @@ void ipv6_mc_up(struct inet6_dev *idev)
 void ipv6_mc_init_dev(struct inet6_dev *idev)
 {
        write_lock_bh(&idev->lock);
-       rwlock_init(&idev->mc_lock);
+       spin_lock_init(&idev->mc_lock);
        idev->mc_gq_running = 0;
        setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire,
                        (unsigned long)idev);
@@ -2346,9 +2376,9 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
        struct net *net = seq_file_net(seq);
 
        state->idev = NULL;
-       for_each_netdev(net, state->dev) {
+       for_each_netdev_rcu(net, state->dev) {
                struct inet6_dev *idev;
-               idev = in6_dev_get(state->dev);
+               idev = __in6_dev_get(state->dev);
                if (!idev)
                        continue;
                read_lock_bh(&idev->lock);
@@ -2358,7 +2388,6 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
                        break;
                }
                read_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
        }
        return im;
 }
@@ -2369,16 +2398,15 @@ static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr
 
        im = im->next;
        while (!im) {
-               if (likely(state->idev != NULL)) {
+               if (likely(state->idev != NULL))
                        read_unlock_bh(&state->idev->lock);
-                       in6_dev_put(state->idev);
-               }
-               state->dev = next_net_device(state->dev);
+
+               state->dev = next_net_device_rcu(state->dev);
                if (!state->dev) {
                        state->idev = NULL;
                        break;
                }
-               state->idev = in6_dev_get(state->dev);
+               state->idev = __in6_dev_get(state->dev);
                if (!state->idev)
                        continue;
                read_lock_bh(&state->idev->lock);
@@ -2397,31 +2425,31 @@ static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(dev_base_lock)
+       __acquires(RCU)
 {
-       read_lock(&dev_base_lock);
+       rcu_read_lock();
        return igmp6_mc_get_idx(seq, *pos);
 }
 
 static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-       struct ifmcaddr6 *im;
-       im = igmp6_mc_get_next(seq, v);
+       struct ifmcaddr6 *im = igmp6_mc_get_next(seq, v);
+
        ++*pos;
        return im;
 }
 
 static void igmp6_mc_seq_stop(struct seq_file *seq, void *v)
-       __releases(dev_base_lock)
+       __releases(RCU)
 {
        struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
+
        if (likely(state->idev != NULL)) {
                read_unlock_bh(&state->idev->lock);
-               in6_dev_put(state->idev);
                state->idev = NULL;
        }
        state->dev = NULL;
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 }
 
 static int igmp6_mc_seq_show(struct seq_file *seq, void *v)
@@ -2430,9 +2458,9 @@ static int igmp6_mc_seq_show(struct seq_file *seq, void *v)
        struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
 
        seq_printf(seq,
-                  "%-4d %-15s " NIP6_SEQFMT " %5d %08X %ld\n",
+                  "%-4d %-15s %pi6 %5d %08X %ld\n",
                   state->dev->ifindex, state->dev->name,
-                  NIP6(im->mca_addr),
+                  &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);
@@ -2478,9 +2506,9 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
 
        state->idev = NULL;
        state->im = NULL;
-       for_each_netdev(net, state->dev) {
+       for_each_netdev_rcu(net, state->dev) {
                struct inet6_dev *idev;
-               idev = in6_dev_get(state->dev);
+               idev = __in6_dev_get(state->dev);
                if (unlikely(idev == NULL))
                        continue;
                read_lock_bh(&idev->lock);
@@ -2496,7 +2524,6 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
                        spin_unlock_bh(&im->mca_lock);
                }
                read_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
        }
        return psf;
 }
@@ -2510,16 +2537,15 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s
                spin_unlock_bh(&state->im->mca_lock);
                state->im = state->im->next;
                while (!state->im) {
-                       if (likely(state->idev != NULL)) {
+                       if (likely(state->idev != NULL))
                                read_unlock_bh(&state->idev->lock);
-                               in6_dev_put(state->idev);
-                       }
-                       state->dev = next_net_device(state->dev);
+
+                       state->dev = next_net_device_rcu(state->dev);
                        if (!state->dev) {
                                state->idev = NULL;
                                goto out;
                        }
-                       state->idev = in6_dev_get(state->dev);
+                       state->idev = __in6_dev_get(state->dev);
                        if (!state->idev)
                                continue;
                        read_lock_bh(&state->idev->lock);
@@ -2544,9 +2570,9 @@ static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(dev_base_lock)
+       __acquires(RCU)
 {
-       read_lock(&dev_base_lock);
+       rcu_read_lock();
        return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
 }
 
@@ -2562,7 +2588,7 @@ static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v)
-       __releases(dev_base_lock)
+       __releases(RCU)
 {
        struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
        if (likely(state->im != NULL)) {
@@ -2571,11 +2597,10 @@ static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v)
        }
        if (likely(state->idev != NULL)) {
                read_unlock_bh(&state->idev->lock);
-               in6_dev_put(state->idev);
                state->idev = NULL;
        }
        state->dev = NULL;
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 }
 
 static int igmp6_mcf_seq_show(struct seq_file *seq, void *v)
@@ -2591,10 +2616,10 @@ static int igmp6_mcf_seq_show(struct seq_file *seq, void *v)
                           "Source Address", "INC", "EXC");
        } else {
                seq_printf(seq,
-                          "%3d %6.6s " NIP6_SEQFMT " " NIP6_SEQFMT " %6lu %6lu\n",
+                          "%3d %6.6s %pi6 %pi6 %6lu %6lu\n",
                           state->dev->ifindex, state->dev->name,
-                          NIP6(state->im->mca_addr),
-                          NIP6(psf->sf_addr),
+                          &state->im->mca_addr,
+                          &psf->sf_addr,
                           psf->sf_count[MCAST_INCLUDE],
                           psf->sf_count[MCAST_EXCLUDE]);
        }
@@ -2622,7 +2647,7 @@ static const struct file_operations igmp6_mcf_seq_fops = {
        .release        =       seq_release_net,
 };
 
-static int igmp6_proc_init(struct net *net)
+static int __net_init igmp6_proc_init(struct net *net)
 {
        int err;
 
@@ -2642,23 +2667,22 @@ out_proc_net_igmp6:
        goto out;
 }
 
-static void igmp6_proc_exit(struct net *net)
+static void __net_exit igmp6_proc_exit(struct net *net)
 {
        proc_net_remove(net, "mcfilter6");
        proc_net_remove(net, "igmp6");
 }
 #else
-static int igmp6_proc_init(struct net *net)
+static inline int igmp6_proc_init(struct net *net)
 {
        return 0;
 }
-static void igmp6_proc_exit(struct net *net)
+static inline void igmp6_proc_exit(struct net *net)
 {
-       ;
 }
 #endif
 
-static int igmp6_net_init(struct net *net)
+static int __net_init igmp6_net_init(struct net *net)
 {
        int err;
 
@@ -2684,7 +2708,7 @@ out_sock_create:
        goto out;
 }
 
-static void igmp6_net_exit(struct net *net)
+static void __net_exit igmp6_net_exit(struct net *net)
 {
        inet_ctl_sock_destroy(net->ipv6.igmp_sk);
        igmp6_proc_exit(net);