ipv6: refactor ipv6_dev_mc_inc()
authorWANG Cong <xiyou.wangcong@gmail.com>
Thu, 11 Sep 2014 22:35:16 +0000 (15:35 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sat, 13 Sep 2014 20:38:42 +0000 (16:38 -0400)
Refactor out allocation and initialization and make
the refcount code more readable.

Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/mcast.c

index d64e263..592eba6 100644 (file)
@@ -641,14 +641,6 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
        return rv;
 }
 
-static void ma_put(struct ifmcaddr6 *mc)
-{
-       if (atomic_dec_and_test(&mc->mca_refcnt)) {
-               in6_dev_put(mc->idev);
-               kfree(mc);
-       }
-}
-
 static void igmp6_group_added(struct ifmcaddr6 *mc)
 {
        struct net_device *dev = mc->idev->dev;
@@ -814,6 +806,48 @@ static void mld_clear_delrec(struct inet6_dev *idev)
        read_unlock_bh(&idev->lock);
 }
 
+static void mca_get(struct ifmcaddr6 *mc)
+{
+       atomic_inc(&mc->mca_refcnt);
+}
+
+static void ma_put(struct ifmcaddr6 *mc)
+{
+       if (atomic_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)
+{
+       struct ifmcaddr6 *mc;
+
+       mc = kzalloc(sizeof(*mc), GFP_ATOMIC);
+       if (mc == NULL)
+               return NULL;
+
+       setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
+
+       mc->mca_addr = *addr;
+       mc->idev = idev; /* reference taken by caller */
+       mc->mca_users = 1;
+       /* mca_stamp should be updated upon changes */
+       mc->mca_cstamp = mc->mca_tstamp = jiffies;
+       atomic_set(&mc->mca_refcnt, 1);
+       spin_lock_init(&mc->mca_lock);
+
+       /* initial mode is (EX, empty) */
+       mc->mca_sfmode = MCAST_EXCLUDE;
+       mc->mca_sfcount[MCAST_EXCLUDE] = 1;
+
+       if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) ||
+           IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL)
+               mc->mca_flags |= MAF_NOREPORT;
+
+       return mc;
+}
 
 /*
  *     device multicast group inc (add if not found)
@@ -849,38 +883,20 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
                }
        }
 
-       /*
-        *      not found: create a new one.
-        */
-
-       mc = kzalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
-
-       if (mc == NULL) {
+       mc = mca_alloc(idev, addr);
+       if (!mc) {
                write_unlock_bh(&idev->lock);
                in6_dev_put(idev);
                return -ENOMEM;
        }
 
-       setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
-
-       mc->mca_addr = *addr;
-       mc->idev = idev; /* (reference taken) */
-       mc->mca_users = 1;
-       /* mca_stamp should be updated upon changes */
-       mc->mca_cstamp = mc->mca_tstamp = jiffies;
-       atomic_set(&mc->mca_refcnt, 2);
-       spin_lock_init(&mc->mca_lock);
-
-       /* initial mode is (EX, empty) */
-       mc->mca_sfmode = MCAST_EXCLUDE;
-       mc->mca_sfcount[MCAST_EXCLUDE] = 1;
-
-       if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) ||
-           IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL)
-               mc->mca_flags |= MAF_NOREPORT;
-
        mc->next = idev->mc_list;
        idev->mc_list = mc;
+
+       /* Hold this for the code below before we unlock,
+        * it is already exposed via idev->mc_list.
+        */
+       mca_get(mc);
        write_unlock_bh(&idev->lock);
 
        mld_del_delrec(idev, &mc->mca_addr);