Skip to content

Commit efbf789

Browse files
congwangdavem330
authored andcommitted
net_sched: get rid of rcu_barrier() in tcf_block_put_ext()
Both Eric and Paolo noticed the rcu_barrier() we use in tcf_block_put_ext() could be a performance bottleneck when we have a lot of tc classes. Paolo provided the following to demonstrate the issue: tc qdisc add dev lo root htb for I in `seq 1 1000`; do tc class add dev lo parent 1: classid 1:$I htb rate 100kbit tc qdisc add dev lo parent 1:$I handle $((I + 1)): htb for J in `seq 1 10`; do tc filter add dev lo parent $((I + 1)): u32 match ip src 1.1.1.$J done done time tc qdisc del dev root real 0m54.764s user 0m0.023s sys 0m0.000s The rcu_barrier() there is to ensure we free the block after all chains are gone, that is, to queue tcf_block_put_final() at the tail of workqueue. We can achieve this ordering requirement by refcnt'ing tcf block instead, that is, the tcf block is freed only when the last chain in this block is gone. This also simplifies the code. Paolo reported after this patch we get: real 0m0.017s user 0m0.000s sys 0m0.017s Tested-by: Paolo Abeni <[email protected]> Cc: Eric Dumazet <[email protected]> Cc: Jiri Pirko <[email protected]> Cc: Jamal Hadi Salim <[email protected]> Signed-off-by: Cong Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3e394ef commit efbf789

File tree

2 files changed

+9
-22
lines changed

2 files changed

+9
-22
lines changed

include/net/sch_generic.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,6 @@ struct tcf_block {
278278
struct net *net;
279279
struct Qdisc *q;
280280
struct list_head cb_list;
281-
struct work_struct work;
282281
};
283282

284283
static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)

net/sched/cls_api.c

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,12 @@ static void tcf_chain_flush(struct tcf_chain *chain)
218218

219219
static void tcf_chain_destroy(struct tcf_chain *chain)
220220
{
221+
struct tcf_block *block = chain->block;
222+
221223
list_del(&chain->list);
222224
kfree(chain);
225+
if (list_empty(&block->chain_list))
226+
kfree(block);
223227
}
224228

225229
static void tcf_chain_hold(struct tcf_chain *chain)
@@ -330,27 +334,13 @@ int tcf_block_get(struct tcf_block **p_block,
330334
}
331335
EXPORT_SYMBOL(tcf_block_get);
332336

333-
static void tcf_block_put_final(struct work_struct *work)
334-
{
335-
struct tcf_block *block = container_of(work, struct tcf_block, work);
336-
struct tcf_chain *chain, *tmp;
337-
338-
rtnl_lock();
339-
340-
/* At this point, all the chains should have refcnt == 1. */
341-
list_for_each_entry_safe(chain, tmp, &block->chain_list, list)
342-
tcf_chain_put(chain);
343-
rtnl_unlock();
344-
kfree(block);
345-
}
346-
347337
/* XXX: Standalone actions are not allowed to jump to any chain, and bound
348338
* actions should be all removed after flushing.
349339
*/
350340
void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
351341
struct tcf_block_ext_info *ei)
352342
{
353-
struct tcf_chain *chain;
343+
struct tcf_chain *chain, *tmp;
354344

355345
/* Hold a refcnt for all chains, except 0, so that they don't disappear
356346
* while we are iterating.
@@ -364,13 +354,11 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
364354

365355
tcf_block_offload_unbind(block, q, ei);
366356

367-
INIT_WORK(&block->work, tcf_block_put_final);
368-
/* Wait for existing RCU callbacks to cool down, make sure their works
369-
* have been queued before this. We can not flush pending works here
370-
* because we are holding the RTNL lock.
357+
/* At this point, all the chains should have refcnt >= 1. Block will be
358+
* freed after all chains are gone.
371359
*/
372-
rcu_barrier();
373-
tcf_queue_work(&block->work);
360+
list_for_each_entry_safe(chain, tmp, &block->chain_list, list)
361+
tcf_chain_put(chain);
374362
}
375363
EXPORT_SYMBOL(tcf_block_put_ext);
376364

0 commit comments

Comments
 (0)