net/sched: cls_api: Fix lockup on flushing explicitly created chain
[ Upstream commit c9a82bec02c339cdda99b37c5e62b3b71fc4209c ]
Mingshuai Ren reports:
When a new chain is added by using tc, one soft lockup alarm will be
generated after delete the prio 0 filter of the chain. To reproduce
the problem, perform the following steps:
(1) tc qdisc add dev eth0 root handle 1: htb default 1
(2) tc chain add dev eth0
(3) tc filter del dev eth0 chain 0 parent 1: prio 0
(4) tc filter add dev eth0 chain 0 parent 1:
Fix the issue by accounting for additional reference to chains that are
explicitly created by RTM_NEWCHAIN message as opposed to implicitly by
RTM_NEWTFILTER message.
Fixes: 726d061286
("net: sched: prevent insertion of new classifiers during chain flush")
Reported-by: Mingshuai Ren <renmingshuai@huawei.com>
Closes: https://lore.kernel.org/lkml/87legswvi3.fsf@nvidia.com/T/
Signed-off-by: Vlad Buslov <vladbu@nvidia.com>
Link: https://lore.kernel.org/r/20230612093426.2867183-1-vladbu@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
0456f470fa
commit
ec694ad393
@ -518,8 +518,8 @@ static void __tcf_chain_put(struct tcf_chain *chain, bool by_act,
|
||||
{
|
||||
struct tcf_block *block = chain->block;
|
||||
const struct tcf_proto_ops *tmplt_ops;
|
||||
unsigned int refcnt, non_act_refcnt;
|
||||
bool free_block = false;
|
||||
unsigned int refcnt;
|
||||
void *tmplt_priv;
|
||||
|
||||
mutex_lock(&block->lock);
|
||||
@ -539,13 +539,15 @@ static void __tcf_chain_put(struct tcf_chain *chain, bool by_act,
|
||||
* save these to temporary variables.
|
||||
*/
|
||||
refcnt = --chain->refcnt;
|
||||
non_act_refcnt = refcnt - chain->action_refcnt;
|
||||
tmplt_ops = chain->tmplt_ops;
|
||||
tmplt_priv = chain->tmplt_priv;
|
||||
|
||||
/* The last dropped non-action reference will trigger notification. */
|
||||
if (refcnt - chain->action_refcnt == 0 && !by_act) {
|
||||
tc_chain_notify_delete(tmplt_ops, tmplt_priv, chain->index,
|
||||
block, NULL, 0, 0, false);
|
||||
if (non_act_refcnt == chain->explicitly_created && !by_act) {
|
||||
if (non_act_refcnt == 0)
|
||||
tc_chain_notify_delete(tmplt_ops, tmplt_priv,
|
||||
chain->index, block, NULL, 0, 0,
|
||||
false);
|
||||
/* Last reference to chain, no need to lock. */
|
||||
chain->flushing = false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user