Function tc_dump_chain() obtains and releases block->lock on each iteration
of its inner loop that dumps all chains on block. Outputting chain template
info is fast operation so locking/unlocking mutex multiple times is an
overhead when lock is highly contested. Modify tc_dump_chain() to only
obtain block->lock once and dump all chains without releasing it.

Signed-off-by: Vlad Buslov <vla...@mellanox.com>
Suggested-by: Cong Wang <xiyou.wangc...@gmail.com>
---
 net/sched/cls_api.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 3543be31d400..5c6a9baa389f 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -2996,12 +2996,12 @@ static int tc_ctl_chain(struct sk_buff *skb, struct 
nlmsghdr *n,
 /* called with RTNL */
 static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct tcf_chain *chain, *chain_prev;
        struct net *net = sock_net(skb->sk);
        struct nlattr *tca[TCA_MAX + 1];
        struct Qdisc *q = NULL;
        struct tcf_block *block;
        struct tcmsg *tcm = nlmsg_data(cb->nlh);
+       struct tcf_chain *chain;
        long index_start;
        long index;
        u32 parent;
@@ -3064,11 +3064,8 @@ static int tc_dump_chain(struct sk_buff *skb, struct 
netlink_callback *cb)
        index_start = cb->args[0];
        index = 0;
 
-       for (chain = __tcf_get_next_chain(block, NULL);
-            chain;
-            chain_prev = chain,
-                    chain = __tcf_get_next_chain(block, chain),
-                    tcf_chain_put(chain_prev)) {
+       mutex_lock(&block->lock);
+       list_for_each_entry(chain, &block->chain_list, list) {
                if ((tca[TCA_CHAIN] &&
                     nla_get_u32(tca[TCA_CHAIN]) != chain->index))
                        continue;
@@ -3076,17 +3073,18 @@ static int tc_dump_chain(struct sk_buff *skb, struct 
netlink_callback *cb)
                        index++;
                        continue;
                }
+               if (tcf_chain_held_by_acts_only(chain))
+                       continue;
                err = tc_chain_fill_node(chain->tmplt_ops, chain->tmplt_priv,
                                         chain->index, net, skb, block,
                                         NETLINK_CB(cb->skb).portid,
                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                         RTM_NEWCHAIN);
-               if (err <= 0) {
-                       tcf_chain_put(chain);
+               if (err <= 0)
                        break;
-               }
                index++;
        }
+       mutex_unlock(&block->lock);
 
        if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK)
                tcf_block_refcnt_put(block, true);
-- 
2.13.6

Reply via email to