Commit f48ef4d5b083c9273d754246e2220d98f3aedd7d

Authored by Vlad Buslov
Committed by David S. Miller
1 parent b2552b8c40

net: sched: flower: add reference counter to flower mask

Extend fl_flow_mask structure with reference counter to allow parallel
modification without relying on rtnl lock. Use rcu read lock to safely
lookup mask and increment reference counter in order to accommodate
concurrent deletes.

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

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

net/sched/cls_flower.c
... ... @@ -76,6 +76,7 @@
76 76 struct list_head filters;
77 77 struct rcu_work rwork;
78 78 struct list_head list;
  79 + refcount_t refcnt;
79 80 };
80 81  
81 82 struct fl_flow_tmplt {
... ... @@ -320,6 +321,7 @@
320 321  
321 322 static void fl_mask_free(struct fl_flow_mask *mask)
322 323 {
  324 + WARN_ON(!list_empty(&mask->filters));
323 325 rhashtable_destroy(&mask->ht);
324 326 kfree(mask);
325 327 }
... ... @@ -335,7 +337,7 @@
335 337 static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask,
336 338 bool async)
337 339 {
338   - if (!list_empty(&mask->filters))
  340 + if (!refcount_dec_and_test(&mask->refcnt))
339 341 return false;
340 342  
341 343 rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params);
... ... @@ -1301,6 +1303,7 @@
1301 1303  
1302 1304 INIT_LIST_HEAD_RCU(&newmask->filters);
1303 1305  
  1306 + refcount_set(&newmask->refcnt, 1);
1304 1307 err = rhashtable_insert_fast(&head->ht, &newmask->ht_node,
1305 1308 mask_ht_params);
1306 1309 if (err)
1307 1310  
1308 1311  
... ... @@ -1324,9 +1327,13 @@
1324 1327 struct fl_flow_mask *mask)
1325 1328 {
1326 1329 struct fl_flow_mask *newmask;
  1330 + int ret = 0;
1327 1331  
  1332 + rcu_read_lock();
1328 1333 fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params);
1329 1334 if (!fnew->mask) {
  1335 + rcu_read_unlock();
  1336 +
1330 1337 if (fold)
1331 1338 return -EINVAL;
1332 1339  
1333 1340  
1334 1341  
... ... @@ -1335,11 +1342,15 @@
1335 1342 return PTR_ERR(newmask);
1336 1343  
1337 1344 fnew->mask = newmask;
  1345 + return 0;
1338 1346 } else if (fold && fold->mask != fnew->mask) {
1339   - return -EINVAL;
  1347 + ret = -EINVAL;
  1348 + } else if (!refcount_inc_not_zero(&fnew->mask->refcnt)) {
  1349 + /* Mask was deleted concurrently, try again */
  1350 + ret = -EAGAIN;
1340 1351 }
1341   -
1342   - return 0;
  1352 + rcu_read_unlock();
  1353 + return ret;
1343 1354 }
1344 1355  
1345 1356 static int fl_set_parms(struct net *net, struct tcf_proto *tp,
... ... @@ -1476,6 +1487,7 @@
1476 1487 list_replace_rcu(&fold->list, &fnew->list);
1477 1488 fold->deleted = true;
1478 1489  
  1490 + fl_mask_put(head, fold->mask, true);
1479 1491 if (!tc_skip_hw(fold->flags))
1480 1492 fl_hw_destroy_filter(tp, fold, NULL);
1481 1493 tcf_unbind_filter(tp, &fold->res);
... ... @@ -1525,7 +1537,7 @@
1525 1537 if (!tc_skip_hw(fnew->flags))
1526 1538 fl_hw_destroy_filter(tp, fnew, NULL);
1527 1539 errout_mask:
1528   - fl_mask_put(head, fnew->mask, false);
  1540 + fl_mask_put(head, fnew->mask, true);
1529 1541 errout:
1530 1542 tcf_exts_destroy(&fnew->exts);
1531 1543 kfree(fnew);