diff options
Diffstat (limited to 'net/phonet/socket.c')
-rw-r--r-- | net/phonet/socket.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/net/phonet/socket.c b/net/phonet/socket.c index ada2a35bf7a2..aa1617a7f265 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c | |||
@@ -412,3 +412,99 @@ found: | |||
412 | return 0; | 412 | return 0; |
413 | } | 413 | } |
414 | EXPORT_SYMBOL(pn_sock_get_port); | 414 | EXPORT_SYMBOL(pn_sock_get_port); |
415 | |||
416 | static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos) | ||
417 | { | ||
418 | struct net *net = seq_file_net(seq); | ||
419 | struct hlist_node *node; | ||
420 | struct sock *sknode; | ||
421 | |||
422 | sk_for_each(sknode, node, &pnsocks.hlist) { | ||
423 | if (!net_eq(net, sock_net(sknode))) | ||
424 | continue; | ||
425 | if (!pos) | ||
426 | return sknode; | ||
427 | pos--; | ||
428 | } | ||
429 | return NULL; | ||
430 | } | ||
431 | |||
432 | static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk) | ||
433 | { | ||
434 | struct net *net = seq_file_net(seq); | ||
435 | |||
436 | do | ||
437 | sk = sk_next(sk); | ||
438 | while (sk && !net_eq(net, sock_net(sk))); | ||
439 | |||
440 | return sk; | ||
441 | } | ||
442 | |||
443 | static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos) | ||
444 | __acquires(pnsocks.lock) | ||
445 | { | ||
446 | spin_lock_bh(&pnsocks.lock); | ||
447 | return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; | ||
448 | } | ||
449 | |||
450 | static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
451 | { | ||
452 | struct sock *sk; | ||
453 | |||
454 | if (v == SEQ_START_TOKEN) | ||
455 | sk = pn_sock_get_idx(seq, 0); | ||
456 | else | ||
457 | sk = pn_sock_get_next(seq, v); | ||
458 | (*pos)++; | ||
459 | return sk; | ||
460 | } | ||
461 | |||
462 | static void pn_sock_seq_stop(struct seq_file *seq, void *v) | ||
463 | __releases(pnsocks.lock) | ||
464 | { | ||
465 | spin_unlock_bh(&pnsocks.lock); | ||
466 | } | ||
467 | |||
468 | static int pn_sock_seq_show(struct seq_file *seq, void *v) | ||
469 | { | ||
470 | int len; | ||
471 | |||
472 | if (v == SEQ_START_TOKEN) | ||
473 | seq_printf(seq, "%s%n", "pt loc rem rs st tx_queue rx_queue " | ||
474 | " uid inode ref pointer drops", &len); | ||
475 | else { | ||
476 | struct sock *sk = v; | ||
477 | struct pn_sock *pn = pn_sk(sk); | ||
478 | |||
479 | seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu " | ||
480 | "%d %p %d%n", | ||
481 | sk->sk_protocol, pn->sobject, 0, pn->resource, | ||
482 | sk->sk_state, | ||
483 | sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk), | ||
484 | sock_i_uid(sk), sock_i_ino(sk), | ||
485 | atomic_read(&sk->sk_refcnt), sk, | ||
486 | atomic_read(&sk->sk_drops), &len); | ||
487 | } | ||
488 | seq_printf(seq, "%*s\n", 127 - len, ""); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static const struct seq_operations pn_sock_seq_ops = { | ||
493 | .start = pn_sock_seq_start, | ||
494 | .next = pn_sock_seq_next, | ||
495 | .stop = pn_sock_seq_stop, | ||
496 | .show = pn_sock_seq_show, | ||
497 | }; | ||
498 | |||
499 | static int pn_sock_open(struct inode *inode, struct file *file) | ||
500 | { | ||
501 | return seq_open(file, &pn_sock_seq_ops); | ||
502 | } | ||
503 | |||
504 | const struct file_operations pn_sock_seq_fops = { | ||
505 | .owner = THIS_MODULE, | ||
506 | .open = pn_sock_open, | ||
507 | .read = seq_read, | ||
508 | .llseek = seq_lseek, | ||
509 | .release = seq_release, | ||
510 | }; | ||