diff options
Diffstat (limited to 'net/sched/act_police.c')
| -rw-r--r-- | net/sched/act_police.c | 12 | 
1 files changed, 11 insertions, 1 deletions
diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 654f73dff7c..537a48732e9 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -97,6 +97,11 @@ nla_put_failure:  	goto done;  } +static void tcf_police_free_rcu(struct rcu_head *head) +{ +	kfree(container_of(head, struct tcf_police, tcf_rcu)); +} +  static void tcf_police_destroy(struct tcf_police *p)  {  	unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); @@ -113,7 +118,11 @@ static void tcf_police_destroy(struct tcf_police *p)  				qdisc_put_rtab(p->tcfp_R_tab);  			if (p->tcfp_P_tab)  				qdisc_put_rtab(p->tcfp_P_tab); -			kfree(p); +			/* +			 * gen_estimator est_timer() might access p->tcf_lock +			 * or bstats, wait a RCU grace period before freeing p +			 */ +			call_rcu(&p->tcf_rcu, tcf_police_free_rcu);  			return;  		}  	} @@ -397,6 +406,7 @@ static void __exit  police_cleanup_module(void)  {  	tcf_unregister_action(&act_police_ops); +	rcu_barrier(); /* Wait for completion of call_rcu()'s (tcf_police_free_rcu) */  }  module_init(police_init_module);  |