Skip to content

Commit f71e0ca

Browse files
jpirkodavem330
authored andcommitted
net: sched: Avoid implicit chain 0 creation
Currently, chain 0 is implicitly created during block creation. However that does not align with chain object exposure, creation and destruction api introduced later on. So make the chain 0 behave the same way as any other chain and only create it when it is needed. Since chain 0 is somehow special as the qdiscs need to hold pointer to the first chain tp, this requires to move the chain head change callback infra to the block structure. Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f34e8bf commit f71e0ca

File tree

2 files changed

+43
-48
lines changed

2 files changed

+43
-48
lines changed

include/net/sch_generic.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,6 @@ typedef void tcf_chain_head_change_t(struct tcf_proto *tp_head, void *priv);
300300

301301
struct tcf_chain {
302302
struct tcf_proto __rcu *filter_chain;
303-
struct list_head filter_chain_list;
304303
struct list_head list;
305304
struct tcf_block *block;
306305
u32 index; /* chain index */
@@ -318,6 +317,10 @@ struct tcf_block {
318317
bool keep_dst;
319318
unsigned int offloadcnt; /* Number of oddloaded filters */
320319
unsigned int nooffloaddevcnt; /* Number of devs unable to do offload */
320+
struct {
321+
struct tcf_chain *chain;
322+
struct list_head filter_chain_list;
323+
} chain0;
321324
};
322325

323326
static inline void tcf_block_offload_inc(struct tcf_block *block, u32 *flags)

net/sched/cls_api.c

Lines changed: 39 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,12 @@ static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
204204
chain = kzalloc(sizeof(*chain), GFP_KERNEL);
205205
if (!chain)
206206
return NULL;
207-
INIT_LIST_HEAD(&chain->filter_chain_list);
208207
list_add_tail(&chain->list, &block->chain_list);
209208
chain->block = block;
210209
chain->index = chain_index;
211210
chain->refcnt = 1;
211+
if (!chain->index)
212+
block->chain0.chain = chain;
212213
return chain;
213214
}
214215

@@ -218,20 +219,24 @@ static void tcf_chain_head_change_item(struct tcf_filter_chain_list_item *item,
218219
if (item->chain_head_change)
219220
item->chain_head_change(tp_head, item->chain_head_change_priv);
220221
}
221-
static void tcf_chain_head_change(struct tcf_chain *chain,
222-
struct tcf_proto *tp_head)
222+
223+
static void tcf_chain0_head_change(struct tcf_chain *chain,
224+
struct tcf_proto *tp_head)
223225
{
224226
struct tcf_filter_chain_list_item *item;
227+
struct tcf_block *block = chain->block;
225228

226-
list_for_each_entry(item, &chain->filter_chain_list, list)
229+
if (chain->index)
230+
return;
231+
list_for_each_entry(item, &block->chain0.filter_chain_list, list)
227232
tcf_chain_head_change_item(item, tp_head);
228233
}
229234

230235
static void tcf_chain_flush(struct tcf_chain *chain)
231236
{
232237
struct tcf_proto *tp = rtnl_dereference(chain->filter_chain);
233238

234-
tcf_chain_head_change(chain, NULL);
239+
tcf_chain0_head_change(chain, NULL);
235240
while (tp) {
236241
RCU_INIT_POINTER(chain->filter_chain, tp->next);
237242
tcf_proto_destroy(tp, NULL);
@@ -245,8 +250,10 @@ static void tcf_chain_destroy(struct tcf_chain *chain)
245250
struct tcf_block *block = chain->block;
246251

247252
list_del(&chain->list);
253+
if (!chain->index)
254+
block->chain0.chain = NULL;
248255
kfree(chain);
249-
if (list_empty(&block->chain_list))
256+
if (list_empty(&block->chain_list) && block->refcnt == 0)
250257
kfree(block);
251258
}
252259

@@ -346,10 +353,11 @@ static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
346353
}
347354

348355
static int
349-
tcf_chain_head_change_cb_add(struct tcf_chain *chain,
350-
struct tcf_block_ext_info *ei,
351-
struct netlink_ext_ack *extack)
356+
tcf_chain0_head_change_cb_add(struct tcf_block *block,
357+
struct tcf_block_ext_info *ei,
358+
struct netlink_ext_ack *extack)
352359
{
360+
struct tcf_chain *chain0 = block->chain0.chain;
353361
struct tcf_filter_chain_list_item *item;
354362

355363
item = kmalloc(sizeof(*item), GFP_KERNEL);
@@ -359,23 +367,25 @@ tcf_chain_head_change_cb_add(struct tcf_chain *chain,
359367
}
360368
item->chain_head_change = ei->chain_head_change;
361369
item->chain_head_change_priv = ei->chain_head_change_priv;
362-
if (chain->filter_chain)
363-
tcf_chain_head_change_item(item, chain->filter_chain);
364-
list_add(&item->list, &chain->filter_chain_list);
370+
if (chain0 && chain0->filter_chain)
371+
tcf_chain_head_change_item(item, chain0->filter_chain);
372+
list_add(&item->list, &block->chain0.filter_chain_list);
365373
return 0;
366374
}
367375

368376
static void
369-
tcf_chain_head_change_cb_del(struct tcf_chain *chain,
370-
struct tcf_block_ext_info *ei)
377+
tcf_chain0_head_change_cb_del(struct tcf_block *block,
378+
struct tcf_block_ext_info *ei)
371379
{
380+
struct tcf_chain *chain0 = block->chain0.chain;
372381
struct tcf_filter_chain_list_item *item;
373382

374-
list_for_each_entry(item, &chain->filter_chain_list, list) {
383+
list_for_each_entry(item, &block->chain0.filter_chain_list, list) {
375384
if ((!ei->chain_head_change && !ei->chain_head_change_priv) ||
376385
(item->chain_head_change == ei->chain_head_change &&
377386
item->chain_head_change_priv == ei->chain_head_change_priv)) {
378-
tcf_chain_head_change_item(item, NULL);
387+
if (chain0)
388+
tcf_chain_head_change_item(item, NULL);
379389
list_del(&item->list);
380390
kfree(item);
381391
return;
@@ -411,8 +421,6 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
411421
struct netlink_ext_ack *extack)
412422
{
413423
struct tcf_block *block;
414-
struct tcf_chain *chain;
415-
int err;
416424

417425
block = kzalloc(sizeof(*block), GFP_KERNEL);
418426
if (!block) {
@@ -422,14 +430,8 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
422430
INIT_LIST_HEAD(&block->chain_list);
423431
INIT_LIST_HEAD(&block->cb_list);
424432
INIT_LIST_HEAD(&block->owner_list);
433+
INIT_LIST_HEAD(&block->chain0.filter_chain_list);
425434

426-
/* Create chain 0 by default, it has to be always present. */
427-
chain = tcf_chain_create(block, 0);
428-
if (!chain) {
429-
NL_SET_ERR_MSG(extack, "Failed to create new tcf chain");
430-
err = -ENOMEM;
431-
goto err_chain_create;
432-
}
433435
block->refcnt = 1;
434436
block->net = net;
435437
block->index = block_index;
@@ -438,10 +440,6 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
438440
if (!tcf_block_shared(block))
439441
block->q = q;
440442
return block;
441-
442-
err_chain_create:
443-
kfree(block);
444-
return ERR_PTR(err);
445443
}
446444

447445
static struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index)
@@ -523,11 +521,6 @@ static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q,
523521
return block;
524522
}
525523

526-
static struct tcf_chain *tcf_block_chain_zero(struct tcf_block *block)
527-
{
528-
return list_first_entry(&block->chain_list, struct tcf_chain, list);
529-
}
530-
531524
struct tcf_block_owner_item {
532525
struct list_head list;
533526
struct Qdisc *q;
@@ -621,10 +614,9 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
621614

622615
tcf_block_owner_netif_keep_dst(block, q, ei->binder_type);
623616

624-
err = tcf_chain_head_change_cb_add(tcf_block_chain_zero(block),
625-
ei, extack);
617+
err = tcf_chain0_head_change_cb_add(block, ei, extack);
626618
if (err)
627-
goto err_chain_head_change_cb_add;
619+
goto err_chain0_head_change_cb_add;
628620

629621
err = tcf_block_offload_bind(block, q, ei, extack);
630622
if (err)
@@ -634,15 +626,14 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
634626
return 0;
635627

636628
err_block_offload_bind:
637-
tcf_chain_head_change_cb_del(tcf_block_chain_zero(block), ei);
638-
err_chain_head_change_cb_add:
629+
tcf_chain0_head_change_cb_del(block, ei);
630+
err_chain0_head_change_cb_add:
639631
tcf_block_owner_del(block, q, ei->binder_type);
640632
err_block_owner_add:
641633
if (created) {
642634
if (tcf_block_shared(block))
643635
tcf_block_remove(block, net);
644636
err_block_insert:
645-
kfree(tcf_block_chain_zero(block));
646637
kfree(block);
647638
} else {
648639
block->refcnt--;
@@ -682,10 +673,10 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
682673

683674
if (!block)
684675
return;
685-
tcf_chain_head_change_cb_del(tcf_block_chain_zero(block), ei);
676+
tcf_chain0_head_change_cb_del(block, ei);
686677
tcf_block_owner_del(block, q, ei->binder_type);
687678

688-
if (--block->refcnt == 0) {
679+
if (block->refcnt == 1) {
689680
if (tcf_block_shared(block))
690681
tcf_block_remove(block, block->net);
691682

@@ -701,13 +692,14 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
701692

702693
tcf_block_offload_unbind(block, q, ei);
703694

704-
if (block->refcnt == 0) {
695+
if (block->refcnt == 1) {
705696
/* At this point, all the chains should have refcnt >= 1. */
706697
list_for_each_entry_safe(chain, tmp, &block->chain_list, list)
707698
tcf_chain_put(chain);
708699

709-
/* Finally, put chain 0 and allow block to be freed. */
710-
tcf_chain_put(tcf_block_chain_zero(block));
700+
block->refcnt--;
701+
if (list_empty(&block->chain_list))
702+
kfree(block);
711703
}
712704
}
713705
EXPORT_SYMBOL(tcf_block_put_ext);
@@ -947,7 +939,7 @@ static void tcf_chain_tp_insert(struct tcf_chain *chain,
947939
struct tcf_proto *tp)
948940
{
949941
if (*chain_info->pprev == chain->filter_chain)
950-
tcf_chain_head_change(chain, tp);
942+
tcf_chain0_head_change(chain, tp);
951943
RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain_info));
952944
rcu_assign_pointer(*chain_info->pprev, tp);
953945
tcf_chain_hold(chain);
@@ -960,7 +952,7 @@ static void tcf_chain_tp_remove(struct tcf_chain *chain,
960952
struct tcf_proto *next = rtnl_dereference(chain_info->next);
961953

962954
if (tp == chain->filter_chain)
963-
tcf_chain_head_change(chain, next);
955+
tcf_chain0_head_change(chain, next);
964956
RCU_INIT_POINTER(*chain_info->pprev, next);
965957
tcf_chain_put(chain);
966958
}

0 commit comments

Comments
 (0)