]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/sched/cls_u32.c
net_sched: move the empty tp check from ->destroy() to ->delete()
[karo-tx-linux.git] / net / sched / cls_u32.c
index 4dbe0c680fe6363a88ca47cb167dcae9327920d1..d20e72a095d578e65eda0dafc62217146aeea1c1 100644 (file)
@@ -585,37 +585,13 @@ static bool ht_empty(struct tc_u_hnode *ht)
        return true;
 }
 
-static bool u32_destroy(struct tcf_proto *tp, bool force)
+static void u32_destroy(struct tcf_proto *tp)
 {
        struct tc_u_common *tp_c = tp->data;
        struct tc_u_hnode *root_ht = rtnl_dereference(tp->root);
 
        WARN_ON(root_ht == NULL);
 
-       if (!force) {
-               if (root_ht) {
-                       if (root_ht->refcnt > 1)
-                               return false;
-                       if (root_ht->refcnt == 1) {
-                               if (!ht_empty(root_ht))
-                                       return false;
-                       }
-               }
-
-               if (tp_c->refcnt > 1)
-                       return false;
-
-               if (tp_c->refcnt == 1) {
-                       struct tc_u_hnode *ht;
-
-                       for (ht = rtnl_dereference(tp_c->hlist);
-                            ht;
-                            ht = rtnl_dereference(ht->next))
-                               if (!ht_empty(ht))
-                                       return false;
-               }
-       }
-
        if (root_ht && --root_ht->refcnt == 0)
                u32_destroy_hnode(tp, root_ht);
 
@@ -640,20 +616,22 @@ static bool u32_destroy(struct tcf_proto *tp, bool force)
        }
 
        tp->data = NULL;
-       return true;
 }
 
-static int u32_delete(struct tcf_proto *tp, unsigned long arg)
+static int u32_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
 {
        struct tc_u_hnode *ht = (struct tc_u_hnode *)arg;
        struct tc_u_hnode *root_ht = rtnl_dereference(tp->root);
+       struct tc_u_common *tp_c = tp->data;
+       int ret = 0;
 
        if (ht == NULL)
-               return 0;
+               goto out;
 
        if (TC_U32_KEY(ht->handle)) {
                u32_remove_hw_knode(tp, ht->handle);
-               return u32_delete_key(tp, (struct tc_u_knode *)ht);
+               ret = u32_delete_key(tp, (struct tc_u_knode *)ht);
+               goto out;
        }
 
        if (root_ht == ht)
@@ -666,7 +644,40 @@ static int u32_delete(struct tcf_proto *tp, unsigned long arg)
                return -EBUSY;
        }
 
-       return 0;
+out:
+       *last = true;
+       if (root_ht) {
+               if (root_ht->refcnt > 1) {
+                       *last = false;
+                       goto ret;
+               }
+               if (root_ht->refcnt == 1) {
+                       if (!ht_empty(root_ht)) {
+                               *last = false;
+                               goto ret;
+                       }
+               }
+       }
+
+       if (tp_c->refcnt > 1) {
+               *last = false;
+               goto ret;
+       }
+
+       if (tp_c->refcnt == 1) {
+               struct tc_u_hnode *ht;
+
+               for (ht = rtnl_dereference(tp_c->hlist);
+                    ht;
+                    ht = rtnl_dereference(ht->next))
+                       if (!ht_empty(ht)) {
+                               *last = false;
+                               break;
+                       }
+       }
+
+ret:
+       return ret;
 }
 
 #define NR_U32_NODE (1<<12)
@@ -860,7 +871,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
        if (opt == NULL)
                return handle ? -EINVAL : 0;
 
-       err = nla_parse_nested(tb, TCA_U32_MAX, opt, u32_policy);
+       err = nla_parse_nested(tb, TCA_U32_MAX, opt, u32_policy, NULL);
        if (err < 0)
                return err;