]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: David Teigland <teigland@redhat.com> |
2 | commit d022509d1c54be4918e7fc8f1195ee8c392e9a57 | |
3 | Author: David Teigland <teigland@redhat.com> | |
4 | Date: Tue Dec 16 14:53:23 2008 -0600 | |
5 | Subject: dlm: add new debugfs entry | |
6 | ||
7 | The new debugfs entry dumps all rsb and lkb structures, and includes | |
8 | a lot more information than has been available before. This includes | |
9 | the new timestamps added by a previous patch for debugging callback | |
10 | issues. | |
11 | ||
12 | Signed-off-by: David Teigland <teigland@redhat.com> | |
13 | Signed-off-by: Coly Li <coly.li@suse.de> | |
14 | ||
15 | --- | |
16 | fs/dlm/debug_fs.c | 296 +++++++++++++++++++++++++++++++++++++++++--------- | |
17 | fs/dlm/dlm_internal.h | 1 | |
18 | 2 files changed, 247 insertions(+), 50 deletions(-) | |
19 | ||
20 | --- a/fs/dlm/debug_fs.c | |
21 | +++ b/fs/dlm/debug_fs.c | |
22 | @@ -1,7 +1,7 @@ | |
23 | /****************************************************************************** | |
24 | ******************************************************************************* | |
25 | ** | |
26 | -** Copyright (C) 2005 Red Hat, Inc. All rights reserved. | |
27 | +** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. | |
28 | ** | |
29 | ** This copyrighted material is made available to anyone wishing to use, | |
30 | ** modify, copy, or redistribute it subject to the terms and conditions | |
31 | @@ -27,7 +27,7 @@ static struct dentry *dlm_root; | |
32 | ||
33 | struct rsb_iter { | |
34 | int entry; | |
35 | - int locks; | |
36 | + int format; | |
37 | int header; | |
38 | struct dlm_ls *ls; | |
39 | struct list_head *next; | |
40 | @@ -60,8 +60,8 @@ static char *print_lockmode(int mode) | |
41 | } | |
42 | } | |
43 | ||
44 | -static void print_resource_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
45 | - struct dlm_rsb *res) | |
46 | +static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
47 | + struct dlm_rsb *res) | |
48 | { | |
49 | seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); | |
50 | ||
51 | @@ -83,7 +83,7 @@ static void print_resource_lock(struct s | |
52 | seq_printf(s, "\n"); | |
53 | } | |
54 | ||
55 | -static int print_resource(struct dlm_rsb *res, struct seq_file *s) | |
56 | +static int print_format1(struct dlm_rsb *res, struct seq_file *s) | |
57 | { | |
58 | struct dlm_lkb *lkb; | |
59 | int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; | |
60 | @@ -134,15 +134,15 @@ static int print_resource(struct dlm_rsb | |
61 | /* Print the locks attached to this resource */ | |
62 | seq_printf(s, "Granted Queue\n"); | |
63 | list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) | |
64 | - print_resource_lock(s, lkb, res); | |
65 | + print_format1_lock(s, lkb, res); | |
66 | ||
67 | seq_printf(s, "Conversion Queue\n"); | |
68 | list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) | |
69 | - print_resource_lock(s, lkb, res); | |
70 | + print_format1_lock(s, lkb, res); | |
71 | ||
72 | seq_printf(s, "Waiting Queue\n"); | |
73 | list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) | |
74 | - print_resource_lock(s, lkb, res); | |
75 | + print_format1_lock(s, lkb, res); | |
76 | ||
77 | if (list_empty(&res->res_lookup)) | |
78 | goto out; | |
79 | @@ -160,7 +160,8 @@ static int print_resource(struct dlm_rsb | |
80 | return 0; | |
81 | } | |
82 | ||
83 | -static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, struct dlm_rsb *r) | |
84 | +static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
85 | + struct dlm_rsb *r) | |
86 | { | |
87 | u64 xid = 0; | |
88 | u64 us; | |
89 | @@ -193,20 +194,108 @@ static void print_lock(struct seq_file * | |
90 | r->res_name); | |
91 | } | |
92 | ||
93 | -static int print_locks(struct dlm_rsb *r, struct seq_file *s) | |
94 | +static int print_format2(struct dlm_rsb *r, struct seq_file *s) | |
95 | { | |
96 | struct dlm_lkb *lkb; | |
97 | ||
98 | lock_rsb(r); | |
99 | ||
100 | list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) | |
101 | - print_lock(s, lkb, r); | |
102 | + print_format2_lock(s, lkb, r); | |
103 | ||
104 | list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) | |
105 | - print_lock(s, lkb, r); | |
106 | + print_format2_lock(s, lkb, r); | |
107 | ||
108 | list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) | |
109 | - print_lock(s, lkb, r); | |
110 | + print_format2_lock(s, lkb, r); | |
111 | + | |
112 | + unlock_rsb(r); | |
113 | + return 0; | |
114 | +} | |
115 | + | |
116 | +static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
117 | + int rsb_lookup) | |
118 | +{ | |
119 | + u64 xid = 0; | |
120 | + | |
121 | + if (lkb->lkb_flags & DLM_IFL_USER) { | |
122 | + if (lkb->lkb_ua) | |
123 | + xid = lkb->lkb_ua->xid; | |
124 | + } | |
125 | + | |
126 | + seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n", | |
127 | + lkb->lkb_id, | |
128 | + lkb->lkb_nodeid, | |
129 | + lkb->lkb_remid, | |
130 | + lkb->lkb_ownpid, | |
131 | + (unsigned long long)xid, | |
132 | + lkb->lkb_exflags, | |
133 | + lkb->lkb_flags, | |
134 | + lkb->lkb_status, | |
135 | + lkb->lkb_grmode, | |
136 | + lkb->lkb_rqmode, | |
137 | + lkb->lkb_highbast, | |
138 | + rsb_lookup, | |
139 | + lkb->lkb_wait_type, | |
140 | + lkb->lkb_lvbseq, | |
141 | + (unsigned long long)ktime_to_ns(lkb->lkb_timestamp), | |
142 | + (unsigned long long)ktime_to_ns(lkb->lkb_time_bast)); | |
143 | +} | |
144 | + | |
145 | +static int print_format3(struct dlm_rsb *r, struct seq_file *s) | |
146 | +{ | |
147 | + struct dlm_lkb *lkb; | |
148 | + int i, lvblen = r->res_ls->ls_lvblen; | |
149 | + int print_name = 1; | |
150 | + | |
151 | + lock_rsb(r); | |
152 | + | |
153 | + seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ", | |
154 | + r, | |
155 | + r->res_nodeid, | |
156 | + r->res_first_lkid, | |
157 | + r->res_flags, | |
158 | + !list_empty(&r->res_root_list), | |
159 | + !list_empty(&r->res_recover_list), | |
160 | + r->res_recover_locks_count, | |
161 | + r->res_length); | |
162 | + | |
163 | + for (i = 0; i < r->res_length; i++) { | |
164 | + if (!isascii(r->res_name[i]) || !isprint(r->res_name[i])) | |
165 | + print_name = 0; | |
166 | + } | |
167 | + | |
168 | + seq_printf(s, "%s", print_name ? "str " : "hex"); | |
169 | + | |
170 | + for (i = 0; i < r->res_length; i++) { | |
171 | + if (print_name) | |
172 | + seq_printf(s, "%c", r->res_name[i]); | |
173 | + else | |
174 | + seq_printf(s, " %02x", (unsigned char)r->res_name[i]); | |
175 | + } | |
176 | + seq_printf(s, "\n"); | |
177 | + | |
178 | + if (!r->res_lvbptr) | |
179 | + goto do_locks; | |
180 | + | |
181 | + seq_printf(s, "lvb %u %d", r->res_lvbseq, lvblen); | |
182 | + | |
183 | + for (i = 0; i < lvblen; i++) | |
184 | + seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]); | |
185 | + seq_printf(s, "\n"); | |
186 | + | |
187 | + do_locks: | |
188 | + list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) | |
189 | + print_format3_lock(s, lkb, 0); | |
190 | + | |
191 | + list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) | |
192 | + print_format3_lock(s, lkb, 0); | |
193 | + | |
194 | + list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) | |
195 | + print_format3_lock(s, lkb, 0); | |
196 | + | |
197 | + list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) | |
198 | + print_format3_lock(s, lkb, 1); | |
199 | ||
200 | unlock_rsb(r); | |
201 | return 0; | |
202 | @@ -231,7 +320,7 @@ static int rsb_iter_next(struct rsb_iter | |
203 | break; | |
204 | } | |
205 | read_unlock(&ls->ls_rsbtbl[i].lock); | |
206 | - } | |
207 | + } | |
208 | ri->entry = i; | |
209 | ||
210 | if (ri->entry >= ls->ls_rsbtbl_size) | |
211 | @@ -248,7 +337,7 @@ static int rsb_iter_next(struct rsb_iter | |
212 | read_unlock(&ls->ls_rsbtbl[i].lock); | |
213 | dlm_put_rsb(old); | |
214 | goto top; | |
215 | - } | |
216 | + } | |
217 | ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); | |
218 | dlm_hold_rsb(ri->rsb); | |
219 | read_unlock(&ls->ls_rsbtbl[i].lock); | |
220 | @@ -274,6 +363,7 @@ static struct rsb_iter *rsb_iter_init(st | |
221 | ri->ls = ls; | |
222 | ri->entry = 0; | |
223 | ri->next = NULL; | |
224 | + ri->format = 1; | |
225 | ||
226 | if (rsb_iter_next(ri)) { | |
227 | rsb_iter_free(ri); | |
228 | @@ -325,16 +415,26 @@ static int rsb_seq_show(struct seq_file | |
229 | { | |
230 | struct rsb_iter *ri = iter_ptr; | |
231 | ||
232 | - if (ri->locks) { | |
233 | + switch (ri->format) { | |
234 | + case 1: | |
235 | + print_format1(ri->rsb, file); | |
236 | + break; | |
237 | + case 2: | |
238 | if (ri->header) { | |
239 | - seq_printf(file, "id nodeid remid pid xid exflags flags " | |
240 | - "sts grmode rqmode time_ms r_nodeid " | |
241 | - "r_len r_name\n"); | |
242 | + seq_printf(file, "id nodeid remid pid xid exflags " | |
243 | + "flags sts grmode rqmode time_ms " | |
244 | + "r_nodeid r_len r_name\n"); | |
245 | ri->header = 0; | |
246 | } | |
247 | - print_locks(ri->rsb, file); | |
248 | - } else { | |
249 | - print_resource(ri->rsb, file); | |
250 | + print_format2(ri->rsb, file); | |
251 | + break; | |
252 | + case 3: | |
253 | + if (ri->header) { | |
254 | + seq_printf(file, "version rsb 1.1 lvb 1.1 lkb 1.1\n"); | |
255 | + ri->header = 0; | |
256 | + } | |
257 | + print_format3(ri->rsb, file); | |
258 | + break; | |
259 | } | |
260 | ||
261 | return 0; | |
262 | @@ -385,7 +485,7 @@ static struct rsb_iter *locks_iter_init( | |
263 | ri->ls = ls; | |
264 | ri->entry = 0; | |
265 | ri->next = NULL; | |
266 | - ri->locks = 1; | |
267 | + ri->format = 2; | |
268 | ||
269 | if (*pos == 0) | |
270 | ri->header = 1; | |
271 | @@ -448,6 +548,84 @@ static const struct file_operations lock | |
272 | }; | |
273 | ||
274 | /* | |
275 | + * Dump all rsb/lvb/lkb state in compact listing, more complete than _locks | |
276 | + * This can replace both formats 1 and 2 eventually. | |
277 | + */ | |
278 | + | |
279 | +static struct rsb_iter *all_iter_init(struct dlm_ls *ls, loff_t *pos) | |
280 | +{ | |
281 | + struct rsb_iter *ri; | |
282 | + | |
283 | + ri = kzalloc(sizeof *ri, GFP_KERNEL); | |
284 | + if (!ri) | |
285 | + return NULL; | |
286 | + | |
287 | + ri->ls = ls; | |
288 | + ri->entry = 0; | |
289 | + ri->next = NULL; | |
290 | + ri->format = 3; | |
291 | + | |
292 | + if (*pos == 0) | |
293 | + ri->header = 1; | |
294 | + | |
295 | + if (rsb_iter_next(ri)) { | |
296 | + rsb_iter_free(ri); | |
297 | + return NULL; | |
298 | + } | |
299 | + | |
300 | + return ri; | |
301 | +} | |
302 | + | |
303 | +static void *all_seq_start(struct seq_file *file, loff_t *pos) | |
304 | +{ | |
305 | + struct rsb_iter *ri; | |
306 | + loff_t n = *pos; | |
307 | + | |
308 | + ri = all_iter_init(file->private, pos); | |
309 | + if (!ri) | |
310 | + return NULL; | |
311 | + | |
312 | + while (n--) { | |
313 | + if (rsb_iter_next(ri)) { | |
314 | + rsb_iter_free(ri); | |
315 | + return NULL; | |
316 | + } | |
317 | + } | |
318 | + | |
319 | + return ri; | |
320 | +} | |
321 | + | |
322 | +static struct seq_operations all_seq_ops = { | |
323 | + .start = all_seq_start, | |
324 | + .next = rsb_seq_next, | |
325 | + .stop = rsb_seq_stop, | |
326 | + .show = rsb_seq_show, | |
327 | +}; | |
328 | + | |
329 | +static int all_open(struct inode *inode, struct file *file) | |
330 | +{ | |
331 | + struct seq_file *seq; | |
332 | + int ret; | |
333 | + | |
334 | + ret = seq_open(file, &all_seq_ops); | |
335 | + if (ret) | |
336 | + return ret; | |
337 | + | |
338 | + seq = file->private_data; | |
339 | + seq->private = inode->i_private; | |
340 | + | |
341 | + return 0; | |
342 | +} | |
343 | + | |
344 | +static const struct file_operations all_fops = { | |
345 | + .owner = THIS_MODULE, | |
346 | + .open = all_open, | |
347 | + .read = seq_read, | |
348 | + .llseek = seq_lseek, | |
349 | + .release = seq_release | |
350 | +}; | |
351 | + | |
352 | +/* | |
353 | * dump lkb's on the ls_waiters list | |
354 | */ | |
355 | ||
356 | @@ -489,30 +667,33 @@ static const struct file_operations wait | |
357 | .read = waiters_read | |
358 | }; | |
359 | ||
360 | +void dlm_delete_debug_file(struct dlm_ls *ls) | |
361 | +{ | |
362 | + if (ls->ls_debug_rsb_dentry) | |
363 | + debugfs_remove(ls->ls_debug_rsb_dentry); | |
364 | + if (ls->ls_debug_waiters_dentry) | |
365 | + debugfs_remove(ls->ls_debug_waiters_dentry); | |
366 | + if (ls->ls_debug_locks_dentry) | |
367 | + debugfs_remove(ls->ls_debug_locks_dentry); | |
368 | + if (ls->ls_debug_all_dentry) | |
369 | + debugfs_remove(ls->ls_debug_all_dentry); | |
370 | +} | |
371 | + | |
372 | int dlm_create_debug_file(struct dlm_ls *ls) | |
373 | { | |
374 | char name[DLM_LOCKSPACE_LEN+8]; | |
375 | ||
376 | + /* format 1 */ | |
377 | + | |
378 | ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name, | |
379 | S_IFREG | S_IRUGO, | |
380 | dlm_root, | |
381 | ls, | |
382 | &rsb_fops); | |
383 | if (!ls->ls_debug_rsb_dentry) | |
384 | - return -ENOMEM; | |
385 | + goto fail; | |
386 | ||
387 | - memset(name, 0, sizeof(name)); | |
388 | - snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name); | |
389 | - | |
390 | - ls->ls_debug_waiters_dentry = debugfs_create_file(name, | |
391 | - S_IFREG | S_IRUGO, | |
392 | - dlm_root, | |
393 | - ls, | |
394 | - &waiters_fops); | |
395 | - if (!ls->ls_debug_waiters_dentry) { | |
396 | - debugfs_remove(ls->ls_debug_rsb_dentry); | |
397 | - return -ENOMEM; | |
398 | - } | |
399 | + /* format 2 */ | |
400 | ||
401 | memset(name, 0, sizeof(name)); | |
402 | snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_locks", ls->ls_name); | |
403 | @@ -522,23 +703,38 @@ int dlm_create_debug_file(struct dlm_ls | |
404 | dlm_root, | |
405 | ls, | |
406 | &locks_fops); | |
407 | - if (!ls->ls_debug_locks_dentry) { | |
408 | - debugfs_remove(ls->ls_debug_waiters_dentry); | |
409 | - debugfs_remove(ls->ls_debug_rsb_dentry); | |
410 | - return -ENOMEM; | |
411 | - } | |
412 | + if (!ls->ls_debug_locks_dentry) | |
413 | + goto fail; | |
414 | + | |
415 | + /* format 3 */ | |
416 | + | |
417 | + memset(name, 0, sizeof(name)); | |
418 | + snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_all", ls->ls_name); | |
419 | + | |
420 | + ls->ls_debug_all_dentry = debugfs_create_file(name, | |
421 | + S_IFREG | S_IRUGO, | |
422 | + dlm_root, | |
423 | + ls, | |
424 | + &all_fops); | |
425 | + if (!ls->ls_debug_all_dentry) | |
426 | + goto fail; | |
427 | + | |
428 | + memset(name, 0, sizeof(name)); | |
429 | + snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name); | |
430 | + | |
431 | + ls->ls_debug_waiters_dentry = debugfs_create_file(name, | |
432 | + S_IFREG | S_IRUGO, | |
433 | + dlm_root, | |
434 | + ls, | |
435 | + &waiters_fops); | |
436 | + if (!ls->ls_debug_waiters_dentry) | |
437 | + goto fail; | |
438 | ||
439 | return 0; | |
440 | -} | |
441 | ||
442 | -void dlm_delete_debug_file(struct dlm_ls *ls) | |
443 | -{ | |
444 | - if (ls->ls_debug_rsb_dentry) | |
445 | - debugfs_remove(ls->ls_debug_rsb_dentry); | |
446 | - if (ls->ls_debug_waiters_dentry) | |
447 | - debugfs_remove(ls->ls_debug_waiters_dentry); | |
448 | - if (ls->ls_debug_locks_dentry) | |
449 | - debugfs_remove(ls->ls_debug_locks_dentry); | |
450 | + fail: | |
451 | + dlm_delete_debug_file(ls); | |
452 | + return -ENOMEM; | |
453 | } | |
454 | ||
455 | int __init dlm_register_debugfs(void) | |
456 | --- a/fs/dlm/dlm_internal.h | |
457 | +++ b/fs/dlm/dlm_internal.h | |
458 | @@ -481,6 +481,7 @@ struct dlm_ls { | |
459 | struct dentry *ls_debug_rsb_dentry; /* debugfs */ | |
460 | struct dentry *ls_debug_waiters_dentry; /* debugfs */ | |
461 | struct dentry *ls_debug_locks_dentry; /* debugfs */ | |
462 | + struct dentry *ls_debug_all_dentry; /* debugfs */ | |
463 | ||
464 | wait_queue_head_t ls_uevent_wait; /* user part of join/leave */ | |
465 | int ls_uevent_result; |