aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/act_police.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/act_police.c')
-rw-r--r--net/sched/act_police.c45
1 files changed, 18 insertions, 27 deletions
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index f201576d25c2..0cc305e7e469 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -60,18 +60,19 @@ struct tc_police_compat {
60static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb, 60static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb,
61 int type, struct tc_action *a) 61 int type, struct tc_action *a)
62{ 62{
63 struct hlist_head *head;
63 struct tcf_common *p; 64 struct tcf_common *p;
64 int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; 65 int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
65 struct nlattr *nest; 66 struct nlattr *nest;
66 67
67 read_lock_bh(&police_hash_info.lock); 68 spin_lock_bh(&police_hash_info.lock);
68 69
69 s_i = cb->args[0]; 70 s_i = cb->args[0];
70 71
71 for (i = 0; i < (POL_TAB_MASK + 1); i++) { 72 for (i = 0; i < (POL_TAB_MASK + 1); i++) {
72 p = police_hash_info.htab[tcf_hash(i, POL_TAB_MASK)]; 73 head = &police_hash_info.htab[tcf_hash(i, POL_TAB_MASK)];
73 74
74 for (; p; p = p->tcfc_next) { 75 hlist_for_each_entry_rcu(p, head, tcfc_head) {
75 index++; 76 index++;
76 if (index < s_i) 77 if (index < s_i)
77 continue; 78 continue;
@@ -94,7 +95,7 @@ static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *c
94 } 95 }
95 } 96 }
96done: 97done:
97 read_unlock_bh(&police_hash_info.lock); 98 spin_unlock_bh(&police_hash_info.lock);
98 if (n_i) 99 if (n_i)
99 cb->args[0] += n_i; 100 cb->args[0] += n_i;
100 return n_i; 101 return n_i;
@@ -106,25 +107,16 @@ nla_put_failure:
106 107
107static void tcf_police_destroy(struct tcf_police *p) 108static void tcf_police_destroy(struct tcf_police *p)
108{ 109{
109 unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); 110 spin_lock_bh(&police_hash_info.lock);
110 struct tcf_common **p1p; 111 hlist_del(&p->tcf_head);
111 112 spin_unlock_bh(&police_hash_info.lock);
112 for (p1p = &police_hash_info.htab[h]; *p1p; p1p = &(*p1p)->tcfc_next) { 113 gen_kill_estimator(&p->tcf_bstats,
113 if (*p1p == &p->common) { 114 &p->tcf_rate_est);
114 write_lock_bh(&police_hash_info.lock); 115 /*
115 *p1p = p->tcf_next; 116 * gen_estimator est_timer() might access p->tcf_lock
116 write_unlock_bh(&police_hash_info.lock); 117 * or bstats, wait a RCU grace period before freeing p
117 gen_kill_estimator(&p->tcf_bstats, 118 */
118 &p->tcf_rate_est); 119 kfree_rcu(p, tcf_rcu);
119 /*
120 * gen_estimator est_timer() might access p->tcf_lock
121 * or bstats, wait a RCU grace period before freeing p
122 */
123 kfree_rcu(p, tcf_rcu);
124 return;
125 }
126 }
127 WARN_ON(1);
128} 120}
129 121
130static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = { 122static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = {
@@ -259,10 +251,9 @@ override:
259 police->tcf_index = parm->index ? parm->index : 251 police->tcf_index = parm->index ? parm->index :
260 tcf_hash_new_index(&police_idx_gen, &police_hash_info); 252 tcf_hash_new_index(&police_idx_gen, &police_hash_info);
261 h = tcf_hash(police->tcf_index, POL_TAB_MASK); 253 h = tcf_hash(police->tcf_index, POL_TAB_MASK);
262 write_lock_bh(&police_hash_info.lock); 254 spin_lock_bh(&police_hash_info.lock);
263 police->tcf_next = police_hash_info.htab[h]; 255 hlist_add_head(&police->tcf_head, &police_hash_info.htab[h]);
264 police_hash_info.htab[h] = &police->common; 256 spin_unlock_bh(&police_hash_info.lock);
265 write_unlock_bh(&police_hash_info.lock);
266 257
267 a->priv = police; 258 a->priv = police;
268 return ret; 259 return ret;