aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm/debug_fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/dlm/debug_fs.c')
-rw-r--r--fs/dlm/debug_fs.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c
new file mode 100644
index 000000000000..98b49a1ece47
--- /dev/null
+++ b/fs/dlm/debug_fs.c
@@ -0,0 +1,310 @@
1/******************************************************************************
2*******************************************************************************
3**
4** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
5**
6** This copyrighted material is made available to anyone wishing to use,
7** modify, copy, or redistribute it subject to the terms and conditions
8** of the GNU General Public License v.2.
9**
10*******************************************************************************
11******************************************************************************/
12
13#include <linux/pagemap.h>
14#include <linux/seq_file.h>
15#include <linux/module.h>
16#include <linux/ctype.h>
17#include <linux/debugfs.h>
18
19#include "dlm_internal.h"
20
21
22static struct dentry *dlm_root;
23
24struct rsb_iter {
25 int entry;
26 struct dlm_ls *ls;
27 struct list_head *next;
28 struct dlm_rsb *rsb;
29};
30
31static char *print_lockmode(int mode)
32{
33 switch (mode) {
34 case DLM_LOCK_IV:
35 return "--";
36 case DLM_LOCK_NL:
37 return "NL";
38 case DLM_LOCK_CR:
39 return "CR";
40 case DLM_LOCK_CW:
41 return "CW";
42 case DLM_LOCK_PR:
43 return "PR";
44 case DLM_LOCK_PW:
45 return "PW";
46 case DLM_LOCK_EX:
47 return "EX";
48 default:
49 return "??";
50 }
51}
52
53static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
54 struct dlm_rsb *res)
55{
56 seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
57
58 if (lkb->lkb_status == DLM_LKSTS_CONVERT
59 || lkb->lkb_status == DLM_LKSTS_WAITING)
60 seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
61
62 if (lkb->lkb_range) {
63 /* FIXME: this warns on Alpha */
64 if (lkb->lkb_status == DLM_LKSTS_CONVERT
65 || lkb->lkb_status == DLM_LKSTS_GRANTED)
66 seq_printf(s, " %" PRIx64 "-%" PRIx64,
67 lkb->lkb_range[GR_RANGE_START],
68 lkb->lkb_range[GR_RANGE_END]);
69 if (lkb->lkb_status == DLM_LKSTS_CONVERT
70 || lkb->lkb_status == DLM_LKSTS_WAITING)
71 seq_printf(s, " (%" PRIx64 "-%" PRIx64 ")",
72 lkb->lkb_range[RQ_RANGE_START],
73 lkb->lkb_range[RQ_RANGE_END]);
74 }
75
76 if (lkb->lkb_nodeid) {
77 if (lkb->lkb_nodeid != res->res_nodeid)
78 seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
79 lkb->lkb_remid);
80 else
81 seq_printf(s, " Master: %08x", lkb->lkb_remid);
82 }
83
84 if (lkb->lkb_wait_type)
85 seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
86
87 seq_printf(s, "\n");
88}
89
90static int print_resource(struct dlm_rsb *res, struct seq_file *s)
91{
92 struct dlm_lkb *lkb;
93 int i, lvblen = res->res_ls->ls_lvblen;
94
95 seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
96 for (i = 0; i < res->res_length; i++) {
97 if (isprint(res->res_name[i]))
98 seq_printf(s, "%c", res->res_name[i]);
99 else
100 seq_printf(s, "%c", '.');
101 }
102 if (res->res_nodeid > 0)
103 seq_printf(s, "\" \nLocal Copy, Master is node %d\n",
104 res->res_nodeid);
105 else if (res->res_nodeid == 0)
106 seq_printf(s, "\" \nMaster Copy\n");
107 else if (res->res_nodeid == -1)
108 seq_printf(s, "\" \nLooking up master (lkid %x)\n",
109 res->res_first_lkid);
110 else
111 seq_printf(s, "\" \nInvalid master %d\n", res->res_nodeid);
112
113 /* Print the LVB: */
114 if (res->res_lvbptr) {
115 seq_printf(s, "LVB: ");
116 for (i = 0; i < lvblen; i++) {
117 if (i == lvblen / 2)
118 seq_printf(s, "\n ");
119 seq_printf(s, "%02x ",
120 (unsigned char) res->res_lvbptr[i]);
121 }
122 if (rsb_flag(res, RSB_VALNOTVALID))
123 seq_printf(s, " (INVALID)");
124 seq_printf(s, "\n");
125 }
126
127 /* Print the locks attached to this resource */
128 seq_printf(s, "Granted Queue\n");
129 list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue)
130 print_lock(s, lkb, res);
131
132 seq_printf(s, "Conversion Queue\n");
133 list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue)
134 print_lock(s, lkb, res);
135
136 seq_printf(s, "Waiting Queue\n");
137 list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue)
138 print_lock(s, lkb, res);
139
140 return 0;
141}
142
143static int rsb_iter_next(struct rsb_iter *ri)
144{
145 struct dlm_ls *ls = ri->ls;
146 int i;
147
148 if (!ri->next) {
149 top:
150 /* Find the next non-empty hash bucket */
151 for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) {
152 read_lock(&ls->ls_rsbtbl[i].lock);
153 if (!list_empty(&ls->ls_rsbtbl[i].list)) {
154 ri->next = ls->ls_rsbtbl[i].list.next;
155 read_unlock(&ls->ls_rsbtbl[i].lock);
156 break;
157 }
158 read_unlock(&ls->ls_rsbtbl[i].lock);
159 }
160 ri->entry = i;
161
162 if (ri->entry >= ls->ls_rsbtbl_size)
163 return 1;
164 } else {
165 i = ri->entry;
166 read_lock(&ls->ls_rsbtbl[i].lock);
167 ri->next = ri->next->next;
168 if (ri->next->next == ls->ls_rsbtbl[i].list.next) {
169 /* End of list - move to next bucket */
170 ri->next = NULL;
171 ri->entry++;
172 read_unlock(&ls->ls_rsbtbl[i].lock);
173 goto top;
174 }
175 read_unlock(&ls->ls_rsbtbl[i].lock);
176 }
177 ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain);
178
179 return 0;
180}
181
182static void rsb_iter_free(struct rsb_iter *ri)
183{
184 kfree(ri);
185}
186
187static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls)
188{
189 struct rsb_iter *ri;
190
191 ri = kmalloc(sizeof *ri, GFP_KERNEL);
192 if (!ri)
193 return NULL;
194
195 ri->ls = ls;
196 ri->entry = 0;
197 ri->next = NULL;
198
199 if (rsb_iter_next(ri)) {
200 rsb_iter_free(ri);
201 return NULL;
202 }
203
204 return ri;
205}
206
207static void *seq_start(struct seq_file *file, loff_t *pos)
208{
209 struct rsb_iter *ri;
210 loff_t n = *pos;
211
212 ri = rsb_iter_init(file->private);
213 if (!ri)
214 return NULL;
215
216 while (n--) {
217 if (rsb_iter_next(ri)) {
218 rsb_iter_free(ri);
219 return NULL;
220 }
221 }
222
223 return ri;
224}
225
226static void *seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos)
227{
228 struct rsb_iter *ri = iter_ptr;
229
230 (*pos)++;
231
232 if (rsb_iter_next(ri)) {
233 rsb_iter_free(ri);
234 return NULL;
235 }
236
237 return ri;
238}
239
240static void seq_stop(struct seq_file *file, void *iter_ptr)
241{
242 /* nothing for now */
243}
244
245static int seq_show(struct seq_file *file, void *iter_ptr)
246{
247 struct rsb_iter *ri = iter_ptr;
248
249 print_resource(ri->rsb, file);
250
251 return 0;
252}
253
254static struct seq_operations dlm_seq_ops = {
255 .start = seq_start,
256 .next = seq_next,
257 .stop = seq_stop,
258 .show = seq_show,
259};
260
261static int do_open(struct inode *inode, struct file *file)
262{
263 struct seq_file *seq;
264 int ret;
265
266 ret = seq_open(file, &dlm_seq_ops);
267 if (ret)
268 return ret;
269
270 seq = file->private_data;
271 seq->private = inode->u.generic_ip;
272
273 return 0;
274}
275
276static struct file_operations dlm_fops = {
277 .owner = THIS_MODULE,
278 .open = do_open,
279 .read = seq_read,
280 .llseek = seq_lseek,
281 .release = seq_release
282};
283
284int dlm_create_debug_file(struct dlm_ls *ls)
285{
286 ls->ls_debug_dentry = debugfs_create_file(ls->ls_name,
287 S_IFREG | S_IRUGO,
288 dlm_root,
289 ls,
290 &dlm_fops);
291 return ls->ls_debug_dentry ? 0 : -ENOMEM;
292}
293
294void dlm_delete_debug_file(struct dlm_ls *ls)
295{
296 if (ls->ls_debug_dentry)
297 debugfs_remove(ls->ls_debug_dentry);
298}
299
300int dlm_register_debugfs(void)
301{
302 dlm_root = debugfs_create_dir("dlm", NULL);
303 return dlm_root ? 0 : -ENOMEM;
304}
305
306void dlm_unregister_debugfs(void)
307{
308 debugfs_remove(dlm_root);
309}
310