]> exis.tech > repos - linux.git/blobdiff - net/ipv6/mcast.c
Merge tag 'hwmon-for-v7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/groec...
[linux.git] / net / ipv6 / mcast.c
index 04b811b3be978e36b0fd4ecd8312313d73ed2ed9..4d2b9377ba2de5ad2b6d503bb4b285bfd1307a55 100644 (file)
@@ -1083,8 +1083,10 @@ static void mld_gq_start_work(struct inet6_dev *idev)
        mc_assert_locked(idev);
 
        idev->mc_gq_running = 1;
-       if (!mod_delayed_work(mld_wq, &idev->mc_gq_work, tv + 2))
-               in6_dev_hold(idev);
+       if (in6_dev_hold_safe(idev)) {
+               if (mod_delayed_work(mld_wq, &idev->mc_gq_work, tv + 2))
+                       in6_dev_put(idev);
+       }
 }
 
 static void mld_gq_stop_work(struct inet6_dev *idev)
@@ -1102,8 +1104,10 @@ static void mld_ifc_start_work(struct inet6_dev *idev, unsigned long delay)
 
        mc_assert_locked(idev);
 
-       if (!mod_delayed_work(mld_wq, &idev->mc_ifc_work, tv + 2))
-               in6_dev_hold(idev);
+       if (in6_dev_hold_safe(idev)) {
+               if (mod_delayed_work(mld_wq, &idev->mc_ifc_work, tv + 2))
+                       in6_dev_put(idev);
+       }
 }
 
 static void mld_ifc_stop_work(struct inet6_dev *idev)
@@ -1121,8 +1125,10 @@ static void mld_dad_start_work(struct inet6_dev *idev, unsigned long delay)
 
        mc_assert_locked(idev);
 
-       if (!mod_delayed_work(mld_wq, &idev->mc_dad_work, tv + 2))
-               in6_dev_hold(idev);
+       if (in6_dev_hold_safe(idev)) {
+               if (mod_delayed_work(mld_wq, &idev->mc_dad_work, tv + 2))
+                       in6_dev_put(idev);
+       }
 }
 
 static void mld_dad_stop_work(struct inet6_dev *idev)
@@ -1395,18 +1401,23 @@ static void mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld,
 void igmp6_event_query(struct sk_buff *skb)
 {
        struct inet6_dev *idev = __in6_dev_get(skb->dev);
+       bool put = false;
 
        if (!idev || idev->dead)
                goto out;
 
        spin_lock_bh(&idev->mc_query_lock);
-       if (skb_queue_len(&idev->mc_query_queue) < MLD_MAX_SKBS) {
+       if (skb_queue_len(&idev->mc_query_queue) < MLD_MAX_SKBS &&
+           in6_dev_hold_safe(idev)) {
                __skb_queue_tail(&idev->mc_query_queue, skb);
-               if (!mod_delayed_work(mld_wq, &idev->mc_query_work, 0))
-                       in6_dev_hold(idev);
+               if (mod_delayed_work(mld_wq, &idev->mc_query_work, 0))
+                       put = true;
                skb = NULL;
        }
        spin_unlock_bh(&idev->mc_query_lock);
+
+       if (put)
+               in6_dev_put(idev);
 out:
        kfree_skb(skb);
 }
@@ -1570,18 +1581,23 @@ static void mld_query_work(struct work_struct *work)
 void igmp6_event_report(struct sk_buff *skb)
 {
        struct inet6_dev *idev = __in6_dev_get(skb->dev);
+       bool put = false;
 
        if (!idev || idev->dead)
                goto out;
 
        spin_lock_bh(&idev->mc_report_lock);
-       if (skb_queue_len(&idev->mc_report_queue) < MLD_MAX_SKBS) {
+       if (skb_queue_len(&idev->mc_report_queue) < MLD_MAX_SKBS &&
+           in6_dev_hold_safe(idev)) {
                __skb_queue_tail(&idev->mc_report_queue, skb);
-               if (!mod_delayed_work(mld_wq, &idev->mc_report_work, 0))
-                       in6_dev_hold(idev);
+               if (mod_delayed_work(mld_wq, &idev->mc_report_work, 0))
+                       put = true;
                skb = NULL;
        }
        spin_unlock_bh(&idev->mc_report_lock);
+
+       if (put)
+               in6_dev_put(idev);
 out:
        kfree_skb(skb);
 }