diff options
author | Patrick McHardy <kaber@trash.net> | 2008-01-31 07:38:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-31 22:27:53 -0500 |
commit | 7d0742da1c8f5df3a34030f0170b30d1a052be80 (patch) | |
tree | f5717a37a9b4fe27abfa7886996d7051c57b91b9 | |
parent | c52fbb410b2662a7bbc5cbe5969d73c733151498 (diff) |
[NETFILTER]: nf_conntrack_expect: use RCU for expectation hash
Use RCU for expectation hash. This doesn't buy much for conntrack
runtime performance, but allows to reduce the use of nf_conntrack_lock
for /proc and nf_netlink_conntrack.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/netfilter/nf_conntrack_expect.h | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c | 14 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 43 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 7 |
4 files changed, 41 insertions, 25 deletions
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 6c3fd254c28e..cb608a1b44e5 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h | |||
@@ -49,6 +49,8 @@ struct nf_conntrack_expect | |||
49 | /* Direction relative to the master connection. */ | 49 | /* Direction relative to the master connection. */ |
50 | enum ip_conntrack_dir dir; | 50 | enum ip_conntrack_dir dir; |
51 | #endif | 51 | #endif |
52 | |||
53 | struct rcu_head rcu; | ||
52 | }; | 54 | }; |
53 | 55 | ||
54 | #define NF_CT_EXPECT_PERMANENT 0x1 | 56 | #define NF_CT_EXPECT_PERMANENT 0x1 |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index 543c02b74c96..2fdcd9233a03 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c | |||
@@ -191,10 +191,12 @@ struct ct_expect_iter_state { | |||
191 | static struct hlist_node *ct_expect_get_first(struct seq_file *seq) | 191 | static struct hlist_node *ct_expect_get_first(struct seq_file *seq) |
192 | { | 192 | { |
193 | struct ct_expect_iter_state *st = seq->private; | 193 | struct ct_expect_iter_state *st = seq->private; |
194 | struct hlist_node *n; | ||
194 | 195 | ||
195 | for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { | 196 | for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { |
196 | if (!hlist_empty(&nf_ct_expect_hash[st->bucket])) | 197 | n = rcu_dereference(nf_ct_expect_hash[st->bucket].first); |
197 | return nf_ct_expect_hash[st->bucket].first; | 198 | if (n) |
199 | return n; | ||
198 | } | 200 | } |
199 | return NULL; | 201 | return NULL; |
200 | } | 202 | } |
@@ -204,11 +206,11 @@ static struct hlist_node *ct_expect_get_next(struct seq_file *seq, | |||
204 | { | 206 | { |
205 | struct ct_expect_iter_state *st = seq->private; | 207 | struct ct_expect_iter_state *st = seq->private; |
206 | 208 | ||
207 | head = head->next; | 209 | head = rcu_dereference(head->next); |
208 | while (head == NULL) { | 210 | while (head == NULL) { |
209 | if (++st->bucket >= nf_ct_expect_hsize) | 211 | if (++st->bucket >= nf_ct_expect_hsize) |
210 | return NULL; | 212 | return NULL; |
211 | head = nf_ct_expect_hash[st->bucket].first; | 213 | head = rcu_dereference(nf_ct_expect_hash[st->bucket].first); |
212 | } | 214 | } |
213 | return head; | 215 | return head; |
214 | } | 216 | } |
@@ -225,7 +227,7 @@ static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos) | |||
225 | 227 | ||
226 | static void *exp_seq_start(struct seq_file *seq, loff_t *pos) | 228 | static void *exp_seq_start(struct seq_file *seq, loff_t *pos) |
227 | { | 229 | { |
228 | read_lock_bh(&nf_conntrack_lock); | 230 | rcu_read_lock(); |
229 | return ct_expect_get_idx(seq, *pos); | 231 | return ct_expect_get_idx(seq, *pos); |
230 | } | 232 | } |
231 | 233 | ||
@@ -237,7 +239,7 @@ static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
237 | 239 | ||
238 | static void exp_seq_stop(struct seq_file *seq, void *v) | 240 | static void exp_seq_stop(struct seq_file *seq, void *v) |
239 | { | 241 | { |
240 | read_unlock_bh(&nf_conntrack_lock); | 242 | rcu_read_unlock(); |
241 | } | 243 | } |
242 | 244 | ||
243 | static int exp_seq_show(struct seq_file *s, void *v) | 245 | static int exp_seq_show(struct seq_file *s, void *v) |
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index e405079e5a49..a5c8ef01f925 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -50,7 +50,7 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) | |||
50 | NF_CT_ASSERT(master_help); | 50 | NF_CT_ASSERT(master_help); |
51 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); | 51 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); |
52 | 52 | ||
53 | hlist_del(&exp->hnode); | 53 | hlist_del_rcu(&exp->hnode); |
54 | nf_ct_expect_count--; | 54 | nf_ct_expect_count--; |
55 | 55 | ||
56 | hlist_del(&exp->lnode); | 56 | hlist_del(&exp->lnode); |
@@ -97,7 +97,7 @@ __nf_ct_expect_find(const struct nf_conntrack_tuple *tuple) | |||
97 | return NULL; | 97 | return NULL; |
98 | 98 | ||
99 | h = nf_ct_expect_dst_hash(tuple); | 99 | h = nf_ct_expect_dst_hash(tuple); |
100 | hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) { | 100 | hlist_for_each_entry_rcu(i, n, &nf_ct_expect_hash[h], hnode) { |
101 | if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) | 101 | if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) |
102 | return i; | 102 | return i; |
103 | } | 103 | } |
@@ -111,11 +111,11 @@ nf_ct_expect_find_get(const struct nf_conntrack_tuple *tuple) | |||
111 | { | 111 | { |
112 | struct nf_conntrack_expect *i; | 112 | struct nf_conntrack_expect *i; |
113 | 113 | ||
114 | read_lock_bh(&nf_conntrack_lock); | 114 | rcu_read_lock(); |
115 | i = __nf_ct_expect_find(tuple); | 115 | i = __nf_ct_expect_find(tuple); |
116 | if (i) | 116 | if (i && !atomic_inc_not_zero(&i->use)) |
117 | atomic_inc(&i->use); | 117 | i = NULL; |
118 | read_unlock_bh(&nf_conntrack_lock); | 118 | rcu_read_unlock(); |
119 | 119 | ||
120 | return i; | 120 | return i; |
121 | } | 121 | } |
@@ -223,6 +223,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me) | |||
223 | 223 | ||
224 | new->master = me; | 224 | new->master = me; |
225 | atomic_set(&new->use, 1); | 225 | atomic_set(&new->use, 1); |
226 | INIT_RCU_HEAD(&new->rcu); | ||
226 | return new; | 227 | return new; |
227 | } | 228 | } |
228 | EXPORT_SYMBOL_GPL(nf_ct_expect_alloc); | 229 | EXPORT_SYMBOL_GPL(nf_ct_expect_alloc); |
@@ -278,10 +279,18 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family, | |||
278 | } | 279 | } |
279 | EXPORT_SYMBOL_GPL(nf_ct_expect_init); | 280 | EXPORT_SYMBOL_GPL(nf_ct_expect_init); |
280 | 281 | ||
282 | static void nf_ct_expect_free_rcu(struct rcu_head *head) | ||
283 | { | ||
284 | struct nf_conntrack_expect *exp; | ||
285 | |||
286 | exp = container_of(head, struct nf_conntrack_expect, rcu); | ||
287 | kmem_cache_free(nf_ct_expect_cachep, exp); | ||
288 | } | ||
289 | |||
281 | void nf_ct_expect_put(struct nf_conntrack_expect *exp) | 290 | void nf_ct_expect_put(struct nf_conntrack_expect *exp) |
282 | { | 291 | { |
283 | if (atomic_dec_and_test(&exp->use)) | 292 | if (atomic_dec_and_test(&exp->use)) |
284 | kmem_cache_free(nf_ct_expect_cachep, exp); | 293 | call_rcu(&exp->rcu, nf_ct_expect_free_rcu); |
285 | } | 294 | } |
286 | EXPORT_SYMBOL_GPL(nf_ct_expect_put); | 295 | EXPORT_SYMBOL_GPL(nf_ct_expect_put); |
287 | 296 | ||
@@ -295,7 +304,7 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) | |||
295 | hlist_add_head(&exp->lnode, &master_help->expectations); | 304 | hlist_add_head(&exp->lnode, &master_help->expectations); |
296 | master_help->expecting++; | 305 | master_help->expecting++; |
297 | 306 | ||
298 | hlist_add_head(&exp->hnode, &nf_ct_expect_hash[h]); | 307 | hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]); |
299 | nf_ct_expect_count++; | 308 | nf_ct_expect_count++; |
300 | 309 | ||
301 | setup_timer(&exp->timeout, nf_ct_expectation_timed_out, | 310 | setup_timer(&exp->timeout, nf_ct_expectation_timed_out, |
@@ -394,10 +403,12 @@ struct ct_expect_iter_state { | |||
394 | static struct hlist_node *ct_expect_get_first(struct seq_file *seq) | 403 | static struct hlist_node *ct_expect_get_first(struct seq_file *seq) |
395 | { | 404 | { |
396 | struct ct_expect_iter_state *st = seq->private; | 405 | struct ct_expect_iter_state *st = seq->private; |
406 | struct hlist_node *n; | ||
397 | 407 | ||
398 | for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { | 408 | for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { |
399 | if (!hlist_empty(&nf_ct_expect_hash[st->bucket])) | 409 | n = rcu_dereference(nf_ct_expect_hash[st->bucket].first); |
400 | return nf_ct_expect_hash[st->bucket].first; | 410 | if (n) |
411 | return n; | ||
401 | } | 412 | } |
402 | return NULL; | 413 | return NULL; |
403 | } | 414 | } |
@@ -407,11 +418,11 @@ static struct hlist_node *ct_expect_get_next(struct seq_file *seq, | |||
407 | { | 418 | { |
408 | struct ct_expect_iter_state *st = seq->private; | 419 | struct ct_expect_iter_state *st = seq->private; |
409 | 420 | ||
410 | head = head->next; | 421 | head = rcu_dereference(head->next); |
411 | while (head == NULL) { | 422 | while (head == NULL) { |
412 | if (++st->bucket >= nf_ct_expect_hsize) | 423 | if (++st->bucket >= nf_ct_expect_hsize) |
413 | return NULL; | 424 | return NULL; |
414 | head = nf_ct_expect_hash[st->bucket].first; | 425 | head = rcu_dereference(nf_ct_expect_hash[st->bucket].first); |
415 | } | 426 | } |
416 | return head; | 427 | return head; |
417 | } | 428 | } |
@@ -427,9 +438,9 @@ static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos) | |||
427 | } | 438 | } |
428 | 439 | ||
429 | static void *exp_seq_start(struct seq_file *seq, loff_t *pos) | 440 | static void *exp_seq_start(struct seq_file *seq, loff_t *pos) |
430 | __acquires(nf_conntrack_lock) | 441 | __acquires(RCU) |
431 | { | 442 | { |
432 | read_lock_bh(&nf_conntrack_lock); | 443 | rcu_read_lock(); |
433 | return ct_expect_get_idx(seq, *pos); | 444 | return ct_expect_get_idx(seq, *pos); |
434 | } | 445 | } |
435 | 446 | ||
@@ -440,9 +451,9 @@ static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
440 | } | 451 | } |
441 | 452 | ||
442 | static void exp_seq_stop(struct seq_file *seq, void *v) | 453 | static void exp_seq_stop(struct seq_file *seq, void *v) |
443 | __releases(nf_conntrack_lock) | 454 | __releases(RCU) |
444 | { | 455 | { |
445 | read_unlock_bh(&nf_conntrack_lock); | 456 | rcu_read_unlock(); |
446 | } | 457 | } |
447 | 458 | ||
448 | static int exp_seq_show(struct seq_file *s, void *v) | 459 | static int exp_seq_show(struct seq_file *s, void *v) |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index b6c0935e09df..557f47137da0 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -1471,7 +1471,7 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
1471 | struct hlist_node *n; | 1471 | struct hlist_node *n; |
1472 | u_int8_t l3proto = nfmsg->nfgen_family; | 1472 | u_int8_t l3proto = nfmsg->nfgen_family; |
1473 | 1473 | ||
1474 | read_lock_bh(&nf_conntrack_lock); | 1474 | rcu_read_lock(); |
1475 | last = (struct nf_conntrack_expect *)cb->args[1]; | 1475 | last = (struct nf_conntrack_expect *)cb->args[1]; |
1476 | for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) { | 1476 | for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) { |
1477 | restart: | 1477 | restart: |
@@ -1488,7 +1488,8 @@ restart: | |||
1488 | cb->nlh->nlmsg_seq, | 1488 | cb->nlh->nlmsg_seq, |
1489 | IPCTNL_MSG_EXP_NEW, | 1489 | IPCTNL_MSG_EXP_NEW, |
1490 | 1, exp) < 0) { | 1490 | 1, exp) < 0) { |
1491 | atomic_inc(&exp->use); | 1491 | if (!atomic_inc_not_zero(&exp->use)) |
1492 | continue; | ||
1492 | cb->args[1] = (unsigned long)exp; | 1493 | cb->args[1] = (unsigned long)exp; |
1493 | goto out; | 1494 | goto out; |
1494 | } | 1495 | } |
@@ -1499,7 +1500,7 @@ restart: | |||
1499 | } | 1500 | } |
1500 | } | 1501 | } |
1501 | out: | 1502 | out: |
1502 | read_unlock_bh(&nf_conntrack_lock); | 1503 | rcu_read_unlock(); |
1503 | if (last) | 1504 | if (last) |
1504 | nf_ct_expect_put(last); | 1505 | nf_ct_expect_put(last); |
1505 | 1506 | ||