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.leit...@gmail.com>
Signed-off-by: Vlad Buslov <vla...@mellanox.com>
Signed-off-by: Jiri Pirko <j...@mellanox.com>
---
Changes from V1 to V2:
- Rename tcf_idr_find_delete to tcf_idr_delete_index.

 include/net/act_api.h |  1 +
 net/sched/act_api.c   | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/include/net/act_api.h b/include/net/act_api.h
index 27823f4e24c4..a8eaae67c264 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -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)
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index aa304d36fee0..0f31f09946ab 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -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)
-- 
2.7.5

Reply via email to