Skip to content

Commit e35a8ee

Browse files
jrfastabdavem330
authored andcommitted
net: sched: fw use RCU
RCU'ify fw classifier. Signed-off-by: John Fastabend <[email protected]> Acked-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 70da9f0 commit e35a8ee

File tree

1 file changed

+77
-34
lines changed

1 file changed

+77
-34
lines changed

net/sched/cls_fw.c

+77-34
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,20 @@
3333

3434
struct fw_head {
3535
u32 mask;
36-
struct fw_filter *ht[HTSIZE];
36+
struct fw_filter __rcu *ht[HTSIZE];
37+
struct rcu_head rcu;
3738
};
3839

3940
struct fw_filter {
40-
struct fw_filter *next;
41+
struct fw_filter __rcu *next;
4142
u32 id;
4243
struct tcf_result res;
4344
#ifdef CONFIG_NET_CLS_IND
4445
int ifindex;
4546
#endif /* CONFIG_NET_CLS_IND */
4647
struct tcf_exts exts;
48+
struct tcf_proto *tp;
49+
struct rcu_head rcu;
4750
};
4851

4952
static u32 fw_hash(u32 handle)
@@ -56,14 +59,16 @@ static u32 fw_hash(u32 handle)
5659
static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
5760
struct tcf_result *res)
5861
{
59-
struct fw_head *head = tp->root;
62+
struct fw_head *head = rcu_dereference_bh(tp->root);
6063
struct fw_filter *f;
6164
int r;
6265
u32 id = skb->mark;
6366

6467
if (head != NULL) {
6568
id &= head->mask;
66-
for (f = head->ht[fw_hash(id)]; f; f = f->next) {
69+
70+
for (f = rcu_dereference_bh(head->ht[fw_hash(id)]); f;
71+
f = rcu_dereference_bh(f->next)) {
6772
if (f->id == id) {
6873
*res = f->res;
6974
#ifdef CONFIG_NET_CLS_IND
@@ -92,13 +97,14 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
9297

9398
static unsigned long fw_get(struct tcf_proto *tp, u32 handle)
9499
{
95-
struct fw_head *head = tp->root;
100+
struct fw_head *head = rtnl_dereference(tp->root);
96101
struct fw_filter *f;
97102

98103
if (head == NULL)
99104
return 0;
100105

101-
for (f = head->ht[fw_hash(handle)]; f; f = f->next) {
106+
f = rtnl_dereference(head->ht[fw_hash(handle)]);
107+
for (; f; f = rtnl_dereference(f->next)) {
102108
if (f->id == handle)
103109
return (unsigned long)f;
104110
}
@@ -114,46 +120,53 @@ static int fw_init(struct tcf_proto *tp)
114120
return 0;
115121
}
116122

117-
static void fw_delete_filter(struct tcf_proto *tp, struct fw_filter *f)
123+
static void fw_delete_filter(struct rcu_head *head)
118124
{
125+
struct fw_filter *f = container_of(head, struct fw_filter, rcu);
126+
struct tcf_proto *tp = f->tp;
127+
119128
tcf_unbind_filter(tp, &f->res);
120129
tcf_exts_destroy(tp, &f->exts);
121130
kfree(f);
122131
}
123132

124133
static void fw_destroy(struct tcf_proto *tp)
125134
{
126-
struct fw_head *head = tp->root;
135+
struct fw_head *head = rtnl_dereference(tp->root);
127136
struct fw_filter *f;
128137
int h;
129138

130139
if (head == NULL)
131140
return;
132141

133142
for (h = 0; h < HTSIZE; h++) {
134-
while ((f = head->ht[h]) != NULL) {
135-
head->ht[h] = f->next;
136-
fw_delete_filter(tp, f);
143+
while ((f = rtnl_dereference(head->ht[h])) != NULL) {
144+
RCU_INIT_POINTER(head->ht[h],
145+
rtnl_dereference(f->next));
146+
call_rcu(&f->rcu, fw_delete_filter);
137147
}
138148
}
139-
kfree(head);
149+
RCU_INIT_POINTER(tp->root, NULL);
150+
kfree_rcu(head, rcu);
140151
}
141152

142153
static int fw_delete(struct tcf_proto *tp, unsigned long arg)
143154
{
144-
struct fw_head *head = tp->root;
155+
struct fw_head *head = rtnl_dereference(tp->root);
145156
struct fw_filter *f = (struct fw_filter *)arg;
146-
struct fw_filter **fp;
157+
struct fw_filter __rcu **fp;
158+
struct fw_filter *pfp;
147159

148160
if (head == NULL || f == NULL)
149161
goto out;
150162

151-
for (fp = &head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) {
152-
if (*fp == f) {
153-
tcf_tree_lock(tp);
154-
*fp = f->next;
155-
tcf_tree_unlock(tp);
156-
fw_delete_filter(tp, f);
163+
fp = &head->ht[fw_hash(f->id)];
164+
165+
for (pfp = rtnl_dereference(*fp); pfp;
166+
fp = &pfp->next, pfp = rtnl_dereference(*fp)) {
167+
if (pfp == f) {
168+
RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
169+
call_rcu(&f->rcu, fw_delete_filter);
157170
return 0;
158171
}
159172
}
@@ -171,7 +184,7 @@ static int
171184
fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
172185
struct nlattr **tb, struct nlattr **tca, unsigned long base, bool ovr)
173186
{
174-
struct fw_head *head = tp->root;
187+
struct fw_head *head = rtnl_dereference(tp->root);
175188
struct tcf_exts e;
176189
u32 mask;
177190
int err;
@@ -220,7 +233,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
220233
struct nlattr **tca,
221234
unsigned long *arg, bool ovr)
222235
{
223-
struct fw_head *head = tp->root;
236+
struct fw_head *head = rtnl_dereference(tp->root);
224237
struct fw_filter *f = (struct fw_filter *) *arg;
225238
struct nlattr *opt = tca[TCA_OPTIONS];
226239
struct nlattr *tb[TCA_FW_MAX + 1];
@@ -233,10 +246,42 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
233246
if (err < 0)
234247
return err;
235248

236-
if (f != NULL) {
249+
if (f) {
250+
struct fw_filter *pfp, *fnew;
251+
struct fw_filter __rcu **fp;
252+
237253
if (f->id != handle && handle)
238254
return -EINVAL;
239-
return fw_change_attrs(net, tp, f, tb, tca, base, ovr);
255+
256+
fnew = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
257+
if (!fnew)
258+
return -ENOBUFS;
259+
260+
fnew->id = f->id;
261+
fnew->res = f->res;
262+
#ifdef CONFIG_NET_CLS_IND
263+
fnew->ifindex = f->ifindex;
264+
#endif /* CONFIG_NET_CLS_IND */
265+
fnew->tp = f->tp;
266+
267+
err = fw_change_attrs(net, tp, fnew, tb, tca, base, ovr);
268+
if (err < 0) {
269+
kfree(fnew);
270+
return err;
271+
}
272+
273+
fp = &head->ht[fw_hash(fnew->id)];
274+
for (pfp = rtnl_dereference(*fp); pfp;
275+
fp = &pfp->next, pfp = rtnl_dereference(*fp))
276+
if (pfp == f)
277+
break;
278+
279+
RCU_INIT_POINTER(fnew->next, rtnl_dereference(pfp->next));
280+
rcu_assign_pointer(*fp, fnew);
281+
call_rcu(&f->rcu, fw_delete_filter);
282+
283+
*arg = (unsigned long)fnew;
284+
return err;
240285
}
241286

242287
if (!handle)
@@ -252,9 +297,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
252297
return -ENOBUFS;
253298
head->mask = mask;
254299

255-
tcf_tree_lock(tp);
256-
tp->root = head;
257-
tcf_tree_unlock(tp);
300+
rcu_assign_pointer(tp->root, head);
258301
}
259302

260303
f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
@@ -263,15 +306,14 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
263306

264307
tcf_exts_init(&f->exts, TCA_FW_ACT, TCA_FW_POLICE);
265308
f->id = handle;
309+
f->tp = tp;
266310

267311
err = fw_change_attrs(net, tp, f, tb, tca, base, ovr);
268312
if (err < 0)
269313
goto errout;
270314

271-
f->next = head->ht[fw_hash(handle)];
272-
tcf_tree_lock(tp);
273-
head->ht[fw_hash(handle)] = f;
274-
tcf_tree_unlock(tp);
315+
RCU_INIT_POINTER(f->next, head->ht[fw_hash(handle)]);
316+
rcu_assign_pointer(head->ht[fw_hash(handle)], f);
275317

276318
*arg = (unsigned long)f;
277319
return 0;
@@ -283,7 +325,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
283325

284326
static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
285327
{
286-
struct fw_head *head = tp->root;
328+
struct fw_head *head = rtnl_dereference(tp->root);
287329
int h;
288330

289331
if (head == NULL)
@@ -295,7 +337,8 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
295337
for (h = 0; h < HTSIZE; h++) {
296338
struct fw_filter *f;
297339

298-
for (f = head->ht[h]; f; f = f->next) {
340+
for (f = rtnl_dereference(head->ht[h]); f;
341+
f = rtnl_dereference(f->next)) {
299342
if (arg->count < arg->skip) {
300343
arg->count++;
301344
continue;
@@ -312,7 +355,7 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
312355
static int fw_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
313356
struct sk_buff *skb, struct tcmsg *t)
314357
{
315-
struct fw_head *head = tp->root;
358+
struct fw_head *head = rtnl_dereference(tp->root);
316359
struct fw_filter *f = (struct fw_filter *)fh;
317360
unsigned char *b = skb_tail_pointer(skb);
318361
struct nlattr *nest;

0 commit comments

Comments
 (0)