1 /* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
4 * Copyright (C) 2005 Oracle. All rights reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 021110-1307, USA.
22 #include <linux/module.h>
23 #include <linux/types.h>
24 #include <linux/slab.h>
25 #include <linux/idr.h>
26 #include <linux/kref.h>
27 #include <linux/seq_file.h>
29 #include <asm/uaccess.h>
32 #include "nodemanager.h"
33 #define MLOG_MASK_PREFIX ML_TCP
36 #include "tcp_internal.h"
38 static spinlock_t o2net_proc_lock = SPIN_LOCK_UNLOCKED;
40 static LIST_HEAD(sock_containers);
41 static LIST_HEAD(send_tracking);
43 void o2net_proc_add_nst(struct o2net_send_tracking *nst)
45 spin_lock(&o2net_proc_lock);
46 list_add(&nst->st_net_proc_item, &send_tracking);
47 spin_unlock(&o2net_proc_lock);
49 void o2net_proc_del_nst(struct o2net_send_tracking *nst)
51 spin_lock(&o2net_proc_lock);
52 if (!list_empty(&nst->st_net_proc_item))
53 list_del_init(&nst->st_net_proc_item);
54 spin_unlock(&o2net_proc_lock);
57 static struct o2net_send_tracking *next_nst(struct o2net_send_tracking *nst_start)
59 struct o2net_send_tracking *nst, *ret = NULL;
61 assert_spin_locked(&o2net_proc_lock);
63 list_for_each_entry(nst, &nst_start->st_net_proc_item,
65 /* discover the head of the list */
66 if (&nst->st_net_proc_item == &send_tracking)
69 /* use st_task to detect real nsts in the list */
70 if (nst->st_task != NULL) {
79 static void *nst_seq_start(struct seq_file *seq, loff_t *pos)
81 struct o2net_send_tracking *nst, *dummy_nst = seq->private;
83 spin_lock(&o2net_proc_lock);
84 nst = next_nst(dummy_nst);
85 spin_unlock(&o2net_proc_lock);
90 static void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos)
92 struct o2net_send_tracking *nst, *dummy_nst = seq->private;
94 spin_lock(&o2net_proc_lock);
95 nst = next_nst(dummy_nst);
96 list_del_init(&dummy_nst->st_net_proc_item);
98 list_add(&dummy_nst->st_net_proc_item,
99 &nst->st_net_proc_item);
100 spin_unlock(&o2net_proc_lock);
102 return nst; /* unused, just needs to be null when done */
105 static int nst_seq_show(struct seq_file *seq, void *v)
107 struct o2net_send_tracking *nst, *dummy_nst = seq->private;
109 spin_lock(&o2net_proc_lock);
110 nst = next_nst(dummy_nst);
113 /* get_task_comm isn't exported. oh well. */
114 seq_printf(seq, "%p:\n"
117 " process name: %s\n"
121 " message type: %u\n"
122 " message key: 0x%08x\n"
123 " sock acquiry: %lu.%lu\n"
124 " send start: %lu.%lu\n"
125 " wait start: %lu.%lu\n",
126 nst, (unsigned long)nst->st_task->pid,
127 (unsigned long)nst->st_task->tgid,
128 nst->st_task->comm, nst->st_node,
129 nst->st_sc, nst->st_id, nst->st_msg_type,
131 nst->st_sock_time.tv_sec, nst->st_sock_time.tv_usec,
132 nst->st_send_time.tv_sec, nst->st_send_time.tv_usec,
133 nst->st_status_time.tv_sec,
134 nst->st_status_time.tv_usec);
137 spin_unlock(&o2net_proc_lock);
142 static void nst_seq_stop(struct seq_file *seq, void *v)
146 static struct seq_operations nst_seq_ops = {
147 .start = nst_seq_start,
148 .next = nst_seq_next,
149 .stop = nst_seq_stop,
150 .show = nst_seq_show,
153 static int nst_fop_open(struct inode *inode, struct file *file)
155 struct o2net_send_tracking *dummy_nst;
156 struct seq_file *seq;
159 dummy_nst = kmalloc(sizeof(struct o2net_send_tracking), GFP_KERNEL);
160 if (dummy_nst == NULL) {
164 dummy_nst->st_task = NULL;
166 ret = seq_open(file, &nst_seq_ops);
170 seq = file->private_data;
171 seq->private = dummy_nst;
172 o2net_proc_add_nst(dummy_nst);
181 static int nst_fop_release(struct inode *inode, struct file *file)
183 struct seq_file *seq = file->private_data;
184 struct o2net_send_tracking *dummy_nst = seq->private;
186 o2net_proc_del_nst(dummy_nst);
187 return seq_release_private(inode, file);
190 static struct file_operations nst_seq_fops = {
191 .owner = THIS_MODULE,
192 .open = nst_fop_open,
195 .release = nst_fop_release,
198 void o2net_proc_add_sc(struct o2net_sock_container *sc)
200 spin_lock(&o2net_proc_lock);
201 list_add(&sc->sc_net_proc_item, &sock_containers);
202 spin_unlock(&o2net_proc_lock);
205 void o2net_proc_del_sc(struct o2net_sock_container *sc)
207 spin_lock(&o2net_proc_lock);
208 list_del_init(&sc->sc_net_proc_item);
209 spin_unlock(&o2net_proc_lock);
212 static struct o2net_sock_container *next_sc(struct o2net_sock_container *sc_start)
214 struct o2net_sock_container *sc, *ret = NULL;
216 assert_spin_locked(&o2net_proc_lock);
218 list_for_each_entry(sc, &sc_start->sc_net_proc_item, sc_net_proc_item) {
219 /* discover the head of the list miscast as a sc */
220 if (&sc->sc_net_proc_item == &sock_containers)
223 /* use sc_page to detect real scs in the list */
224 if (sc->sc_page != NULL) {
233 static void *sc_seq_start(struct seq_file *seq, loff_t *pos)
235 struct o2net_sock_container *sc, *dummy_sc = seq->private;
237 spin_lock(&o2net_proc_lock);
238 sc = next_sc(dummy_sc);
239 spin_unlock(&o2net_proc_lock);
244 static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
246 struct o2net_sock_container *sc, *dummy_sc = seq->private;
248 spin_lock(&o2net_proc_lock);
249 sc = next_sc(dummy_sc);
250 list_del_init(&dummy_sc->sc_net_proc_item);
252 list_add(&dummy_sc->sc_net_proc_item, &sc->sc_net_proc_item);
253 spin_unlock(&o2net_proc_lock);
255 return sc; /* unused, just needs to be null when done */
258 #define TV_SEC_USEC(TV) TV.tv_sec, TV.tv_usec
260 static int sc_seq_show(struct seq_file *seq, void *v)
262 struct o2net_sock_container *sc, *dummy_sc = seq->private;
264 spin_lock(&o2net_proc_lock);
265 sc = next_sc(dummy_sc);
268 /* netdev 1, world 0 */
269 #ifdef INET_SK_RETURNS_INET_OPT
270 struct inet_opt *inet = NULL;
272 struct inet_sock *inet = NULL;
274 __be32 saddr = 0, daddr = 0;
275 __be16 sport = 0, dport = 0;
278 inet = inet_sk(sc->sc_sock->sk);
279 /* the stack's structs aren't sparse endian clean */
280 saddr = (__force __be32)inet->saddr;
281 daddr = (__force __be32)inet->daddr;
282 sport = (__force __be16)inet->sport;
283 dport = (__force __be16)inet->dport;
286 /* XXX sigh, inet-> doesn't have sparse annotation so any
287 * use of it here generates a warning with -Wbitwise */
288 seq_printf(seq, "%p:\n"
290 " sock: %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n"
293 " handshake ok: %u\n"
295 " data ready: %lu.%lu\n"
296 " advance start: %lu.%lu\n"
297 " advance stop: %lu.%lu\n"
298 " func start: %lu.%lu\n"
299 " func stop: %lu.%lu\n"
303 atomic_read(&sc->sc_kref.refcount),
304 NIPQUAD(saddr), inet ? ntohs(sport) : 0,
305 NIPQUAD(daddr), inet ? ntohs(dport) : 0,
306 sc->sc_node->nd_name,
309 TV_SEC_USEC(sc->sc_tv_timer),
310 TV_SEC_USEC(sc->sc_tv_data_ready),
311 TV_SEC_USEC(sc->sc_tv_advance_start),
312 TV_SEC_USEC(sc->sc_tv_advance_stop),
313 TV_SEC_USEC(sc->sc_tv_func_start),
314 TV_SEC_USEC(sc->sc_tv_func_stop),
320 spin_unlock(&o2net_proc_lock);
325 static void sc_seq_stop(struct seq_file *seq, void *v)
329 static struct seq_operations sc_seq_ops = {
330 .start = sc_seq_start,
336 static int sc_fop_open(struct inode *inode, struct file *file)
338 struct o2net_sock_container *dummy_sc;
339 struct seq_file *seq;
342 dummy_sc = kmalloc(sizeof(struct o2net_sock_container), GFP_KERNEL);
343 if (dummy_sc == NULL) {
347 dummy_sc->sc_page = NULL;
349 ret = seq_open(file, &sc_seq_ops);
353 seq = file->private_data;
354 seq->private = dummy_sc;
355 o2net_proc_add_sc(dummy_sc);
364 static int sc_fop_release(struct inode *inode, struct file *file)
366 struct seq_file *seq = file->private_data;
367 struct o2net_sock_container *dummy_sc = seq->private;
369 o2net_proc_del_sc(dummy_sc);
370 return seq_release_private(inode, file);
373 static struct file_operations sc_seq_fops = {
374 .owner = THIS_MODULE,
378 .release = sc_fop_release,
381 #define SC_PROC_NAME "sock_containers"
382 #define NST_PROC_NAME "send_tracking"
384 void o2net_proc_exit(struct proc_dir_entry *parent)
386 remove_proc_entry(SC_PROC_NAME, parent);
387 remove_proc_entry(NST_PROC_NAME, parent);
389 EXPORT_SYMBOL_GPL(o2net_proc_exit);
391 int o2net_proc_init(struct proc_dir_entry *parent)
393 struct proc_dir_entry *proc_sc = NULL, *proc_nst = NULL;
396 proc_sc = create_proc_entry(SC_PROC_NAME, S_IRUGO, parent);
397 proc_nst = create_proc_entry(NST_PROC_NAME, S_IRUGO, parent);
399 if (proc_sc && proc_nst) {
401 proc_sc->proc_fops = &sc_seq_fops;
402 proc_nst->proc_fops = &nst_seq_fops;
406 remove_proc_entry(SC_PROC_NAME, parent);
408 remove_proc_entry(NST_PROC_NAME, parent);
413 EXPORT_SYMBOL_GPL(o2net_proc_init);