Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
[firefly-linux-kernel-4.4.55.git] / net / sched / cls_tcindex.c
index a9f4279fbd698ea2ecf177bd0dee26f9f7ff12ad..30f10fb07f4a7d50e390c7df730f94366e00fb73 100644 (file)
@@ -81,7 +81,7 @@ tcindex_lookup(struct tcindex_data *p, u16 key)
 static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                            struct tcf_result *res)
 {
-       struct tcindex_data *p = rcu_dereference(tp->root);
+       struct tcindex_data *p = rcu_dereference_bh(tp->root);
        struct tcindex_filter_result *f;
        int key = (skb->tc_index & p->mask) >> p->shift;
 
@@ -169,7 +169,7 @@ found:
                rcu_assign_pointer(*walk, rtnl_dereference(f->next));
        }
        tcf_unbind_filter(tp, &r->res);
-       tcf_exts_destroy(tp, &r->exts);
+       tcf_exts_destroy(&r->exts);
        if (f)
                kfree_rcu(f, rcu);
        return 0;
@@ -237,13 +237,14 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
        if (err < 0)
                return err;
 
+       err = -ENOMEM;
        /* tcindex_data attributes must look atomic to classifier/lookup so
         * allocate new tcindex data and RCU assign it onto root. Keeping
         * perfect hash and hash pointers from old data.
         */
-       cp = kzalloc(sizeof(cp), GFP_KERNEL);
+       cp = kzalloc(sizeof(*cp), GFP_KERNEL);
        if (!cp)
-               return -ENOMEM;
+               goto errout;
 
        cp->mask = p->mask;
        cp->shift = p->shift;
@@ -253,17 +254,20 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
        cp->tp = tp;
 
        if (p->perfect) {
+               int i;
+
                cp->perfect = kmemdup(p->perfect,
                                      sizeof(*r) * cp->hash, GFP_KERNEL);
                if (!cp->perfect)
                        goto errout;
+               for (i = 0; i < cp->hash; i++)
+                       tcf_exts_init(&cp->perfect[i].exts,
+                                     TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
+               balloc = 1;
        }
        cp->h = p->h;
 
-       memset(&new_filter_result, 0, sizeof(new_filter_result));
-       tcf_exts_init(&new_filter_result.exts,
-                     TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
-
+       tcindex_filter_result_init(&new_filter_result);
        tcindex_filter_result_init(&cr);
        if (old_r)
                cr.res = r->res;
@@ -285,9 +289,9 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
        if (cp->perfect) {
                if (!valid_perfect_hash(cp) ||
                    cp->hash > cp->alloc_hash)
-                       goto errout;
+                       goto errout_alloc;
        } else if (cp->h && cp->hash != cp->alloc_hash) {
-               goto errout;
+               goto errout_alloc;
        }
 
        err = -EINVAL;
@@ -304,7 +308,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
                        cp->hash = DEFAULT_HASH_SIZE;
        }
 
-       if (!cp->perfect && cp->h)
+       if (!cp->perfect && !cp->h)
                cp->alloc_hash = cp->hash;
 
        /* Note: this could be as restrictive as if (handle & ~(mask >> shift))
@@ -314,7 +318,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
         */
        if (cp->perfect || valid_perfect_hash(cp))
                if (handle >= cp->alloc_hash)
-                       goto errout;
+                       goto errout_alloc;
 
 
        err = -ENOMEM;
@@ -324,7 +328,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
 
                        cp->perfect = kcalloc(cp->hash, sizeof(*r), GFP_KERNEL);
                        if (!cp->perfect)
-                               goto errout;
+                               goto errout_alloc;
                        for (i = 0; i < cp->hash; i++)
                                tcf_exts_init(&cp->perfect[i].exts,
                                              TCA_TCINDEX_ACT,
@@ -338,7 +342,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
                                       GFP_KERNEL);
 
                        if (!hash)
-                               goto errout;
+                               goto errout_alloc;
 
                        cp->h = hash;
                        balloc = 2;
@@ -354,6 +358,9 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
                f = kzalloc(sizeof(*f), GFP_KERNEL);
                if (!f)
                        goto errout_alloc;
+               f->key = handle;
+               tcindex_filter_result_init(&f->result);
+               f->next = NULL;
        }
 
        if (tb[TCA_TCINDEX_CLASSID]) {
@@ -377,11 +384,9 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
                struct tcindex_filter *nfp;
                struct tcindex_filter __rcu **fp;
 
-               f->key = handle;
-               f->result = new_filter_result;
-               f->next = NULL;
+               tcf_exts_change(tp, &f->result.exts, &r->exts);
 
-               fp = p->h + (handle % p->hash);
+               fp = cp->h + (handle % cp->hash);
                for (nfp = rtnl_dereference(*fp);
                     nfp;
                     fp = &nfp->next, nfp = rtnl_dereference(*fp))
@@ -401,7 +406,7 @@ errout_alloc:
                kfree(cp->h);
 errout:
        kfree(cp);
-       tcf_exts_destroy(tp, &e);
+       tcf_exts_destroy(&e);
        return err;
 }