Loading include/net/pkt_cls.h +0 −3 Original line number Diff line number Diff line Loading @@ -40,11 +40,8 @@ struct tcf_block_cb; bool tcf_queue_work(struct rcu_work *rwork, work_func_t func); #ifdef CONFIG_NET_CLS struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create); struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index); void tcf_chain_put(struct tcf_chain *chain); void tcf_chain_put_by_act(struct tcf_chain *chain); void tcf_block_netif_keep_dst(struct tcf_block *block); int tcf_block_get(struct tcf_block **p_block, Loading net/sched/cls_api.c +62 −51 Original line number Diff line number Diff line Loading @@ -232,19 +232,6 @@ static void tcf_chain0_head_change(struct tcf_chain *chain, tcf_chain_head_change_item(item, tp_head); } static void tcf_chain_flush(struct tcf_chain *chain) { struct tcf_proto *tp = rtnl_dereference(chain->filter_chain); tcf_chain0_head_change(chain, NULL); while (tp) { RCU_INIT_POINTER(chain->filter_chain, tp->next); tcf_proto_destroy(tp, NULL); tp = rtnl_dereference(chain->filter_chain); tcf_chain_put(chain); } } static void tcf_chain_destroy(struct tcf_chain *chain) { struct tcf_block *block = chain->block; Loading @@ -262,21 +249,10 @@ static void tcf_chain_hold(struct tcf_chain *chain) ++chain->refcnt; } static void tcf_chain_hold_by_act(struct tcf_chain *chain) { ++chain->action_refcnt; } static void tcf_chain_release_by_act(struct tcf_chain *chain) { --chain->action_refcnt; } static bool tcf_chain_is_zombie(struct tcf_chain *chain) static bool tcf_chain_held_by_acts_only(struct tcf_chain *chain) { /* In case all the references are action references, this * chain is a zombie and should not be listed in the chain * dump list. * chain should not be shown to the user. */ return chain->refcnt == chain->action_refcnt; } Loading @@ -296,52 +272,75 @@ static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block, static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb, u32 seq, u16 flags, int event, bool unicast); struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create) static struct tcf_chain *__tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create, bool by_act) { struct tcf_chain *chain = tcf_chain_lookup(block, chain_index); if (chain) { tcf_chain_hold(chain); return chain; } } else { if (!create) return NULL; chain = tcf_chain_create(block, chain_index); if (!chain) return NULL; } if (by_act) ++chain->action_refcnt; /* Send notification only in case we got the first * non-action reference. Until then, the chain acts only as * a placeholder for actions pointing to it and user ought * not know about them. */ if (chain->refcnt - chain->action_refcnt == 1 && !by_act) tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL, RTM_NEWCHAIN, false); return chain; } EXPORT_SYMBOL(tcf_chain_get); struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index) static struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create) { struct tcf_chain *chain = tcf_chain_get(block, chain_index, true); return __tcf_chain_get(block, chain_index, create, false); } tcf_chain_hold_by_act(chain); return chain; struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index) { return __tcf_chain_get(block, chain_index, true, true); } EXPORT_SYMBOL(tcf_chain_get_by_act); static void tc_chain_tmplt_del(struct tcf_chain *chain); void tcf_chain_put(struct tcf_chain *chain) static void __tcf_chain_put(struct tcf_chain *chain, bool by_act) { if (--chain->refcnt == 0) { if (by_act) chain->action_refcnt--; chain->refcnt--; /* The last dropped non-action reference will trigger notification. */ if (chain->refcnt - chain->action_refcnt == 0 && !by_act) tc_chain_notify(chain, NULL, 0, 0, RTM_DELCHAIN, false); if (chain->refcnt == 0) { tc_chain_tmplt_del(chain); tcf_chain_destroy(chain); } } EXPORT_SYMBOL(tcf_chain_put); static void tcf_chain_put(struct tcf_chain *chain) { __tcf_chain_put(chain, false); } void tcf_chain_put_by_act(struct tcf_chain *chain) { tcf_chain_release_by_act(chain); tcf_chain_put(chain); __tcf_chain_put(chain, true); } EXPORT_SYMBOL(tcf_chain_put_by_act); Loading @@ -351,6 +350,19 @@ static void tcf_chain_put_explicitly_created(struct tcf_chain *chain) tcf_chain_put(chain); } static void tcf_chain_flush(struct tcf_chain *chain) { struct tcf_proto *tp = rtnl_dereference(chain->filter_chain); tcf_chain0_head_change(chain, NULL); while (tp) { RCU_INIT_POINTER(chain->filter_chain, tp->next); tcf_proto_destroy(tp, NULL); tp = rtnl_dereference(chain->filter_chain); tcf_chain_put(chain); } } static bool tcf_block_offload_in_use(struct tcf_block *block) { return block->offloadcnt; Loading Loading @@ -1838,10 +1850,9 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n, chain = tcf_chain_lookup(block, chain_index); if (n->nlmsg_type == RTM_NEWCHAIN) { if (chain) { if (tcf_chain_is_zombie(chain)) { if (tcf_chain_held_by_acts_only(chain)) { /* The chain exists only because there is * some action referencing it, meaning it * is a zombie. * some action referencing it. */ tcf_chain_hold(chain); } else { Loading @@ -1860,7 +1871,7 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n, } } } else { if (!chain || tcf_chain_is_zombie(chain)) { if (!chain || tcf_chain_held_by_acts_only(chain)) { NL_SET_ERR_MSG(extack, "Cannot find specified filter chain"); return -EINVAL; } Loading Loading @@ -1988,7 +1999,7 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb) index++; continue; } if (tcf_chain_is_zombie(chain)) if (tcf_chain_held_by_acts_only(chain)) continue; err = tc_chain_fill_node(chain, net, skb, block, NETLINK_CB(cb->skb).portid, Loading Loading
include/net/pkt_cls.h +0 −3 Original line number Diff line number Diff line Loading @@ -40,11 +40,8 @@ struct tcf_block_cb; bool tcf_queue_work(struct rcu_work *rwork, work_func_t func); #ifdef CONFIG_NET_CLS struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create); struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index); void tcf_chain_put(struct tcf_chain *chain); void tcf_chain_put_by_act(struct tcf_chain *chain); void tcf_block_netif_keep_dst(struct tcf_block *block); int tcf_block_get(struct tcf_block **p_block, Loading
net/sched/cls_api.c +62 −51 Original line number Diff line number Diff line Loading @@ -232,19 +232,6 @@ static void tcf_chain0_head_change(struct tcf_chain *chain, tcf_chain_head_change_item(item, tp_head); } static void tcf_chain_flush(struct tcf_chain *chain) { struct tcf_proto *tp = rtnl_dereference(chain->filter_chain); tcf_chain0_head_change(chain, NULL); while (tp) { RCU_INIT_POINTER(chain->filter_chain, tp->next); tcf_proto_destroy(tp, NULL); tp = rtnl_dereference(chain->filter_chain); tcf_chain_put(chain); } } static void tcf_chain_destroy(struct tcf_chain *chain) { struct tcf_block *block = chain->block; Loading @@ -262,21 +249,10 @@ static void tcf_chain_hold(struct tcf_chain *chain) ++chain->refcnt; } static void tcf_chain_hold_by_act(struct tcf_chain *chain) { ++chain->action_refcnt; } static void tcf_chain_release_by_act(struct tcf_chain *chain) { --chain->action_refcnt; } static bool tcf_chain_is_zombie(struct tcf_chain *chain) static bool tcf_chain_held_by_acts_only(struct tcf_chain *chain) { /* In case all the references are action references, this * chain is a zombie and should not be listed in the chain * dump list. * chain should not be shown to the user. */ return chain->refcnt == chain->action_refcnt; } Loading @@ -296,52 +272,75 @@ static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block, static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb, u32 seq, u16 flags, int event, bool unicast); struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create) static struct tcf_chain *__tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create, bool by_act) { struct tcf_chain *chain = tcf_chain_lookup(block, chain_index); if (chain) { tcf_chain_hold(chain); return chain; } } else { if (!create) return NULL; chain = tcf_chain_create(block, chain_index); if (!chain) return NULL; } if (by_act) ++chain->action_refcnt; /* Send notification only in case we got the first * non-action reference. Until then, the chain acts only as * a placeholder for actions pointing to it and user ought * not know about them. */ if (chain->refcnt - chain->action_refcnt == 1 && !by_act) tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL, RTM_NEWCHAIN, false); return chain; } EXPORT_SYMBOL(tcf_chain_get); struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index) static struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create) { struct tcf_chain *chain = tcf_chain_get(block, chain_index, true); return __tcf_chain_get(block, chain_index, create, false); } tcf_chain_hold_by_act(chain); return chain; struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index) { return __tcf_chain_get(block, chain_index, true, true); } EXPORT_SYMBOL(tcf_chain_get_by_act); static void tc_chain_tmplt_del(struct tcf_chain *chain); void tcf_chain_put(struct tcf_chain *chain) static void __tcf_chain_put(struct tcf_chain *chain, bool by_act) { if (--chain->refcnt == 0) { if (by_act) chain->action_refcnt--; chain->refcnt--; /* The last dropped non-action reference will trigger notification. */ if (chain->refcnt - chain->action_refcnt == 0 && !by_act) tc_chain_notify(chain, NULL, 0, 0, RTM_DELCHAIN, false); if (chain->refcnt == 0) { tc_chain_tmplt_del(chain); tcf_chain_destroy(chain); } } EXPORT_SYMBOL(tcf_chain_put); static void tcf_chain_put(struct tcf_chain *chain) { __tcf_chain_put(chain, false); } void tcf_chain_put_by_act(struct tcf_chain *chain) { tcf_chain_release_by_act(chain); tcf_chain_put(chain); __tcf_chain_put(chain, true); } EXPORT_SYMBOL(tcf_chain_put_by_act); Loading @@ -351,6 +350,19 @@ static void tcf_chain_put_explicitly_created(struct tcf_chain *chain) tcf_chain_put(chain); } static void tcf_chain_flush(struct tcf_chain *chain) { struct tcf_proto *tp = rtnl_dereference(chain->filter_chain); tcf_chain0_head_change(chain, NULL); while (tp) { RCU_INIT_POINTER(chain->filter_chain, tp->next); tcf_proto_destroy(tp, NULL); tp = rtnl_dereference(chain->filter_chain); tcf_chain_put(chain); } } static bool tcf_block_offload_in_use(struct tcf_block *block) { return block->offloadcnt; Loading Loading @@ -1838,10 +1850,9 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n, chain = tcf_chain_lookup(block, chain_index); if (n->nlmsg_type == RTM_NEWCHAIN) { if (chain) { if (tcf_chain_is_zombie(chain)) { if (tcf_chain_held_by_acts_only(chain)) { /* The chain exists only because there is * some action referencing it, meaning it * is a zombie. * some action referencing it. */ tcf_chain_hold(chain); } else { Loading @@ -1860,7 +1871,7 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n, } } } else { if (!chain || tcf_chain_is_zombie(chain)) { if (!chain || tcf_chain_held_by_acts_only(chain)) { NL_SET_ERR_MSG(extack, "Cannot find specified filter chain"); return -EINVAL; } Loading Loading @@ -1988,7 +1999,7 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb) index++; continue; } if (tcf_chain_is_zombie(chain)) if (tcf_chain_held_by_acts_only(chain)) continue; err = tc_chain_fill_node(chain, net, skb, block, NETLINK_CB(cb->skb).portid, Loading