summaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2015-08-26 01:38:12 +0200
committerDavid S. Miller <davem@davemloft.net>2015-08-26 02:02:48 +0200
commita6c1aea044e490da3e59124ec55991fe316818d5 (patch)
tree80260a1e1e08d619e508574bc5ef407755b3ab15 /net/sched
parentnet: fec: use reinit_completion() in mdio accessor functions (diff)
downloadlinux-a6c1aea044e490da3e59124ec55991fe316818d5.tar.xz
linux-a6c1aea044e490da3e59124ec55991fe316818d5.zip
cls_u32: complete the check for non-forced case in u32_destroy()
In commit 1e052be69d04 ("net_sched: destroy proto tp when all filters are gone") I added a check in u32_destroy() to see if all real filters are gone for each tp, however, that is only done for root_ht, same is needed for others. This can be reproduced by the following tc commands: tc filter add dev eth0 parent 1:0 prio 5 handle 15: protocol ip u32 divisor 256 tc filter add dev eth0 protocol ip parent 1: prio 5 handle 15:2:2 u32 ht 15:2: match ip src 10.0.0.2 flowid 1:10 tc filter add dev eth0 protocol ip parent 1: prio 5 handle 15:2:3 u32 ht 15:2: match ip src 10.0.0.3 flowid 1:10 Fixes: 1e052be69d04 ("net_sched: destroy proto tp when all filters are gone") Reported-by: Akshat Kakkar <akshat.1984@gmail.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: Cong Wang <cwang@twopensource.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/cls_u32.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index cab9e9b43967..4fbb67430ce4 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -490,6 +490,19 @@ static bool u32_destroy(struct tcf_proto *tp, bool force)
return false;
}
}
+
+ if (tp_c->refcnt > 1)
+ return false;
+
+ if (tp_c->refcnt == 1) {
+ struct tc_u_hnode *ht;
+
+ for (ht = rtnl_dereference(tp_c->hlist);
+ ht;
+ ht = rtnl_dereference(ht->next))
+ if (!ht_empty(ht))
+ return false;
+ }
}
if (root_ht && --root_ht->refcnt == 0)