Merge branches 'acpi-fan', 'acpi-ec', 'acpi-drivers' and 'acpi-osl'
[cascardo/linux.git] / net / kcm / kcmproc.c
1 #include <linux/in.h>
2 #include <linux/inet.h>
3 #include <linux/list.h>
4 #include <linux/module.h>
5 #include <linux/net.h>
6 #include <linux/proc_fs.h>
7 #include <linux/rculist.h>
8 #include <linux/seq_file.h>
9 #include <linux/socket.h>
10 #include <net/inet_sock.h>
11 #include <net/kcm.h>
12 #include <net/net_namespace.h>
13 #include <net/netns/generic.h>
14 #include <net/tcp.h>
15
16 #ifdef CONFIG_PROC_FS
17 struct kcm_seq_muxinfo {
18         char                            *name;
19         const struct file_operations    *seq_fops;
20         const struct seq_operations     seq_ops;
21 };
22
23 static struct kcm_mux *kcm_get_first(struct seq_file *seq)
24 {
25         struct net *net = seq_file_net(seq);
26         struct kcm_net *knet = net_generic(net, kcm_net_id);
27
28         return list_first_or_null_rcu(&knet->mux_list,
29                                       struct kcm_mux, kcm_mux_list);
30 }
31
32 static struct kcm_mux *kcm_get_next(struct kcm_mux *mux)
33 {
34         struct kcm_net *knet = mux->knet;
35
36         return list_next_or_null_rcu(&knet->mux_list, &mux->kcm_mux_list,
37                                      struct kcm_mux, kcm_mux_list);
38 }
39
40 static struct kcm_mux *kcm_get_idx(struct seq_file *seq, loff_t pos)
41 {
42         struct net *net = seq_file_net(seq);
43         struct kcm_net *knet = net_generic(net, kcm_net_id);
44         struct kcm_mux *m;
45
46         list_for_each_entry_rcu(m, &knet->mux_list, kcm_mux_list) {
47                 if (!pos)
48                         return m;
49                 --pos;
50         }
51         return NULL;
52 }
53
54 static void *kcm_seq_next(struct seq_file *seq, void *v, loff_t *pos)
55 {
56         void *p;
57
58         if (v == SEQ_START_TOKEN)
59                 p = kcm_get_first(seq);
60         else
61                 p = kcm_get_next(v);
62         ++*pos;
63         return p;
64 }
65
66 static void *kcm_seq_start(struct seq_file *seq, loff_t *pos)
67         __acquires(rcu)
68 {
69         rcu_read_lock();
70
71         if (!*pos)
72                 return SEQ_START_TOKEN;
73         else
74                 return kcm_get_idx(seq, *pos - 1);
75 }
76
77 static void kcm_seq_stop(struct seq_file *seq, void *v)
78         __releases(rcu)
79 {
80         rcu_read_unlock();
81 }
82
83 struct kcm_proc_mux_state {
84         struct seq_net_private p;
85         int idx;
86 };
87
88 static int kcm_seq_open(struct inode *inode, struct file *file)
89 {
90         struct kcm_seq_muxinfo *muxinfo = PDE_DATA(inode);
91
92         return seq_open_net(inode, file, &muxinfo->seq_ops,
93                            sizeof(struct kcm_proc_mux_state));
94 }
95
96 static void kcm_format_mux_header(struct seq_file *seq)
97 {
98         struct net *net = seq_file_net(seq);
99         struct kcm_net *knet = net_generic(net, kcm_net_id);
100
101         seq_printf(seq,
102                    "*** KCM statistics (%d MUX) ****\n",
103                    knet->count);
104
105         seq_printf(seq,
106                    "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s",
107                    "Object",
108                    "RX-Msgs",
109                    "RX-Bytes",
110                    "TX-Msgs",
111                    "TX-Bytes",
112                    "Recv-Q",
113                    "Rmem",
114                    "Send-Q",
115                    "Smem",
116                    "Status");
117
118         /* XXX: pdsts header stuff here */
119         seq_puts(seq, "\n");
120 }
121
122 static void kcm_format_sock(struct kcm_sock *kcm, struct seq_file *seq,
123                             int i, int *len)
124 {
125         seq_printf(seq,
126                    "   kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ",
127                    kcm->index,
128                    kcm->stats.rx_msgs,
129                    kcm->stats.rx_bytes,
130                    kcm->stats.tx_msgs,
131                    kcm->stats.tx_bytes,
132                    kcm->sk.sk_receive_queue.qlen,
133                    sk_rmem_alloc_get(&kcm->sk),
134                    kcm->sk.sk_write_queue.qlen,
135                    "-");
136
137         if (kcm->tx_psock)
138                 seq_printf(seq, "Psck-%u ", kcm->tx_psock->index);
139
140         if (kcm->tx_wait)
141                 seq_puts(seq, "TxWait ");
142
143         if (kcm->tx_wait_more)
144                 seq_puts(seq, "WMore ");
145
146         if (kcm->rx_wait)
147                 seq_puts(seq, "RxWait ");
148
149         seq_puts(seq, "\n");
150 }
151
152 static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
153                              int i, int *len)
154 {
155         seq_printf(seq,
156                    "   psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ",
157                    psock->index,
158                    psock->stats.rx_msgs,
159                    psock->stats.rx_bytes,
160                    psock->stats.tx_msgs,
161                    psock->stats.tx_bytes,
162                    psock->sk->sk_receive_queue.qlen,
163                    atomic_read(&psock->sk->sk_rmem_alloc),
164                    psock->sk->sk_write_queue.qlen,
165                    atomic_read(&psock->sk->sk_wmem_alloc));
166
167         if (psock->done)
168                 seq_puts(seq, "Done ");
169
170         if (psock->tx_stopped)
171                 seq_puts(seq, "TxStop ");
172
173         if (psock->rx_stopped)
174                 seq_puts(seq, "RxStop ");
175
176         if (psock->tx_kcm)
177                 seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index);
178
179         if (psock->ready_rx_msg)
180                 seq_puts(seq, "RdyRx ");
181
182         seq_puts(seq, "\n");
183 }
184
185 static void
186 kcm_format_mux(struct kcm_mux *mux, loff_t idx, struct seq_file *seq)
187 {
188         int i, len;
189         struct kcm_sock *kcm;
190         struct kcm_psock *psock;
191
192         /* mux information */
193         seq_printf(seq,
194                    "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ",
195                    "mux", "",
196                    mux->stats.rx_msgs,
197                    mux->stats.rx_bytes,
198                    mux->stats.tx_msgs,
199                    mux->stats.tx_bytes,
200                    "-", "-", "-", "-");
201
202         seq_printf(seq, "KCMs: %d, Psocks %d\n",
203                    mux->kcm_socks_cnt, mux->psocks_cnt);
204
205         /* kcm sock information */
206         i = 0;
207         spin_lock_bh(&mux->lock);
208         list_for_each_entry(kcm, &mux->kcm_socks, kcm_sock_list) {
209                 kcm_format_sock(kcm, seq, i, &len);
210                 i++;
211         }
212         i = 0;
213         list_for_each_entry(psock, &mux->psocks, psock_list) {
214                 kcm_format_psock(psock, seq, i, &len);
215                 i++;
216         }
217         spin_unlock_bh(&mux->lock);
218 }
219
220 static int kcm_seq_show(struct seq_file *seq, void *v)
221 {
222         struct kcm_proc_mux_state *mux_state;
223
224         mux_state = seq->private;
225         if (v == SEQ_START_TOKEN) {
226                 mux_state->idx = 0;
227                 kcm_format_mux_header(seq);
228         } else {
229                 kcm_format_mux(v, mux_state->idx, seq);
230                 mux_state->idx++;
231         }
232         return 0;
233 }
234
235 static const struct file_operations kcm_seq_fops = {
236         .owner          = THIS_MODULE,
237         .open           = kcm_seq_open,
238         .read           = seq_read,
239         .llseek         = seq_lseek,
240         .release        = seq_release_net,
241 };
242
243 static struct kcm_seq_muxinfo kcm_seq_muxinfo = {
244         .name           = "kcm",
245         .seq_fops       = &kcm_seq_fops,
246         .seq_ops        = {
247                 .show   = kcm_seq_show,
248                 .start  = kcm_seq_start,
249                 .next   = kcm_seq_next,
250                 .stop   = kcm_seq_stop,
251         }
252 };
253
254 static int kcm_proc_register(struct net *net, struct kcm_seq_muxinfo *muxinfo)
255 {
256         struct proc_dir_entry *p;
257         int rc = 0;
258
259         p = proc_create_data(muxinfo->name, S_IRUGO, net->proc_net,
260                              muxinfo->seq_fops, muxinfo);
261         if (!p)
262                 rc = -ENOMEM;
263         return rc;
264 }
265 EXPORT_SYMBOL(kcm_proc_register);
266
267 static void kcm_proc_unregister(struct net *net,
268                                 struct kcm_seq_muxinfo *muxinfo)
269 {
270         remove_proc_entry(muxinfo->name, net->proc_net);
271 }
272 EXPORT_SYMBOL(kcm_proc_unregister);
273
274 static int kcm_stats_seq_show(struct seq_file *seq, void *v)
275 {
276         struct kcm_psock_stats psock_stats;
277         struct kcm_mux_stats mux_stats;
278         struct kcm_mux *mux;
279         struct kcm_psock *psock;
280         struct net *net = seq->private;
281         struct kcm_net *knet = net_generic(net, kcm_net_id);
282
283         memset(&mux_stats, 0, sizeof(mux_stats));
284         memset(&psock_stats, 0, sizeof(psock_stats));
285
286         mutex_lock(&knet->mutex);
287
288         aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats);
289         aggregate_psock_stats(&knet->aggregate_psock_stats,
290                               &psock_stats);
291
292         list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) {
293                 spin_lock_bh(&mux->lock);
294                 aggregate_mux_stats(&mux->stats, &mux_stats);
295                 aggregate_psock_stats(&mux->aggregate_psock_stats,
296                                       &psock_stats);
297                 list_for_each_entry(psock, &mux->psocks, psock_list)
298                         aggregate_psock_stats(&psock->stats, &psock_stats);
299                 spin_unlock_bh(&mux->lock);
300         }
301
302         mutex_unlock(&knet->mutex);
303
304         seq_printf(seq,
305                    "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n",
306                    "MUX",
307                    "RX-Msgs",
308                    "RX-Bytes",
309                    "TX-Msgs",
310                    "TX-Bytes",
311                    "TX-Retries",
312                    "Attach",
313                    "Unattach",
314                    "UnattchRsvd",
315                    "RX-RdyDrops");
316
317         seq_printf(seq,
318                    "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n",
319                    "",
320                    mux_stats.rx_msgs,
321                    mux_stats.rx_bytes,
322                    mux_stats.tx_msgs,
323                    mux_stats.tx_bytes,
324                    mux_stats.tx_retries,
325                    mux_stats.psock_attach,
326                    mux_stats.psock_unattach_rsvd,
327                    mux_stats.psock_unattach,
328                    mux_stats.rx_ready_drops);
329
330         seq_printf(seq,
331                    "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
332                    "Psock",
333                    "RX-Msgs",
334                    "RX-Bytes",
335                    "TX-Msgs",
336                    "TX-Bytes",
337                    "Reserved",
338                    "Unreserved",
339                    "RX-Aborts",
340                    "RX-MemFail",
341                    "RX-NeedMor",
342                    "RX-BadLen",
343                    "RX-TooBig",
344                    "RX-Timeout",
345                    "TX-Aborts");
346
347         seq_printf(seq,
348                    "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",
349                    "",
350                    psock_stats.rx_msgs,
351                    psock_stats.rx_bytes,
352                    psock_stats.tx_msgs,
353                    psock_stats.tx_bytes,
354                    psock_stats.reserved,
355                    psock_stats.unreserved,
356                    psock_stats.rx_aborts,
357                    psock_stats.rx_mem_fail,
358                    psock_stats.rx_need_more_hdr,
359                    psock_stats.rx_bad_hdr_len,
360                    psock_stats.rx_msg_too_big,
361                    psock_stats.rx_msg_timeouts,
362                    psock_stats.tx_aborts);
363
364         return 0;
365 }
366
367 static int kcm_stats_seq_open(struct inode *inode, struct file *file)
368 {
369         return single_open_net(inode, file, kcm_stats_seq_show);
370 }
371
372 static const struct file_operations kcm_stats_seq_fops = {
373         .owner   = THIS_MODULE,
374         .open    = kcm_stats_seq_open,
375         .read    = seq_read,
376         .llseek  = seq_lseek,
377         .release = single_release_net,
378 };
379
380 static int kcm_proc_init_net(struct net *net)
381 {
382         int err;
383
384         if (!proc_create("kcm_stats", S_IRUGO, net->proc_net,
385                          &kcm_stats_seq_fops)) {
386                 err = -ENOMEM;
387                 goto out_kcm_stats;
388         }
389
390         err = kcm_proc_register(net, &kcm_seq_muxinfo);
391         if (err)
392                 goto out_kcm;
393
394         return 0;
395
396 out_kcm:
397         remove_proc_entry("kcm_stats", net->proc_net);
398 out_kcm_stats:
399         return err;
400 }
401
402 static void kcm_proc_exit_net(struct net *net)
403 {
404         kcm_proc_unregister(net, &kcm_seq_muxinfo);
405         remove_proc_entry("kcm_stats", net->proc_net);
406 }
407
408 static struct pernet_operations kcm_net_ops = {
409         .init = kcm_proc_init_net,
410         .exit = kcm_proc_exit_net,
411 };
412
413 int __init kcm_proc_init(void)
414 {
415         return register_pernet_subsys(&kcm_net_ops);
416 }
417
418 void __exit kcm_proc_exit(void)
419 {
420         unregister_pernet_subsys(&kcm_net_ops);
421 }
422
423 #endif /* CONFIG_PROC_FS */