diff options
author | Rémi Denis-Courmont <remi.denis-courmont@nokia.com> | 2009-07-20 21:57:57 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-07-23 20:58:19 -0400 |
commit | c1dc13e9d0bc35a8d85bf4238c48c1b627d48f35 (patch) | |
tree | 7bc3ecf8a72b1dc940f6cd676eb9bcfebfc2402e | |
parent | e8834a63bddf87f7b85955d1ba60d28343d88469 (diff) |
Phonet: sockets list through proc_fs
This provides a list of sockets with their Phonet bind addresses and
some socket debug informations through /proc/net/phonet.
Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/phonet/pn_dev.h | 2 | ||||
-rw-r--r-- | net/phonet/pn_dev.c | 7 | ||||
-rw-r--r-- | net/phonet/socket.c | 96 |
3 files changed, 105 insertions, 0 deletions
diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h index 29d126736611..44c923c9e21d 100644 --- a/include/net/phonet/pn_dev.h +++ b/include/net/phonet/pn_dev.h | |||
@@ -49,4 +49,6 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr); | |||
49 | 49 | ||
50 | #define PN_NO_ADDR 0xff | 50 | #define PN_NO_ADDR 0xff |
51 | 51 | ||
52 | extern const struct file_operations pn_sock_seq_fops; | ||
53 | |||
52 | #endif | 54 | #endif |
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index b0d6ddd82a9d..5107b7949c9c 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c | |||
@@ -218,6 +218,11 @@ static int phonet_init_net(struct net *net) | |||
218 | if (!pnn) | 218 | if (!pnn) |
219 | return -ENOMEM; | 219 | return -ENOMEM; |
220 | 220 | ||
221 | if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) { | ||
222 | kfree(pnn); | ||
223 | return -ENOMEM; | ||
224 | } | ||
225 | |||
221 | INIT_LIST_HEAD(&pnn->pndevs.list); | 226 | INIT_LIST_HEAD(&pnn->pndevs.list); |
222 | spin_lock_init(&pnn->pndevs.lock); | 227 | spin_lock_init(&pnn->pndevs.lock); |
223 | net_assign_generic(net, phonet_net_id, pnn); | 228 | net_assign_generic(net, phonet_net_id, pnn); |
@@ -233,6 +238,8 @@ static void phonet_exit_net(struct net *net) | |||
233 | for_each_netdev(net, dev) | 238 | for_each_netdev(net, dev) |
234 | phonet_device_destroy(dev); | 239 | phonet_device_destroy(dev); |
235 | rtnl_unlock(); | 240 | rtnl_unlock(); |
241 | |||
242 | proc_net_remove(net, "phonet"); | ||
236 | kfree(pnn); | 243 | kfree(pnn); |
237 | } | 244 | } |
238 | 245 | ||
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 | }; | ||