diff options
author | Patrick McHardy <kaber@trash.net> | 2007-07-08 01:34:07 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-11 01:18:00 -0400 |
commit | 5d08ad440feae11b8d6e7599147a8a20ac60f99a (patch) | |
tree | 41043588598c7dae1b1edecaac3764924f0cf3bf /net/netfilter | |
parent | a71c085562bcc99e8b711cab4222bff1f6e955da (diff) |
[NETFILTER]: nf_conntrack_expect: convert proc functions to hash
Convert from the global expectation list to the hash table.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 85 |
1 files changed, 61 insertions, 24 deletions
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 0696f87aaef1..c5006b0a4e65 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -377,47 +377,68 @@ out: | |||
377 | EXPORT_SYMBOL_GPL(nf_ct_expect_related); | 377 | EXPORT_SYMBOL_GPL(nf_ct_expect_related); |
378 | 378 | ||
379 | #ifdef CONFIG_PROC_FS | 379 | #ifdef CONFIG_PROC_FS |
380 | static void *exp_seq_start(struct seq_file *s, loff_t *pos) | 380 | struct ct_expect_iter_state { |
381 | unsigned int bucket; | ||
382 | }; | ||
383 | |||
384 | static struct hlist_node *ct_expect_get_first(struct seq_file *seq) | ||
381 | { | 385 | { |
382 | struct list_head *e = &nf_ct_expect_list; | 386 | struct ct_expect_iter_state *st = seq->private; |
383 | loff_t i; | ||
384 | 387 | ||
385 | /* strange seq_file api calls stop even if we fail, | 388 | for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { |
386 | * thus we need to grab lock since stop unlocks */ | 389 | if (!hlist_empty(&nf_ct_expect_hash[st->bucket])) |
387 | read_lock_bh(&nf_conntrack_lock); | 390 | return nf_ct_expect_hash[st->bucket].first; |
391 | } | ||
392 | return NULL; | ||
393 | } | ||
388 | 394 | ||
389 | if (list_empty(e)) | 395 | static struct hlist_node *ct_expect_get_next(struct seq_file *seq, |
390 | return NULL; | 396 | struct hlist_node *head) |
397 | { | ||
398 | struct ct_expect_iter_state *st = seq->private; | ||
391 | 399 | ||
392 | for (i = 0; i <= *pos; i++) { | 400 | head = head->next; |
393 | e = e->next; | 401 | while (head == NULL) { |
394 | if (e == &nf_ct_expect_list) | 402 | if (++st->bucket >= nf_ct_expect_hsize) |
395 | return NULL; | 403 | return NULL; |
404 | head = nf_ct_expect_hash[st->bucket].first; | ||
396 | } | 405 | } |
397 | return e; | 406 | return head; |
398 | } | 407 | } |
399 | 408 | ||
400 | static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos) | 409 | static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos) |
401 | { | 410 | { |
402 | struct list_head *e = v; | 411 | struct hlist_node *head = ct_expect_get_first(seq); |
403 | 412 | ||
404 | ++*pos; | 413 | if (head) |
405 | e = e->next; | 414 | while (pos && (head = ct_expect_get_next(seq, head))) |
415 | pos--; | ||
416 | return pos ? NULL : head; | ||
417 | } | ||
406 | 418 | ||
407 | if (e == &nf_ct_expect_list) | 419 | static void *exp_seq_start(struct seq_file *seq, loff_t *pos) |
408 | return NULL; | 420 | { |
421 | read_lock_bh(&nf_conntrack_lock); | ||
422 | return ct_expect_get_idx(seq, *pos); | ||
423 | } | ||
409 | 424 | ||
410 | return e; | 425 | static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
426 | { | ||
427 | (*pos)++; | ||
428 | return ct_expect_get_next(seq, v); | ||
411 | } | 429 | } |
412 | 430 | ||
413 | static void exp_seq_stop(struct seq_file *s, void *v) | 431 | static void exp_seq_stop(struct seq_file *seq, void *v) |
414 | { | 432 | { |
415 | read_unlock_bh(&nf_conntrack_lock); | 433 | read_unlock_bh(&nf_conntrack_lock); |
416 | } | 434 | } |
417 | 435 | ||
418 | static int exp_seq_show(struct seq_file *s, void *v) | 436 | static int exp_seq_show(struct seq_file *s, void *v) |
419 | { | 437 | { |
420 | struct nf_conntrack_expect *expect = v; | 438 | struct nf_conntrack_expect *expect; |
439 | struct hlist_node *n = v; | ||
440 | |||
441 | expect = hlist_entry(n, struct nf_conntrack_expect, hnode); | ||
421 | 442 | ||
422 | if (expect->timeout.function) | 443 | if (expect->timeout.function) |
423 | seq_printf(s, "%ld ", timer_pending(&expect->timeout) | 444 | seq_printf(s, "%ld ", timer_pending(&expect->timeout) |
@@ -443,15 +464,31 @@ static struct seq_operations exp_seq_ops = { | |||
443 | 464 | ||
444 | static int exp_open(struct inode *inode, struct file *file) | 465 | static int exp_open(struct inode *inode, struct file *file) |
445 | { | 466 | { |
446 | return seq_open(file, &exp_seq_ops); | 467 | struct seq_file *seq; |
468 | struct ct_expect_iter_state *st; | ||
469 | int ret; | ||
470 | |||
471 | st = kmalloc(sizeof(struct ct_expect_iter_state), GFP_KERNEL); | ||
472 | if (st == NULL) | ||
473 | return -ENOMEM; | ||
474 | ret = seq_open(file, &exp_seq_ops); | ||
475 | if (ret) | ||
476 | goto out_free; | ||
477 | seq = file->private_data; | ||
478 | seq->private = st; | ||
479 | memset(st, 0, sizeof(struct ct_expect_iter_state)); | ||
480 | return ret; | ||
481 | out_free: | ||
482 | kfree(st); | ||
483 | return ret; | ||
447 | } | 484 | } |
448 | 485 | ||
449 | const struct file_operations exp_file_ops = { | 486 | static const struct file_operations exp_file_ops = { |
450 | .owner = THIS_MODULE, | 487 | .owner = THIS_MODULE, |
451 | .open = exp_open, | 488 | .open = exp_open, |
452 | .read = seq_read, | 489 | .read = seq_read, |
453 | .llseek = seq_lseek, | 490 | .llseek = seq_lseek, |
454 | .release = seq_release | 491 | .release = seq_release_private, |
455 | }; | 492 | }; |
456 | #endif /* CONFIG_PROC_FS */ | 493 | #endif /* CONFIG_PROC_FS */ |
457 | 494 | ||