diff options
Diffstat (limited to 'fs/ocfs2/cluster/netdebug.c')
-rw-r--r-- | fs/ocfs2/cluster/netdebug.c | 286 |
1 files changed, 193 insertions, 93 deletions
diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c index a3f150e52b02..3a5835904b3d 100644 --- a/fs/ocfs2/cluster/netdebug.c +++ b/fs/ocfs2/cluster/netdebug.c | |||
@@ -46,10 +46,15 @@ | |||
46 | #define O2NET_DEBUG_DIR "o2net" | 46 | #define O2NET_DEBUG_DIR "o2net" |
47 | #define SC_DEBUG_NAME "sock_containers" | 47 | #define SC_DEBUG_NAME "sock_containers" |
48 | #define NST_DEBUG_NAME "send_tracking" | 48 | #define NST_DEBUG_NAME "send_tracking" |
49 | #define STATS_DEBUG_NAME "stats" | ||
50 | |||
51 | #define SHOW_SOCK_CONTAINERS 0 | ||
52 | #define SHOW_SOCK_STATS 1 | ||
49 | 53 | ||
50 | static struct dentry *o2net_dentry; | 54 | static struct dentry *o2net_dentry; |
51 | static struct dentry *sc_dentry; | 55 | static struct dentry *sc_dentry; |
52 | static struct dentry *nst_dentry; | 56 | static struct dentry *nst_dentry; |
57 | static struct dentry *stats_dentry; | ||
53 | 58 | ||
54 | static DEFINE_SPINLOCK(o2net_debug_lock); | 59 | static DEFINE_SPINLOCK(o2net_debug_lock); |
55 | 60 | ||
@@ -123,37 +128,42 @@ static void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
123 | static int nst_seq_show(struct seq_file *seq, void *v) | 128 | static int nst_seq_show(struct seq_file *seq, void *v) |
124 | { | 129 | { |
125 | struct o2net_send_tracking *nst, *dummy_nst = seq->private; | 130 | struct o2net_send_tracking *nst, *dummy_nst = seq->private; |
131 | ktime_t now; | ||
132 | s64 sock, send, status; | ||
126 | 133 | ||
127 | spin_lock(&o2net_debug_lock); | 134 | spin_lock(&o2net_debug_lock); |
128 | nst = next_nst(dummy_nst); | 135 | nst = next_nst(dummy_nst); |
136 | if (!nst) | ||
137 | goto out; | ||
129 | 138 | ||
130 | if (nst != NULL) { | 139 | now = ktime_get(); |
131 | /* get_task_comm isn't exported. oh well. */ | 140 | sock = ktime_to_us(ktime_sub(now, nst->st_sock_time)); |
132 | seq_printf(seq, "%p:\n" | 141 | send = ktime_to_us(ktime_sub(now, nst->st_send_time)); |
133 | " pid: %lu\n" | 142 | status = ktime_to_us(ktime_sub(now, nst->st_status_time)); |
134 | " tgid: %lu\n" | 143 | |
135 | " process name: %s\n" | 144 | /* get_task_comm isn't exported. oh well. */ |
136 | " node: %u\n" | 145 | seq_printf(seq, "%p:\n" |
137 | " sc: %p\n" | 146 | " pid: %lu\n" |
138 | " message id: %d\n" | 147 | " tgid: %lu\n" |
139 | " message type: %u\n" | 148 | " process name: %s\n" |
140 | " message key: 0x%08x\n" | 149 | " node: %u\n" |
141 | " sock acquiry: %lu.%ld\n" | 150 | " sc: %p\n" |
142 | " send start: %lu.%ld\n" | 151 | " message id: %d\n" |
143 | " wait start: %lu.%ld\n", | 152 | " message type: %u\n" |
144 | nst, (unsigned long)nst->st_task->pid, | 153 | " message key: 0x%08x\n" |
145 | (unsigned long)nst->st_task->tgid, | 154 | " sock acquiry: %lld usecs ago\n" |
146 | nst->st_task->comm, nst->st_node, | 155 | " send start: %lld usecs ago\n" |
147 | nst->st_sc, nst->st_id, nst->st_msg_type, | 156 | " wait start: %lld usecs ago\n", |
148 | nst->st_msg_key, | 157 | nst, (unsigned long)task_pid_nr(nst->st_task), |
149 | nst->st_sock_time.tv_sec, | 158 | (unsigned long)nst->st_task->tgid, |
150 | (long)nst->st_sock_time.tv_usec, | 159 | nst->st_task->comm, nst->st_node, |
151 | nst->st_send_time.tv_sec, | 160 | nst->st_sc, nst->st_id, nst->st_msg_type, |
152 | (long)nst->st_send_time.tv_usec, | 161 | nst->st_msg_key, |
153 | nst->st_status_time.tv_sec, | 162 | (long long)sock, |
154 | (long)nst->st_status_time.tv_usec); | 163 | (long long)send, |
155 | } | 164 | (long long)status); |
156 | 165 | ||
166 | out: | ||
157 | spin_unlock(&o2net_debug_lock); | 167 | spin_unlock(&o2net_debug_lock); |
158 | 168 | ||
159 | return 0; | 169 | return 0; |
@@ -228,6 +238,11 @@ void o2net_debug_del_sc(struct o2net_sock_container *sc) | |||
228 | spin_unlock(&o2net_debug_lock); | 238 | spin_unlock(&o2net_debug_lock); |
229 | } | 239 | } |
230 | 240 | ||
241 | struct o2net_sock_debug { | ||
242 | int dbg_ctxt; | ||
243 | struct o2net_sock_container *dbg_sock; | ||
244 | }; | ||
245 | |||
231 | static struct o2net_sock_container | 246 | static struct o2net_sock_container |
232 | *next_sc(struct o2net_sock_container *sc_start) | 247 | *next_sc(struct o2net_sock_container *sc_start) |
233 | { | 248 | { |
@@ -253,7 +268,8 @@ static struct o2net_sock_container | |||
253 | 268 | ||
254 | static void *sc_seq_start(struct seq_file *seq, loff_t *pos) | 269 | static void *sc_seq_start(struct seq_file *seq, loff_t *pos) |
255 | { | 270 | { |
256 | struct o2net_sock_container *sc, *dummy_sc = seq->private; | 271 | struct o2net_sock_debug *sd = seq->private; |
272 | struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock; | ||
257 | 273 | ||
258 | spin_lock(&o2net_debug_lock); | 274 | spin_lock(&o2net_debug_lock); |
259 | sc = next_sc(dummy_sc); | 275 | sc = next_sc(dummy_sc); |
@@ -264,7 +280,8 @@ static void *sc_seq_start(struct seq_file *seq, loff_t *pos) | |||
264 | 280 | ||
265 | static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 281 | static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
266 | { | 282 | { |
267 | struct o2net_sock_container *sc, *dummy_sc = seq->private; | 283 | struct o2net_sock_debug *sd = seq->private; |
284 | struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock; | ||
268 | 285 | ||
269 | spin_lock(&o2net_debug_lock); | 286 | spin_lock(&o2net_debug_lock); |
270 | sc = next_sc(dummy_sc); | 287 | sc = next_sc(dummy_sc); |
@@ -276,65 +293,107 @@ static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
276 | return sc; /* unused, just needs to be null when done */ | 293 | return sc; /* unused, just needs to be null when done */ |
277 | } | 294 | } |
278 | 295 | ||
279 | #define TV_SEC_USEC(TV) TV.tv_sec, (long)TV.tv_usec | 296 | #ifdef CONFIG_OCFS2_FS_STATS |
297 | # define sc_send_count(_s) ((_s)->sc_send_count) | ||
298 | # define sc_recv_count(_s) ((_s)->sc_recv_count) | ||
299 | # define sc_tv_acquiry_total_ns(_s) (ktime_to_ns((_s)->sc_tv_acquiry_total)) | ||
300 | # define sc_tv_send_total_ns(_s) (ktime_to_ns((_s)->sc_tv_send_total)) | ||
301 | # define sc_tv_status_total_ns(_s) (ktime_to_ns((_s)->sc_tv_status_total)) | ||
302 | # define sc_tv_process_total_ns(_s) (ktime_to_ns((_s)->sc_tv_process_total)) | ||
303 | #else | ||
304 | # define sc_send_count(_s) (0U) | ||
305 | # define sc_recv_count(_s) (0U) | ||
306 | # define sc_tv_acquiry_total_ns(_s) (0LL) | ||
307 | # define sc_tv_send_total_ns(_s) (0LL) | ||
308 | # define sc_tv_status_total_ns(_s) (0LL) | ||
309 | # define sc_tv_process_total_ns(_s) (0LL) | ||
310 | #endif | ||
311 | |||
312 | /* So that debugfs.ocfs2 can determine which format is being used */ | ||
313 | #define O2NET_STATS_STR_VERSION 1 | ||
314 | static void sc_show_sock_stats(struct seq_file *seq, | ||
315 | struct o2net_sock_container *sc) | ||
316 | { | ||
317 | if (!sc) | ||
318 | return; | ||
319 | |||
320 | seq_printf(seq, "%d,%u,%lu,%lld,%lld,%lld,%lu,%lld\n", O2NET_STATS_STR_VERSION, | ||
321 | sc->sc_node->nd_num, (unsigned long)sc_send_count(sc), | ||
322 | (long long)sc_tv_acquiry_total_ns(sc), | ||
323 | (long long)sc_tv_send_total_ns(sc), | ||
324 | (long long)sc_tv_status_total_ns(sc), | ||
325 | (unsigned long)sc_recv_count(sc), | ||
326 | (long long)sc_tv_process_total_ns(sc)); | ||
327 | } | ||
328 | |||
329 | static void sc_show_sock_container(struct seq_file *seq, | ||
330 | struct o2net_sock_container *sc) | ||
331 | { | ||
332 | struct inet_sock *inet = NULL; | ||
333 | __be32 saddr = 0, daddr = 0; | ||
334 | __be16 sport = 0, dport = 0; | ||
335 | |||
336 | if (!sc) | ||
337 | return; | ||
338 | |||
339 | if (sc->sc_sock) { | ||
340 | inet = inet_sk(sc->sc_sock->sk); | ||
341 | /* the stack's structs aren't sparse endian clean */ | ||
342 | saddr = (__force __be32)inet->inet_saddr; | ||
343 | daddr = (__force __be32)inet->inet_daddr; | ||
344 | sport = (__force __be16)inet->inet_sport; | ||
345 | dport = (__force __be16)inet->inet_dport; | ||
346 | } | ||
347 | |||
348 | /* XXX sigh, inet-> doesn't have sparse annotation so any | ||
349 | * use of it here generates a warning with -Wbitwise */ | ||
350 | seq_printf(seq, "%p:\n" | ||
351 | " krefs: %d\n" | ||
352 | " sock: %pI4:%u -> " | ||
353 | "%pI4:%u\n" | ||
354 | " remote node: %s\n" | ||
355 | " page off: %zu\n" | ||
356 | " handshake ok: %u\n" | ||
357 | " timer: %lld usecs\n" | ||
358 | " data ready: %lld usecs\n" | ||
359 | " advance start: %lld usecs\n" | ||
360 | " advance stop: %lld usecs\n" | ||
361 | " func start: %lld usecs\n" | ||
362 | " func stop: %lld usecs\n" | ||
363 | " func key: 0x%08x\n" | ||
364 | " func type: %u\n", | ||
365 | sc, | ||
366 | atomic_read(&sc->sc_kref.refcount), | ||
367 | &saddr, inet ? ntohs(sport) : 0, | ||
368 | &daddr, inet ? ntohs(dport) : 0, | ||
369 | sc->sc_node->nd_name, | ||
370 | sc->sc_page_off, | ||
371 | sc->sc_handshake_ok, | ||
372 | (long long)ktime_to_us(sc->sc_tv_timer), | ||
373 | (long long)ktime_to_us(sc->sc_tv_data_ready), | ||
374 | (long long)ktime_to_us(sc->sc_tv_advance_start), | ||
375 | (long long)ktime_to_us(sc->sc_tv_advance_stop), | ||
376 | (long long)ktime_to_us(sc->sc_tv_func_start), | ||
377 | (long long)ktime_to_us(sc->sc_tv_func_stop), | ||
378 | sc->sc_msg_key, | ||
379 | sc->sc_msg_type); | ||
380 | } | ||
280 | 381 | ||
281 | static int sc_seq_show(struct seq_file *seq, void *v) | 382 | static int sc_seq_show(struct seq_file *seq, void *v) |
282 | { | 383 | { |
283 | struct o2net_sock_container *sc, *dummy_sc = seq->private; | 384 | struct o2net_sock_debug *sd = seq->private; |
385 | struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock; | ||
284 | 386 | ||
285 | spin_lock(&o2net_debug_lock); | 387 | spin_lock(&o2net_debug_lock); |
286 | sc = next_sc(dummy_sc); | 388 | sc = next_sc(dummy_sc); |
287 | 389 | ||
288 | if (sc != NULL) { | 390 | if (sc) { |
289 | struct inet_sock *inet = NULL; | 391 | if (sd->dbg_ctxt == SHOW_SOCK_CONTAINERS) |
290 | 392 | sc_show_sock_container(seq, sc); | |
291 | __be32 saddr = 0, daddr = 0; | 393 | else |
292 | __be16 sport = 0, dport = 0; | 394 | sc_show_sock_stats(seq, sc); |
293 | |||
294 | if (sc->sc_sock) { | ||
295 | inet = inet_sk(sc->sc_sock->sk); | ||
296 | /* the stack's structs aren't sparse endian clean */ | ||
297 | saddr = (__force __be32)inet->inet_saddr; | ||
298 | daddr = (__force __be32)inet->inet_daddr; | ||
299 | sport = (__force __be16)inet->inet_sport; | ||
300 | dport = (__force __be16)inet->inet_dport; | ||
301 | } | ||
302 | |||
303 | /* XXX sigh, inet-> doesn't have sparse annotation so any | ||
304 | * use of it here generates a warning with -Wbitwise */ | ||
305 | seq_printf(seq, "%p:\n" | ||
306 | " krefs: %d\n" | ||
307 | " sock: %pI4:%u -> " | ||
308 | "%pI4:%u\n" | ||
309 | " remote node: %s\n" | ||
310 | " page off: %zu\n" | ||
311 | " handshake ok: %u\n" | ||
312 | " timer: %lu.%ld\n" | ||
313 | " data ready: %lu.%ld\n" | ||
314 | " advance start: %lu.%ld\n" | ||
315 | " advance stop: %lu.%ld\n" | ||
316 | " func start: %lu.%ld\n" | ||
317 | " func stop: %lu.%ld\n" | ||
318 | " func key: %u\n" | ||
319 | " func type: %u\n", | ||
320 | sc, | ||
321 | atomic_read(&sc->sc_kref.refcount), | ||
322 | &saddr, inet ? ntohs(sport) : 0, | ||
323 | &daddr, inet ? ntohs(dport) : 0, | ||
324 | sc->sc_node->nd_name, | ||
325 | sc->sc_page_off, | ||
326 | sc->sc_handshake_ok, | ||
327 | TV_SEC_USEC(sc->sc_tv_timer), | ||
328 | TV_SEC_USEC(sc->sc_tv_data_ready), | ||
329 | TV_SEC_USEC(sc->sc_tv_advance_start), | ||
330 | TV_SEC_USEC(sc->sc_tv_advance_stop), | ||
331 | TV_SEC_USEC(sc->sc_tv_func_start), | ||
332 | TV_SEC_USEC(sc->sc_tv_func_stop), | ||
333 | sc->sc_msg_key, | ||
334 | sc->sc_msg_type); | ||
335 | } | 395 | } |
336 | 396 | ||
337 | |||
338 | spin_unlock(&o2net_debug_lock); | 397 | spin_unlock(&o2net_debug_lock); |
339 | 398 | ||
340 | return 0; | 399 | return 0; |
@@ -351,7 +410,7 @@ static const struct seq_operations sc_seq_ops = { | |||
351 | .show = sc_seq_show, | 410 | .show = sc_seq_show, |
352 | }; | 411 | }; |
353 | 412 | ||
354 | static int sc_fop_open(struct inode *inode, struct file *file) | 413 | static int sc_common_open(struct file *file, struct o2net_sock_debug *sd) |
355 | { | 414 | { |
356 | struct o2net_sock_container *dummy_sc; | 415 | struct o2net_sock_container *dummy_sc; |
357 | struct seq_file *seq; | 416 | struct seq_file *seq; |
@@ -369,7 +428,8 @@ static int sc_fop_open(struct inode *inode, struct file *file) | |||
369 | goto out; | 428 | goto out; |
370 | 429 | ||
371 | seq = file->private_data; | 430 | seq = file->private_data; |
372 | seq->private = dummy_sc; | 431 | seq->private = sd; |
432 | sd->dbg_sock = dummy_sc; | ||
373 | o2net_debug_add_sc(dummy_sc); | 433 | o2net_debug_add_sc(dummy_sc); |
374 | 434 | ||
375 | dummy_sc = NULL; | 435 | dummy_sc = NULL; |
@@ -382,12 +442,48 @@ out: | |||
382 | static int sc_fop_release(struct inode *inode, struct file *file) | 442 | static int sc_fop_release(struct inode *inode, struct file *file) |
383 | { | 443 | { |
384 | struct seq_file *seq = file->private_data; | 444 | struct seq_file *seq = file->private_data; |
385 | struct o2net_sock_container *dummy_sc = seq->private; | 445 | struct o2net_sock_debug *sd = seq->private; |
446 | struct o2net_sock_container *dummy_sc = sd->dbg_sock; | ||
386 | 447 | ||
387 | o2net_debug_del_sc(dummy_sc); | 448 | o2net_debug_del_sc(dummy_sc); |
388 | return seq_release_private(inode, file); | 449 | return seq_release_private(inode, file); |
389 | } | 450 | } |
390 | 451 | ||
452 | static int stats_fop_open(struct inode *inode, struct file *file) | ||
453 | { | ||
454 | struct o2net_sock_debug *sd; | ||
455 | |||
456 | sd = kmalloc(sizeof(struct o2net_sock_debug), GFP_KERNEL); | ||
457 | if (sd == NULL) | ||
458 | return -ENOMEM; | ||
459 | |||
460 | sd->dbg_ctxt = SHOW_SOCK_STATS; | ||
461 | sd->dbg_sock = NULL; | ||
462 | |||
463 | return sc_common_open(file, sd); | ||
464 | } | ||
465 | |||
466 | static const struct file_operations stats_seq_fops = { | ||
467 | .open = stats_fop_open, | ||
468 | .read = seq_read, | ||
469 | .llseek = seq_lseek, | ||
470 | .release = sc_fop_release, | ||
471 | }; | ||
472 | |||
473 | static int sc_fop_open(struct inode *inode, struct file *file) | ||
474 | { | ||
475 | struct o2net_sock_debug *sd; | ||
476 | |||
477 | sd = kmalloc(sizeof(struct o2net_sock_debug), GFP_KERNEL); | ||
478 | if (sd == NULL) | ||
479 | return -ENOMEM; | ||
480 | |||
481 | sd->dbg_ctxt = SHOW_SOCK_CONTAINERS; | ||
482 | sd->dbg_sock = NULL; | ||
483 | |||
484 | return sc_common_open(file, sd); | ||
485 | } | ||
486 | |||
391 | static const struct file_operations sc_seq_fops = { | 487 | static const struct file_operations sc_seq_fops = { |
392 | .open = sc_fop_open, | 488 | .open = sc_fop_open, |
393 | .read = seq_read, | 489 | .read = seq_read, |
@@ -419,25 +515,29 @@ int o2net_debugfs_init(void) | |||
419 | goto bail; | 515 | goto bail; |
420 | } | 516 | } |
421 | 517 | ||
518 | stats_dentry = debugfs_create_file(STATS_DEBUG_NAME, S_IFREG|S_IRUSR, | ||
519 | o2net_dentry, NULL, | ||
520 | &stats_seq_fops); | ||
521 | if (!stats_dentry) { | ||
522 | mlog_errno(-ENOMEM); | ||
523 | goto bail; | ||
524 | } | ||
525 | |||
422 | return 0; | 526 | return 0; |
423 | bail: | 527 | bail: |
424 | if (sc_dentry) | 528 | debugfs_remove(stats_dentry); |
425 | debugfs_remove(sc_dentry); | 529 | debugfs_remove(sc_dentry); |
426 | if (nst_dentry) | 530 | debugfs_remove(nst_dentry); |
427 | debugfs_remove(nst_dentry); | 531 | debugfs_remove(o2net_dentry); |
428 | if (o2net_dentry) | ||
429 | debugfs_remove(o2net_dentry); | ||
430 | return -ENOMEM; | 532 | return -ENOMEM; |
431 | } | 533 | } |
432 | 534 | ||
433 | void o2net_debugfs_exit(void) | 535 | void o2net_debugfs_exit(void) |
434 | { | 536 | { |
435 | if (sc_dentry) | 537 | debugfs_remove(stats_dentry); |
436 | debugfs_remove(sc_dentry); | 538 | debugfs_remove(sc_dentry); |
437 | if (nst_dentry) | 539 | debugfs_remove(nst_dentry); |
438 | debugfs_remove(nst_dentry); | 540 | debugfs_remove(o2net_dentry); |
439 | if (o2net_dentry) | ||
440 | debugfs_remove(o2net_dentry); | ||
441 | } | 541 | } |
442 | 542 | ||
443 | #endif /* CONFIG_DEBUG_FS */ | 543 | #endif /* CONFIG_DEBUG_FS */ |