In order to remove dependency on rtnl lock, protect
tcf_chain->explicitly_created flag with block->lock. Consolidate code that
checks and resets 'explicitly_created' flag into __tcf_chain_put() to
execute it atomically with rest of code that puts chain reference.

Signed-off-by: Vlad Buslov <vla...@mellanox.com>
---
 net/sched/cls_api.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 806e7158a7e8..2ebf8e53038a 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -370,13 +370,22 @@ EXPORT_SYMBOL(tcf_chain_get_by_act);
 
 static void tc_chain_tmplt_del(struct tcf_chain *chain);
 
-static void __tcf_chain_put(struct tcf_chain *chain, bool by_act)
+static void __tcf_chain_put(struct tcf_chain *chain, bool by_act,
+                           bool explicitly_created)
 {
        struct tcf_block *block = chain->block;
        bool is_last, free_block = false;
        unsigned int refcnt;
 
        mutex_lock(&block->lock);
+       if (explicitly_created) {
+               if (!chain->explicitly_created) {
+                       mutex_unlock(&block->lock);
+                       return;
+               }
+               chain->explicitly_created = false;
+       }
+
        if (by_act)
                chain->action_refcnt--;
 
@@ -402,19 +411,18 @@ static void __tcf_chain_put(struct tcf_chain *chain, bool 
by_act)
 
 static void tcf_chain_put(struct tcf_chain *chain)
 {
-       __tcf_chain_put(chain, false);
+       __tcf_chain_put(chain, false, false);
 }
 
 void tcf_chain_put_by_act(struct tcf_chain *chain)
 {
-       __tcf_chain_put(chain, true);
+       __tcf_chain_put(chain, true, false);
 }
 EXPORT_SYMBOL(tcf_chain_put_by_act);
 
 static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
 {
-       if (chain->explicitly_created)
-               tcf_chain_put(chain);
+       __tcf_chain_put(chain, false, true);
 }
 
 static void tcf_chain_flush(struct tcf_chain *chain)
@@ -2305,7 +2313,6 @@ static int tc_ctl_chain(struct sk_buff *skb, struct 
nlmsghdr *n,
                 * to the chain previously taken during addition.
                 */
                tcf_chain_put_explicitly_created(chain);
-               chain->explicitly_created = false;
                break;
        case RTM_GETCHAIN:
                err = tc_chain_notify(chain, skb, n->nlmsg_seq,
-- 
2.13.6

Reply via email to