aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorMasatake YAMATO <yamato@redhat.com>2012-07-25 12:26:32 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-08-06 14:02:58 -0400
commit256a06c8a85df676e80263af349daad1283e529e (patch)
treefeb44aa2fcbcc0ec6a4827f8323153bba4a380fc /net/bluetooth
parent4af66c691f4e5c2db9bb00793669a548e9db1974 (diff)
Bluetooth: /proc/net/ entries for bluetooth protocols
lsof command can tell the type of socket processes are using. Internal lsof uses inode numbers on socket fs to resolve the type of sockets. Files under /proc/net/, such as tcp, udp, unix, etc provides such inode information. Unfortunately bluetooth related protocols don't provide such inode information. This patch series introduces /proc/net files for the protocols. This patch against af_bluetooth.c provides facility to the implementation of protocols. This patch extends bt_sock_list and introduces two exported function bt_procfs_init, bt_procfs_cleanup. The type bt_sock_list is already used in some of implementation of protocols. bt_procfs_init prepare seq_operations which converts protocol own bt_sock_list data to protocol own proc entry when the entry is accessed. What I, lsof user, need is just inode number of bluetooth socket. However, people may want more information. The bt_procfs_init takes a function pointer for customizing the show handler of seq_operations. In v4 patch, __acquires and __releases attributes are added to suppress sparse warning. Suggested by Andrei Emeltchenko. In v5 patch, linux/proc_fs.h is included to use PDE. Build error is reported by Fengguang Wu. Signed-off-by: Masatake YAMATO <yamato@redhat.com> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/af_bluetooth.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index f7db5792ec64..58f9762b339a 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -28,6 +28,7 @@
28#include <asm/ioctls.h> 28#include <asm/ioctls.h>
29 29
30#include <net/bluetooth/bluetooth.h> 30#include <net/bluetooth/bluetooth.h>
31#include <linux/proc_fs.h>
31 32
32#define VERSION "2.16" 33#define VERSION "2.16"
33 34
@@ -532,6 +533,146 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
532} 533}
533EXPORT_SYMBOL(bt_sock_wait_state); 534EXPORT_SYMBOL(bt_sock_wait_state);
534 535
536#ifdef CONFIG_PROC_FS
537struct bt_seq_state {
538 struct bt_sock_list *l;
539};
540
541static void *bt_seq_start(struct seq_file *seq, loff_t *pos)
542 __acquires(seq->private->l->lock)
543{
544 struct bt_seq_state *s = seq->private;
545 struct bt_sock_list *l = s->l;
546
547 read_lock(&l->lock);
548 return seq_hlist_start_head(&l->head, *pos);
549}
550
551static void *bt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
552{
553 struct bt_seq_state *s = seq->private;
554 struct bt_sock_list *l = s->l;
555
556 return seq_hlist_next(v, &l->head, pos);
557}
558
559static void bt_seq_stop(struct seq_file *seq, void *v)
560 __releases(seq->private->l->lock)
561{
562 struct bt_seq_state *s = seq->private;
563 struct bt_sock_list *l = s->l;
564
565 read_unlock(&l->lock);
566}
567
568static int bt_seq_show(struct seq_file *seq, void *v)
569{
570 struct sock *sk;
571 struct bt_sock *bt;
572 struct bt_seq_state *s = seq->private;
573 struct bt_sock_list *l = s->l;
574 bdaddr_t src_baswapped, dst_baswapped;
575
576 if (v == SEQ_START_TOKEN) {
577 seq_puts(seq ,"sk RefCnt Rmem Wmem User Inode Src Dst Parent");
578
579 if (l->custom_seq_show) {
580 seq_putc(seq, ' ');
581 l->custom_seq_show(seq, v);
582 }
583
584 seq_putc(seq, '\n');
585 } else {
586 sk = sk_entry(v);
587 bt = bt_sk(sk);
588 baswap(&src_baswapped, &bt->src);
589 baswap(&dst_baswapped, &bt->dst);
590
591 seq_printf(seq, "%pK %-6d %-6u %-6u %-6u %-6lu %pM %pM %-6lu",
592 sk,
593 atomic_read(&sk->sk_refcnt),
594 sk_rmem_alloc_get(sk),
595 sk_wmem_alloc_get(sk),
596 sock_i_uid(sk),
597 sock_i_ino(sk),
598 &src_baswapped,
599 &dst_baswapped,
600 bt->parent? sock_i_ino(bt->parent): 0LU);
601
602 if (l->custom_seq_show) {
603 seq_putc(seq, ' ');
604 l->custom_seq_show(seq, v);
605 }
606
607 seq_putc(seq, '\n');
608 }
609 return 0;
610}
611
612static struct seq_operations bt_seq_ops = {
613 .start = bt_seq_start,
614 .next = bt_seq_next,
615 .stop = bt_seq_stop,
616 .show = bt_seq_show,
617};
618
619static int bt_seq_open(struct inode *inode, struct file *file)
620{
621 struct bt_sock_list *sk_list;
622 struct bt_seq_state *s;
623
624 sk_list = PDE(inode)->data;
625 s = __seq_open_private(file, &bt_seq_ops,
626 sizeof(struct bt_seq_state));
627 if (s == NULL)
628 return -ENOMEM;
629
630 s->l = sk_list;
631 return 0;
632}
633
634int bt_procfs_init(struct module* module, struct net *net, const char *name,
635 struct bt_sock_list* sk_list,
636 int (* seq_show)(struct seq_file *, void *))
637{
638 struct proc_dir_entry * pde;
639
640 sk_list->custom_seq_show = seq_show;
641
642 sk_list->fops.owner = module;
643 sk_list->fops.open = bt_seq_open;
644 sk_list->fops.read = seq_read;
645 sk_list->fops.llseek = seq_lseek;
646 sk_list->fops.release = seq_release_private;
647
648 pde = proc_net_fops_create(net, name, 0, &sk_list->fops);
649 if (pde == NULL)
650 return -ENOMEM;
651
652 pde->data = sk_list;
653
654 return 0;
655}
656
657void bt_procfs_cleanup(struct net *net, const char *name)
658{
659 proc_net_remove(net, name);
660}
661#else
662int bt_procfs_init(struct module* module, struct net *net, const char *name,
663 struct bt_sock_list* sk_list,
664 int (* seq_show)(struct seq_file *, void *))
665{
666 return 0;
667}
668
669void bt_procfs_cleanup(struct net *net, const char *name)
670{
671}
672#endif
673EXPORT_SYMBOL(bt_procfs_init);
674EXPORT_SYMBOL(bt_procfs_cleanup);
675
535static struct net_proto_family bt_sock_family_ops = { 676static struct net_proto_family bt_sock_family_ops = {
536 .owner = THIS_MODULE, 677 .owner = THIS_MODULE,
537 .family = PF_BLUETOOTH, 678 .family = PF_BLUETOOTH,