diff options
author | Sunil Mushran <sunil.mushran@oracle.com> | 2008-03-10 18:16:23 -0400 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2008-04-18 11:56:08 -0400 |
commit | 007dce53a29ccffc000ab5373d188f73881390fd (patch) | |
tree | 84ce6e26cc3bed0cb2e041b1a4aabca3449498ff | |
parent | 6325b4a22b8f5e40ea9353288b3d6a32181f9718 (diff) |
ocfs2/dlm: Dump the dlm state in a debugfs file
This patch dumps the dlm state (dlm_ctxt) into a debugfs file.
Useful for debugging.
Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com>
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
-rw-r--r-- | fs/ocfs2/dlm/dlmcommon.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmdebug.c | 296 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmdebug.h | 20 | ||||
-rw-r--r-- | fs/ocfs2/dlm/dlmdomain.c | 8 |
4 files changed, 325 insertions, 0 deletions
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index 6a491403bbfb..f7a51ca64a2e 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h | |||
@@ -123,6 +123,7 @@ struct dlm_ctxt | |||
123 | atomic_t remote_resources; | 123 | atomic_t remote_resources; |
124 | atomic_t unknown_resources; | 124 | atomic_t unknown_resources; |
125 | 125 | ||
126 | struct dlm_debug_ctxt *dlm_debug_ctxt; | ||
126 | struct dentry *dlm_debugfs_subroot; | 127 | struct dentry *dlm_debugfs_subroot; |
127 | 128 | ||
128 | /* NOTE: Next three are protected by dlm_domain_lock */ | 129 | /* NOTE: Next three are protected by dlm_domain_lock */ |
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c index 62e2a4cbf60d..e33540380013 100644 --- a/fs/ocfs2/dlm/dlmdebug.c +++ b/fs/ocfs2/dlm/dlmdebug.c | |||
@@ -274,6 +274,294 @@ EXPORT_SYMBOL_GPL(dlm_errname); | |||
274 | static struct dentry *dlm_debugfs_root = NULL; | 274 | static struct dentry *dlm_debugfs_root = NULL; |
275 | 275 | ||
276 | #define DLM_DEBUGFS_DIR "o2dlm" | 276 | #define DLM_DEBUGFS_DIR "o2dlm" |
277 | #define DLM_DEBUGFS_DLM_STATE "dlm_state" | ||
278 | |||
279 | /* begin - utils funcs */ | ||
280 | static void dlm_debug_free(struct kref *kref) | ||
281 | { | ||
282 | struct dlm_debug_ctxt *dc; | ||
283 | |||
284 | dc = container_of(kref, struct dlm_debug_ctxt, debug_refcnt); | ||
285 | |||
286 | kfree(dc); | ||
287 | } | ||
288 | |||
289 | void dlm_debug_put(struct dlm_debug_ctxt *dc) | ||
290 | { | ||
291 | if (dc) | ||
292 | kref_put(&dc->debug_refcnt, dlm_debug_free); | ||
293 | } | ||
294 | |||
295 | static void dlm_debug_get(struct dlm_debug_ctxt *dc) | ||
296 | { | ||
297 | kref_get(&dc->debug_refcnt); | ||
298 | } | ||
299 | |||
300 | static int stringify_nodemap(unsigned long *nodemap, int maxnodes, | ||
301 | char *buf, int len) | ||
302 | { | ||
303 | int out = 0; | ||
304 | int i = -1; | ||
305 | |||
306 | while ((i = find_next_bit(nodemap, maxnodes, i + 1)) < maxnodes) | ||
307 | out += snprintf(buf + out, len - out, "%d ", i); | ||
308 | |||
309 | return out; | ||
310 | } | ||
311 | |||
312 | static struct debug_buffer *debug_buffer_allocate(void) | ||
313 | { | ||
314 | struct debug_buffer *db = NULL; | ||
315 | |||
316 | db = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); | ||
317 | if (!db) | ||
318 | goto bail; | ||
319 | |||
320 | db->len = PAGE_SIZE; | ||
321 | db->buf = kmalloc(db->len, GFP_KERNEL); | ||
322 | if (!db->buf) | ||
323 | goto bail; | ||
324 | |||
325 | return db; | ||
326 | bail: | ||
327 | kfree(db); | ||
328 | return NULL; | ||
329 | } | ||
330 | |||
331 | static ssize_t debug_buffer_read(struct file *file, char __user *buf, | ||
332 | size_t nbytes, loff_t *ppos) | ||
333 | { | ||
334 | struct debug_buffer *db = file->private_data; | ||
335 | |||
336 | return simple_read_from_buffer(buf, nbytes, ppos, db->buf, db->len); | ||
337 | } | ||
338 | |||
339 | static loff_t debug_buffer_llseek(struct file *file, loff_t off, int whence) | ||
340 | { | ||
341 | struct debug_buffer *db = file->private_data; | ||
342 | loff_t new = -1; | ||
343 | |||
344 | switch (whence) { | ||
345 | case 0: | ||
346 | new = off; | ||
347 | break; | ||
348 | case 1: | ||
349 | new = file->f_pos + off; | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | if (new < 0 || new > db->len) | ||
354 | return -EINVAL; | ||
355 | |||
356 | return (file->f_pos = new); | ||
357 | } | ||
358 | |||
359 | static int debug_buffer_release(struct inode *inode, struct file *file) | ||
360 | { | ||
361 | struct debug_buffer *db = (struct debug_buffer *)file->private_data; | ||
362 | |||
363 | if (db) | ||
364 | kfree(db->buf); | ||
365 | kfree(db); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | /* end - util funcs */ | ||
370 | |||
371 | /* begin - debug state funcs */ | ||
372 | static int debug_state_print(struct dlm_ctxt *dlm, struct debug_buffer *db) | ||
373 | { | ||
374 | int out = 0; | ||
375 | struct dlm_reco_node_data *node; | ||
376 | char *state; | ||
377 | int lres, rres, ures, tres; | ||
378 | |||
379 | lres = atomic_read(&dlm->local_resources); | ||
380 | rres = atomic_read(&dlm->remote_resources); | ||
381 | ures = atomic_read(&dlm->unknown_resources); | ||
382 | tres = lres + rres + ures; | ||
383 | |||
384 | spin_lock(&dlm->spinlock); | ||
385 | |||
386 | switch (dlm->dlm_state) { | ||
387 | case DLM_CTXT_NEW: | ||
388 | state = "NEW"; break; | ||
389 | case DLM_CTXT_JOINED: | ||
390 | state = "JOINED"; break; | ||
391 | case DLM_CTXT_IN_SHUTDOWN: | ||
392 | state = "SHUTDOWN"; break; | ||
393 | case DLM_CTXT_LEAVING: | ||
394 | state = "LEAVING"; break; | ||
395 | default: | ||
396 | state = "UNKNOWN"; break; | ||
397 | } | ||
398 | |||
399 | /* Domain: xxxxxxxxxx Key: 0xdfbac769 */ | ||
400 | out += snprintf(db->buf + out, db->len - out, | ||
401 | "Domain: %s Key: 0x%08x\n", dlm->name, dlm->key); | ||
402 | |||
403 | /* Thread Pid: xxx Node: xxx State: xxxxx */ | ||
404 | out += snprintf(db->buf + out, db->len - out, | ||
405 | "Thread Pid: %d Node: %d State: %s\n", | ||
406 | dlm->dlm_thread_task->pid, dlm->node_num, state); | ||
407 | |||
408 | /* Number of Joins: xxx Joining Node: xxx */ | ||
409 | out += snprintf(db->buf + out, db->len - out, | ||
410 | "Number of Joins: %d Joining Node: %d\n", | ||
411 | dlm->num_joins, dlm->joining_node); | ||
412 | |||
413 | /* Domain Map: xx xx xx */ | ||
414 | out += snprintf(db->buf + out, db->len - out, "Domain Map: "); | ||
415 | out += stringify_nodemap(dlm->domain_map, O2NM_MAX_NODES, | ||
416 | db->buf + out, db->len - out); | ||
417 | out += snprintf(db->buf + out, db->len - out, "\n"); | ||
418 | |||
419 | /* Live Map: xx xx xx */ | ||
420 | out += snprintf(db->buf + out, db->len - out, "Live Map: "); | ||
421 | out += stringify_nodemap(dlm->live_nodes_map, O2NM_MAX_NODES, | ||
422 | db->buf + out, db->len - out); | ||
423 | out += snprintf(db->buf + out, db->len - out, "\n"); | ||
424 | |||
425 | /* Mastered Resources Total: xxx Locally: xxx Remotely: ... */ | ||
426 | out += snprintf(db->buf + out, db->len - out, | ||
427 | "Mastered Resources Total: %d Locally: %d " | ||
428 | "Remotely: %d Unknown: %d\n", | ||
429 | tres, lres, rres, ures); | ||
430 | |||
431 | /* Lists: Dirty=Empty Purge=InUse PendingASTs=Empty ... */ | ||
432 | out += snprintf(db->buf + out, db->len - out, | ||
433 | "Lists: Dirty=%s Purge=%s PendingASTs=%s " | ||
434 | "PendingBASTs=%s Master=%s\n", | ||
435 | (list_empty(&dlm->dirty_list) ? "Empty" : "InUse"), | ||
436 | (list_empty(&dlm->purge_list) ? "Empty" : "InUse"), | ||
437 | (list_empty(&dlm->pending_asts) ? "Empty" : "InUse"), | ||
438 | (list_empty(&dlm->pending_basts) ? "Empty" : "InUse"), | ||
439 | (list_empty(&dlm->master_list) ? "Empty" : "InUse")); | ||
440 | |||
441 | /* Purge Count: xxx Refs: xxx */ | ||
442 | out += snprintf(db->buf + out, db->len - out, | ||
443 | "Purge Count: %d Refs: %d\n", dlm->purge_count, | ||
444 | atomic_read(&dlm->dlm_refs.refcount)); | ||
445 | |||
446 | /* Dead Node: xxx */ | ||
447 | out += snprintf(db->buf + out, db->len - out, | ||
448 | "Dead Node: %d\n", dlm->reco.dead_node); | ||
449 | |||
450 | /* What about DLM_RECO_STATE_FINALIZE? */ | ||
451 | if (dlm->reco.state == DLM_RECO_STATE_ACTIVE) | ||
452 | state = "ACTIVE"; | ||
453 | else | ||
454 | state = "INACTIVE"; | ||
455 | |||
456 | /* Recovery Pid: xxxx Master: xxx State: xxxx */ | ||
457 | out += snprintf(db->buf + out, db->len - out, | ||
458 | "Recovery Pid: %d Master: %d State: %s\n", | ||
459 | dlm->dlm_reco_thread_task->pid, | ||
460 | dlm->reco.new_master, state); | ||
461 | |||
462 | /* Recovery Map: xx xx */ | ||
463 | out += snprintf(db->buf + out, db->len - out, "Recovery Map: "); | ||
464 | out += stringify_nodemap(dlm->recovery_map, O2NM_MAX_NODES, | ||
465 | db->buf + out, db->len - out); | ||
466 | out += snprintf(db->buf + out, db->len - out, "\n"); | ||
467 | |||
468 | /* Recovery Node State: */ | ||
469 | out += snprintf(db->buf + out, db->len - out, "Recovery Node State:\n"); | ||
470 | list_for_each_entry(node, &dlm->reco.node_data, list) { | ||
471 | switch (node->state) { | ||
472 | case DLM_RECO_NODE_DATA_INIT: | ||
473 | state = "INIT"; | ||
474 | break; | ||
475 | case DLM_RECO_NODE_DATA_REQUESTING: | ||
476 | state = "REQUESTING"; | ||
477 | break; | ||
478 | case DLM_RECO_NODE_DATA_DEAD: | ||
479 | state = "DEAD"; | ||
480 | break; | ||
481 | case DLM_RECO_NODE_DATA_RECEIVING: | ||
482 | state = "RECEIVING"; | ||
483 | break; | ||
484 | case DLM_RECO_NODE_DATA_REQUESTED: | ||
485 | state = "REQUESTED"; | ||
486 | break; | ||
487 | case DLM_RECO_NODE_DATA_DONE: | ||
488 | state = "DONE"; | ||
489 | break; | ||
490 | case DLM_RECO_NODE_DATA_FINALIZE_SENT: | ||
491 | state = "FINALIZE-SENT"; | ||
492 | break; | ||
493 | default: | ||
494 | state = "BAD"; | ||
495 | break; | ||
496 | } | ||
497 | out += snprintf(db->buf + out, db->len - out, "\t%u - %s\n", | ||
498 | node->node_num, state); | ||
499 | } | ||
500 | |||
501 | spin_unlock(&dlm->spinlock); | ||
502 | |||
503 | return out; | ||
504 | } | ||
505 | |||
506 | static int debug_state_open(struct inode *inode, struct file *file) | ||
507 | { | ||
508 | struct dlm_ctxt *dlm = inode->i_private; | ||
509 | struct debug_buffer *db = NULL; | ||
510 | |||
511 | db = debug_buffer_allocate(); | ||
512 | if (!db) | ||
513 | goto bail; | ||
514 | |||
515 | db->len = debug_state_print(dlm, db); | ||
516 | |||
517 | file->private_data = db; | ||
518 | |||
519 | return 0; | ||
520 | bail: | ||
521 | return -ENOMEM; | ||
522 | } | ||
523 | |||
524 | static struct file_operations debug_state_fops = { | ||
525 | .open = debug_state_open, | ||
526 | .release = debug_buffer_release, | ||
527 | .read = debug_buffer_read, | ||
528 | .llseek = debug_buffer_llseek, | ||
529 | }; | ||
530 | /* end - debug state funcs */ | ||
531 | |||
532 | /* files in subroot */ | ||
533 | int dlm_debug_init(struct dlm_ctxt *dlm) | ||
534 | { | ||
535 | struct dlm_debug_ctxt *dc = dlm->dlm_debug_ctxt; | ||
536 | |||
537 | /* for dumping dlm_ctxt */ | ||
538 | dc->debug_state_dentry = debugfs_create_file(DLM_DEBUGFS_DLM_STATE, | ||
539 | S_IFREG|S_IRUSR, | ||
540 | dlm->dlm_debugfs_subroot, | ||
541 | dlm, &debug_state_fops); | ||
542 | if (!dc->debug_state_dentry) { | ||
543 | mlog_errno(-ENOMEM); | ||
544 | goto bail; | ||
545 | } | ||
546 | |||
547 | dlm_debug_get(dc); | ||
548 | return 0; | ||
549 | |||
550 | bail: | ||
551 | dlm_debug_shutdown(dlm); | ||
552 | return -ENOMEM; | ||
553 | } | ||
554 | |||
555 | void dlm_debug_shutdown(struct dlm_ctxt *dlm) | ||
556 | { | ||
557 | struct dlm_debug_ctxt *dc = dlm->dlm_debug_ctxt; | ||
558 | |||
559 | if (dc) { | ||
560 | if (dc->debug_state_dentry) | ||
561 | debugfs_remove(dc->debug_state_dentry); | ||
562 | dlm_debug_put(dc); | ||
563 | } | ||
564 | } | ||
277 | 565 | ||
278 | /* subroot - domain dir */ | 566 | /* subroot - domain dir */ |
279 | int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm) | 567 | int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm) |
@@ -285,6 +573,14 @@ int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm) | |||
285 | goto bail; | 573 | goto bail; |
286 | } | 574 | } |
287 | 575 | ||
576 | dlm->dlm_debug_ctxt = kzalloc(sizeof(struct dlm_debug_ctxt), | ||
577 | GFP_KERNEL); | ||
578 | if (!dlm->dlm_debug_ctxt) { | ||
579 | mlog_errno(-ENOMEM); | ||
580 | goto bail; | ||
581 | } | ||
582 | kref_init(&dlm->dlm_debug_ctxt->debug_refcnt); | ||
583 | |||
288 | return 0; | 584 | return 0; |
289 | bail: | 585 | bail: |
290 | dlm_destroy_debugfs_subroot(dlm); | 586 | dlm_destroy_debugfs_subroot(dlm); |
diff --git a/fs/ocfs2/dlm/dlmdebug.h b/fs/ocfs2/dlm/dlmdebug.h index b96959512d96..94cc10a4e19c 100644 --- a/fs/ocfs2/dlm/dlmdebug.h +++ b/fs/ocfs2/dlm/dlmdebug.h | |||
@@ -27,6 +27,19 @@ | |||
27 | 27 | ||
28 | #ifdef CONFIG_DEBUG_FS | 28 | #ifdef CONFIG_DEBUG_FS |
29 | 29 | ||
30 | struct dlm_debug_ctxt { | ||
31 | struct kref debug_refcnt; | ||
32 | struct dentry *debug_state_dentry; | ||
33 | }; | ||
34 | |||
35 | struct debug_buffer { | ||
36 | int len; | ||
37 | char *buf; | ||
38 | }; | ||
39 | |||
40 | int dlm_debug_init(struct dlm_ctxt *dlm); | ||
41 | void dlm_debug_shutdown(struct dlm_ctxt *dlm); | ||
42 | |||
30 | int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm); | 43 | int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm); |
31 | void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm); | 44 | void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm); |
32 | 45 | ||
@@ -35,6 +48,13 @@ void dlm_destroy_debugfs_root(void); | |||
35 | 48 | ||
36 | #else | 49 | #else |
37 | 50 | ||
51 | static int dlm_debug_init(struct dlm_ctxt *dlm) | ||
52 | { | ||
53 | return 0; | ||
54 | } | ||
55 | static void dlm_debug_shutdown(struct dlm_ctxt *dlm) | ||
56 | { | ||
57 | } | ||
38 | static int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm) | 58 | static int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm) |
39 | { | 59 | { |
40 | return 0; | 60 | return 0; |
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index c137d693cef3..63f8125824e8 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c | |||
@@ -398,6 +398,7 @@ static void dlm_destroy_dlm_worker(struct dlm_ctxt *dlm) | |||
398 | static void dlm_complete_dlm_shutdown(struct dlm_ctxt *dlm) | 398 | static void dlm_complete_dlm_shutdown(struct dlm_ctxt *dlm) |
399 | { | 399 | { |
400 | dlm_unregister_domain_handlers(dlm); | 400 | dlm_unregister_domain_handlers(dlm); |
401 | dlm_debug_shutdown(dlm); | ||
401 | dlm_complete_thread(dlm); | 402 | dlm_complete_thread(dlm); |
402 | dlm_complete_recovery_thread(dlm); | 403 | dlm_complete_recovery_thread(dlm); |
403 | dlm_destroy_dlm_worker(dlm); | 404 | dlm_destroy_dlm_worker(dlm); |
@@ -1418,6 +1419,12 @@ static int dlm_join_domain(struct dlm_ctxt *dlm) | |||
1418 | goto bail; | 1419 | goto bail; |
1419 | } | 1420 | } |
1420 | 1421 | ||
1422 | status = dlm_debug_init(dlm); | ||
1423 | if (status < 0) { | ||
1424 | mlog_errno(status); | ||
1425 | goto bail; | ||
1426 | } | ||
1427 | |||
1421 | status = dlm_launch_thread(dlm); | 1428 | status = dlm_launch_thread(dlm); |
1422 | if (status < 0) { | 1429 | if (status < 0) { |
1423 | mlog_errno(status); | 1430 | mlog_errno(status); |
@@ -1485,6 +1492,7 @@ bail: | |||
1485 | 1492 | ||
1486 | if (status) { | 1493 | if (status) { |
1487 | dlm_unregister_domain_handlers(dlm); | 1494 | dlm_unregister_domain_handlers(dlm); |
1495 | dlm_debug_shutdown(dlm); | ||
1488 | dlm_complete_thread(dlm); | 1496 | dlm_complete_thread(dlm); |
1489 | dlm_complete_recovery_thread(dlm); | 1497 | dlm_complete_recovery_thread(dlm); |
1490 | dlm_destroy_dlm_worker(dlm); | 1498 | dlm_destroy_dlm_worker(dlm); |