33
33
34
34
struct fw_head {
35
35
u32 mask ;
36
- struct fw_filter * ht [HTSIZE ];
36
+ struct fw_filter __rcu * ht [HTSIZE ];
37
+ struct rcu_head rcu ;
37
38
};
38
39
39
40
struct fw_filter {
40
- struct fw_filter * next ;
41
+ struct fw_filter __rcu * next ;
41
42
u32 id ;
42
43
struct tcf_result res ;
43
44
#ifdef CONFIG_NET_CLS_IND
44
45
int ifindex ;
45
46
#endif /* CONFIG_NET_CLS_IND */
46
47
struct tcf_exts exts ;
48
+ struct tcf_proto * tp ;
49
+ struct rcu_head rcu ;
47
50
};
48
51
49
52
static u32 fw_hash (u32 handle )
@@ -56,14 +59,16 @@ static u32 fw_hash(u32 handle)
56
59
static int fw_classify (struct sk_buff * skb , const struct tcf_proto * tp ,
57
60
struct tcf_result * res )
58
61
{
59
- struct fw_head * head = tp -> root ;
62
+ struct fw_head * head = rcu_dereference_bh ( tp -> root ) ;
60
63
struct fw_filter * f ;
61
64
int r ;
62
65
u32 id = skb -> mark ;
63
66
64
67
if (head != NULL ) {
65
68
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 )) {
67
72
if (f -> id == id ) {
68
73
* res = f -> res ;
69
74
#ifdef CONFIG_NET_CLS_IND
@@ -92,13 +97,14 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
92
97
93
98
static unsigned long fw_get (struct tcf_proto * tp , u32 handle )
94
99
{
95
- struct fw_head * head = tp -> root ;
100
+ struct fw_head * head = rtnl_dereference ( tp -> root ) ;
96
101
struct fw_filter * f ;
97
102
98
103
if (head == NULL )
99
104
return 0 ;
100
105
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 )) {
102
108
if (f -> id == handle )
103
109
return (unsigned long )f ;
104
110
}
@@ -114,46 +120,53 @@ static int fw_init(struct tcf_proto *tp)
114
120
return 0 ;
115
121
}
116
122
117
- static void fw_delete_filter (struct tcf_proto * tp , struct fw_filter * f )
123
+ static void fw_delete_filter (struct rcu_head * head )
118
124
{
125
+ struct fw_filter * f = container_of (head , struct fw_filter , rcu );
126
+ struct tcf_proto * tp = f -> tp ;
127
+
119
128
tcf_unbind_filter (tp , & f -> res );
120
129
tcf_exts_destroy (tp , & f -> exts );
121
130
kfree (f );
122
131
}
123
132
124
133
static void fw_destroy (struct tcf_proto * tp )
125
134
{
126
- struct fw_head * head = tp -> root ;
135
+ struct fw_head * head = rtnl_dereference ( tp -> root ) ;
127
136
struct fw_filter * f ;
128
137
int h ;
129
138
130
139
if (head == NULL )
131
140
return ;
132
141
133
142
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 );
137
147
}
138
148
}
139
- kfree (head );
149
+ RCU_INIT_POINTER (tp -> root , NULL );
150
+ kfree_rcu (head , rcu );
140
151
}
141
152
142
153
static int fw_delete (struct tcf_proto * tp , unsigned long arg )
143
154
{
144
- struct fw_head * head = tp -> root ;
155
+ struct fw_head * head = rtnl_dereference ( tp -> root ) ;
145
156
struct fw_filter * f = (struct fw_filter * )arg ;
146
- struct fw_filter * * fp ;
157
+ struct fw_filter __rcu * * fp ;
158
+ struct fw_filter * pfp ;
147
159
148
160
if (head == NULL || f == NULL )
149
161
goto out ;
150
162
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 );
157
170
return 0 ;
158
171
}
159
172
}
@@ -171,7 +184,7 @@ static int
171
184
fw_change_attrs (struct net * net , struct tcf_proto * tp , struct fw_filter * f ,
172
185
struct nlattr * * tb , struct nlattr * * tca , unsigned long base , bool ovr )
173
186
{
174
- struct fw_head * head = tp -> root ;
187
+ struct fw_head * head = rtnl_dereference ( tp -> root ) ;
175
188
struct tcf_exts e ;
176
189
u32 mask ;
177
190
int err ;
@@ -220,7 +233,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
220
233
struct nlattr * * tca ,
221
234
unsigned long * arg , bool ovr )
222
235
{
223
- struct fw_head * head = tp -> root ;
236
+ struct fw_head * head = rtnl_dereference ( tp -> root ) ;
224
237
struct fw_filter * f = (struct fw_filter * ) * arg ;
225
238
struct nlattr * opt = tca [TCA_OPTIONS ];
226
239
struct nlattr * tb [TCA_FW_MAX + 1 ];
@@ -233,10 +246,42 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
233
246
if (err < 0 )
234
247
return err ;
235
248
236
- if (f != NULL ) {
249
+ if (f ) {
250
+ struct fw_filter * pfp , * fnew ;
251
+ struct fw_filter __rcu * * fp ;
252
+
237
253
if (f -> id != handle && handle )
238
254
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 ;
240
285
}
241
286
242
287
if (!handle )
@@ -252,9 +297,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
252
297
return - ENOBUFS ;
253
298
head -> mask = mask ;
254
299
255
- tcf_tree_lock (tp );
256
- tp -> root = head ;
257
- tcf_tree_unlock (tp );
300
+ rcu_assign_pointer (tp -> root , head );
258
301
}
259
302
260
303
f = kzalloc (sizeof (struct fw_filter ), GFP_KERNEL );
@@ -263,15 +306,14 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
263
306
264
307
tcf_exts_init (& f -> exts , TCA_FW_ACT , TCA_FW_POLICE );
265
308
f -> id = handle ;
309
+ f -> tp = tp ;
266
310
267
311
err = fw_change_attrs (net , tp , f , tb , tca , base , ovr );
268
312
if (err < 0 )
269
313
goto errout ;
270
314
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 );
275
317
276
318
* arg = (unsigned long )f ;
277
319
return 0 ;
@@ -283,7 +325,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
283
325
284
326
static void fw_walk (struct tcf_proto * tp , struct tcf_walker * arg )
285
327
{
286
- struct fw_head * head = tp -> root ;
328
+ struct fw_head * head = rtnl_dereference ( tp -> root ) ;
287
329
int h ;
288
330
289
331
if (head == NULL )
@@ -295,7 +337,8 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
295
337
for (h = 0 ; h < HTSIZE ; h ++ ) {
296
338
struct fw_filter * f ;
297
339
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 )) {
299
342
if (arg -> count < arg -> skip ) {
300
343
arg -> count ++ ;
301
344
continue ;
@@ -312,7 +355,7 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
312
355
static int fw_dump (struct net * net , struct tcf_proto * tp , unsigned long fh ,
313
356
struct sk_buff * skb , struct tcmsg * t )
314
357
{
315
- struct fw_head * head = tp -> root ;
358
+ struct fw_head * head = rtnl_dereference ( tp -> root ) ;
316
359
struct fw_filter * f = (struct fw_filter * )fh ;
317
360
unsigned char * b = skb_tail_pointer (skb );
318
361
struct nlattr * nest ;
0 commit comments