net: sched: implement action API that deletes action by index
authorVlad Buslov <vladbu@mellanox.com>
Thu, 5 Jul 2018 14:24:27 +0000 (17:24 +0300)
committerDavid S. Miller <davem@davemloft.net>
Sun, 8 Jul 2018 03:42:28 +0000 (12:42 +0900)
Implement new action API function that atomically finds and deletes action
from idr by index. Intended to be used by lockless actions that do not rely
on rtnl lock.

Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/act_api.h
net/sched/act_api.c

index 27823f4..a8eaae6 100644 (file)
@@ -153,6 +153,7 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
                   int bind, bool cpustats);
 void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a);
 
+int tcf_idr_delete_index(struct tc_action_net *tn, u32 index);
 int __tcf_idr_release(struct tc_action *a, bool bind, bool strict);
 
 static inline int tcf_idr_release(struct tc_action *a, bool bind)
index aa304d3..0f31f09 100644 (file)
@@ -319,6 +319,45 @@ bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a,
 }
 EXPORT_SYMBOL(tcf_idr_check);
 
+int tcf_idr_delete_index(struct tc_action_net *tn, u32 index)
+{
+       struct tcf_idrinfo *idrinfo = tn->idrinfo;
+       struct tc_action *p;
+       int ret = 0;
+
+       spin_lock(&idrinfo->lock);
+       p = idr_find(&idrinfo->action_idr, index);
+       if (!p) {
+               spin_unlock(&idrinfo->lock);
+               return -ENOENT;
+       }
+
+       if (!atomic_read(&p->tcfa_bindcnt)) {
+               if (refcount_dec_and_test(&p->tcfa_refcnt)) {
+                       struct module *owner = p->ops->owner;
+
+                       WARN_ON(p != idr_remove(&idrinfo->action_idr,
+                                               p->tcfa_index));
+                       spin_unlock(&idrinfo->lock);
+
+                       if (p->ops->cleanup)
+                               p->ops->cleanup(p);
+
+                       gen_kill_estimator(&p->tcfa_rate_est);
+                       free_tcf(p);
+                       module_put(owner);
+                       return 0;
+               }
+               ret = 0;
+       } else {
+               ret = -EPERM;
+       }
+
+       spin_unlock(&idrinfo->lock);
+       return ret;
+}
+EXPORT_SYMBOL(tcf_idr_delete_index);
+
 int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
                   struct tc_action **a, const struct tc_action_ops *ops,
                   int bind, bool cpustats)