diff options
author | Sunil Mushran <sunil.mushran@oracle.com> | 2008-04-14 13:46:19 -0400 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2008-04-18 11:56:20 -0400 |
commit | 2309e9e040fe29469fb85a384636c455b62fe525 (patch) | |
tree | e3ecf7af432e1504a0c785525bc4247305916173 /fs | |
parent | 93b06edb5127315473d87e075b2b1d1acf74659c (diff) |
ocfs2/net: Add debug interface to o2net
This patch exposes o2net information via debugfs. The information includes
the list of sockets (sock_containers) as well as the list of outstanding
messages (send_tracking). Useful for o2dlm debugging.
(This patch is derived from an earlier one written by Zach Brown that
exposed the same information via /proc.)
[Mark: checkpatch fixes]
Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com>
Reviewed-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/cluster/Makefile | 2 | ||||
-rw-r--r-- | fs/ocfs2/cluster/netdebug.c | 441 | ||||
-rw-r--r-- | fs/ocfs2/cluster/nodemanager.c | 5 | ||||
-rw-r--r-- | fs/ocfs2/cluster/tcp.c | 68 | ||||
-rw-r--r-- | fs/ocfs2/cluster/tcp.h | 32 | ||||
-rw-r--r-- | fs/ocfs2/cluster/tcp_internal.h | 24 |
6 files changed, 569 insertions, 3 deletions
diff --git a/fs/ocfs2/cluster/Makefile b/fs/ocfs2/cluster/Makefile index cdd162f13650..bc8c5e7d8608 100644 --- a/fs/ocfs2/cluster/Makefile +++ b/fs/ocfs2/cluster/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-$(CONFIG_OCFS2_FS) += ocfs2_nodemanager.o | 1 | obj-$(CONFIG_OCFS2_FS) += ocfs2_nodemanager.o |
2 | 2 | ||
3 | ocfs2_nodemanager-objs := heartbeat.o masklog.o sys.o nodemanager.o \ | 3 | ocfs2_nodemanager-objs := heartbeat.o masklog.o sys.o nodemanager.o \ |
4 | quorum.o tcp.o ver.o | 4 | quorum.o tcp.o netdebug.o ver.o |
diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c new file mode 100644 index 000000000000..7bf3c0ea7bd9 --- /dev/null +++ b/fs/ocfs2/cluster/netdebug.c | |||
@@ -0,0 +1,441 @@ | |||
1 | /* -*- mode: c; c-basic-offset: 8; -*- | ||
2 | * vim: noexpandtab sw=8 ts=8 sts=0: | ||
3 | * | ||
4 | * netdebug.c | ||
5 | * | ||
6 | * debug functionality for o2net | ||
7 | * | ||
8 | * Copyright (C) 2005, 2008 Oracle. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public | ||
12 | * License as published by the Free Software Foundation; either | ||
13 | * version 2 of the License, or (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public | ||
21 | * License along with this program; if not, write to the | ||
22 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
23 | * Boston, MA 021110-1307, USA. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifdef CONFIG_DEBUG_FS | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/types.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/idr.h> | ||
33 | #include <linux/kref.h> | ||
34 | #include <linux/seq_file.h> | ||
35 | #include <linux/debugfs.h> | ||
36 | |||
37 | #include <linux/uaccess.h> | ||
38 | |||
39 | #include "tcp.h" | ||
40 | #include "nodemanager.h" | ||
41 | #define MLOG_MASK_PREFIX ML_TCP | ||
42 | #include "masklog.h" | ||
43 | |||
44 | #include "tcp_internal.h" | ||
45 | |||
46 | #define O2NET_DEBUG_DIR "o2net" | ||
47 | #define SC_DEBUG_NAME "sock_containers" | ||
48 | #define NST_DEBUG_NAME "send_tracking" | ||
49 | |||
50 | static struct dentry *o2net_dentry; | ||
51 | static struct dentry *sc_dentry; | ||
52 | static struct dentry *nst_dentry; | ||
53 | |||
54 | static DEFINE_SPINLOCK(o2net_debug_lock); | ||
55 | |||
56 | static LIST_HEAD(sock_containers); | ||
57 | static LIST_HEAD(send_tracking); | ||
58 | |||
59 | void o2net_debug_add_nst(struct o2net_send_tracking *nst) | ||
60 | { | ||
61 | spin_lock(&o2net_debug_lock); | ||
62 | list_add(&nst->st_net_debug_item, &send_tracking); | ||
63 | spin_unlock(&o2net_debug_lock); | ||
64 | } | ||
65 | |||
66 | void o2net_debug_del_nst(struct o2net_send_tracking *nst) | ||
67 | { | ||
68 | spin_lock(&o2net_debug_lock); | ||
69 | if (!list_empty(&nst->st_net_debug_item)) | ||
70 | list_del_init(&nst->st_net_debug_item); | ||
71 | spin_unlock(&o2net_debug_lock); | ||
72 | } | ||
73 | |||
74 | static struct o2net_send_tracking | ||
75 | *next_nst(struct o2net_send_tracking *nst_start) | ||
76 | { | ||
77 | struct o2net_send_tracking *nst, *ret = NULL; | ||
78 | |||
79 | assert_spin_locked(&o2net_debug_lock); | ||
80 | |||
81 | list_for_each_entry(nst, &nst_start->st_net_debug_item, | ||
82 | st_net_debug_item) { | ||
83 | /* discover the head of the list */ | ||
84 | if (&nst->st_net_debug_item == &send_tracking) | ||
85 | break; | ||
86 | |||
87 | /* use st_task to detect real nsts in the list */ | ||
88 | if (nst->st_task != NULL) { | ||
89 | ret = nst; | ||
90 | break; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | static void *nst_seq_start(struct seq_file *seq, loff_t *pos) | ||
98 | { | ||
99 | struct o2net_send_tracking *nst, *dummy_nst = seq->private; | ||
100 | |||
101 | spin_lock(&o2net_debug_lock); | ||
102 | nst = next_nst(dummy_nst); | ||
103 | spin_unlock(&o2net_debug_lock); | ||
104 | |||
105 | return nst; | ||
106 | } | ||
107 | |||
108 | static void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
109 | { | ||
110 | struct o2net_send_tracking *nst, *dummy_nst = seq->private; | ||
111 | |||
112 | spin_lock(&o2net_debug_lock); | ||
113 | nst = next_nst(dummy_nst); | ||
114 | list_del_init(&dummy_nst->st_net_debug_item); | ||
115 | if (nst) | ||
116 | list_add(&dummy_nst->st_net_debug_item, | ||
117 | &nst->st_net_debug_item); | ||
118 | spin_unlock(&o2net_debug_lock); | ||
119 | |||
120 | return nst; /* unused, just needs to be null when done */ | ||
121 | } | ||
122 | |||
123 | static int nst_seq_show(struct seq_file *seq, void *v) | ||
124 | { | ||
125 | struct o2net_send_tracking *nst, *dummy_nst = seq->private; | ||
126 | |||
127 | spin_lock(&o2net_debug_lock); | ||
128 | nst = next_nst(dummy_nst); | ||
129 | |||
130 | if (nst != NULL) { | ||
131 | /* get_task_comm isn't exported. oh well. */ | ||
132 | seq_printf(seq, "%p:\n" | ||
133 | " pid: %lu\n" | ||
134 | " tgid: %lu\n" | ||
135 | " process name: %s\n" | ||
136 | " node: %u\n" | ||
137 | " sc: %p\n" | ||
138 | " message id: %d\n" | ||
139 | " message type: %u\n" | ||
140 | " message key: 0x%08x\n" | ||
141 | " sock acquiry: %lu.%lu\n" | ||
142 | " send start: %lu.%lu\n" | ||
143 | " wait start: %lu.%lu\n", | ||
144 | nst, (unsigned long)nst->st_task->pid, | ||
145 | (unsigned long)nst->st_task->tgid, | ||
146 | nst->st_task->comm, nst->st_node, | ||
147 | nst->st_sc, nst->st_id, nst->st_msg_type, | ||
148 | nst->st_msg_key, | ||
149 | nst->st_sock_time.tv_sec, nst->st_sock_time.tv_usec, | ||
150 | nst->st_send_time.tv_sec, nst->st_send_time.tv_usec, | ||
151 | nst->st_status_time.tv_sec, | ||
152 | nst->st_status_time.tv_usec); | ||
153 | } | ||
154 | |||
155 | spin_unlock(&o2net_debug_lock); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static void nst_seq_stop(struct seq_file *seq, void *v) | ||
161 | { | ||
162 | } | ||
163 | |||
164 | static struct seq_operations nst_seq_ops = { | ||
165 | .start = nst_seq_start, | ||
166 | .next = nst_seq_next, | ||
167 | .stop = nst_seq_stop, | ||
168 | .show = nst_seq_show, | ||
169 | }; | ||
170 | |||
171 | static int nst_fop_open(struct inode *inode, struct file *file) | ||
172 | { | ||
173 | struct o2net_send_tracking *dummy_nst; | ||
174 | struct seq_file *seq; | ||
175 | int ret; | ||
176 | |||
177 | dummy_nst = kmalloc(sizeof(struct o2net_send_tracking), GFP_KERNEL); | ||
178 | if (dummy_nst == NULL) { | ||
179 | ret = -ENOMEM; | ||
180 | goto out; | ||
181 | } | ||
182 | dummy_nst->st_task = NULL; | ||
183 | |||
184 | ret = seq_open(file, &nst_seq_ops); | ||
185 | if (ret) | ||
186 | goto out; | ||
187 | |||
188 | seq = file->private_data; | ||
189 | seq->private = dummy_nst; | ||
190 | o2net_debug_add_nst(dummy_nst); | ||
191 | |||
192 | dummy_nst = NULL; | ||
193 | |||
194 | out: | ||
195 | kfree(dummy_nst); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | static int nst_fop_release(struct inode *inode, struct file *file) | ||
200 | { | ||
201 | struct seq_file *seq = file->private_data; | ||
202 | struct o2net_send_tracking *dummy_nst = seq->private; | ||
203 | |||
204 | o2net_debug_del_nst(dummy_nst); | ||
205 | return seq_release_private(inode, file); | ||
206 | } | ||
207 | |||
208 | static struct file_operations nst_seq_fops = { | ||
209 | .open = nst_fop_open, | ||
210 | .read = seq_read, | ||
211 | .llseek = seq_lseek, | ||
212 | .release = nst_fop_release, | ||
213 | }; | ||
214 | |||
215 | void o2net_debug_add_sc(struct o2net_sock_container *sc) | ||
216 | { | ||
217 | spin_lock(&o2net_debug_lock); | ||
218 | list_add(&sc->sc_net_debug_item, &sock_containers); | ||
219 | spin_unlock(&o2net_debug_lock); | ||
220 | } | ||
221 | |||
222 | void o2net_debug_del_sc(struct o2net_sock_container *sc) | ||
223 | { | ||
224 | spin_lock(&o2net_debug_lock); | ||
225 | list_del_init(&sc->sc_net_debug_item); | ||
226 | spin_unlock(&o2net_debug_lock); | ||
227 | } | ||
228 | |||
229 | static struct o2net_sock_container | ||
230 | *next_sc(struct o2net_sock_container *sc_start) | ||
231 | { | ||
232 | struct o2net_sock_container *sc, *ret = NULL; | ||
233 | |||
234 | assert_spin_locked(&o2net_debug_lock); | ||
235 | |||
236 | list_for_each_entry(sc, &sc_start->sc_net_debug_item, | ||
237 | sc_net_debug_item) { | ||
238 | /* discover the head of the list miscast as a sc */ | ||
239 | if (&sc->sc_net_debug_item == &sock_containers) | ||
240 | break; | ||
241 | |||
242 | /* use sc_page to detect real scs in the list */ | ||
243 | if (sc->sc_page != NULL) { | ||
244 | ret = sc; | ||
245 | break; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | static void *sc_seq_start(struct seq_file *seq, loff_t *pos) | ||
253 | { | ||
254 | struct o2net_sock_container *sc, *dummy_sc = seq->private; | ||
255 | |||
256 | spin_lock(&o2net_debug_lock); | ||
257 | sc = next_sc(dummy_sc); | ||
258 | spin_unlock(&o2net_debug_lock); | ||
259 | |||
260 | return sc; | ||
261 | } | ||
262 | |||
263 | static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
264 | { | ||
265 | struct o2net_sock_container *sc, *dummy_sc = seq->private; | ||
266 | |||
267 | spin_lock(&o2net_debug_lock); | ||
268 | sc = next_sc(dummy_sc); | ||
269 | list_del_init(&dummy_sc->sc_net_debug_item); | ||
270 | if (sc) | ||
271 | list_add(&dummy_sc->sc_net_debug_item, &sc->sc_net_debug_item); | ||
272 | spin_unlock(&o2net_debug_lock); | ||
273 | |||
274 | return sc; /* unused, just needs to be null when done */ | ||
275 | } | ||
276 | |||
277 | #define TV_SEC_USEC(TV) TV.tv_sec, TV.tv_usec | ||
278 | |||
279 | static int sc_seq_show(struct seq_file *seq, void *v) | ||
280 | { | ||
281 | struct o2net_sock_container *sc, *dummy_sc = seq->private; | ||
282 | |||
283 | spin_lock(&o2net_debug_lock); | ||
284 | sc = next_sc(dummy_sc); | ||
285 | |||
286 | if (sc != NULL) { | ||
287 | struct inet_sock *inet = NULL; | ||
288 | |||
289 | __be32 saddr = 0, daddr = 0; | ||
290 | __be16 sport = 0, dport = 0; | ||
291 | |||
292 | if (sc->sc_sock) { | ||
293 | inet = inet_sk(sc->sc_sock->sk); | ||
294 | /* the stack's structs aren't sparse endian clean */ | ||
295 | saddr = (__force __be32)inet->saddr; | ||
296 | daddr = (__force __be32)inet->daddr; | ||
297 | sport = (__force __be16)inet->sport; | ||
298 | dport = (__force __be16)inet->dport; | ||
299 | } | ||
300 | |||
301 | /* XXX sigh, inet-> doesn't have sparse annotation so any | ||
302 | * use of it here generates a warning with -Wbitwise */ | ||
303 | seq_printf(seq, "%p:\n" | ||
304 | " krefs: %d\n" | ||
305 | " sock: %u.%u.%u.%u:%u -> " | ||
306 | "%u.%u.%u.%u:%u\n" | ||
307 | " remote node: %s\n" | ||
308 | " page off: %zu\n" | ||
309 | " handshake ok: %u\n" | ||
310 | " timer: %lu.%lu\n" | ||
311 | " data ready: %lu.%lu\n" | ||
312 | " advance start: %lu.%lu\n" | ||
313 | " advance stop: %lu.%lu\n" | ||
314 | " func start: %lu.%lu\n" | ||
315 | " func stop: %lu.%lu\n" | ||
316 | " func key: %u\n" | ||
317 | " func type: %u\n", | ||
318 | sc, | ||
319 | atomic_read(&sc->sc_kref.refcount), | ||
320 | NIPQUAD(saddr), inet ? ntohs(sport) : 0, | ||
321 | NIPQUAD(daddr), inet ? ntohs(dport) : 0, | ||
322 | sc->sc_node->nd_name, | ||
323 | sc->sc_page_off, | ||
324 | sc->sc_handshake_ok, | ||
325 | TV_SEC_USEC(sc->sc_tv_timer), | ||
326 | TV_SEC_USEC(sc->sc_tv_data_ready), | ||
327 | TV_SEC_USEC(sc->sc_tv_advance_start), | ||
328 | TV_SEC_USEC(sc->sc_tv_advance_stop), | ||
329 | TV_SEC_USEC(sc->sc_tv_func_start), | ||
330 | TV_SEC_USEC(sc->sc_tv_func_stop), | ||
331 | sc->sc_msg_key, | ||
332 | sc->sc_msg_type); | ||
333 | } | ||
334 | |||
335 | |||
336 | spin_unlock(&o2net_debug_lock); | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static void sc_seq_stop(struct seq_file *seq, void *v) | ||
342 | { | ||
343 | } | ||
344 | |||
345 | static struct seq_operations sc_seq_ops = { | ||
346 | .start = sc_seq_start, | ||
347 | .next = sc_seq_next, | ||
348 | .stop = sc_seq_stop, | ||
349 | .show = sc_seq_show, | ||
350 | }; | ||
351 | |||
352 | static int sc_fop_open(struct inode *inode, struct file *file) | ||
353 | { | ||
354 | struct o2net_sock_container *dummy_sc; | ||
355 | struct seq_file *seq; | ||
356 | int ret; | ||
357 | |||
358 | dummy_sc = kmalloc(sizeof(struct o2net_sock_container), GFP_KERNEL); | ||
359 | if (dummy_sc == NULL) { | ||
360 | ret = -ENOMEM; | ||
361 | goto out; | ||
362 | } | ||
363 | dummy_sc->sc_page = NULL; | ||
364 | |||
365 | ret = seq_open(file, &sc_seq_ops); | ||
366 | if (ret) | ||
367 | goto out; | ||
368 | |||
369 | seq = file->private_data; | ||
370 | seq->private = dummy_sc; | ||
371 | o2net_debug_add_sc(dummy_sc); | ||
372 | |||
373 | dummy_sc = NULL; | ||
374 | |||
375 | out: | ||
376 | kfree(dummy_sc); | ||
377 | return ret; | ||
378 | } | ||
379 | |||
380 | static int sc_fop_release(struct inode *inode, struct file *file) | ||
381 | { | ||
382 | struct seq_file *seq = file->private_data; | ||
383 | struct o2net_sock_container *dummy_sc = seq->private; | ||
384 | |||
385 | o2net_debug_del_sc(dummy_sc); | ||
386 | return seq_release_private(inode, file); | ||
387 | } | ||
388 | |||
389 | static struct file_operations sc_seq_fops = { | ||
390 | .open = sc_fop_open, | ||
391 | .read = seq_read, | ||
392 | .llseek = seq_lseek, | ||
393 | .release = sc_fop_release, | ||
394 | }; | ||
395 | |||
396 | int o2net_debugfs_init(void) | ||
397 | { | ||
398 | o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL); | ||
399 | if (!o2net_dentry) { | ||
400 | mlog_errno(-ENOMEM); | ||
401 | goto bail; | ||
402 | } | ||
403 | |||
404 | nst_dentry = debugfs_create_file(NST_DEBUG_NAME, S_IFREG|S_IRUSR, | ||
405 | o2net_dentry, NULL, | ||
406 | &nst_seq_fops); | ||
407 | if (!nst_dentry) { | ||
408 | mlog_errno(-ENOMEM); | ||
409 | goto bail; | ||
410 | } | ||
411 | |||
412 | sc_dentry = debugfs_create_file(SC_DEBUG_NAME, S_IFREG|S_IRUSR, | ||
413 | o2net_dentry, NULL, | ||
414 | &sc_seq_fops); | ||
415 | if (!sc_dentry) { | ||
416 | mlog_errno(-ENOMEM); | ||
417 | goto bail; | ||
418 | } | ||
419 | |||
420 | return 0; | ||
421 | bail: | ||
422 | if (sc_dentry) | ||
423 | debugfs_remove(sc_dentry); | ||
424 | if (nst_dentry) | ||
425 | debugfs_remove(nst_dentry); | ||
426 | if (o2net_dentry) | ||
427 | debugfs_remove(o2net_dentry); | ||
428 | return -ENOMEM; | ||
429 | } | ||
430 | |||
431 | void o2net_debugfs_exit(void) | ||
432 | { | ||
433 | if (sc_dentry) | ||
434 | debugfs_remove(sc_dentry); | ||
435 | if (nst_dentry) | ||
436 | debugfs_remove(nst_dentry); | ||
437 | if (o2net_dentry) | ||
438 | debugfs_remove(o2net_dentry); | ||
439 | } | ||
440 | |||
441 | #endif /* CONFIG_DEBUG_FS */ | ||
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index 709fba25bf7e..cf9401e8cd0b 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c | |||
@@ -959,7 +959,10 @@ static int __init init_o2nm(void) | |||
959 | cluster_print_version(); | 959 | cluster_print_version(); |
960 | 960 | ||
961 | o2hb_init(); | 961 | o2hb_init(); |
962 | o2net_init(); | 962 | |
963 | ret = o2net_init(); | ||
964 | if (ret) | ||
965 | goto out; | ||
963 | 966 | ||
964 | ocfs2_table_header = register_sysctl_table(ocfs2_root_table); | 967 | ocfs2_table_header = register_sysctl_table(ocfs2_root_table); |
965 | if (!ocfs2_table_header) { | 968 | if (!ocfs2_table_header) { |
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 1170918a9311..1e44ad14881a 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c | |||
@@ -142,6 +142,54 @@ static void o2net_idle_timer(unsigned long data); | |||
142 | static void o2net_sc_postpone_idle(struct o2net_sock_container *sc); | 142 | static void o2net_sc_postpone_idle(struct o2net_sock_container *sc); |
143 | static void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc); | 143 | static void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc); |
144 | 144 | ||
145 | static void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, | ||
146 | u32 msgkey, struct task_struct *task, u8 node) | ||
147 | { | ||
148 | #ifdef CONFIG_DEBUG_FS | ||
149 | INIT_LIST_HEAD(&nst->st_net_debug_item); | ||
150 | nst->st_task = task; | ||
151 | nst->st_msg_type = msgtype; | ||
152 | nst->st_msg_key = msgkey; | ||
153 | nst->st_node = node; | ||
154 | #endif | ||
155 | } | ||
156 | |||
157 | static void o2net_set_nst_sock_time(struct o2net_send_tracking *nst) | ||
158 | { | ||
159 | #ifdef CONFIG_DEBUG_FS | ||
160 | do_gettimeofday(&nst->st_sock_time); | ||
161 | #endif | ||
162 | } | ||
163 | |||
164 | static void o2net_set_nst_send_time(struct o2net_send_tracking *nst) | ||
165 | { | ||
166 | #ifdef CONFIG_DEBUG_FS | ||
167 | do_gettimeofday(&nst->st_send_time); | ||
168 | #endif | ||
169 | } | ||
170 | |||
171 | static void o2net_set_nst_status_time(struct o2net_send_tracking *nst) | ||
172 | { | ||
173 | #ifdef CONFIG_DEBUG_FS | ||
174 | do_gettimeofday(&nst->st_status_time); | ||
175 | #endif | ||
176 | } | ||
177 | |||
178 | static void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, | ||
179 | struct o2net_sock_container *sc) | ||
180 | { | ||
181 | #ifdef CONFIG_DEBUG_FS | ||
182 | nst->st_sc = sc; | ||
183 | #endif | ||
184 | } | ||
185 | |||
186 | static void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, u32 msg_id) | ||
187 | { | ||
188 | #ifdef CONFIG_DEBUG_FS | ||
189 | nst->st_id = msg_id; | ||
190 | #endif | ||
191 | } | ||
192 | |||
145 | static inline int o2net_reconnect_delay(void) | 193 | static inline int o2net_reconnect_delay(void) |
146 | { | 194 | { |
147 | return o2nm_single_cluster->cl_reconnect_delay_ms; | 195 | return o2nm_single_cluster->cl_reconnect_delay_ms; |
@@ -290,6 +338,7 @@ static void sc_kref_release(struct kref *kref) | |||
290 | o2nm_node_put(sc->sc_node); | 338 | o2nm_node_put(sc->sc_node); |
291 | sc->sc_node = NULL; | 339 | sc->sc_node = NULL; |
292 | 340 | ||
341 | o2net_debug_del_sc(sc); | ||
293 | kfree(sc); | 342 | kfree(sc); |
294 | } | 343 | } |
295 | 344 | ||
@@ -330,6 +379,7 @@ static struct o2net_sock_container *sc_alloc(struct o2nm_node *node) | |||
330 | 379 | ||
331 | ret = sc; | 380 | ret = sc; |
332 | sc->sc_page = page; | 381 | sc->sc_page = page; |
382 | o2net_debug_add_sc(sc); | ||
333 | sc = NULL; | 383 | sc = NULL; |
334 | page = NULL; | 384 | page = NULL; |
335 | 385 | ||
@@ -913,6 +963,9 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, | |||
913 | struct o2net_status_wait nsw = { | 963 | struct o2net_status_wait nsw = { |
914 | .ns_node_item = LIST_HEAD_INIT(nsw.ns_node_item), | 964 | .ns_node_item = LIST_HEAD_INIT(nsw.ns_node_item), |
915 | }; | 965 | }; |
966 | struct o2net_send_tracking nst; | ||
967 | |||
968 | o2net_init_nst(&nst, msg_type, key, current, target_node); | ||
916 | 969 | ||
917 | if (o2net_wq == NULL) { | 970 | if (o2net_wq == NULL) { |
918 | mlog(0, "attempt to tx without o2netd running\n"); | 971 | mlog(0, "attempt to tx without o2netd running\n"); |
@@ -938,6 +991,10 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, | |||
938 | goto out; | 991 | goto out; |
939 | } | 992 | } |
940 | 993 | ||
994 | o2net_debug_add_nst(&nst); | ||
995 | |||
996 | o2net_set_nst_sock_time(&nst); | ||
997 | |||
941 | ret = wait_event_interruptible(nn->nn_sc_wq, | 998 | ret = wait_event_interruptible(nn->nn_sc_wq, |
942 | o2net_tx_can_proceed(nn, &sc, &error)); | 999 | o2net_tx_can_proceed(nn, &sc, &error)); |
943 | if (!ret && error) | 1000 | if (!ret && error) |
@@ -945,6 +1002,8 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, | |||
945 | if (ret) | 1002 | if (ret) |
946 | goto out; | 1003 | goto out; |
947 | 1004 | ||
1005 | o2net_set_nst_sock_container(&nst, sc); | ||
1006 | |||
948 | veclen = caller_veclen + 1; | 1007 | veclen = caller_veclen + 1; |
949 | vec = kmalloc(sizeof(struct kvec) * veclen, GFP_ATOMIC); | 1008 | vec = kmalloc(sizeof(struct kvec) * veclen, GFP_ATOMIC); |
950 | if (vec == NULL) { | 1009 | if (vec == NULL) { |
@@ -971,6 +1030,9 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, | |||
971 | goto out; | 1030 | goto out; |
972 | 1031 | ||
973 | msg->msg_num = cpu_to_be32(nsw.ns_id); | 1032 | msg->msg_num = cpu_to_be32(nsw.ns_id); |
1033 | o2net_set_nst_msg_id(&nst, nsw.ns_id); | ||
1034 | |||
1035 | o2net_set_nst_send_time(&nst); | ||
974 | 1036 | ||
975 | /* finally, convert the message header to network byte-order | 1037 | /* finally, convert the message header to network byte-order |
976 | * and send */ | 1038 | * and send */ |
@@ -985,6 +1047,7 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, | |||
985 | } | 1047 | } |
986 | 1048 | ||
987 | /* wait on other node's handler */ | 1049 | /* wait on other node's handler */ |
1050 | o2net_set_nst_status_time(&nst); | ||
988 | wait_event(nsw.ns_wq, o2net_nsw_completed(nn, &nsw)); | 1051 | wait_event(nsw.ns_wq, o2net_nsw_completed(nn, &nsw)); |
989 | 1052 | ||
990 | /* Note that we avoid overwriting the callers status return | 1053 | /* Note that we avoid overwriting the callers status return |
@@ -997,6 +1060,7 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, | |||
997 | mlog(0, "woken, returning system status %d, user status %d\n", | 1060 | mlog(0, "woken, returning system status %d, user status %d\n", |
998 | ret, nsw.ns_status); | 1061 | ret, nsw.ns_status); |
999 | out: | 1062 | out: |
1063 | o2net_debug_del_nst(&nst); /* must be before dropping sc and node */ | ||
1000 | if (sc) | 1064 | if (sc) |
1001 | sc_put(sc); | 1065 | sc_put(sc); |
1002 | if (vec) | 1066 | if (vec) |
@@ -1935,6 +1999,9 @@ int o2net_init(void) | |||
1935 | 1999 | ||
1936 | o2quo_init(); | 2000 | o2quo_init(); |
1937 | 2001 | ||
2002 | if (o2net_debugfs_init()) | ||
2003 | return -ENOMEM; | ||
2004 | |||
1938 | o2net_hand = kzalloc(sizeof(struct o2net_handshake), GFP_KERNEL); | 2005 | o2net_hand = kzalloc(sizeof(struct o2net_handshake), GFP_KERNEL); |
1939 | o2net_keep_req = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL); | 2006 | o2net_keep_req = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL); |
1940 | o2net_keep_resp = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL); | 2007 | o2net_keep_resp = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL); |
@@ -1976,4 +2043,5 @@ void o2net_exit(void) | |||
1976 | kfree(o2net_hand); | 2043 | kfree(o2net_hand); |
1977 | kfree(o2net_keep_req); | 2044 | kfree(o2net_keep_req); |
1978 | kfree(o2net_keep_resp); | 2045 | kfree(o2net_keep_resp); |
2046 | o2net_debugfs_exit(); | ||
1979 | } | 2047 | } |
diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h index f36f66aab3dd..a705d5d19036 100644 --- a/fs/ocfs2/cluster/tcp.h +++ b/fs/ocfs2/cluster/tcp.h | |||
@@ -117,4 +117,36 @@ int o2net_num_connected_peers(void); | |||
117 | int o2net_init(void); | 117 | int o2net_init(void); |
118 | void o2net_exit(void); | 118 | void o2net_exit(void); |
119 | 119 | ||
120 | struct o2net_send_tracking; | ||
121 | struct o2net_sock_container; | ||
122 | |||
123 | #ifdef CONFIG_DEBUG_FS | ||
124 | int o2net_debugfs_init(void); | ||
125 | void o2net_debugfs_exit(void); | ||
126 | void o2net_debug_add_nst(struct o2net_send_tracking *nst); | ||
127 | void o2net_debug_del_nst(struct o2net_send_tracking *nst); | ||
128 | void o2net_debug_add_sc(struct o2net_sock_container *sc); | ||
129 | void o2net_debug_del_sc(struct o2net_sock_container *sc); | ||
130 | #else | ||
131 | static int o2net_debugfs_init(void) | ||
132 | { | ||
133 | return 0; | ||
134 | } | ||
135 | static void o2net_debugfs_exit(void) | ||
136 | { | ||
137 | } | ||
138 | static void o2net_debug_add_nst(struct o2net_send_tracking *nst) | ||
139 | { | ||
140 | } | ||
141 | static void o2net_debug_del_nst(struct o2net_send_tracking *nst) | ||
142 | { | ||
143 | } | ||
144 | static void o2net_debug_add_sc(struct o2net_sock_container *sc) | ||
145 | { | ||
146 | } | ||
147 | static void o2net_debug_del_sc(struct o2net_sock_container *sc) | ||
148 | { | ||
149 | } | ||
150 | #endif /* CONFIG_DEBUG_FS */ | ||
151 | |||
120 | #endif /* O2CLUSTER_TCP_H */ | 152 | #endif /* O2CLUSTER_TCP_H */ |
diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h index b4c5586f46ea..8d58cfe410b1 100644 --- a/fs/ocfs2/cluster/tcp_internal.h +++ b/fs/ocfs2/cluster/tcp_internal.h | |||
@@ -166,7 +166,9 @@ struct o2net_sock_container { | |||
166 | /* original handlers for the sockets */ | 166 | /* original handlers for the sockets */ |
167 | void (*sc_state_change)(struct sock *sk); | 167 | void (*sc_state_change)(struct sock *sk); |
168 | void (*sc_data_ready)(struct sock *sk, int bytes); | 168 | void (*sc_data_ready)(struct sock *sk, int bytes); |
169 | 169 | #ifdef CONFIG_DEBUG_FS | |
170 | struct list_head sc_net_debug_item; | ||
171 | #endif | ||
170 | struct timeval sc_tv_timer; | 172 | struct timeval sc_tv_timer; |
171 | struct timeval sc_tv_data_ready; | 173 | struct timeval sc_tv_data_ready; |
172 | struct timeval sc_tv_advance_start; | 174 | struct timeval sc_tv_advance_start; |
@@ -208,4 +210,24 @@ struct o2net_status_wait { | |||
208 | struct list_head ns_node_item; | 210 | struct list_head ns_node_item; |
209 | }; | 211 | }; |
210 | 212 | ||
213 | #ifdef CONFIG_DEBUG_FS | ||
214 | /* just for state dumps */ | ||
215 | struct o2net_send_tracking { | ||
216 | struct list_head st_net_debug_item; | ||
217 | struct task_struct *st_task; | ||
218 | struct o2net_sock_container *st_sc; | ||
219 | u32 st_id; | ||
220 | u32 st_msg_type; | ||
221 | u32 st_msg_key; | ||
222 | u8 st_node; | ||
223 | struct timeval st_sock_time; | ||
224 | struct timeval st_send_time; | ||
225 | struct timeval st_status_time; | ||
226 | }; | ||
227 | #else | ||
228 | struct o2net_send_tracking { | ||
229 | u32 dummy; | ||
230 | }; | ||
231 | #endif /* CONFIG_DEBUG_FS */ | ||
232 | |||
211 | #endif /* O2CLUSTER_TCP_INTERNAL_H */ | 233 | #endif /* O2CLUSTER_TCP_INTERNAL_H */ |