Commit 99815f50 authored by Vlad Buslov's avatar Vlad Buslov Committed by David S. Miller

net: sched: flower: don't call synchronize_rcu() on mask creation

Current flower mask creating code assumes that temporary mask that is used
when inserting new filter is stack allocated. To prevent race condition
with data patch synchronize_rcu() is called every time fl_create_new_mask()
replaces temporary stack allocated mask. As reported by Jiri, this
increases runtime of creating 20000 flower classifiers from 4 seconds to
163 seconds. However, this design is no longer necessary since temporary
mask was converted to be dynamically allocated by commit 2cddd201
("net/sched: cls_flower: allocate mask dynamically in fl_change()").

Remove synchronize_rcu() calls from mask creation code. Instead, refactor
fl_change() to always deallocate temporary mask with rcu grace period.

Fixes: 195c234d ("net: sched: flower: handle concurrent mask insertion")
Reported-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarVlad Buslov <vladbu@mellanox.com>
Tested-by: default avatarJiri Pirko <jiri@mellanox.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f0c03ee0
...@@ -320,10 +320,13 @@ static int fl_init(struct tcf_proto *tp) ...@@ -320,10 +320,13 @@ static int fl_init(struct tcf_proto *tp)
return rhashtable_init(&head->ht, &mask_ht_params); return rhashtable_init(&head->ht, &mask_ht_params);
} }
static void fl_mask_free(struct fl_flow_mask *mask) static void fl_mask_free(struct fl_flow_mask *mask, bool mask_init_done)
{ {
WARN_ON(!list_empty(&mask->filters)); /* temporary masks don't have their filters list and ht initialized */
rhashtable_destroy(&mask->ht); if (mask_init_done) {
WARN_ON(!list_empty(&mask->filters));
rhashtable_destroy(&mask->ht);
}
kfree(mask); kfree(mask);
} }
...@@ -332,7 +335,15 @@ static void fl_mask_free_work(struct work_struct *work) ...@@ -332,7 +335,15 @@ static void fl_mask_free_work(struct work_struct *work)
struct fl_flow_mask *mask = container_of(to_rcu_work(work), struct fl_flow_mask *mask = container_of(to_rcu_work(work),
struct fl_flow_mask, rwork); struct fl_flow_mask, rwork);
fl_mask_free(mask); fl_mask_free(mask, true);
}
static void fl_uninit_mask_free_work(struct work_struct *work)
{
struct fl_flow_mask *mask = container_of(to_rcu_work(work),
struct fl_flow_mask, rwork);
fl_mask_free(mask, false);
} }
static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask) static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask)
...@@ -1346,9 +1357,6 @@ static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head, ...@@ -1346,9 +1357,6 @@ static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
if (err) if (err)
goto errout_destroy; goto errout_destroy;
/* Wait until any potential concurrent users of mask are finished */
synchronize_rcu();
spin_lock(&head->masks_lock); spin_lock(&head->masks_lock);
list_add_tail_rcu(&newmask->list, &head->masks); list_add_tail_rcu(&newmask->list, &head->masks);
spin_unlock(&head->masks_lock); spin_unlock(&head->masks_lock);
...@@ -1375,11 +1383,7 @@ static int fl_check_assign_mask(struct cls_fl_head *head, ...@@ -1375,11 +1383,7 @@ static int fl_check_assign_mask(struct cls_fl_head *head,
/* Insert mask as temporary node to prevent concurrent creation of mask /* Insert mask as temporary node to prevent concurrent creation of mask
* with same key. Any concurrent lookups with same key will return * with same key. Any concurrent lookups with same key will return
* -EAGAIN because mask's refcnt is zero. It is safe to insert * -EAGAIN because mask's refcnt is zero.
* stack-allocated 'mask' to masks hash table because we call
* synchronize_rcu() before returning from this function (either in case
* of error or after replacing it with heap-allocated mask in
* fl_create_new_mask()).
*/ */
fnew->mask = rhashtable_lookup_get_insert_fast(&head->ht, fnew->mask = rhashtable_lookup_get_insert_fast(&head->ht,
&mask->ht_node, &mask->ht_node,
...@@ -1414,8 +1418,6 @@ static int fl_check_assign_mask(struct cls_fl_head *head, ...@@ -1414,8 +1418,6 @@ static int fl_check_assign_mask(struct cls_fl_head *head,
errout_cleanup: errout_cleanup:
rhashtable_remove_fast(&head->ht, &mask->ht_node, rhashtable_remove_fast(&head->ht, &mask->ht_node,
mask_ht_params); mask_ht_params);
/* Wait until any potential concurrent users of mask are finished */
synchronize_rcu();
return ret; return ret;
} }
...@@ -1644,7 +1646,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, ...@@ -1644,7 +1646,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
*arg = fnew; *arg = fnew;
kfree(tb); kfree(tb);
kfree(mask); tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work);
return 0; return 0;
errout_ht: errout_ht:
...@@ -1664,7 +1666,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, ...@@ -1664,7 +1666,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
errout_tb: errout_tb:
kfree(tb); kfree(tb);
errout_mask_alloc: errout_mask_alloc:
kfree(mask); tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work);
errout_fold: errout_fold:
if (fold) if (fold)
__fl_put(fold); __fl_put(fold);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment