|
@@ -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);
|