gen estimator has been rewritten in commit 1c0d32fde5bd ("net_sched: gen_estimator: complete rewrite of rate estimators"), the caller is no longer needed to wait for a grace period. So this patch gets rid of it. This also completely closes a race condition between action free path and filter chain add/remove path for the following patch. Because otherwise the nested RCU callback can't be caught by rcu_barrier(). Please see also the comments in code.
Unified · Split
| @@ -34,7 +34,6 @@ struct tc_action { · 33 unmodified lines | ||
| 34 | 34 | struct gnet_stats_queue tcfa_qstats; |
| 35 | 35 | struct net_rate_estimator __rcu *tcfa_rate_est; |
| 36 | 36 | spinlock_t tcfa_lock; |
| 37 | − struct rcu_head tcfa_rcu; | |
| 38 | 37 | struct gnet_stats_basic_cpu __percpu *cpu_bstats; |
| 39 | 38 | struct gnet_stats_queue __percpu *cpu_qstats; |
| 40 | 39 | struct tc_cookie *act_cookie; |
| @@ -50,7 +49,6 @@ struct tc_action { · 9 unmodified lines | ||
| 50 | 49 | #define tcf_qstats common.tcfa_qstats |
| 51 | 50 | #define tcf_rate_est common.tcfa_rate_est |
| 52 | 51 | #define tcf_lock common.tcfa_lock |
| 53 | −#define tcf_rcu common.tcfa_rcu | |
| 54 | 52 | |
| 55 | 53 | /* Update lastuse only if needed, to avoid dirtying a cache line. |
| 56 | 54 | * We use a temp variable to avoid fetching jiffies twice. |
| @@ -53,10 +53,13 @@ static void tcf_action_goto_chain_exec(const struct tc_action *a, · 52 unmodified lines | ||
| 53 | 53 | res->goto_tp = rcu_dereference_bh(chain->filter_chain); |
| 54 | 54 | } |
| 55 | 55 | |
| 56 | −static void free_tcf(struct rcu_head *head) | |
| 56 | +/* XXX: For standalone actions, we don't need a RCU grace period either, because | |
| 57 | + * actions are always connected to filters and filters are already destroyed in | |
| 58 | + * RCU callbacks, so after a RCU grace period actions are already disconnected | |
| 59 | + * from filters. Readers later can not find us. | |
| 60 | + */ | |
| 61 | +static void free_tcf(struct tc_action *p) | |
| 57 | 62 | { |
| 58 | − struct tc_action *p = container_of(head, struct tc_action, tcfa_rcu); | |
| 59 | − | |
| 60 | 63 | free_percpu(p->cpu_bstats); |
| 61 | 64 | free_percpu(p->cpu_qstats); |
| 62 | 65 | |
| @@ -76,11 +79,7 @@ static void tcf_idr_remove(struct tcf_idrinfo *idrinfo, struct tc_action *p) · 13 unmodified lines | ||
| 76 | 79 | idr_remove_ext(&idrinfo->action_idr, p->tcfa_index); |
| 77 | 80 | spin_unlock_bh(&idrinfo->lock); |
| 78 | 81 | gen_kill_estimator(&p->tcfa_rate_est); |
| 79 | − /* | |
| 80 | − * gen_estimator est_timer() might access p->tcfa_lock | |
| 81 | − * or bstats, wait a RCU grace period before freeing p | |
| 82 | − */ | |
| 83 | − call_rcu(&p->tcfa_rcu, free_tcf); | |
| 82 | + free_tcf(p); | |
| 84 | 83 | } |
| 85 | 84 | |
| 86 | 85 | int __tcf_idr_release(struct tc_action *p, bool bind, bool strict) |
| @@ -259,7 +258,7 @@ void tcf_idr_cleanup(struct tc_action *a, struct nlattr *est) · 172 unmodified lines | ||
| 259 | 258 | { |
| 260 | 259 | if (est) |
| 261 | 260 | gen_kill_estimator(&a->tcfa_rate_est); |
| 262 | − call_rcu(&a->tcfa_rcu, free_tcf); | |
| 261 | + free_tcf(a); | |
| 263 | 262 | } |
| 264 | 263 | EXPORT_SYMBOL(tcf_idr_cleanup); |
| 265 | 264 | |