diff options
Diffstat (limited to 'fs/dlm/debug_fs.c')
-rw-r--r-- | fs/dlm/debug_fs.c | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c new file mode 100644 index 000000000000..49deca845dba --- /dev/null +++ b/fs/dlm/debug_fs.c | |||
@@ -0,0 +1,296 @@ | |||
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 | |||
22 | static struct dentry *dlm_root; | ||
23 | |||
24 | struct rsb_iter { | ||
25 | int entry; | ||
26 | struct dlm_ls *ls; | ||
27 | struct list_head *next; | ||
28 | struct dlm_rsb *rsb; | ||
29 | }; | ||
30 | |||
31 | static 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 | |||
53 | static 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_nodeid) { | ||
63 | if (lkb->lkb_nodeid != res->res_nodeid) | ||
64 | seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid, | ||
65 | lkb->lkb_remid); | ||
66 | else | ||
67 | seq_printf(s, " Master: %08x", lkb->lkb_remid); | ||
68 | } | ||
69 | |||
70 | if (lkb->lkb_wait_type) | ||
71 | seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); | ||
72 | |||
73 | seq_printf(s, "\n"); | ||
74 | } | ||
75 | |||
76 | static int print_resource(struct dlm_rsb *res, struct seq_file *s) | ||
77 | { | ||
78 | struct dlm_lkb *lkb; | ||
79 | int i, lvblen = res->res_ls->ls_lvblen; | ||
80 | |||
81 | seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); | ||
82 | for (i = 0; i < res->res_length; i++) { | ||
83 | if (isprint(res->res_name[i])) | ||
84 | seq_printf(s, "%c", res->res_name[i]); | ||
85 | else | ||
86 | seq_printf(s, "%c", '.'); | ||
87 | } | ||
88 | if (res->res_nodeid > 0) | ||
89 | seq_printf(s, "\" \nLocal Copy, Master is node %d\n", | ||
90 | res->res_nodeid); | ||
91 | else if (res->res_nodeid == 0) | ||
92 | seq_printf(s, "\" \nMaster Copy\n"); | ||
93 | else if (res->res_nodeid == -1) | ||
94 | seq_printf(s, "\" \nLooking up master (lkid %x)\n", | ||
95 | res->res_first_lkid); | ||
96 | else | ||
97 | seq_printf(s, "\" \nInvalid master %d\n", res->res_nodeid); | ||
98 | |||
99 | /* Print the LVB: */ | ||
100 | if (res->res_lvbptr) { | ||
101 | seq_printf(s, "LVB: "); | ||
102 | for (i = 0; i < lvblen; i++) { | ||
103 | if (i == lvblen / 2) | ||
104 | seq_printf(s, "\n "); | ||
105 | seq_printf(s, "%02x ", | ||
106 | (unsigned char) res->res_lvbptr[i]); | ||
107 | } | ||
108 | if (rsb_flag(res, RSB_VALNOTVALID)) | ||
109 | seq_printf(s, " (INVALID)"); | ||
110 | seq_printf(s, "\n"); | ||
111 | } | ||
112 | |||
113 | /* Print the locks attached to this resource */ | ||
114 | seq_printf(s, "Granted Queue\n"); | ||
115 | list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) | ||
116 | print_lock(s, lkb, res); | ||
117 | |||
118 | seq_printf(s, "Conversion Queue\n"); | ||
119 | list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) | ||
120 | print_lock(s, lkb, res); | ||
121 | |||
122 | seq_printf(s, "Waiting Queue\n"); | ||
123 | list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) | ||
124 | print_lock(s, lkb, res); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int rsb_iter_next(struct rsb_iter *ri) | ||
130 | { | ||
131 | struct dlm_ls *ls = ri->ls; | ||
132 | int i; | ||
133 | |||
134 | if (!ri->next) { | ||
135 | top: | ||
136 | /* Find the next non-empty hash bucket */ | ||
137 | for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) { | ||
138 | read_lock(&ls->ls_rsbtbl[i].lock); | ||
139 | if (!list_empty(&ls->ls_rsbtbl[i].list)) { | ||
140 | ri->next = ls->ls_rsbtbl[i].list.next; | ||
141 | read_unlock(&ls->ls_rsbtbl[i].lock); | ||
142 | break; | ||
143 | } | ||
144 | read_unlock(&ls->ls_rsbtbl[i].lock); | ||
145 | } | ||
146 | ri->entry = i; | ||
147 | |||
148 | if (ri->entry >= ls->ls_rsbtbl_size) | ||
149 | return 1; | ||
150 | } else { | ||
151 | i = ri->entry; | ||
152 | read_lock(&ls->ls_rsbtbl[i].lock); | ||
153 | ri->next = ri->next->next; | ||
154 | if (ri->next->next == ls->ls_rsbtbl[i].list.next) { | ||
155 | /* End of list - move to next bucket */ | ||
156 | ri->next = NULL; | ||
157 | ri->entry++; | ||
158 | read_unlock(&ls->ls_rsbtbl[i].lock); | ||
159 | goto top; | ||
160 | } | ||
161 | read_unlock(&ls->ls_rsbtbl[i].lock); | ||
162 | } | ||
163 | ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static void rsb_iter_free(struct rsb_iter *ri) | ||
169 | { | ||
170 | kfree(ri); | ||
171 | } | ||
172 | |||
173 | static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls) | ||
174 | { | ||
175 | struct rsb_iter *ri; | ||
176 | |||
177 | ri = kmalloc(sizeof *ri, GFP_KERNEL); | ||
178 | if (!ri) | ||
179 | return NULL; | ||
180 | |||
181 | ri->ls = ls; | ||
182 | ri->entry = 0; | ||
183 | ri->next = NULL; | ||
184 | |||
185 | if (rsb_iter_next(ri)) { | ||
186 | rsb_iter_free(ri); | ||
187 | return NULL; | ||
188 | } | ||
189 | |||
190 | return ri; | ||
191 | } | ||
192 | |||
193 | static void *seq_start(struct seq_file *file, loff_t *pos) | ||
194 | { | ||
195 | struct rsb_iter *ri; | ||
196 | loff_t n = *pos; | ||
197 | |||
198 | ri = rsb_iter_init(file->private); | ||
199 | if (!ri) | ||
200 | return NULL; | ||
201 | |||
202 | while (n--) { | ||
203 | if (rsb_iter_next(ri)) { | ||
204 | rsb_iter_free(ri); | ||
205 | return NULL; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | return ri; | ||
210 | } | ||
211 | |||
212 | static void *seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) | ||
213 | { | ||
214 | struct rsb_iter *ri = iter_ptr; | ||
215 | |||
216 | (*pos)++; | ||
217 | |||
218 | if (rsb_iter_next(ri)) { | ||
219 | rsb_iter_free(ri); | ||
220 | return NULL; | ||
221 | } | ||
222 | |||
223 | return ri; | ||
224 | } | ||
225 | |||
226 | static void seq_stop(struct seq_file *file, void *iter_ptr) | ||
227 | { | ||
228 | /* nothing for now */ | ||
229 | } | ||
230 | |||
231 | static int seq_show(struct seq_file *file, void *iter_ptr) | ||
232 | { | ||
233 | struct rsb_iter *ri = iter_ptr; | ||
234 | |||
235 | print_resource(ri->rsb, file); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static struct seq_operations dlm_seq_ops = { | ||
241 | .start = seq_start, | ||
242 | .next = seq_next, | ||
243 | .stop = seq_stop, | ||
244 | .show = seq_show, | ||
245 | }; | ||
246 | |||
247 | static int do_open(struct inode *inode, struct file *file) | ||
248 | { | ||
249 | struct seq_file *seq; | ||
250 | int ret; | ||
251 | |||
252 | ret = seq_open(file, &dlm_seq_ops); | ||
253 | if (ret) | ||
254 | return ret; | ||
255 | |||
256 | seq = file->private_data; | ||
257 | seq->private = inode->u.generic_ip; | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static struct file_operations dlm_fops = { | ||
263 | .owner = THIS_MODULE, | ||
264 | .open = do_open, | ||
265 | .read = seq_read, | ||
266 | .llseek = seq_lseek, | ||
267 | .release = seq_release | ||
268 | }; | ||
269 | |||
270 | int dlm_create_debug_file(struct dlm_ls *ls) | ||
271 | { | ||
272 | ls->ls_debug_dentry = debugfs_create_file(ls->ls_name, | ||
273 | S_IFREG | S_IRUGO, | ||
274 | dlm_root, | ||
275 | ls, | ||
276 | &dlm_fops); | ||
277 | return ls->ls_debug_dentry ? 0 : -ENOMEM; | ||
278 | } | ||
279 | |||
280 | void dlm_delete_debug_file(struct dlm_ls *ls) | ||
281 | { | ||
282 | if (ls->ls_debug_dentry) | ||
283 | debugfs_remove(ls->ls_debug_dentry); | ||
284 | } | ||
285 | |||
286 | int dlm_register_debugfs(void) | ||
287 | { | ||
288 | dlm_root = debugfs_create_dir("dlm", NULL); | ||
289 | return dlm_root ? 0 : -ENOMEM; | ||
290 | } | ||
291 | |||
292 | void dlm_unregister_debugfs(void) | ||
293 | { | ||
294 | debugfs_remove(dlm_root); | ||
295 | } | ||
296 | |||