diff options
Diffstat (limited to 'net/sched/cls_api.c')
-rw-r--r-- | net/sched/cls_api.c | 29 |
1 files changed, 16 insertions, 13 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 6593c245f714..478095d50f95 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -238,18 +238,23 @@ static void tcf_proto_put(struct tcf_proto *tp, bool rtnl_held, tcf_proto_destroy(tp, rtnl_held, extack); } -static int walker_noop(struct tcf_proto *tp, void *d, struct tcf_walker *arg) +static int walker_check_empty(struct tcf_proto *tp, void *fh, + struct tcf_walker *arg) { - return -1; + if (fh) { + arg->nonempty = true; + return -1; + } + return 0; } static bool tcf_proto_is_empty(struct tcf_proto *tp, bool rtnl_held) { - struct tcf_walker walker = { .fn = walker_noop, }; + struct tcf_walker walker = { .fn = walker_check_empty, }; if (tp->ops->walk) { tp->ops->walk(tp, &walker, rtnl_held); - return !walker.stop; + return !walker.nonempty; } return true; } @@ -2907,12 +2912,12 @@ errout_block_locked: /* 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; @@ -2975,11 +2980,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; @@ -2987,17 +2989,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); |