net: sched: act_pedit: remove dependency on rtnl lock
authorVlad Buslov <vladbu@mellanox.com>
Fri, 10 Aug 2018 17:51:46 +0000 (20:51 +0300)
committerDavid S. Miller <davem@davemloft.net>
Sat, 11 Aug 2018 19:37:09 +0000 (12:37 -0700)
Rearrange pedit init code to only access pedit action data while holding
tcf spinlock. Change keys allocation type to atomic to allow it to execute
while holding tcf spinlock. Take tcf spinlock in dump function when
accessing pedit action data.

Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sched/act_pedit.c

index 43ba999b2d2322c7abb1063ceebe6af10d80c6b7..3f62da72ab6a9c1f68b53513ef6dd59b99af8bea 100644 (file)
@@ -187,44 +187,38 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
                        tcf_idr_cleanup(tn, parm->index);
                        goto out_free;
                }
-               p = to_pedit(*a);
-               keys = kmalloc(ksize, GFP_KERNEL);
-               if (!keys) {
-                       tcf_idr_release(*a, bind);
-                       ret = -ENOMEM;
-                       goto out_free;
-               }
                ret = ACT_P_CREATED;
        } else if (err > 0) {
                if (bind)
                        goto out_free;
                if (!ovr) {
-                       tcf_idr_release(*a, bind);
                        ret = -EEXIST;
-                       goto out_free;
-               }
-               p = to_pedit(*a);
-               if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) {
-                       keys = kmalloc(ksize, GFP_KERNEL);
-                       if (!keys) {
-                               ret = -ENOMEM;
-                               goto out_free;
-                       }
+                       goto out_release;
                }
        } else {
                return err;
        }
 
+       p = to_pedit(*a);
        spin_lock_bh(&p->tcf_lock);
-       p->tcfp_flags = parm->flags;
-       p->tcf_action = parm->action;
-       if (keys) {
+
+       if (ret == ACT_P_CREATED ||
+           (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys)) {
+               keys = kmalloc(ksize, GFP_ATOMIC);
+               if (!keys) {
+                       spin_unlock_bh(&p->tcf_lock);
+                       ret = -ENOMEM;
+                       goto out_release;
+               }
                kfree(p->tcfp_keys);
                p->tcfp_keys = keys;
                p->tcfp_nkeys = parm->nkeys;
        }
        memcpy(p->tcfp_keys, parm->keys, ksize);
 
+       p->tcfp_flags = parm->flags;
+       p->tcf_action = parm->action;
+
        kfree(p->tcfp_keys_ex);
        p->tcfp_keys_ex = keys_ex;
 
@@ -232,6 +226,9 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
        if (ret == ACT_P_CREATED)
                tcf_idr_insert(tn, *a);
        return ret;
+
+out_release:
+       tcf_idr_release(*a, bind);
 out_free:
        kfree(keys_ex);
        return ret;
@@ -410,6 +407,7 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,
        if (unlikely(!opt))
                return -ENOBUFS;
 
+       spin_lock_bh(&p->tcf_lock);
        memcpy(opt->keys, p->tcfp_keys,
               p->tcfp_nkeys * sizeof(struct tc_pedit_key));
        opt->index = p->tcf_index;
@@ -432,11 +430,13 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,
        tcf_tm_dump(&t, &p->tcf_tm);
        if (nla_put_64bit(skb, TCA_PEDIT_TM, sizeof(t), &t, TCA_PEDIT_PAD))
                goto nla_put_failure;
+       spin_unlock_bh(&p->tcf_lock);
 
        kfree(opt);
        return skb->len;
 
 nla_put_failure:
+       spin_unlock_bh(&p->tcf_lock);
        nlmsg_trim(skb, b);
        kfree(opt);
        return -1;