1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * debug functionality for the dlm
7 * Copyright (C) 2004, 2008 Oracle. All rights reserved.
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <linux/highmem.h>
13 #include <linux/sysctl.h>
14 #include <linux/spinlock.h>
15 #include <linux/debugfs.h>
16 #include <linux/export.h>
17 #include <linux/string_choices.h>
19 #include "../cluster/heartbeat.h"
20 #include "../cluster/nodemanager.h"
21 #include "../cluster/tcp.h"
24 #include "dlmcommon.h"
25 #include "dlmdomain.h"
28 #define MLOG_MASK_PREFIX ML_DLM
29 #include "../cluster/masklog.h"
31 static int stringify_lockname(const char *lockname
, int locklen
, char *buf
,
34 void dlm_print_one_lock_resource(struct dlm_lock_resource
*res
)
36 spin_lock(&res
->spinlock
);
37 __dlm_print_one_lock_resource(res
);
38 spin_unlock(&res
->spinlock
);
41 static void dlm_print_lockres_refmap(struct dlm_lock_resource
*res
)
44 assert_spin_locked(&res
->spinlock
);
46 printk(" refmap nodes: [ ");
49 bit
= find_next_bit(res
->refmap
, O2NM_MAX_NODES
, bit
);
50 if (bit
>= O2NM_MAX_NODES
)
55 printk("], inflight=%u\n", res
->inflight_locks
);
58 static void __dlm_print_lock(struct dlm_lock
*lock
)
60 spin_lock(&lock
->spinlock
);
62 printk(" type=%d, conv=%d, node=%u, cookie=%u:%llu, "
63 "ref=%u, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c), "
64 "pending=(conv=%c,lock=%c,cancel=%c,unlock=%c)\n",
65 lock
->ml
.type
, lock
->ml
.convert_type
, lock
->ml
.node
,
66 dlm_get_lock_cookie_node(be64_to_cpu(lock
->ml
.cookie
)),
67 dlm_get_lock_cookie_seq(be64_to_cpu(lock
->ml
.cookie
)),
68 kref_read(&lock
->lock_refs
),
69 (list_empty(&lock
->ast_list
) ? 'y' : 'n'),
70 (lock
->ast_pending
? 'y' : 'n'),
71 (list_empty(&lock
->bast_list
) ? 'y' : 'n'),
72 (lock
->bast_pending
? 'y' : 'n'),
73 (lock
->convert_pending
? 'y' : 'n'),
74 (lock
->lock_pending
? 'y' : 'n'),
75 (lock
->cancel_pending
? 'y' : 'n'),
76 (lock
->unlock_pending
? 'y' : 'n'));
78 spin_unlock(&lock
->spinlock
);
81 void __dlm_print_one_lock_resource(struct dlm_lock_resource
*res
)
83 struct dlm_lock
*lock
;
84 char buf
[DLM_LOCKID_NAME_MAX
];
86 assert_spin_locked(&res
->spinlock
);
88 stringify_lockname(res
->lockname
.name
, res
->lockname
.len
,
90 printk("lockres: %s, owner=%u, state=%u\n",
91 buf
, res
->owner
, res
->state
);
92 printk(" last used: %lu, refcnt: %u, on purge list: %s\n",
93 res
->last_used
, kref_read(&res
->refs
),
94 str_no_yes(list_empty(&res
->purge
)));
95 printk(" on dirty list: %s, on reco list: %s, "
96 "migrating pending: %s\n",
97 str_no_yes(list_empty(&res
->dirty
)),
98 str_no_yes(list_empty(&res
->recovering
)),
99 str_yes_no(res
->migration_pending
));
100 printk(" inflight locks: %d, asts reserved: %d\n",
101 res
->inflight_locks
, atomic_read(&res
->asts_reserved
));
102 dlm_print_lockres_refmap(res
);
103 printk(" granted queue:\n");
104 list_for_each_entry(lock
, &res
->granted
, list
) {
105 __dlm_print_lock(lock
);
107 printk(" converting queue:\n");
108 list_for_each_entry(lock
, &res
->converting
, list
) {
109 __dlm_print_lock(lock
);
111 printk(" blocked queue:\n");
112 list_for_each_entry(lock
, &res
->blocked
, list
) {
113 __dlm_print_lock(lock
);
117 void dlm_print_one_lock(struct dlm_lock
*lockid
)
119 dlm_print_one_lock_resource(lockid
->lockres
);
121 EXPORT_SYMBOL_GPL(dlm_print_one_lock
);
123 static const char *dlm_errnames
[] = {
124 [DLM_NORMAL
] = "DLM_NORMAL",
125 [DLM_GRANTED
] = "DLM_GRANTED",
126 [DLM_DENIED
] = "DLM_DENIED",
127 [DLM_DENIED_NOLOCKS
] = "DLM_DENIED_NOLOCKS",
128 [DLM_WORKING
] = "DLM_WORKING",
129 [DLM_BLOCKED
] = "DLM_BLOCKED",
130 [DLM_BLOCKED_ORPHAN
] = "DLM_BLOCKED_ORPHAN",
131 [DLM_DENIED_GRACE_PERIOD
] = "DLM_DENIED_GRACE_PERIOD",
132 [DLM_SYSERR
] = "DLM_SYSERR",
133 [DLM_NOSUPPORT
] = "DLM_NOSUPPORT",
134 [DLM_CANCELGRANT
] = "DLM_CANCELGRANT",
135 [DLM_IVLOCKID
] = "DLM_IVLOCKID",
136 [DLM_SYNC
] = "DLM_SYNC",
137 [DLM_BADTYPE
] = "DLM_BADTYPE",
138 [DLM_BADRESOURCE
] = "DLM_BADRESOURCE",
139 [DLM_MAXHANDLES
] = "DLM_MAXHANDLES",
140 [DLM_NOCLINFO
] = "DLM_NOCLINFO",
141 [DLM_NOLOCKMGR
] = "DLM_NOLOCKMGR",
142 [DLM_NOPURGED
] = "DLM_NOPURGED",
143 [DLM_BADARGS
] = "DLM_BADARGS",
144 [DLM_VOID
] = "DLM_VOID",
145 [DLM_NOTQUEUED
] = "DLM_NOTQUEUED",
146 [DLM_IVBUFLEN
] = "DLM_IVBUFLEN",
147 [DLM_CVTUNGRANT
] = "DLM_CVTUNGRANT",
148 [DLM_BADPARAM
] = "DLM_BADPARAM",
149 [DLM_VALNOTVALID
] = "DLM_VALNOTVALID",
150 [DLM_REJECTED
] = "DLM_REJECTED",
151 [DLM_ABORT
] = "DLM_ABORT",
152 [DLM_CANCEL
] = "DLM_CANCEL",
153 [DLM_IVRESHANDLE
] = "DLM_IVRESHANDLE",
154 [DLM_DEADLOCK
] = "DLM_DEADLOCK",
155 [DLM_DENIED_NOASTS
] = "DLM_DENIED_NOASTS",
156 [DLM_FORWARD
] = "DLM_FORWARD",
157 [DLM_TIMEOUT
] = "DLM_TIMEOUT",
158 [DLM_IVGROUPID
] = "DLM_IVGROUPID",
159 [DLM_VERS_CONFLICT
] = "DLM_VERS_CONFLICT",
160 [DLM_BAD_DEVICE_PATH
] = "DLM_BAD_DEVICE_PATH",
161 [DLM_NO_DEVICE_PERMISSION
] = "DLM_NO_DEVICE_PERMISSION",
162 [DLM_NO_CONTROL_DEVICE
] = "DLM_NO_CONTROL_DEVICE ",
163 [DLM_RECOVERING
] = "DLM_RECOVERING",
164 [DLM_MIGRATING
] = "DLM_MIGRATING",
165 [DLM_MAXSTATS
] = "DLM_MAXSTATS",
168 const char *dlm_errname(enum dlm_status err
)
170 if (err
>= DLM_MAXSTATS
|| err
< 0)
171 return dlm_errnames
[DLM_MAXSTATS
];
172 return dlm_errnames
[err
];
174 EXPORT_SYMBOL_GPL(dlm_errname
);
176 /* NOTE: This function converts a lockname into a string. It uses knowledge
177 * of the format of the lockname that should be outside the purview of the dlm.
178 * We are adding only to make dlm debugging slightly easier.
180 * For more on lockname formats, please refer to dlmglue.c and ocfs2_lockid.h.
182 static int stringify_lockname(const char *lockname
, int locklen
, char *buf
,
186 __be64 inode_blkno_be
;
188 #define OCFS2_DENTRY_LOCK_INO_START 18
189 if (*lockname
== 'N') {
190 memcpy((__be64
*)&inode_blkno_be
,
191 (char *)&lockname
[OCFS2_DENTRY_LOCK_INO_START
],
193 out
+= scnprintf(buf
+ out
, len
- out
, "%.*s%08x",
194 OCFS2_DENTRY_LOCK_INO_START
- 1, lockname
,
195 (unsigned int)be64_to_cpu(inode_blkno_be
));
197 out
+= scnprintf(buf
+ out
, len
- out
, "%.*s",
202 static int stringify_nodemap(unsigned long *nodemap
, int maxnodes
,
208 while ((i
= find_next_bit(nodemap
, maxnodes
, i
+ 1)) < maxnodes
)
209 out
+= scnprintf(buf
+ out
, len
- out
, "%d ", i
);
214 static int dump_mle(struct dlm_master_list_entry
*mle
, char *buf
, int len
)
219 if (mle
->type
== DLM_MLE_BLOCK
)
221 else if (mle
->type
== DLM_MLE_MASTER
)
226 out
+= stringify_lockname(mle
->mname
, mle
->mnamelen
, buf
+ out
, len
- out
);
227 out
+= scnprintf(buf
+ out
, len
- out
,
228 "\t%3s\tmas=%3u\tnew=%3u\tevt=%1d\tuse=%1d\tref=%3d\n",
229 mle_type
, mle
->master
, mle
->new_master
,
230 !list_empty(&mle
->hb_events
),
232 kref_read(&mle
->mle_refs
));
234 out
+= scnprintf(buf
+ out
, len
- out
, "Maybe=");
235 out
+= stringify_nodemap(mle
->maybe_map
, O2NM_MAX_NODES
,
236 buf
+ out
, len
- out
);
237 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
239 out
+= scnprintf(buf
+ out
, len
- out
, "Vote=");
240 out
+= stringify_nodemap(mle
->vote_map
, O2NM_MAX_NODES
,
241 buf
+ out
, len
- out
);
242 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
244 out
+= scnprintf(buf
+ out
, len
- out
, "Response=");
245 out
+= stringify_nodemap(mle
->response_map
, O2NM_MAX_NODES
,
246 buf
+ out
, len
- out
);
247 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
249 out
+= scnprintf(buf
+ out
, len
- out
, "Node=");
250 out
+= stringify_nodemap(mle
->node_map
, O2NM_MAX_NODES
,
251 buf
+ out
, len
- out
);
252 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
254 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
259 void dlm_print_one_mle(struct dlm_master_list_entry
*mle
)
263 buf
= (char *) get_zeroed_page(GFP_ATOMIC
);
265 dump_mle(mle
, buf
, PAGE_SIZE
- 1);
266 free_page((unsigned long)buf
);
270 #ifdef CONFIG_DEBUG_FS
272 static struct dentry
*dlm_debugfs_root
;
274 #define DLM_DEBUGFS_DIR "o2dlm"
275 #define DLM_DEBUGFS_DLM_STATE "dlm_state"
276 #define DLM_DEBUGFS_LOCKING_STATE "locking_state"
277 #define DLM_DEBUGFS_MLE_STATE "mle_state"
278 #define DLM_DEBUGFS_PURGE_LIST "purge_list"
280 /* begin - utils funcs */
281 static int debug_release(struct inode
*inode
, struct file
*file
)
283 free_page((unsigned long)file
->private_data
);
287 static ssize_t
debug_read(struct file
*file
, char __user
*buf
,
288 size_t nbytes
, loff_t
*ppos
)
290 return simple_read_from_buffer(buf
, nbytes
, ppos
, file
->private_data
,
291 i_size_read(file
->f_mapping
->host
));
293 /* end - util funcs */
295 /* begin - purge list funcs */
296 static int debug_purgelist_print(struct dlm_ctxt
*dlm
, char *buf
, int len
)
298 struct dlm_lock_resource
*res
;
300 unsigned long total
= 0;
302 out
+= scnprintf(buf
+ out
, len
- out
,
303 "Dumping Purgelist for Domain: %s\n", dlm
->name
);
305 spin_lock(&dlm
->spinlock
);
306 list_for_each_entry(res
, &dlm
->purge_list
, purge
) {
310 spin_lock(&res
->spinlock
);
311 out
+= stringify_lockname(res
->lockname
.name
,
313 buf
+ out
, len
- out
);
314 out
+= scnprintf(buf
+ out
, len
- out
, "\t%ld\n",
315 (jiffies
- res
->last_used
)/HZ
);
316 spin_unlock(&res
->spinlock
);
318 spin_unlock(&dlm
->spinlock
);
320 out
+= scnprintf(buf
+ out
, len
- out
, "Total on list: %lu\n", total
);
325 static int debug_purgelist_open(struct inode
*inode
, struct file
*file
)
327 struct dlm_ctxt
*dlm
= inode
->i_private
;
330 buf
= (char *) get_zeroed_page(GFP_NOFS
);
334 i_size_write(inode
, debug_purgelist_print(dlm
, buf
, PAGE_SIZE
- 1));
336 file
->private_data
= buf
;
343 static const struct file_operations debug_purgelist_fops
= {
344 .open
= debug_purgelist_open
,
345 .release
= debug_release
,
347 .llseek
= generic_file_llseek
,
349 /* end - purge list funcs */
351 /* begin - debug mle funcs */
352 static int debug_mle_print(struct dlm_ctxt
*dlm
, char *buf
, int len
)
354 struct dlm_master_list_entry
*mle
;
355 struct hlist_head
*bucket
;
357 unsigned long total
= 0, longest
= 0, bucket_count
= 0;
359 out
+= scnprintf(buf
+ out
, len
- out
,
360 "Dumping MLEs for Domain: %s\n", dlm
->name
);
362 spin_lock(&dlm
->master_lock
);
363 for (i
= 0; i
< DLM_HASH_BUCKETS
; i
++) {
364 bucket
= dlm_master_hash(dlm
, i
);
365 hlist_for_each_entry(mle
, bucket
, master_hash_node
) {
370 out
+= dump_mle(mle
, buf
+ out
, len
- out
);
372 longest
= max(longest
, bucket_count
);
375 spin_unlock(&dlm
->master_lock
);
377 out
+= scnprintf(buf
+ out
, len
- out
,
378 "Total: %lu, Longest: %lu\n", total
, longest
);
382 static int debug_mle_open(struct inode
*inode
, struct file
*file
)
384 struct dlm_ctxt
*dlm
= inode
->i_private
;
387 buf
= (char *) get_zeroed_page(GFP_NOFS
);
391 i_size_write(inode
, debug_mle_print(dlm
, buf
, PAGE_SIZE
- 1));
393 file
->private_data
= buf
;
400 static const struct file_operations debug_mle_fops
= {
401 .open
= debug_mle_open
,
402 .release
= debug_release
,
404 .llseek
= generic_file_llseek
,
407 /* end - debug mle funcs */
409 /* begin - debug lockres funcs */
410 static int dump_lock(struct dlm_lock
*lock
, int list_type
, char *buf
, int len
)
414 #define DEBUG_LOCK_VERSION 1
415 spin_lock(&lock
->spinlock
);
416 out
= scnprintf(buf
, len
, "LOCK:%d,%d,%d,%d,%d,%d:%lld,%d,%d,%d,%d,%d,"
419 list_type
, lock
->ml
.type
, lock
->ml
.convert_type
,
421 dlm_get_lock_cookie_node(be64_to_cpu(lock
->ml
.cookie
)),
422 dlm_get_lock_cookie_seq(be64_to_cpu(lock
->ml
.cookie
)),
423 !list_empty(&lock
->ast_list
),
424 !list_empty(&lock
->bast_list
),
425 lock
->ast_pending
, lock
->bast_pending
,
426 lock
->convert_pending
, lock
->lock_pending
,
427 lock
->cancel_pending
, lock
->unlock_pending
,
428 kref_read(&lock
->lock_refs
));
429 spin_unlock(&lock
->spinlock
);
434 static int dump_lockres(struct dlm_lock_resource
*res
, char *buf
, int len
)
436 struct dlm_lock
*lock
;
440 out
+= scnprintf(buf
+ out
, len
- out
, "NAME:");
441 out
+= stringify_lockname(res
->lockname
.name
, res
->lockname
.len
,
442 buf
+ out
, len
- out
);
443 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
445 #define DEBUG_LRES_VERSION 1
446 out
+= scnprintf(buf
+ out
, len
- out
,
447 "LRES:%d,%d,%d,%ld,%d,%d,%d,%d,%d,%d,%d\n",
449 res
->owner
, res
->state
, res
->last_used
,
450 !list_empty(&res
->purge
),
451 !list_empty(&res
->dirty
),
452 !list_empty(&res
->recovering
),
453 res
->inflight_locks
, res
->migration_pending
,
454 atomic_read(&res
->asts_reserved
),
455 kref_read(&res
->refs
));
458 out
+= scnprintf(buf
+ out
, len
- out
, "RMAP:");
459 out
+= stringify_nodemap(res
->refmap
, O2NM_MAX_NODES
,
460 buf
+ out
, len
- out
);
461 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
464 out
+= scnprintf(buf
+ out
, len
- out
, "LVBX:");
465 for (i
= 0; i
< DLM_LVB_LEN
; i
++)
466 out
+= scnprintf(buf
+ out
, len
- out
,
467 "%02x", (unsigned char)res
->lvb
[i
]);
468 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
471 list_for_each_entry(lock
, &res
->granted
, list
)
472 out
+= dump_lock(lock
, 0, buf
+ out
, len
- out
);
475 list_for_each_entry(lock
, &res
->converting
, list
)
476 out
+= dump_lock(lock
, 1, buf
+ out
, len
- out
);
479 list_for_each_entry(lock
, &res
->blocked
, list
)
480 out
+= dump_lock(lock
, 2, buf
+ out
, len
- out
);
482 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
487 static void *lockres_seq_start(struct seq_file
*m
, loff_t
*pos
)
489 struct debug_lockres
*dl
= m
->private;
490 struct dlm_ctxt
*dlm
= dl
->dl_ctxt
;
491 struct dlm_lock_resource
*oldres
= dl
->dl_res
;
492 struct dlm_lock_resource
*res
= NULL
, *iter
;
493 struct list_head
*track_list
;
495 spin_lock(&dlm
->track_lock
);
497 track_list
= &oldres
->tracking
;
499 track_list
= &dlm
->tracking_list
;
500 if (list_empty(track_list
)) {
502 spin_unlock(&dlm
->track_lock
);
507 list_for_each_entry(iter
, track_list
, tracking
) {
508 if (&iter
->tracking
!= &dlm
->tracking_list
) {
509 dlm_lockres_get(iter
);
514 spin_unlock(&dlm
->track_lock
);
517 dlm_lockres_put(oldres
);
522 spin_lock(&res
->spinlock
);
523 dump_lockres(res
, dl
->dl_buf
, dl
->dl_len
- 1);
524 spin_unlock(&res
->spinlock
);
529 /* passed to seq_show */
533 static void lockres_seq_stop(struct seq_file
*m
, void *v
)
537 static void *lockres_seq_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
542 static int lockres_seq_show(struct seq_file
*s
, void *v
)
544 struct debug_lockres
*dl
= (struct debug_lockres
*)v
;
546 seq_printf(s
, "%s", dl
->dl_buf
);
551 static const struct seq_operations debug_lockres_ops
= {
552 .start
= lockres_seq_start
,
553 .stop
= lockres_seq_stop
,
554 .next
= lockres_seq_next
,
555 .show
= lockres_seq_show
,
558 static int debug_lockres_open(struct inode
*inode
, struct file
*file
)
560 struct dlm_ctxt
*dlm
= inode
->i_private
;
561 struct debug_lockres
*dl
;
564 buf
= kmalloc(PAGE_SIZE
, GFP_KERNEL
);
568 dl
= __seq_open_private(file
, &debug_lockres_ops
, sizeof(*dl
));
572 dl
->dl_len
= PAGE_SIZE
;
587 static int debug_lockres_release(struct inode
*inode
, struct file
*file
)
589 struct seq_file
*seq
= file
->private_data
;
590 struct debug_lockres
*dl
= (struct debug_lockres
*)seq
->private;
593 dlm_lockres_put(dl
->dl_res
);
594 dlm_put(dl
->dl_ctxt
);
596 return seq_release_private(inode
, file
);
599 static const struct file_operations debug_lockres_fops
= {
600 .open
= debug_lockres_open
,
601 .release
= debug_lockres_release
,
605 /* end - debug lockres funcs */
607 /* begin - debug state funcs */
608 static int debug_state_print(struct dlm_ctxt
*dlm
, char *buf
, int len
)
611 struct dlm_reco_node_data
*node
;
613 int cur_mles
= 0, tot_mles
= 0;
616 spin_lock(&dlm
->spinlock
);
618 switch (dlm
->dlm_state
) {
620 state
= "NEW"; break;
621 case DLM_CTXT_JOINED
:
622 state
= "JOINED"; break;
623 case DLM_CTXT_IN_SHUTDOWN
:
624 state
= "SHUTDOWN"; break;
625 case DLM_CTXT_LEAVING
:
626 state
= "LEAVING"; break;
628 state
= "UNKNOWN"; break;
631 /* Domain: xxxxxxxxxx Key: 0xdfbac769 */
632 out
+= scnprintf(buf
+ out
, len
- out
,
633 "Domain: %s Key: 0x%08x Protocol: %d.%d\n",
634 dlm
->name
, dlm
->key
, dlm
->dlm_locking_proto
.pv_major
,
635 dlm
->dlm_locking_proto
.pv_minor
);
637 /* Thread Pid: xxx Node: xxx State: xxxxx */
638 out
+= scnprintf(buf
+ out
, len
- out
,
639 "Thread Pid: %d Node: %d State: %s\n",
640 task_pid_nr(dlm
->dlm_thread_task
), dlm
->node_num
, state
);
642 /* Number of Joins: xxx Joining Node: xxx */
643 out
+= scnprintf(buf
+ out
, len
- out
,
644 "Number of Joins: %d Joining Node: %d\n",
645 dlm
->num_joins
, dlm
->joining_node
);
647 /* Domain Map: xx xx xx */
648 out
+= scnprintf(buf
+ out
, len
- out
, "Domain Map: ");
649 out
+= stringify_nodemap(dlm
->domain_map
, O2NM_MAX_NODES
,
650 buf
+ out
, len
- out
);
651 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
653 /* Exit Domain Map: xx xx xx */
654 out
+= scnprintf(buf
+ out
, len
- out
, "Exit Domain Map: ");
655 out
+= stringify_nodemap(dlm
->exit_domain_map
, O2NM_MAX_NODES
,
656 buf
+ out
, len
- out
);
657 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
659 /* Live Map: xx xx xx */
660 out
+= scnprintf(buf
+ out
, len
- out
, "Live Map: ");
661 out
+= stringify_nodemap(dlm
->live_nodes_map
, O2NM_MAX_NODES
,
662 buf
+ out
, len
- out
);
663 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
665 /* Lock Resources: xxx (xxx) */
666 out
+= scnprintf(buf
+ out
, len
- out
,
667 "Lock Resources: %d (%d)\n",
668 atomic_read(&dlm
->res_cur_count
),
669 atomic_read(&dlm
->res_tot_count
));
671 for (i
= 0; i
< DLM_MLE_NUM_TYPES
; ++i
)
672 tot_mles
+= atomic_read(&dlm
->mle_tot_count
[i
]);
674 for (i
= 0; i
< DLM_MLE_NUM_TYPES
; ++i
)
675 cur_mles
+= atomic_read(&dlm
->mle_cur_count
[i
]);
677 /* MLEs: xxx (xxx) */
678 out
+= scnprintf(buf
+ out
, len
- out
,
679 "MLEs: %d (%d)\n", cur_mles
, tot_mles
);
681 /* Blocking: xxx (xxx) */
682 out
+= scnprintf(buf
+ out
, len
- out
,
683 " Blocking: %d (%d)\n",
684 atomic_read(&dlm
->mle_cur_count
[DLM_MLE_BLOCK
]),
685 atomic_read(&dlm
->mle_tot_count
[DLM_MLE_BLOCK
]));
687 /* Mastery: xxx (xxx) */
688 out
+= scnprintf(buf
+ out
, len
- out
,
689 " Mastery: %d (%d)\n",
690 atomic_read(&dlm
->mle_cur_count
[DLM_MLE_MASTER
]),
691 atomic_read(&dlm
->mle_tot_count
[DLM_MLE_MASTER
]));
693 /* Migration: xxx (xxx) */
694 out
+= scnprintf(buf
+ out
, len
- out
,
695 " Migration: %d (%d)\n",
696 atomic_read(&dlm
->mle_cur_count
[DLM_MLE_MIGRATION
]),
697 atomic_read(&dlm
->mle_tot_count
[DLM_MLE_MIGRATION
]));
699 /* Lists: Dirty=Empty Purge=InUse PendingASTs=Empty ... */
700 out
+= scnprintf(buf
+ out
, len
- out
,
701 "Lists: Dirty=%s Purge=%s PendingASTs=%s "
703 (list_empty(&dlm
->dirty_list
) ? "Empty" : "InUse"),
704 (list_empty(&dlm
->purge_list
) ? "Empty" : "InUse"),
705 (list_empty(&dlm
->pending_asts
) ? "Empty" : "InUse"),
706 (list_empty(&dlm
->pending_basts
) ? "Empty" : "InUse"));
708 /* Purge Count: xxx Refs: xxx */
709 out
+= scnprintf(buf
+ out
, len
- out
,
710 "Purge Count: %d Refs: %d\n", dlm
->purge_count
,
711 kref_read(&dlm
->dlm_refs
));
714 out
+= scnprintf(buf
+ out
, len
- out
,
715 "Dead Node: %d\n", dlm
->reco
.dead_node
);
717 /* What about DLM_RECO_STATE_FINALIZE? */
718 if (dlm
->reco
.state
== DLM_RECO_STATE_ACTIVE
)
723 /* Recovery Pid: xxxx Master: xxx State: xxxx */
724 out
+= scnprintf(buf
+ out
, len
- out
,
725 "Recovery Pid: %d Master: %d State: %s\n",
726 task_pid_nr(dlm
->dlm_reco_thread_task
),
727 dlm
->reco
.new_master
, state
);
729 /* Recovery Map: xx xx */
730 out
+= scnprintf(buf
+ out
, len
- out
, "Recovery Map: ");
731 out
+= stringify_nodemap(dlm
->recovery_map
, O2NM_MAX_NODES
,
732 buf
+ out
, len
- out
);
733 out
+= scnprintf(buf
+ out
, len
- out
, "\n");
735 /* Recovery Node State: */
736 out
+= scnprintf(buf
+ out
, len
- out
, "Recovery Node State:\n");
737 list_for_each_entry(node
, &dlm
->reco
.node_data
, list
) {
738 switch (node
->state
) {
739 case DLM_RECO_NODE_DATA_INIT
:
742 case DLM_RECO_NODE_DATA_REQUESTING
:
743 state
= "REQUESTING";
745 case DLM_RECO_NODE_DATA_DEAD
:
748 case DLM_RECO_NODE_DATA_RECEIVING
:
751 case DLM_RECO_NODE_DATA_REQUESTED
:
754 case DLM_RECO_NODE_DATA_DONE
:
757 case DLM_RECO_NODE_DATA_FINALIZE_SENT
:
758 state
= "FINALIZE-SENT";
764 out
+= scnprintf(buf
+ out
, len
- out
, "\t%u - %s\n",
765 node
->node_num
, state
);
768 spin_unlock(&dlm
->spinlock
);
773 static int debug_state_open(struct inode
*inode
, struct file
*file
)
775 struct dlm_ctxt
*dlm
= inode
->i_private
;
778 buf
= (char *) get_zeroed_page(GFP_NOFS
);
782 i_size_write(inode
, debug_state_print(dlm
, buf
, PAGE_SIZE
- 1));
784 file
->private_data
= buf
;
791 static const struct file_operations debug_state_fops
= {
792 .open
= debug_state_open
,
793 .release
= debug_release
,
795 .llseek
= generic_file_llseek
,
797 /* end - debug state funcs */
799 /* files in subroot */
800 void dlm_debug_init(struct dlm_ctxt
*dlm
)
802 /* for dumping dlm_ctxt */
803 debugfs_create_file(DLM_DEBUGFS_DLM_STATE
, S_IFREG
|S_IRUSR
,
804 dlm
->dlm_debugfs_subroot
, dlm
, &debug_state_fops
);
806 /* for dumping lockres */
807 debugfs_create_file(DLM_DEBUGFS_LOCKING_STATE
, S_IFREG
|S_IRUSR
,
808 dlm
->dlm_debugfs_subroot
, dlm
, &debug_lockres_fops
);
810 /* for dumping mles */
811 debugfs_create_file(DLM_DEBUGFS_MLE_STATE
, S_IFREG
|S_IRUSR
,
812 dlm
->dlm_debugfs_subroot
, dlm
, &debug_mle_fops
);
814 /* for dumping lockres on the purge list */
815 debugfs_create_file(DLM_DEBUGFS_PURGE_LIST
, S_IFREG
|S_IRUSR
,
816 dlm
->dlm_debugfs_subroot
, dlm
,
817 &debug_purgelist_fops
);
820 /* subroot - domain dir */
821 void dlm_create_debugfs_subroot(struct dlm_ctxt
*dlm
)
823 dlm
->dlm_debugfs_subroot
= debugfs_create_dir(dlm
->name
,
827 void dlm_destroy_debugfs_subroot(struct dlm_ctxt
*dlm
)
829 debugfs_remove_recursive(dlm
->dlm_debugfs_subroot
);
833 void dlm_create_debugfs_root(void)
835 dlm_debugfs_root
= debugfs_create_dir(DLM_DEBUGFS_DIR
, NULL
);
838 void dlm_destroy_debugfs_root(void)
840 debugfs_remove(dlm_debugfs_root
);
842 #endif /* CONFIG_DEBUG_FS */