Merge branch 'Remove-rtnl-lock-dependency-from-all-action-implementations'
[linux-2.6-microblaze.git] / net / sched / act_nat.c
index 4b5848b..4dd9188 100644 (file)
@@ -38,7 +38,7 @@ static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
 
 static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
                        struct tc_action **a, int ovr, int bind,
-                       struct netlink_ext_ack *extack)
+                       bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct tc_action_net *tn = net_generic(net, nat_net_id);
        struct nlattr *tb[TCA_NAT_MAX + 1];
@@ -57,18 +57,24 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
                return -EINVAL;
        parm = nla_data(tb[TCA_NAT_PARMS]);
 
-       if (!tcf_idr_check(tn, parm->index, a, bind)) {
+       err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+       if (!err) {
                ret = tcf_idr_create(tn, parm->index, est, a,
                                     &act_nat_ops, bind, false);
-               if (ret)
+               if (ret) {
+                       tcf_idr_cleanup(tn, parm->index);
                        return ret;
+               }
                ret = ACT_P_CREATED;
-       } else {
+       } else if (err > 0) {
                if (bind)
                        return 0;
-               tcf_idr_release(*a, bind);
-               if (!ovr)
+               if (!ovr) {
+                       tcf_idr_release(*a, bind);
                        return -EEXIST;
+               }
+       } else {
+               return err;
        }
        p = to_tcf_nat(*a);
 
@@ -257,8 +263,8 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a,
 
                .index    = p->tcf_index,
                .action   = p->tcf_action,
-               .refcnt   = p->tcf_refcnt - ref,
-               .bindcnt  = p->tcf_bindcnt - bind,
+               .refcnt   = refcount_read(&p->tcf_refcnt) - ref,
+               .bindcnt  = atomic_read(&p->tcf_bindcnt) - bind,
        };
        struct tcf_t t;
 
@@ -294,6 +300,13 @@ static int tcf_nat_search(struct net *net, struct tc_action **a, u32 index,
        return tcf_idr_search(tn, a, index);
 }
 
+static int tcf_nat_delete(struct net *net, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
+
+       return tcf_idr_delete_index(tn, index);
+}
+
 static struct tc_action_ops act_nat_ops = {
        .kind           =       "nat",
        .type           =       TCA_ACT_NAT,
@@ -303,6 +316,7 @@ static struct tc_action_ops act_nat_ops = {
        .init           =       tcf_nat_init,
        .walk           =       tcf_nat_walker,
        .lookup         =       tcf_nat_search,
+       .delete         =       tcf_nat_delete,
        .size           =       sizeof(struct tcf_nat),
 };