@@ -30,6 +30,7 @@ MODULE_ALIAS("ip_set_list:set");
30
30
struct set_elem {
31
31
struct rcu_head rcu ;
32
32
struct list_head list ;
33
+ struct ip_set * set ; /* Sigh, in order to cleanup reference */
33
34
ip_set_id_t id ;
34
35
} __aligned (__alignof__ (u64 ));
35
36
@@ -151,30 +152,29 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
151
152
/* Userspace interfaces: we are protected by the nfnl mutex */
152
153
153
154
static void
154
- __list_set_del (struct ip_set * set , struct set_elem * e )
155
+ __list_set_del_rcu (struct rcu_head * rcu )
155
156
{
157
+ struct set_elem * e = container_of (rcu , struct set_elem , rcu );
158
+ struct ip_set * set = e -> set ;
156
159
struct list_set * map = set -> data ;
157
160
158
161
ip_set_put_byindex (map -> net , e -> id );
159
- /* We may call it, because we don't have a to be destroyed
160
- * extension which is used by the kernel.
161
- */
162
162
ip_set_ext_destroy (set , e );
163
- kfree_rcu ( e , rcu );
163
+ kfree ( e );
164
164
}
165
165
166
166
static inline void
167
167
list_set_del (struct ip_set * set , struct set_elem * e )
168
168
{
169
169
list_del_rcu (& e -> list );
170
- __list_set_del ( set , e );
170
+ call_rcu ( & e -> rcu , __list_set_del_rcu );
171
171
}
172
172
173
173
static inline void
174
- list_set_replace (struct ip_set * set , struct set_elem * e , struct set_elem * old )
174
+ list_set_replace (struct set_elem * e , struct set_elem * old )
175
175
{
176
176
list_replace_rcu (& old -> list , & e -> list );
177
- __list_set_del ( set , old );
177
+ call_rcu ( & old -> rcu , __list_set_del_rcu );
178
178
}
179
179
180
180
static void
@@ -244,9 +244,6 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
244
244
struct set_elem * e , * n , * prev , * next ;
245
245
bool flag_exist = flags & IPSET_FLAG_EXIST ;
246
246
247
- if (SET_WITH_TIMEOUT (set ))
248
- set_cleanup_entries (set );
249
-
250
247
/* Find where to add the new entry */
251
248
n = prev = next = NULL ;
252
249
list_for_each_entry (e , & map -> members , list ) {
@@ -301,10 +298,11 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
301
298
if (!e )
302
299
return - ENOMEM ;
303
300
e -> id = d -> id ;
301
+ e -> set = set ;
304
302
INIT_LIST_HEAD (& e -> list );
305
303
list_set_init_extensions (set , ext , e );
306
304
if (n )
307
- list_set_replace (set , e , n );
305
+ list_set_replace (e , n );
308
306
else if (next )
309
307
list_add_tail_rcu (& e -> list , & next -> list );
310
308
else if (prev )
@@ -431,6 +429,7 @@ list_set_destroy(struct ip_set *set)
431
429
432
430
if (SET_WITH_TIMEOUT (set ))
433
431
del_timer_sync (& map -> gc );
432
+
434
433
list_for_each_entry_safe (e , n , & map -> members , list ) {
435
434
list_del (& e -> list );
436
435
ip_set_put_byindex (map -> net , e -> id );
@@ -450,8 +449,10 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
450
449
struct set_elem * e ;
451
450
u32 n = 0 ;
452
451
453
- list_for_each_entry (e , & map -> members , list )
452
+ rcu_read_lock ();
453
+ list_for_each_entry_rcu (e , & map -> members , list )
454
454
n ++ ;
455
+ rcu_read_unlock ();
455
456
456
457
nested = ipset_nest_start (skb , IPSET_ATTR_DATA );
457
458
if (!nested )
@@ -483,33 +484,25 @@ list_set_list(const struct ip_set *set,
483
484
atd = ipset_nest_start (skb , IPSET_ATTR_ADT );
484
485
if (!atd )
485
486
return - EMSGSIZE ;
486
- list_for_each_entry (e , & map -> members , list ) {
487
- if (i == first )
488
- break ;
489
- i ++ ;
490
- }
491
487
492
488
rcu_read_lock ();
493
- list_for_each_entry_from (e , & map -> members , list ) {
494
- i ++ ;
495
- if (SET_WITH_TIMEOUT (set ) &&
496
- ip_set_timeout_expired (ext_timeout (e , set )))
489
+ list_for_each_entry_rcu (e , & map -> members , list ) {
490
+ if (i < first ||
491
+ (SET_WITH_TIMEOUT (set ) &&
492
+ ip_set_timeout_expired (ext_timeout (e , set )))) {
493
+ i ++ ;
497
494
continue ;
495
+ }
498
496
nested = ipset_nest_start (skb , IPSET_ATTR_DATA );
499
- if (!nested ) {
500
- if (i == first ) {
501
- nla_nest_cancel (skb , atd );
502
- ret = - EMSGSIZE ;
503
- goto out ;
504
- }
497
+ if (!nested )
505
498
goto nla_put_failure ;
506
- }
507
499
if (nla_put_string (skb , IPSET_ATTR_NAME ,
508
500
ip_set_name_byindex (map -> net , e -> id )))
509
501
goto nla_put_failure ;
510
502
if (ip_set_put_extensions (skb , set , e , true))
511
503
goto nla_put_failure ;
512
504
ipset_nest_end (skb , nested );
505
+ i ++ ;
513
506
}
514
507
515
508
ipset_nest_end (skb , atd );
@@ -520,10 +513,12 @@ list_set_list(const struct ip_set *set,
520
513
nla_put_failure :
521
514
nla_nest_cancel (skb , nested );
522
515
if (unlikely (i == first )) {
516
+ nla_nest_cancel (skb , atd );
523
517
cb -> args [IPSET_CB_ARG0 ] = 0 ;
524
518
ret = - EMSGSIZE ;
519
+ } else {
520
+ cb -> args [IPSET_CB_ARG0 ] = i ;
525
521
}
526
- cb -> args [IPSET_CB_ARG0 ] = i - 1 ;
527
522
ipset_nest_end (skb , atd );
528
523
out :
529
524
rcu_read_unlock ();
0 commit comments