Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-microblaze.git] / net / sched / cls_u32.c
index 82f85d6..6c7601a 100644 (file)
@@ -392,10 +392,12 @@ static int u32_init(struct tcf_proto *tp)
 static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n,
                           bool free_pf)
 {
+       struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
+
        tcf_exts_destroy(&n->exts);
        tcf_exts_put_net(&n->exts);
-       if (n->ht_down)
-               n->ht_down->refcnt--;
+       if (ht && --ht->refcnt == 0)
+               kfree(ht);
 #ifdef CONFIG_CLS_U32_PERF
        if (free_pf)
                free_percpu(n->pf);
@@ -653,16 +655,15 @@ static void u32_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
 
                hlist_del(&tp_c->hnode);
 
-               for (ht = rtnl_dereference(tp_c->hlist);
-                    ht;
-                    ht = rtnl_dereference(ht->next)) {
-                       ht->refcnt--;
-                       u32_clear_hnode(tp, ht, extack);
-               }
-
                while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) {
+                       u32_clear_hnode(tp, ht, extack);
                        RCU_INIT_POINTER(tp_c->hlist, ht->next);
-                       kfree_rcu(ht, rcu);
+
+                       /* u32_destroy_key() will later free ht for us, if it's
+                        * still referenced by some knode
+                        */
+                       if (--ht->refcnt == 0)
+                               kfree_rcu(ht, rcu);
                }
 
                idr_destroy(&tp_c->handle_idr);
@@ -946,7 +947,8 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
                        return -EINVAL;
                }
 
-               if (n->flags != flags) {
+               if ((n->flags ^ flags) &
+                   ~(TCA_CLS_FLAGS_IN_HW | TCA_CLS_FLAGS_NOT_IN_HW)) {
                        NL_SET_ERR_MSG_MOD(extack, "Key node flags do not match passed flags");
                        return -EINVAL;
                }