Phonet: sockets list through proc_fs
authorRémi Denis-Courmont <remi.denis-courmont@nokia.com>
Tue, 21 Jul 2009 01:57:57 +0000 (01:57 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 24 Jul 2009 00:58:19 +0000 (17:58 -0700)
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>
include/net/phonet/pn_dev.h
net/phonet/pn_dev.c
net/phonet/socket.c

index 29d126736611c7ad693f9e84439d3bab56f012ad..44c923c9e21da3bce72b7f86e43873b5d180c226 100644 (file)
@@ -49,4 +49,6 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr);
 
 #define PN_NO_ADDR     0xff
 
+extern const struct file_operations pn_sock_seq_fops;
+
 #endif
index b0d6ddd82a9da1b20ce14bf2b76099cdf72362bc..5107b7949c9cf1e950679d0265e4b5715fbf404f 100644 (file)
@@ -218,6 +218,11 @@ static int phonet_init_net(struct net *net)
        if (!pnn)
                return -ENOMEM;
 
+       if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops)) {
+               kfree(pnn);
+               return -ENOMEM;
+       }
+
        INIT_LIST_HEAD(&pnn->pndevs.list);
        spin_lock_init(&pnn->pndevs.lock);
        net_assign_generic(net, phonet_net_id, pnn);
@@ -233,6 +238,8 @@ static void phonet_exit_net(struct net *net)
        for_each_netdev(net, dev)
                phonet_device_destroy(dev);
        rtnl_unlock();
+
+       proc_net_remove(net, "phonet");
        kfree(pnn);
 }
 
index ada2a35bf7a2382f49c49f771403e70d6b5d0359..aa1617a7f265ceef49af3971fbd414724cff71c7 100644 (file)
@@ -412,3 +412,99 @@ found:
        return 0;
 }
 EXPORT_SYMBOL(pn_sock_get_port);
+
+static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos)
+{
+       struct net *net = seq_file_net(seq);
+       struct hlist_node *node;
+       struct sock *sknode;
+
+       sk_for_each(sknode, node, &pnsocks.hlist) {
+               if (!net_eq(net, sock_net(sknode)))
+                       continue;
+               if (!pos)
+                       return sknode;
+               pos--;
+       }
+       return NULL;
+}
+
+static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk)
+{
+       struct net *net = seq_file_net(seq);
+
+       do
+               sk = sk_next(sk);
+       while (sk && !net_eq(net, sock_net(sk)));
+
+       return sk;
+}
+
+static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(pnsocks.lock)
+{
+       spin_lock_bh(&pnsocks.lock);
+       return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct sock *sk;
+
+       if (v == SEQ_START_TOKEN)
+               sk = pn_sock_get_idx(seq, 0);
+       else
+               sk = pn_sock_get_next(seq, v);
+       (*pos)++;
+       return sk;
+}
+
+static void pn_sock_seq_stop(struct seq_file *seq, void *v)
+       __releases(pnsocks.lock)
+{
+       spin_unlock_bh(&pnsocks.lock);
+}
+
+static int pn_sock_seq_show(struct seq_file *seq, void *v)
+{
+       int len;
+
+       if (v == SEQ_START_TOKEN)
+               seq_printf(seq, "%s%n", "pt  loc  rem rs st tx_queue rx_queue "
+                       "  uid inode ref pointer drops", &len);
+       else {
+               struct sock *sk = v;
+               struct pn_sock *pn = pn_sk(sk);
+
+               seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
+                       "%d %p %d%n",
+                       sk->sk_protocol, pn->sobject, 0, pn->resource,
+                       sk->sk_state,
+                       sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
+                       sock_i_uid(sk), sock_i_ino(sk),
+                       atomic_read(&sk->sk_refcnt), sk,
+                       atomic_read(&sk->sk_drops), &len);
+       }
+       seq_printf(seq, "%*s\n", 127 - len, "");
+       return 0;
+}
+
+static const struct seq_operations pn_sock_seq_ops = {
+       .start = pn_sock_seq_start,
+       .next = pn_sock_seq_next,
+       .stop = pn_sock_seq_stop,
+       .show = pn_sock_seq_show,
+};
+
+static int pn_sock_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &pn_sock_seq_ops);
+}
+
+const struct file_operations pn_sock_seq_fops = {
+       .owner = THIS_MODULE,
+       .open = pn_sock_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};