net_sched: move tcf_lock down after gen_replace_estimator()
authorWANG Cong <xiyou.wangcong@gmail.com>
Tue, 13 Jun 2017 20:36:24 +0000 (13:36 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 14 Jun 2017 18:39:19 +0000 (14:39 -0400)
Laura reported a sleep-in-atomic kernel warning inside
tcf_act_police_init() which calls gen_replace_estimator() with
spinlock protection.

It is not necessary in this case, we already have RTNL lock here
so it is enough to protect concurrent writers. For the reader,
i.e. tcf_act_police(), it needs to make decision based on this
rate estimator, in the worst case we drop more/less packets than
necessary while changing the rate in parallel, it is still acceptable.

Reported-by: Laura Abbott <labbott@redhat.com>
Reported-by: Nick Huber <nicholashuber@gmail.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/act_police.c

index f42008b293112d1a6da2bcf6ef8af564b382ba39..b062bc80c7cb11b0ea473916c58957b54db21594 100644 (file)
@@ -132,21 +132,21 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla,
                }
        }
 
-       spin_lock_bh(&police->tcf_lock);
        if (est) {
                err = gen_replace_estimator(&police->tcf_bstats, NULL,
                                            &police->tcf_rate_est,
                                            &police->tcf_lock,
                                            NULL, est);
                if (err)
-                       goto failure_unlock;
+                       goto failure;
        } else if (tb[TCA_POLICE_AVRATE] &&
                   (ret == ACT_P_CREATED ||
                    !gen_estimator_active(&police->tcf_rate_est))) {
                err = -EINVAL;
-               goto failure_unlock;
+               goto failure;
        }
 
+       spin_lock_bh(&police->tcf_lock);
        /* No failure allowed after this point */
        police->tcfp_mtu = parm->mtu;
        if (police->tcfp_mtu == 0) {
@@ -192,8 +192,6 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla,
 
        return ret;
 
-failure_unlock:
-       spin_unlock_bh(&police->tcf_lock);
 failure:
        qdisc_put_rtab(P_tab);
        qdisc_put_rtab(R_tab);