diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/netfilter/nf_conncount.c | 46 |
1 files changed, 20 insertions, 26 deletions
diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c index ce7f7d1212a6..d0fd195b19a8 100644 --- a/net/netfilter/nf_conncount.c +++ b/net/netfilter/nf_conncount.c | |||
| @@ -43,8 +43,6 @@ struct nf_conncount_tuple { | |||
| 43 | struct nf_conntrack_zone zone; | 43 | struct nf_conntrack_zone zone; |
| 44 | int cpu; | 44 | int cpu; |
| 45 | u32 jiffies32; | 45 | u32 jiffies32; |
| 46 | bool dead; | ||
| 47 | struct rcu_head rcu_head; | ||
| 48 | }; | 46 | }; |
| 49 | 47 | ||
| 50 | struct nf_conncount_rb { | 48 | struct nf_conncount_rb { |
| @@ -83,36 +81,21 @@ static int key_diff(const u32 *a, const u32 *b, unsigned int klen) | |||
| 83 | return memcmp(a, b, klen * sizeof(u32)); | 81 | return memcmp(a, b, klen * sizeof(u32)); |
| 84 | } | 82 | } |
| 85 | 83 | ||
| 86 | static void __conn_free(struct rcu_head *h) | ||
| 87 | { | ||
| 88 | struct nf_conncount_tuple *conn; | ||
| 89 | |||
| 90 | conn = container_of(h, struct nf_conncount_tuple, rcu_head); | ||
| 91 | kmem_cache_free(conncount_conn_cachep, conn); | ||
| 92 | } | ||
| 93 | |||
| 94 | static bool conn_free(struct nf_conncount_list *list, | 84 | static bool conn_free(struct nf_conncount_list *list, |
| 95 | struct nf_conncount_tuple *conn) | 85 | struct nf_conncount_tuple *conn) |
| 96 | { | 86 | { |
| 97 | bool free_entry = false; | 87 | bool free_entry = false; |
| 98 | 88 | ||
| 99 | spin_lock_bh(&list->list_lock); | 89 | lockdep_assert_held(&list->list_lock); |
| 100 | |||
| 101 | if (conn->dead) { | ||
| 102 | spin_unlock_bh(&list->list_lock); | ||
| 103 | return free_entry; | ||
| 104 | } | ||
| 105 | 90 | ||
| 106 | list->count--; | 91 | list->count--; |
| 107 | conn->dead = true; | 92 | list_del(&conn->node); |
| 108 | list_del_rcu(&conn->node); | ||
| 109 | if (list->count == 0) { | 93 | if (list->count == 0) { |
| 110 | list->dead = true; | 94 | list->dead = true; |
| 111 | free_entry = true; | 95 | free_entry = true; |
| 112 | } | 96 | } |
| 113 | 97 | ||
| 114 | spin_unlock_bh(&list->list_lock); | 98 | kmem_cache_free(conncount_conn_cachep, conn); |
| 115 | call_rcu(&conn->rcu_head, __conn_free); | ||
| 116 | return free_entry; | 99 | return free_entry; |
| 117 | } | 100 | } |
| 118 | 101 | ||
| @@ -242,7 +225,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list) | |||
| 242 | } | 225 | } |
| 243 | EXPORT_SYMBOL_GPL(nf_conncount_list_init); | 226 | EXPORT_SYMBOL_GPL(nf_conncount_list_init); |
| 244 | 227 | ||
| 245 | /* Return true if the list is empty */ | 228 | /* Return true if the list is empty. Must be called with BH disabled. */ |
| 246 | bool nf_conncount_gc_list(struct net *net, | 229 | bool nf_conncount_gc_list(struct net *net, |
| 247 | struct nf_conncount_list *list) | 230 | struct nf_conncount_list *list) |
| 248 | { | 231 | { |
| @@ -253,12 +236,18 @@ bool nf_conncount_gc_list(struct net *net, | |||
| 253 | bool free_entry = false; | 236 | bool free_entry = false; |
| 254 | bool ret = false; | 237 | bool ret = false; |
| 255 | 238 | ||
| 239 | /* don't bother if other cpu is already doing GC */ | ||
| 240 | if (!spin_trylock(&list->list_lock)) | ||
| 241 | return false; | ||
| 242 | |||
| 256 | list_for_each_entry_safe(conn, conn_n, &list->head, node) { | 243 | list_for_each_entry_safe(conn, conn_n, &list->head, node) { |
| 257 | found = find_or_evict(net, list, conn, &free_entry); | 244 | found = find_or_evict(net, list, conn, &free_entry); |
| 258 | if (IS_ERR(found)) { | 245 | if (IS_ERR(found)) { |
| 259 | if (PTR_ERR(found) == -ENOENT) { | 246 | if (PTR_ERR(found) == -ENOENT) { |
| 260 | if (free_entry) | 247 | if (free_entry) { |
| 248 | spin_unlock(&list->list_lock); | ||
| 261 | return true; | 249 | return true; |
| 250 | } | ||
| 262 | collected++; | 251 | collected++; |
| 263 | } | 252 | } |
| 264 | continue; | 253 | continue; |
| @@ -271,23 +260,24 @@ bool nf_conncount_gc_list(struct net *net, | |||
| 271 | * closed already -> ditch it | 260 | * closed already -> ditch it |
| 272 | */ | 261 | */ |
| 273 | nf_ct_put(found_ct); | 262 | nf_ct_put(found_ct); |
| 274 | if (conn_free(list, conn)) | 263 | if (conn_free(list, conn)) { |
| 264 | spin_unlock(&list->list_lock); | ||
| 275 | return true; | 265 | return true; |
| 266 | } | ||
| 276 | collected++; | 267 | collected++; |
| 277 | continue; | 268 | continue; |
| 278 | } | 269 | } |
| 279 | 270 | ||
| 280 | nf_ct_put(found_ct); | 271 | nf_ct_put(found_ct); |
| 281 | if (collected > CONNCOUNT_GC_MAX_NODES) | 272 | if (collected > CONNCOUNT_GC_MAX_NODES) |
| 282 | return false; | 273 | break; |
| 283 | } | 274 | } |
| 284 | 275 | ||
| 285 | spin_lock_bh(&list->list_lock); | ||
| 286 | if (!list->count) { | 276 | if (!list->count) { |
| 287 | list->dead = true; | 277 | list->dead = true; |
| 288 | ret = true; | 278 | ret = true; |
| 289 | } | 279 | } |
| 290 | spin_unlock_bh(&list->list_lock); | 280 | spin_unlock(&list->list_lock); |
| 291 | 281 | ||
| 292 | return ret; | 282 | return ret; |
| 293 | } | 283 | } |
| @@ -478,6 +468,7 @@ static void tree_gc_worker(struct work_struct *work) | |||
| 478 | tree = data->gc_tree % CONNCOUNT_SLOTS; | 468 | tree = data->gc_tree % CONNCOUNT_SLOTS; |
| 479 | root = &data->root[tree]; | 469 | root = &data->root[tree]; |
| 480 | 470 | ||
| 471 | local_bh_disable(); | ||
| 481 | rcu_read_lock(); | 472 | rcu_read_lock(); |
| 482 | for (node = rb_first(root); node != NULL; node = rb_next(node)) { | 473 | for (node = rb_first(root); node != NULL; node = rb_next(node)) { |
| 483 | rbconn = rb_entry(node, struct nf_conncount_rb, node); | 474 | rbconn = rb_entry(node, struct nf_conncount_rb, node); |
| @@ -485,6 +476,9 @@ static void tree_gc_worker(struct work_struct *work) | |||
| 485 | gc_count++; | 476 | gc_count++; |
| 486 | } | 477 | } |
| 487 | rcu_read_unlock(); | 478 | rcu_read_unlock(); |
| 479 | local_bh_enable(); | ||
| 480 | |||
| 481 | cond_resched(); | ||
| 488 | 482 | ||
| 489 | spin_lock_bh(&nf_conncount_locks[tree]); | 483 | spin_lock_bh(&nf_conncount_locks[tree]); |
| 490 | if (gc_count < ARRAY_SIZE(gc_nodes)) | 484 | if (gc_count < ARRAY_SIZE(gc_nodes)) |
