Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[sfrench/cifs-2.6.git] / net / sched / act_api.c
index a306974e2fb4bfe866628d84b8c4aa7ae4fddb8c..ca2ff0b3123f9d37e4b0549e55254bf46efb5e1a 100644 (file)
@@ -53,10 +53,13 @@ static void tcf_action_goto_chain_exec(const struct tc_action *a,
        res->goto_tp = rcu_dereference_bh(chain->filter_chain);
 }
 
-static void free_tcf(struct rcu_head *head)
+/* XXX: For standalone actions, we don't need a RCU grace period either, because
+ * actions are always connected to filters and filters are already destroyed in
+ * RCU callbacks, so after a RCU grace period actions are already disconnected
+ * from filters. Readers later can not find us.
+ */
+static void free_tcf(struct tc_action *p)
 {
-       struct tc_action *p = container_of(head, struct tc_action, tcfa_rcu);
-
        free_percpu(p->cpu_bstats);
        free_percpu(p->cpu_qstats);
 
@@ -75,18 +78,17 @@ static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p)
        spin_lock_bh(&idrinfo->lock);
        idr_remove_ext(&idrinfo->action_idr, p->tcfa_index);
        spin_unlock_bh(&idrinfo->lock);
+       put_net(idrinfo->net);
        gen_kill_estimator(&p->tcfa_rate_est);
-       /*
-        * gen_estimator est_timer() might access p->tcfa_lock
-        * or bstats, wait a RCU grace period before freeing p
-        */
-       call_rcu(&p->tcfa_rcu, free_tcf);
+       free_tcf(p);
 }
 
 int __tcf_idr_release(struct tc_action *p, bool bind, bool strict)
 {
        int ret = 0;
 
+       ASSERT_RTNL();
+
        if (p) {
                if (bind)
                        p->tcfa_bindcnt--;
@@ -181,7 +183,7 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
        idr_for_each_entry_ext(idr, p, id) {
                ret = __tcf_idr_release(p, false, true);
                if (ret == ACT_P_DELETED) {
-                       module_put(p->ops->owner);
+                       module_put(ops->owner);
                        n_i++;
                } else if (ret < 0) {
                        goto nla_put_failure;
@@ -259,7 +261,7 @@ void tcf_idr_cleanup(struct tc_action *a, struct nlattr *est)
 {
        if (est)
                gen_kill_estimator(&a->tcfa_rate_est);
-       call_rcu(&a->tcfa_rcu, free_tcf);
+       free_tcf(a);
 }
 EXPORT_SYMBOL(tcf_idr_cleanup);
 
@@ -335,6 +337,7 @@ err3:
        p->idrinfo = idrinfo;
        p->ops = ops;
        INIT_LIST_HEAD(&p->list);
+       get_net(idrinfo->net);
        *a = p;
        return 0;
 }
@@ -515,13 +518,15 @@ EXPORT_SYMBOL(tcf_action_exec);
 
 int tcf_action_destroy(struct list_head *actions, int bind)
 {
+       const struct tc_action_ops *ops;
        struct tc_action *a, *tmp;
        int ret = 0;
 
        list_for_each_entry_safe(a, tmp, actions, list) {
+               ops = a->ops;
                ret = __tcf_idr_release(a, bind, true);
                if (ret == ACT_P_DELETED)
-                       module_put(a->ops->owner);
+                       module_put(ops->owner);
                else if (ret < 0)
                        return ret;
        }