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 | |
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')
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c | 83 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 85 |
2 files changed, 121 insertions, 47 deletions
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index 12d6a6327b63..ab8e4c607b7a 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c | |||
@@ -207,47 +207,68 @@ static const struct file_operations ct_file_ops = { | |||
207 | }; | 207 | }; |
208 | 208 | ||
209 | /* expects */ | 209 | /* expects */ |
210 | static void *exp_seq_start(struct seq_file *s, loff_t *pos) | 210 | struct ct_expect_iter_state { |
211 | unsigned int bucket; | ||
212 | }; | ||
213 | |||
214 | static struct hlist_node *ct_expect_get_first(struct seq_file *seq) | ||
211 | { | 215 | { |
212 | struct list_head *e = &nf_ct_expect_list; | 216 | struct ct_expect_iter_state *st = seq->private; |
213 | loff_t i; | ||
214 | 217 | ||
215 | /* strange seq_file api calls stop even if we fail, | 218 | for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { |
216 | * thus we need to grab lock since stop unlocks */ | 219 | if (!hlist_empty(&nf_ct_expect_hash[st->bucket])) |
217 | read_lock_bh(&nf_conntrack_lock); | 220 | return nf_ct_expect_hash[st->bucket].first; |
221 | } | ||
222 | return NULL; | ||
223 | } | ||
218 | 224 | ||
219 | if (list_empty(e)) | 225 | static struct hlist_node *ct_expect_get_next(struct seq_file *seq, |
220 | return NULL; | 226 | struct hlist_node *head) |
227 | { | ||
228 | struct ct_expect_iter_state *st = seq->private; | ||
221 | 229 | ||
222 | for (i = 0; i <= *pos; i++) { | 230 | head = head->next; |
223 | e = e->next; | 231 | while (head == NULL) { |
224 | if (e == &nf_ct_expect_list) | 232 | if (++st->bucket >= nf_ct_expect_hsize) |
225 | return NULL; | 233 | return NULL; |
234 | head = nf_ct_expect_hash[st->bucket].first; | ||
226 | } | 235 | } |
227 | return e; | 236 | return head; |
228 | } | 237 | } |
229 | 238 | ||
230 | static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos) | 239 | static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos) |
231 | { | 240 | { |
232 | struct list_head *e = v; | 241 | struct hlist_node *head = ct_expect_get_first(seq); |
233 | 242 | ||
234 | ++*pos; | 243 | if (head) |
235 | e = e->next; | 244 | while (pos && (head = ct_expect_get_next(seq, head))) |
245 | pos--; | ||
246 | return pos ? NULL : head; | ||
247 | } | ||
236 | 248 | ||
237 | if (e == &nf_ct_expect_list) | 249 | static void *exp_seq_start(struct seq_file *seq, loff_t *pos) |
238 | return NULL; | 250 | { |
251 | read_lock_bh(&nf_conntrack_lock); | ||
252 | return ct_expect_get_idx(seq, *pos); | ||
253 | } | ||
239 | 254 | ||
240 | return e; | 255 | static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
256 | { | ||
257 | (*pos)++; | ||
258 | return ct_expect_get_next(seq, v); | ||
241 | } | 259 | } |
242 | 260 | ||
243 | static void exp_seq_stop(struct seq_file *s, void *v) | 261 | static void exp_seq_stop(struct seq_file *seq, void *v) |
244 | { | 262 | { |
245 | read_unlock_bh(&nf_conntrack_lock); | 263 | read_unlock_bh(&nf_conntrack_lock); |
246 | } | 264 | } |
247 | 265 | ||
248 | static int exp_seq_show(struct seq_file *s, void *v) | 266 | static int exp_seq_show(struct seq_file *s, void *v) |
249 | { | 267 | { |
250 | struct nf_conntrack_expect *exp = v; | 268 | struct nf_conntrack_expect *exp; |
269 | struct hlist_node *n = v; | ||
270 | |||
271 | exp = hlist_entry(n, struct nf_conntrack_expect, hnode); | ||
251 | 272 | ||
252 | if (exp->tuple.src.l3num != AF_INET) | 273 | if (exp->tuple.src.l3num != AF_INET) |
253 | return 0; | 274 | return 0; |
@@ -276,7 +297,23 @@ static struct seq_operations exp_seq_ops = { | |||
276 | 297 | ||
277 | static int exp_open(struct inode *inode, struct file *file) | 298 | static int exp_open(struct inode *inode, struct file *file) |
278 | { | 299 | { |
279 | return seq_open(file, &exp_seq_ops); | 300 | struct seq_file *seq; |
301 | struct ct_expect_iter_state *st; | ||
302 | int ret; | ||
303 | |||
304 | st = kmalloc(sizeof(struct ct_expect_iter_state), GFP_KERNEL); | ||
305 | if (st == NULL) | ||
306 | return -ENOMEM; | ||
307 | ret = seq_open(file, &exp_seq_ops); | ||
308 | if (ret) | ||
309 | goto out_free; | ||
310 | seq = file->private_data; | ||
311 | seq->private = st; | ||
312 | memset(st, 0, sizeof(struct ct_expect_iter_state)); | ||
313 | return ret; | ||
314 | out_free: | ||
315 | kfree(st); | ||
316 | return ret; | ||
280 | } | 317 | } |
281 | 318 | ||
282 | static const struct file_operations ip_exp_file_ops = { | 319 | static const struct file_operations ip_exp_file_ops = { |
@@ -284,7 +321,7 @@ static const struct file_operations ip_exp_file_ops = { | |||
284 | .open = exp_open, | 321 | .open = exp_open, |
285 | .read = seq_read, | 322 | .read = seq_read, |
286 | .llseek = seq_lseek, | 323 | .llseek = seq_lseek, |
287 | .release = seq_release | 324 | .release = seq_release_private, |
288 | }; | 325 | }; |
289 | 326 | ||
290 | static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) | 327 | static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) |
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 | ||