xref: /linux/fs/ocfs2/cluster/netdebug.c (revision 2309e9e040fe29469fb85a384636c455b62fe525)
1*2309e9e0SSunil Mushran /* -*- mode: c; c-basic-offset: 8; -*-
2*2309e9e0SSunil Mushran  * vim: noexpandtab sw=8 ts=8 sts=0:
3*2309e9e0SSunil Mushran  *
4*2309e9e0SSunil Mushran  * netdebug.c
5*2309e9e0SSunil Mushran  *
6*2309e9e0SSunil Mushran  * debug functionality for o2net
7*2309e9e0SSunil Mushran  *
8*2309e9e0SSunil Mushran  * Copyright (C) 2005, 2008 Oracle.  All rights reserved.
9*2309e9e0SSunil Mushran  *
10*2309e9e0SSunil Mushran  * This program is free software; you can redistribute it and/or
11*2309e9e0SSunil Mushran  * modify it under the terms of the GNU General Public
12*2309e9e0SSunil Mushran  * License as published by the Free Software Foundation; either
13*2309e9e0SSunil Mushran  * version 2 of the License, or (at your option) any later version.
14*2309e9e0SSunil Mushran  *
15*2309e9e0SSunil Mushran  * This program is distributed in the hope that it will be useful,
16*2309e9e0SSunil Mushran  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*2309e9e0SSunil Mushran  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18*2309e9e0SSunil Mushran  * General Public License for more details.
19*2309e9e0SSunil Mushran  *
20*2309e9e0SSunil Mushran  * You should have received a copy of the GNU General Public
21*2309e9e0SSunil Mushran  * License along with this program; if not, write to the
22*2309e9e0SSunil Mushran  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23*2309e9e0SSunil Mushran  * Boston, MA 021110-1307, USA.
24*2309e9e0SSunil Mushran  *
25*2309e9e0SSunil Mushran  */
26*2309e9e0SSunil Mushran 
27*2309e9e0SSunil Mushran #ifdef CONFIG_DEBUG_FS
28*2309e9e0SSunil Mushran 
29*2309e9e0SSunil Mushran #include <linux/module.h>
30*2309e9e0SSunil Mushran #include <linux/types.h>
31*2309e9e0SSunil Mushran #include <linux/slab.h>
32*2309e9e0SSunil Mushran #include <linux/idr.h>
33*2309e9e0SSunil Mushran #include <linux/kref.h>
34*2309e9e0SSunil Mushran #include <linux/seq_file.h>
35*2309e9e0SSunil Mushran #include <linux/debugfs.h>
36*2309e9e0SSunil Mushran 
37*2309e9e0SSunil Mushran #include <linux/uaccess.h>
38*2309e9e0SSunil Mushran 
39*2309e9e0SSunil Mushran #include "tcp.h"
40*2309e9e0SSunil Mushran #include "nodemanager.h"
41*2309e9e0SSunil Mushran #define MLOG_MASK_PREFIX ML_TCP
42*2309e9e0SSunil Mushran #include "masklog.h"
43*2309e9e0SSunil Mushran 
44*2309e9e0SSunil Mushran #include "tcp_internal.h"
45*2309e9e0SSunil Mushran 
46*2309e9e0SSunil Mushran #define O2NET_DEBUG_DIR		"o2net"
47*2309e9e0SSunil Mushran #define SC_DEBUG_NAME		"sock_containers"
48*2309e9e0SSunil Mushran #define NST_DEBUG_NAME		"send_tracking"
49*2309e9e0SSunil Mushran 
50*2309e9e0SSunil Mushran static struct dentry *o2net_dentry;
51*2309e9e0SSunil Mushran static struct dentry *sc_dentry;
52*2309e9e0SSunil Mushran static struct dentry *nst_dentry;
53*2309e9e0SSunil Mushran 
54*2309e9e0SSunil Mushran static DEFINE_SPINLOCK(o2net_debug_lock);
55*2309e9e0SSunil Mushran 
56*2309e9e0SSunil Mushran static LIST_HEAD(sock_containers);
57*2309e9e0SSunil Mushran static LIST_HEAD(send_tracking);
58*2309e9e0SSunil Mushran 
59*2309e9e0SSunil Mushran void o2net_debug_add_nst(struct o2net_send_tracking *nst)
60*2309e9e0SSunil Mushran {
61*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
62*2309e9e0SSunil Mushran 	list_add(&nst->st_net_debug_item, &send_tracking);
63*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
64*2309e9e0SSunil Mushran }
65*2309e9e0SSunil Mushran 
66*2309e9e0SSunil Mushran void o2net_debug_del_nst(struct o2net_send_tracking *nst)
67*2309e9e0SSunil Mushran {
68*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
69*2309e9e0SSunil Mushran 	if (!list_empty(&nst->st_net_debug_item))
70*2309e9e0SSunil Mushran 		list_del_init(&nst->st_net_debug_item);
71*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
72*2309e9e0SSunil Mushran }
73*2309e9e0SSunil Mushran 
74*2309e9e0SSunil Mushran static struct o2net_send_tracking
75*2309e9e0SSunil Mushran 			*next_nst(struct o2net_send_tracking *nst_start)
76*2309e9e0SSunil Mushran {
77*2309e9e0SSunil Mushran 	struct o2net_send_tracking *nst, *ret = NULL;
78*2309e9e0SSunil Mushran 
79*2309e9e0SSunil Mushran 	assert_spin_locked(&o2net_debug_lock);
80*2309e9e0SSunil Mushran 
81*2309e9e0SSunil Mushran 	list_for_each_entry(nst, &nst_start->st_net_debug_item,
82*2309e9e0SSunil Mushran 			    st_net_debug_item) {
83*2309e9e0SSunil Mushran 		/* discover the head of the list */
84*2309e9e0SSunil Mushran 		if (&nst->st_net_debug_item == &send_tracking)
85*2309e9e0SSunil Mushran 			break;
86*2309e9e0SSunil Mushran 
87*2309e9e0SSunil Mushran 		/* use st_task to detect real nsts in the list */
88*2309e9e0SSunil Mushran 		if (nst->st_task != NULL) {
89*2309e9e0SSunil Mushran 			ret = nst;
90*2309e9e0SSunil Mushran 			break;
91*2309e9e0SSunil Mushran 		}
92*2309e9e0SSunil Mushran 	}
93*2309e9e0SSunil Mushran 
94*2309e9e0SSunil Mushran 	return ret;
95*2309e9e0SSunil Mushran }
96*2309e9e0SSunil Mushran 
97*2309e9e0SSunil Mushran static void *nst_seq_start(struct seq_file *seq, loff_t *pos)
98*2309e9e0SSunil Mushran {
99*2309e9e0SSunil Mushran 	struct o2net_send_tracking *nst, *dummy_nst = seq->private;
100*2309e9e0SSunil Mushran 
101*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
102*2309e9e0SSunil Mushran 	nst = next_nst(dummy_nst);
103*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
104*2309e9e0SSunil Mushran 
105*2309e9e0SSunil Mushran 	return nst;
106*2309e9e0SSunil Mushran }
107*2309e9e0SSunil Mushran 
108*2309e9e0SSunil Mushran static void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos)
109*2309e9e0SSunil Mushran {
110*2309e9e0SSunil Mushran 	struct o2net_send_tracking *nst, *dummy_nst = seq->private;
111*2309e9e0SSunil Mushran 
112*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
113*2309e9e0SSunil Mushran 	nst = next_nst(dummy_nst);
114*2309e9e0SSunil Mushran 	list_del_init(&dummy_nst->st_net_debug_item);
115*2309e9e0SSunil Mushran 	if (nst)
116*2309e9e0SSunil Mushran 		list_add(&dummy_nst->st_net_debug_item,
117*2309e9e0SSunil Mushran 			 &nst->st_net_debug_item);
118*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
119*2309e9e0SSunil Mushran 
120*2309e9e0SSunil Mushran 	return nst; /* unused, just needs to be null when done */
121*2309e9e0SSunil Mushran }
122*2309e9e0SSunil Mushran 
123*2309e9e0SSunil Mushran static int nst_seq_show(struct seq_file *seq, void *v)
124*2309e9e0SSunil Mushran {
125*2309e9e0SSunil Mushran 	struct o2net_send_tracking *nst, *dummy_nst = seq->private;
126*2309e9e0SSunil Mushran 
127*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
128*2309e9e0SSunil Mushran 	nst = next_nst(dummy_nst);
129*2309e9e0SSunil Mushran 
130*2309e9e0SSunil Mushran 	if (nst != NULL) {
131*2309e9e0SSunil Mushran 		/* get_task_comm isn't exported.  oh well. */
132*2309e9e0SSunil Mushran 		seq_printf(seq, "%p:\n"
133*2309e9e0SSunil Mushran 			   "  pid:          %lu\n"
134*2309e9e0SSunil Mushran 			   "  tgid:         %lu\n"
135*2309e9e0SSunil Mushran 			   "  process name: %s\n"
136*2309e9e0SSunil Mushran 			   "  node:         %u\n"
137*2309e9e0SSunil Mushran 			   "  sc:           %p\n"
138*2309e9e0SSunil Mushran 			   "  message id:   %d\n"
139*2309e9e0SSunil Mushran 			   "  message type: %u\n"
140*2309e9e0SSunil Mushran 			   "  message key:  0x%08x\n"
141*2309e9e0SSunil Mushran 			   "  sock acquiry: %lu.%lu\n"
142*2309e9e0SSunil Mushran 			   "  send start:   %lu.%lu\n"
143*2309e9e0SSunil Mushran 			   "  wait start:   %lu.%lu\n",
144*2309e9e0SSunil Mushran 			   nst, (unsigned long)nst->st_task->pid,
145*2309e9e0SSunil Mushran 			   (unsigned long)nst->st_task->tgid,
146*2309e9e0SSunil Mushran 			   nst->st_task->comm, nst->st_node,
147*2309e9e0SSunil Mushran 			   nst->st_sc, nst->st_id, nst->st_msg_type,
148*2309e9e0SSunil Mushran 			   nst->st_msg_key,
149*2309e9e0SSunil Mushran 			   nst->st_sock_time.tv_sec, nst->st_sock_time.tv_usec,
150*2309e9e0SSunil Mushran 			   nst->st_send_time.tv_sec, nst->st_send_time.tv_usec,
151*2309e9e0SSunil Mushran 			   nst->st_status_time.tv_sec,
152*2309e9e0SSunil Mushran 			   nst->st_status_time.tv_usec);
153*2309e9e0SSunil Mushran 	}
154*2309e9e0SSunil Mushran 
155*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
156*2309e9e0SSunil Mushran 
157*2309e9e0SSunil Mushran 	return 0;
158*2309e9e0SSunil Mushran }
159*2309e9e0SSunil Mushran 
160*2309e9e0SSunil Mushran static void nst_seq_stop(struct seq_file *seq, void *v)
161*2309e9e0SSunil Mushran {
162*2309e9e0SSunil Mushran }
163*2309e9e0SSunil Mushran 
164*2309e9e0SSunil Mushran static struct seq_operations nst_seq_ops = {
165*2309e9e0SSunil Mushran 	.start = nst_seq_start,
166*2309e9e0SSunil Mushran 	.next = nst_seq_next,
167*2309e9e0SSunil Mushran 	.stop = nst_seq_stop,
168*2309e9e0SSunil Mushran 	.show = nst_seq_show,
169*2309e9e0SSunil Mushran };
170*2309e9e0SSunil Mushran 
171*2309e9e0SSunil Mushran static int nst_fop_open(struct inode *inode, struct file *file)
172*2309e9e0SSunil Mushran {
173*2309e9e0SSunil Mushran 	struct o2net_send_tracking *dummy_nst;
174*2309e9e0SSunil Mushran 	struct seq_file *seq;
175*2309e9e0SSunil Mushran 	int ret;
176*2309e9e0SSunil Mushran 
177*2309e9e0SSunil Mushran 	dummy_nst = kmalloc(sizeof(struct o2net_send_tracking), GFP_KERNEL);
178*2309e9e0SSunil Mushran 	if (dummy_nst == NULL) {
179*2309e9e0SSunil Mushran 		ret = -ENOMEM;
180*2309e9e0SSunil Mushran 		goto out;
181*2309e9e0SSunil Mushran 	}
182*2309e9e0SSunil Mushran 	dummy_nst->st_task = NULL;
183*2309e9e0SSunil Mushran 
184*2309e9e0SSunil Mushran 	ret = seq_open(file, &nst_seq_ops);
185*2309e9e0SSunil Mushran 	if (ret)
186*2309e9e0SSunil Mushran 		goto out;
187*2309e9e0SSunil Mushran 
188*2309e9e0SSunil Mushran 	seq = file->private_data;
189*2309e9e0SSunil Mushran 	seq->private = dummy_nst;
190*2309e9e0SSunil Mushran 	o2net_debug_add_nst(dummy_nst);
191*2309e9e0SSunil Mushran 
192*2309e9e0SSunil Mushran 	dummy_nst = NULL;
193*2309e9e0SSunil Mushran 
194*2309e9e0SSunil Mushran out:
195*2309e9e0SSunil Mushran 	kfree(dummy_nst);
196*2309e9e0SSunil Mushran 	return ret;
197*2309e9e0SSunil Mushran }
198*2309e9e0SSunil Mushran 
199*2309e9e0SSunil Mushran static int nst_fop_release(struct inode *inode, struct file *file)
200*2309e9e0SSunil Mushran {
201*2309e9e0SSunil Mushran 	struct seq_file *seq = file->private_data;
202*2309e9e0SSunil Mushran 	struct o2net_send_tracking *dummy_nst = seq->private;
203*2309e9e0SSunil Mushran 
204*2309e9e0SSunil Mushran 	o2net_debug_del_nst(dummy_nst);
205*2309e9e0SSunil Mushran 	return seq_release_private(inode, file);
206*2309e9e0SSunil Mushran }
207*2309e9e0SSunil Mushran 
208*2309e9e0SSunil Mushran static struct file_operations nst_seq_fops = {
209*2309e9e0SSunil Mushran 	.open = nst_fop_open,
210*2309e9e0SSunil Mushran 	.read = seq_read,
211*2309e9e0SSunil Mushran 	.llseek = seq_lseek,
212*2309e9e0SSunil Mushran 	.release = nst_fop_release,
213*2309e9e0SSunil Mushran };
214*2309e9e0SSunil Mushran 
215*2309e9e0SSunil Mushran void o2net_debug_add_sc(struct o2net_sock_container *sc)
216*2309e9e0SSunil Mushran {
217*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
218*2309e9e0SSunil Mushran 	list_add(&sc->sc_net_debug_item, &sock_containers);
219*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
220*2309e9e0SSunil Mushran }
221*2309e9e0SSunil Mushran 
222*2309e9e0SSunil Mushran void o2net_debug_del_sc(struct o2net_sock_container *sc)
223*2309e9e0SSunil Mushran {
224*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
225*2309e9e0SSunil Mushran 	list_del_init(&sc->sc_net_debug_item);
226*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
227*2309e9e0SSunil Mushran }
228*2309e9e0SSunil Mushran 
229*2309e9e0SSunil Mushran static struct o2net_sock_container
230*2309e9e0SSunil Mushran 			*next_sc(struct o2net_sock_container *sc_start)
231*2309e9e0SSunil Mushran {
232*2309e9e0SSunil Mushran 	struct o2net_sock_container *sc, *ret = NULL;
233*2309e9e0SSunil Mushran 
234*2309e9e0SSunil Mushran 	assert_spin_locked(&o2net_debug_lock);
235*2309e9e0SSunil Mushran 
236*2309e9e0SSunil Mushran 	list_for_each_entry(sc, &sc_start->sc_net_debug_item,
237*2309e9e0SSunil Mushran 			    sc_net_debug_item) {
238*2309e9e0SSunil Mushran 		/* discover the head of the list miscast as a sc */
239*2309e9e0SSunil Mushran 		if (&sc->sc_net_debug_item == &sock_containers)
240*2309e9e0SSunil Mushran 			break;
241*2309e9e0SSunil Mushran 
242*2309e9e0SSunil Mushran 		/* use sc_page to detect real scs in the list */
243*2309e9e0SSunil Mushran 		if (sc->sc_page != NULL) {
244*2309e9e0SSunil Mushran 			ret = sc;
245*2309e9e0SSunil Mushran 			break;
246*2309e9e0SSunil Mushran 		}
247*2309e9e0SSunil Mushran 	}
248*2309e9e0SSunil Mushran 
249*2309e9e0SSunil Mushran 	return ret;
250*2309e9e0SSunil Mushran }
251*2309e9e0SSunil Mushran 
252*2309e9e0SSunil Mushran static void *sc_seq_start(struct seq_file *seq, loff_t *pos)
253*2309e9e0SSunil Mushran {
254*2309e9e0SSunil Mushran 	struct o2net_sock_container *sc, *dummy_sc = seq->private;
255*2309e9e0SSunil Mushran 
256*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
257*2309e9e0SSunil Mushran 	sc = next_sc(dummy_sc);
258*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
259*2309e9e0SSunil Mushran 
260*2309e9e0SSunil Mushran 	return sc;
261*2309e9e0SSunil Mushran }
262*2309e9e0SSunil Mushran 
263*2309e9e0SSunil Mushran static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
264*2309e9e0SSunil Mushran {
265*2309e9e0SSunil Mushran 	struct o2net_sock_container *sc, *dummy_sc = seq->private;
266*2309e9e0SSunil Mushran 
267*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
268*2309e9e0SSunil Mushran 	sc = next_sc(dummy_sc);
269*2309e9e0SSunil Mushran 	list_del_init(&dummy_sc->sc_net_debug_item);
270*2309e9e0SSunil Mushran 	if (sc)
271*2309e9e0SSunil Mushran 		list_add(&dummy_sc->sc_net_debug_item, &sc->sc_net_debug_item);
272*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
273*2309e9e0SSunil Mushran 
274*2309e9e0SSunil Mushran 	return sc; /* unused, just needs to be null when done */
275*2309e9e0SSunil Mushran }
276*2309e9e0SSunil Mushran 
277*2309e9e0SSunil Mushran #define TV_SEC_USEC(TV) TV.tv_sec, TV.tv_usec
278*2309e9e0SSunil Mushran 
279*2309e9e0SSunil Mushran static int sc_seq_show(struct seq_file *seq, void *v)
280*2309e9e0SSunil Mushran {
281*2309e9e0SSunil Mushran 	struct o2net_sock_container *sc, *dummy_sc = seq->private;
282*2309e9e0SSunil Mushran 
283*2309e9e0SSunil Mushran 	spin_lock(&o2net_debug_lock);
284*2309e9e0SSunil Mushran 	sc = next_sc(dummy_sc);
285*2309e9e0SSunil Mushran 
286*2309e9e0SSunil Mushran 	if (sc != NULL) {
287*2309e9e0SSunil Mushran 		struct inet_sock *inet = NULL;
288*2309e9e0SSunil Mushran 
289*2309e9e0SSunil Mushran 		__be32 saddr = 0, daddr = 0;
290*2309e9e0SSunil Mushran 		__be16 sport = 0, dport = 0;
291*2309e9e0SSunil Mushran 
292*2309e9e0SSunil Mushran 		if (sc->sc_sock) {
293*2309e9e0SSunil Mushran 			inet = inet_sk(sc->sc_sock->sk);
294*2309e9e0SSunil Mushran 			/* the stack's structs aren't sparse endian clean */
295*2309e9e0SSunil Mushran 			saddr = (__force __be32)inet->saddr;
296*2309e9e0SSunil Mushran 			daddr = (__force __be32)inet->daddr;
297*2309e9e0SSunil Mushran 			sport = (__force __be16)inet->sport;
298*2309e9e0SSunil Mushran 			dport = (__force __be16)inet->dport;
299*2309e9e0SSunil Mushran 		}
300*2309e9e0SSunil Mushran 
301*2309e9e0SSunil Mushran 		/* XXX sigh, inet-> doesn't have sparse annotation so any
302*2309e9e0SSunil Mushran 		 * use of it here generates a warning with -Wbitwise */
303*2309e9e0SSunil Mushran 		seq_printf(seq, "%p:\n"
304*2309e9e0SSunil Mushran 			   "  krefs:           %d\n"
305*2309e9e0SSunil Mushran 			   "  sock:            %u.%u.%u.%u:%u -> "
306*2309e9e0SSunil Mushran 					      "%u.%u.%u.%u:%u\n"
307*2309e9e0SSunil Mushran 			   "  remote node:     %s\n"
308*2309e9e0SSunil Mushran 			   "  page off:        %zu\n"
309*2309e9e0SSunil Mushran 			   "  handshake ok:    %u\n"
310*2309e9e0SSunil Mushran 			   "  timer:           %lu.%lu\n"
311*2309e9e0SSunil Mushran 			   "  data ready:      %lu.%lu\n"
312*2309e9e0SSunil Mushran 			   "  advance start:   %lu.%lu\n"
313*2309e9e0SSunil Mushran 			   "  advance stop:    %lu.%lu\n"
314*2309e9e0SSunil Mushran 			   "  func start:      %lu.%lu\n"
315*2309e9e0SSunil Mushran 			   "  func stop:       %lu.%lu\n"
316*2309e9e0SSunil Mushran 			   "  func key:        %u\n"
317*2309e9e0SSunil Mushran 			   "  func type:       %u\n",
318*2309e9e0SSunil Mushran 			   sc,
319*2309e9e0SSunil Mushran 			   atomic_read(&sc->sc_kref.refcount),
320*2309e9e0SSunil Mushran 			   NIPQUAD(saddr), inet ? ntohs(sport) : 0,
321*2309e9e0SSunil Mushran 			   NIPQUAD(daddr), inet ? ntohs(dport) : 0,
322*2309e9e0SSunil Mushran 			   sc->sc_node->nd_name,
323*2309e9e0SSunil Mushran 			   sc->sc_page_off,
324*2309e9e0SSunil Mushran 			   sc->sc_handshake_ok,
325*2309e9e0SSunil Mushran 			   TV_SEC_USEC(sc->sc_tv_timer),
326*2309e9e0SSunil Mushran 			   TV_SEC_USEC(sc->sc_tv_data_ready),
327*2309e9e0SSunil Mushran 			   TV_SEC_USEC(sc->sc_tv_advance_start),
328*2309e9e0SSunil Mushran 			   TV_SEC_USEC(sc->sc_tv_advance_stop),
329*2309e9e0SSunil Mushran 			   TV_SEC_USEC(sc->sc_tv_func_start),
330*2309e9e0SSunil Mushran 			   TV_SEC_USEC(sc->sc_tv_func_stop),
331*2309e9e0SSunil Mushran 			   sc->sc_msg_key,
332*2309e9e0SSunil Mushran 			   sc->sc_msg_type);
333*2309e9e0SSunil Mushran 	}
334*2309e9e0SSunil Mushran 
335*2309e9e0SSunil Mushran 
336*2309e9e0SSunil Mushran 	spin_unlock(&o2net_debug_lock);
337*2309e9e0SSunil Mushran 
338*2309e9e0SSunil Mushran 	return 0;
339*2309e9e0SSunil Mushran }
340*2309e9e0SSunil Mushran 
341*2309e9e0SSunil Mushran static void sc_seq_stop(struct seq_file *seq, void *v)
342*2309e9e0SSunil Mushran {
343*2309e9e0SSunil Mushran }
344*2309e9e0SSunil Mushran 
345*2309e9e0SSunil Mushran static struct seq_operations sc_seq_ops = {
346*2309e9e0SSunil Mushran 	.start = sc_seq_start,
347*2309e9e0SSunil Mushran 	.next = sc_seq_next,
348*2309e9e0SSunil Mushran 	.stop = sc_seq_stop,
349*2309e9e0SSunil Mushran 	.show = sc_seq_show,
350*2309e9e0SSunil Mushran };
351*2309e9e0SSunil Mushran 
352*2309e9e0SSunil Mushran static int sc_fop_open(struct inode *inode, struct file *file)
353*2309e9e0SSunil Mushran {
354*2309e9e0SSunil Mushran 	struct o2net_sock_container *dummy_sc;
355*2309e9e0SSunil Mushran 	struct seq_file *seq;
356*2309e9e0SSunil Mushran 	int ret;
357*2309e9e0SSunil Mushran 
358*2309e9e0SSunil Mushran 	dummy_sc = kmalloc(sizeof(struct o2net_sock_container), GFP_KERNEL);
359*2309e9e0SSunil Mushran 	if (dummy_sc == NULL) {
360*2309e9e0SSunil Mushran 		ret = -ENOMEM;
361*2309e9e0SSunil Mushran 		goto out;
362*2309e9e0SSunil Mushran 	}
363*2309e9e0SSunil Mushran 	dummy_sc->sc_page = NULL;
364*2309e9e0SSunil Mushran 
365*2309e9e0SSunil Mushran 	ret = seq_open(file, &sc_seq_ops);
366*2309e9e0SSunil Mushran 	if (ret)
367*2309e9e0SSunil Mushran 		goto out;
368*2309e9e0SSunil Mushran 
369*2309e9e0SSunil Mushran 	seq = file->private_data;
370*2309e9e0SSunil Mushran 	seq->private = dummy_sc;
371*2309e9e0SSunil Mushran 	o2net_debug_add_sc(dummy_sc);
372*2309e9e0SSunil Mushran 
373*2309e9e0SSunil Mushran 	dummy_sc = NULL;
374*2309e9e0SSunil Mushran 
375*2309e9e0SSunil Mushran out:
376*2309e9e0SSunil Mushran 	kfree(dummy_sc);
377*2309e9e0SSunil Mushran 	return ret;
378*2309e9e0SSunil Mushran }
379*2309e9e0SSunil Mushran 
380*2309e9e0SSunil Mushran static int sc_fop_release(struct inode *inode, struct file *file)
381*2309e9e0SSunil Mushran {
382*2309e9e0SSunil Mushran 	struct seq_file *seq = file->private_data;
383*2309e9e0SSunil Mushran 	struct o2net_sock_container *dummy_sc = seq->private;
384*2309e9e0SSunil Mushran 
385*2309e9e0SSunil Mushran 	o2net_debug_del_sc(dummy_sc);
386*2309e9e0SSunil Mushran 	return seq_release_private(inode, file);
387*2309e9e0SSunil Mushran }
388*2309e9e0SSunil Mushran 
389*2309e9e0SSunil Mushran static struct file_operations sc_seq_fops = {
390*2309e9e0SSunil Mushran 	.open = sc_fop_open,
391*2309e9e0SSunil Mushran 	.read = seq_read,
392*2309e9e0SSunil Mushran 	.llseek = seq_lseek,
393*2309e9e0SSunil Mushran 	.release = sc_fop_release,
394*2309e9e0SSunil Mushran };
395*2309e9e0SSunil Mushran 
396*2309e9e0SSunil Mushran int o2net_debugfs_init(void)
397*2309e9e0SSunil Mushran {
398*2309e9e0SSunil Mushran 	o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL);
399*2309e9e0SSunil Mushran 	if (!o2net_dentry) {
400*2309e9e0SSunil Mushran 		mlog_errno(-ENOMEM);
401*2309e9e0SSunil Mushran 		goto bail;
402*2309e9e0SSunil Mushran 	}
403*2309e9e0SSunil Mushran 
404*2309e9e0SSunil Mushran 	nst_dentry = debugfs_create_file(NST_DEBUG_NAME, S_IFREG|S_IRUSR,
405*2309e9e0SSunil Mushran 					 o2net_dentry, NULL,
406*2309e9e0SSunil Mushran 					 &nst_seq_fops);
407*2309e9e0SSunil Mushran 	if (!nst_dentry) {
408*2309e9e0SSunil Mushran 		mlog_errno(-ENOMEM);
409*2309e9e0SSunil Mushran 		goto bail;
410*2309e9e0SSunil Mushran 	}
411*2309e9e0SSunil Mushran 
412*2309e9e0SSunil Mushran 	sc_dentry = debugfs_create_file(SC_DEBUG_NAME, S_IFREG|S_IRUSR,
413*2309e9e0SSunil Mushran 					o2net_dentry, NULL,
414*2309e9e0SSunil Mushran 					&sc_seq_fops);
415*2309e9e0SSunil Mushran 	if (!sc_dentry) {
416*2309e9e0SSunil Mushran 		mlog_errno(-ENOMEM);
417*2309e9e0SSunil Mushran 		goto bail;
418*2309e9e0SSunil Mushran 	}
419*2309e9e0SSunil Mushran 
420*2309e9e0SSunil Mushran 	return 0;
421*2309e9e0SSunil Mushran bail:
422*2309e9e0SSunil Mushran 	if (sc_dentry)
423*2309e9e0SSunil Mushran 		debugfs_remove(sc_dentry);
424*2309e9e0SSunil Mushran 	if (nst_dentry)
425*2309e9e0SSunil Mushran 		debugfs_remove(nst_dentry);
426*2309e9e0SSunil Mushran 	if (o2net_dentry)
427*2309e9e0SSunil Mushran 		debugfs_remove(o2net_dentry);
428*2309e9e0SSunil Mushran 	return -ENOMEM;
429*2309e9e0SSunil Mushran }
430*2309e9e0SSunil Mushran 
431*2309e9e0SSunil Mushran void o2net_debugfs_exit(void)
432*2309e9e0SSunil Mushran {
433*2309e9e0SSunil Mushran 	if (sc_dentry)
434*2309e9e0SSunil Mushran 		debugfs_remove(sc_dentry);
435*2309e9e0SSunil Mushran 	if (nst_dentry)
436*2309e9e0SSunil Mushran 		debugfs_remove(nst_dentry);
437*2309e9e0SSunil Mushran 	if (o2net_dentry)
438*2309e9e0SSunil Mushran 		debugfs_remove(o2net_dentry);
439*2309e9e0SSunil Mushran }
440*2309e9e0SSunil Mushran 
441*2309e9e0SSunil Mushran #endif	/* CONFIG_DEBUG_FS */
442