Commit e474619a2498c57f7f0ed8b4abb29d6c62e2393b

Authored by Vlad Buslov
Committed by David S. Miller
1 parent 31f1a0e37c

net: sched: flower: don't check for rtnl on head dereference

Flower classifier only changes root pointer during init and destroy. Cls
API implements reference counting for tcf_proto, so there is no danger of
concurrent access to tp when it is being destroyed, even without protection
provided by rtnl lock.

Implement new function fl_head_dereference() to dereference tp->root
without checking for rtnl lock. Use it in all flower function that obtain
head pointer instead of rtnl_dereference().

Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 17 additions and 7 deletions Side-by-side Diff

net/sched/cls_flower.c
... ... @@ -437,10 +437,20 @@
437 437 cls_flower.stats.lastused);
438 438 }
439 439  
  440 +static struct cls_fl_head *fl_head_dereference(struct tcf_proto *tp)
  441 +{
  442 + /* Flower classifier only changes root pointer during init and destroy.
  443 + * Users must obtain reference to tcf_proto instance before calling its
  444 + * API, so tp->root pointer is protected from concurrent call to
  445 + * fl_destroy() by reference counting.
  446 + */
  447 + return rcu_dereference_raw(tp->root);
  448 +}
  449 +
440 450 static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
441 451 struct netlink_ext_ack *extack)
442 452 {
443   - struct cls_fl_head *head = rtnl_dereference(tp->root);
  453 + struct cls_fl_head *head = fl_head_dereference(tp);
444 454 bool async = tcf_exts_get_net(&f->exts);
445 455 bool last;
446 456  
... ... @@ -472,7 +482,7 @@
472 482 static void fl_destroy(struct tcf_proto *tp, bool rtnl_held,
473 483 struct netlink_ext_ack *extack)
474 484 {
475   - struct cls_fl_head *head = rtnl_dereference(tp->root);
  485 + struct cls_fl_head *head = fl_head_dereference(tp);
476 486 struct fl_flow_mask *mask, *next_mask;
477 487 struct cls_fl_filter *f, *next;
478 488  
... ... @@ -490,7 +500,7 @@
490 500  
491 501 static void *fl_get(struct tcf_proto *tp, u32 handle)
492 502 {
493   - struct cls_fl_head *head = rtnl_dereference(tp->root);
  503 + struct cls_fl_head *head = fl_head_dereference(tp);
494 504  
495 505 return idr_find(&head->handle_idr, handle);
496 506 }
... ... @@ -1308,7 +1318,7 @@
1308 1318 void **arg, bool ovr, bool rtnl_held,
1309 1319 struct netlink_ext_ack *extack)
1310 1320 {
1311   - struct cls_fl_head *head = rtnl_dereference(tp->root);
  1321 + struct cls_fl_head *head = fl_head_dereference(tp);
1312 1322 struct cls_fl_filter *fold = *arg;
1313 1323 struct cls_fl_filter *fnew;
1314 1324 struct fl_flow_mask *mask;
... ... @@ -1446,7 +1456,7 @@
1446 1456 static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
1447 1457 bool rtnl_held, struct netlink_ext_ack *extack)
1448 1458 {
1449   - struct cls_fl_head *head = rtnl_dereference(tp->root);
  1459 + struct cls_fl_head *head = fl_head_dereference(tp);
1450 1460 struct cls_fl_filter *f = arg;
1451 1461  
1452 1462 rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
... ... @@ -1459,7 +1469,7 @@
1459 1469 static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
1460 1470 bool rtnl_held)
1461 1471 {
1462   - struct cls_fl_head *head = rtnl_dereference(tp->root);
  1472 + struct cls_fl_head *head = fl_head_dereference(tp);
1463 1473 struct cls_fl_filter *f;
1464 1474  
1465 1475 arg->count = arg->skip;
... ... @@ -1478,7 +1488,7 @@
1478 1488 static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
1479 1489 void *cb_priv, struct netlink_ext_ack *extack)
1480 1490 {
1481   - struct cls_fl_head *head = rtnl_dereference(tp->root);
  1491 + struct cls_fl_head *head = fl_head_dereference(tp);
1482 1492 struct tc_cls_flower_offload cls_flower = {};
1483 1493 struct tcf_block *block = tp->chain->block;
1484 1494 struct fl_flow_mask *mask;