24
24
struct basic_head {
25
25
u32 hgenerator ;
26
26
struct list_head flist ;
27
+ struct rcu_head rcu ;
27
28
};
28
29
29
30
struct basic_filter {
30
31
u32 handle ;
31
32
struct tcf_exts exts ;
32
33
struct tcf_ematch_tree ematches ;
33
34
struct tcf_result res ;
35
+ struct tcf_proto * tp ;
34
36
struct list_head link ;
37
+ struct rcu_head rcu ;
35
38
};
36
39
37
40
static int basic_classify (struct sk_buff * skb , const struct tcf_proto * tp ,
38
41
struct tcf_result * res )
39
42
{
40
43
int r ;
41
- struct basic_head * head = tp -> root ;
44
+ struct basic_head * head = rcu_dereference_bh ( tp -> root ) ;
42
45
struct basic_filter * f ;
43
46
44
- list_for_each_entry (f , & head -> flist , link ) {
47
+ list_for_each_entry_rcu (f , & head -> flist , link ) {
45
48
if (!tcf_em_tree_match (skb , & f -> ematches , NULL ))
46
49
continue ;
47
50
* res = f -> res ;
@@ -56,7 +59,7 @@ static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
56
59
static unsigned long basic_get (struct tcf_proto * tp , u32 handle )
57
60
{
58
61
unsigned long l = 0UL ;
59
- struct basic_head * head = tp -> root ;
62
+ struct basic_head * head = rtnl_dereference ( tp -> root ) ;
60
63
struct basic_filter * f ;
61
64
62
65
if (head == NULL )
@@ -81,12 +84,15 @@ static int basic_init(struct tcf_proto *tp)
81
84
if (head == NULL )
82
85
return - ENOBUFS ;
83
86
INIT_LIST_HEAD (& head -> flist );
84
- tp -> root = head ;
87
+ rcu_assign_pointer ( tp -> root , head ) ;
85
88
return 0 ;
86
89
}
87
90
88
- static void basic_delete_filter (struct tcf_proto * tp , struct basic_filter * f )
91
+ static void basic_delete_filter (struct rcu_head * head )
89
92
{
93
+ struct basic_filter * f = container_of (head , struct basic_filter , rcu );
94
+ struct tcf_proto * tp = f -> tp ;
95
+
90
96
tcf_unbind_filter (tp , & f -> res );
91
97
tcf_exts_destroy (tp , & f -> exts );
92
98
tcf_em_tree_destroy (tp , & f -> ematches );
@@ -95,27 +101,26 @@ static void basic_delete_filter(struct tcf_proto *tp, struct basic_filter *f)
95
101
96
102
static void basic_destroy (struct tcf_proto * tp )
97
103
{
98
- struct basic_head * head = tp -> root ;
104
+ struct basic_head * head = rtnl_dereference ( tp -> root ) ;
99
105
struct basic_filter * f , * n ;
100
106
101
107
list_for_each_entry_safe (f , n , & head -> flist , link ) {
102
- list_del (& f -> link );
103
- basic_delete_filter ( tp , f );
108
+ list_del_rcu (& f -> link );
109
+ call_rcu ( & f -> rcu , basic_delete_filter );
104
110
}
105
- kfree (head );
111
+ RCU_INIT_POINTER (tp -> root , NULL );
112
+ kfree_rcu (head , rcu );
106
113
}
107
114
108
115
static int basic_delete (struct tcf_proto * tp , unsigned long arg )
109
116
{
110
- struct basic_head * head = tp -> root ;
117
+ struct basic_head * head = rtnl_dereference ( tp -> root ) ;
111
118
struct basic_filter * t , * f = (struct basic_filter * ) arg ;
112
119
113
120
list_for_each_entry (t , & head -> flist , link )
114
121
if (t == f ) {
115
- tcf_tree_lock (tp );
116
- list_del (& t -> link );
117
- tcf_tree_unlock (tp );
118
- basic_delete_filter (tp , t );
122
+ list_del_rcu (& t -> link );
123
+ call_rcu (& t -> rcu , basic_delete_filter );
119
124
return 0 ;
120
125
}
121
126
@@ -152,6 +157,7 @@ static int basic_set_parms(struct net *net, struct tcf_proto *tp,
152
157
153
158
tcf_exts_change (tp , & f -> exts , & e );
154
159
tcf_em_tree_change (tp , & f -> ematches , & t );
160
+ f -> tp = tp ;
155
161
156
162
return 0 ;
157
163
errout :
@@ -164,9 +170,10 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
164
170
struct nlattr * * tca , unsigned long * arg , bool ovr )
165
171
{
166
172
int err ;
167
- struct basic_head * head = tp -> root ;
173
+ struct basic_head * head = rtnl_dereference ( tp -> root ) ;
168
174
struct nlattr * tb [TCA_BASIC_MAX + 1 ];
169
- struct basic_filter * f = (struct basic_filter * ) * arg ;
175
+ struct basic_filter * fold = (struct basic_filter * ) * arg ;
176
+ struct basic_filter * fnew ;
170
177
171
178
if (tca [TCA_OPTIONS ] == NULL )
172
179
return - EINVAL ;
@@ -176,22 +183,23 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
176
183
if (err < 0 )
177
184
return err ;
178
185
179
- if (f != NULL ) {
180
- if (handle && f -> handle != handle )
186
+ if (fold != NULL ) {
187
+ if (handle && fold -> handle != handle )
181
188
return - EINVAL ;
182
- return basic_set_parms (net , tp , f , base , tb , tca [TCA_RATE ], ovr );
183
189
}
184
190
185
191
err = - ENOBUFS ;
186
- f = kzalloc (sizeof (* f ), GFP_KERNEL );
187
- if (f == NULL )
192
+ fnew = kzalloc (sizeof (* fnew ), GFP_KERNEL );
193
+ if (fnew == NULL )
188
194
goto errout ;
189
195
190
- tcf_exts_init (& f -> exts , TCA_BASIC_ACT , TCA_BASIC_POLICE );
196
+ tcf_exts_init (& fnew -> exts , TCA_BASIC_ACT , TCA_BASIC_POLICE );
191
197
err = - EINVAL ;
192
- if (handle )
193
- f -> handle = handle ;
194
- else {
198
+ if (handle ) {
199
+ fnew -> handle = handle ;
200
+ } else if (fold ) {
201
+ fnew -> handle = fold -> handle ;
202
+ } else {
195
203
unsigned int i = 0x80000000 ;
196
204
do {
197
205
if (++ head -> hgenerator == 0x7FFFFFFF )
@@ -203,29 +211,31 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
203
211
goto errout ;
204
212
}
205
213
206
- f -> handle = head -> hgenerator ;
214
+ fnew -> handle = head -> hgenerator ;
207
215
}
208
216
209
- err = basic_set_parms (net , tp , f , base , tb , tca [TCA_RATE ], ovr );
217
+ err = basic_set_parms (net , tp , fnew , base , tb , tca [TCA_RATE ], ovr );
210
218
if (err < 0 )
211
219
goto errout ;
212
220
213
- tcf_tree_lock (tp );
214
- list_add (& f -> link , & head -> flist );
215
- tcf_tree_unlock (tp );
216
- * arg = (unsigned long ) f ;
221
+ * arg = (unsigned long )fnew ;
222
+
223
+ if (fold ) {
224
+ list_replace_rcu (& fold -> link , & fnew -> link );
225
+ call_rcu (& fold -> rcu , basic_delete_filter );
226
+ } else {
227
+ list_add_rcu (& fnew -> link , & head -> flist );
228
+ }
217
229
218
230
return 0 ;
219
231
errout :
220
- if (* arg == 0UL && f )
221
- kfree (f );
222
-
232
+ kfree (fnew );
223
233
return err ;
224
234
}
225
235
226
236
static void basic_walk (struct tcf_proto * tp , struct tcf_walker * arg )
227
237
{
228
- struct basic_head * head = tp -> root ;
238
+ struct basic_head * head = rtnl_dereference ( tp -> root ) ;
229
239
struct basic_filter * f ;
230
240
231
241
list_for_each_entry (f , & head -> flist , link ) {
0 commit comments