aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2013-12-15 23:15:09 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-18 12:52:07 -0500
commit89819dc01f4c5920783f561597a48d9d75220e9e (patch)
tree2c37980c3b2cc34fece254b4e15b8fb56a24cead
parent369ba56787d7469c0afda70bb9ff76ad5faaead5 (diff)
net_sched: convert tcf_hashinfo to hlist and use spinlock
So that we don't need to play with singly linked list, and since the code is not on hot path, we can use spinlock instead of rwlock. Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/act_api.h16
-rw-r--r--net/sched/act_api.c69
-rw-r--r--net/sched/act_police.c45
3 files changed, 58 insertions, 72 deletions
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 2b5ec5abfeb3..22418d1a8396 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -9,7 +9,7 @@
9#include <net/pkt_sched.h> 9#include <net/pkt_sched.h>
10 10
11struct tcf_common { 11struct tcf_common {
12 struct tcf_common *tcfc_next; 12 struct hlist_node tcfc_head;
13 u32 tcfc_index; 13 u32 tcfc_index;
14 int tcfc_refcnt; 14 int tcfc_refcnt;
15 int tcfc_bindcnt; 15 int tcfc_bindcnt;
@@ -22,7 +22,7 @@ struct tcf_common {
22 spinlock_t tcfc_lock; 22 spinlock_t tcfc_lock;
23 struct rcu_head tcfc_rcu; 23 struct rcu_head tcfc_rcu;
24}; 24};
25#define tcf_next common.tcfc_next 25#define tcf_head common.tcfc_head
26#define tcf_index common.tcfc_index 26#define tcf_index common.tcfc_index
27#define tcf_refcnt common.tcfc_refcnt 27#define tcf_refcnt common.tcfc_refcnt
28#define tcf_bindcnt common.tcfc_bindcnt 28#define tcf_bindcnt common.tcfc_bindcnt
@@ -36,9 +36,9 @@ struct tcf_common {
36#define tcf_rcu common.tcfc_rcu 36#define tcf_rcu common.tcfc_rcu
37 37
38struct tcf_hashinfo { 38struct tcf_hashinfo {
39 struct tcf_common **htab; 39 struct hlist_head *htab;
40 unsigned int hmask; 40 unsigned int hmask;
41 rwlock_t lock; 41 spinlock_t lock;
42}; 42};
43 43
44static inline unsigned int tcf_hash(u32 index, unsigned int hmask) 44static inline unsigned int tcf_hash(u32 index, unsigned int hmask)
@@ -48,12 +48,16 @@ static inline unsigned int tcf_hash(u32 index, unsigned int hmask)
48 48
49static inline int tcf_hashinfo_init(struct tcf_hashinfo *hf, unsigned int mask) 49static inline int tcf_hashinfo_init(struct tcf_hashinfo *hf, unsigned int mask)
50{ 50{
51 rwlock_init(&hf->lock); 51 int i;
52
53 spin_lock_init(&hf->lock);
52 hf->hmask = mask; 54 hf->hmask = mask;
53 hf->htab = kzalloc((mask + 1) * sizeof(struct tcf_common *), 55 hf->htab = kzalloc((mask + 1) * sizeof(struct hlist_head),
54 GFP_KERNEL); 56 GFP_KERNEL);
55 if (!hf->htab) 57 if (!hf->htab)
56 return -ENOMEM; 58 return -ENOMEM;
59 for (i = 0; i < mask + 1; i++)
60 INIT_HLIST_HEAD(&hf->htab[i]);
57 return 0; 61 return 0;
58} 62}
59 63
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 125673d5d877..dc457c957656 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -29,25 +29,16 @@
29 29
30void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) 30void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
31{ 31{
32 unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); 32 spin_lock_bh(&hinfo->lock);
33 struct tcf_common **p1p; 33 hlist_del(&p->tcfc_head);
34 34 spin_unlock_bh(&hinfo->lock);
35 for (p1p = &hinfo->htab[h]; *p1p; p1p = &(*p1p)->tcfc_next) { 35 gen_kill_estimator(&p->tcfc_bstats,
36 if (*p1p == p) { 36 &p->tcfc_rate_est);
37 write_lock_bh(&hinfo->lock); 37 /*
38 *p1p = p->tcfc_next; 38 * gen_estimator est_timer() might access p->tcfc_lock
39 write_unlock_bh(&hinfo->lock); 39 * or bstats, wait a RCU grace period before freeing p
40 gen_kill_estimator(&p->tcfc_bstats, 40 */
41 &p->tcfc_rate_est); 41 kfree_rcu(p, tcfc_rcu);
42 /*
43 * gen_estimator est_timer() might access p->tcfc_lock
44 * or bstats, wait a RCU grace period before freeing p
45 */
46 kfree_rcu(p, tcfc_rcu);
47 return;
48 }
49 }
50 WARN_ON(1);
51} 42}
52EXPORT_SYMBOL(tcf_hash_destroy); 43EXPORT_SYMBOL(tcf_hash_destroy);
53 44
@@ -73,18 +64,19 @@ EXPORT_SYMBOL(tcf_hash_release);
73static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, 64static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
74 struct tc_action *a, struct tcf_hashinfo *hinfo) 65 struct tc_action *a, struct tcf_hashinfo *hinfo)
75{ 66{
67 struct hlist_head *head;
76 struct tcf_common *p; 68 struct tcf_common *p;
77 int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; 69 int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
78 struct nlattr *nest; 70 struct nlattr *nest;
79 71
80 read_lock_bh(&hinfo->lock); 72 spin_lock_bh(&hinfo->lock);
81 73
82 s_i = cb->args[0]; 74 s_i = cb->args[0];
83 75
84 for (i = 0; i < (hinfo->hmask + 1); i++) { 76 for (i = 0; i < (hinfo->hmask + 1); i++) {
85 p = hinfo->htab[tcf_hash(i, hinfo->hmask)]; 77 head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
86 78
87 for (; p; p = p->tcfc_next) { 79 hlist_for_each_entry_rcu(p, head, tcfc_head) {
88 index++; 80 index++;
89 if (index < s_i) 81 if (index < s_i)
90 continue; 82 continue;
@@ -107,7 +99,7 @@ static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
107 } 99 }
108 } 100 }
109done: 101done:
110 read_unlock_bh(&hinfo->lock); 102 spin_unlock_bh(&hinfo->lock);
111 if (n_i) 103 if (n_i)
112 cb->args[0] += n_i; 104 cb->args[0] += n_i;
113 return n_i; 105 return n_i;
@@ -120,7 +112,9 @@ nla_put_failure:
120static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a, 112static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a,
121 struct tcf_hashinfo *hinfo) 113 struct tcf_hashinfo *hinfo)
122{ 114{
123 struct tcf_common *p, *s_p; 115 struct hlist_head *head;
116 struct hlist_node *n;
117 struct tcf_common *p;
124 struct nlattr *nest; 118 struct nlattr *nest;
125 int i = 0, n_i = 0; 119 int i = 0, n_i = 0;
126 120
@@ -130,14 +124,11 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a,
130 if (nla_put_string(skb, TCA_KIND, a->ops->kind)) 124 if (nla_put_string(skb, TCA_KIND, a->ops->kind))
131 goto nla_put_failure; 125 goto nla_put_failure;
132 for (i = 0; i < (hinfo->hmask + 1); i++) { 126 for (i = 0; i < (hinfo->hmask + 1); i++) {
133 p = hinfo->htab[tcf_hash(i, hinfo->hmask)]; 127 head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
134 128 hlist_for_each_entry_safe(p, n, head, tcfc_head) {
135 while (p != NULL) {
136 s_p = p->tcfc_next;
137 if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo)) 129 if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo))
138 module_put(a->ops->owner); 130 module_put(a->ops->owner);
139 n_i++; 131 n_i++;
140 p = s_p;
141 } 132 }
142 } 133 }
143 if (nla_put_u32(skb, TCA_FCNT, n_i)) 134 if (nla_put_u32(skb, TCA_FCNT, n_i))
@@ -168,15 +159,15 @@ EXPORT_SYMBOL(tcf_generic_walker);
168 159
169struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo) 160struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
170{ 161{
171 struct tcf_common *p; 162 struct tcf_common *p = NULL;
163 struct hlist_head *head;
172 164
173 read_lock_bh(&hinfo->lock); 165 spin_lock_bh(&hinfo->lock);
174 for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p; 166 head = &hinfo->htab[tcf_hash(index, hinfo->hmask)];
175 p = p->tcfc_next) { 167 hlist_for_each_entry_rcu(p, head, tcfc_head)
176 if (p->tcfc_index == index) 168 if (p->tcfc_index == index)
177 break; 169 break;
178 } 170 spin_unlock_bh(&hinfo->lock);
179 read_unlock_bh(&hinfo->lock);
180 171
181 return p; 172 return p;
182} 173}
@@ -236,6 +227,7 @@ struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
236 p->tcfc_bindcnt = 1; 227 p->tcfc_bindcnt = 1;
237 228
238 spin_lock_init(&p->tcfc_lock); 229 spin_lock_init(&p->tcfc_lock);
230 INIT_HLIST_NODE(&p->tcfc_head);
239 p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo); 231 p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo);
240 p->tcfc_tm.install = jiffies; 232 p->tcfc_tm.install = jiffies;
241 p->tcfc_tm.lastuse = jiffies; 233 p->tcfc_tm.lastuse = jiffies;
@@ -257,10 +249,9 @@ void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo)
257{ 249{
258 unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); 250 unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
259 251
260 write_lock_bh(&hinfo->lock); 252 spin_lock_bh(&hinfo->lock);
261 p->tcfc_next = hinfo->htab[h]; 253 hlist_add_head(&p->tcfc_head, &hinfo->htab[h]);
262 hinfo->htab[h] = p; 254 spin_unlock_bh(&hinfo->lock);
263 write_unlock_bh(&hinfo->lock);
264} 255}
265EXPORT_SYMBOL(tcf_hash_insert); 256EXPORT_SYMBOL(tcf_hash_insert);
266 257
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;