diff options
Diffstat (limited to 'fs/dlm/debug_fs.c')
-rw-r--r-- | fs/dlm/debug_fs.c | 186 |
1 files changed, 178 insertions, 8 deletions
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 61ba670b9e02..12c3bfd5e660 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/debugfs.h> | 17 | #include <linux/debugfs.h> |
18 | 18 | ||
19 | #include "dlm_internal.h" | 19 | #include "dlm_internal.h" |
20 | #include "lock.h" | ||
20 | 21 | ||
21 | #define DLM_DEBUG_BUF_LEN 4096 | 22 | #define DLM_DEBUG_BUF_LEN 4096 |
22 | static char debug_buf[DLM_DEBUG_BUF_LEN]; | 23 | static char debug_buf[DLM_DEBUG_BUF_LEN]; |
@@ -26,6 +27,8 @@ static struct dentry *dlm_root; | |||
26 | 27 | ||
27 | struct rsb_iter { | 28 | struct rsb_iter { |
28 | int entry; | 29 | int entry; |
30 | int locks; | ||
31 | int header; | ||
29 | struct dlm_ls *ls; | 32 | struct dlm_ls *ls; |
30 | struct list_head *next; | 33 | struct list_head *next; |
31 | struct dlm_rsb *rsb; | 34 | struct dlm_rsb *rsb; |
@@ -57,8 +60,8 @@ static char *print_lockmode(int mode) | |||
57 | } | 60 | } |
58 | } | 61 | } |
59 | 62 | ||
60 | static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, | 63 | static void print_resource_lock(struct seq_file *s, struct dlm_lkb *lkb, |
61 | struct dlm_rsb *res) | 64 | struct dlm_rsb *res) |
62 | { | 65 | { |
63 | seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); | 66 | seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); |
64 | 67 | ||
@@ -85,6 +88,8 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) | |||
85 | struct dlm_lkb *lkb; | 88 | struct dlm_lkb *lkb; |
86 | int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; | 89 | int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; |
87 | 90 | ||
91 | lock_rsb(res); | ||
92 | |||
88 | seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); | 93 | seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); |
89 | for (i = 0; i < res->res_length; i++) { | 94 | for (i = 0; i < res->res_length; i++) { |
90 | if (isprint(res->res_name[i])) | 95 | if (isprint(res->res_name[i])) |
@@ -129,15 +134,15 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) | |||
129 | /* Print the locks attached to this resource */ | 134 | /* Print the locks attached to this resource */ |
130 | seq_printf(s, "Granted Queue\n"); | 135 | seq_printf(s, "Granted Queue\n"); |
131 | list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) | 136 | list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) |
132 | print_lock(s, lkb, res); | 137 | print_resource_lock(s, lkb, res); |
133 | 138 | ||
134 | seq_printf(s, "Conversion Queue\n"); | 139 | seq_printf(s, "Conversion Queue\n"); |
135 | list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) | 140 | list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) |
136 | print_lock(s, lkb, res); | 141 | print_resource_lock(s, lkb, res); |
137 | 142 | ||
138 | seq_printf(s, "Waiting Queue\n"); | 143 | seq_printf(s, "Waiting Queue\n"); |
139 | list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) | 144 | list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) |
140 | print_lock(s, lkb, res); | 145 | print_resource_lock(s, lkb, res); |
141 | 146 | ||
142 | if (list_empty(&res->res_lookup)) | 147 | if (list_empty(&res->res_lookup)) |
143 | goto out; | 148 | goto out; |
@@ -151,6 +156,61 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) | |||
151 | seq_printf(s, "\n"); | 156 | seq_printf(s, "\n"); |
152 | } | 157 | } |
153 | out: | 158 | out: |
159 | unlock_rsb(res); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, struct dlm_rsb *r) | ||
164 | { | ||
165 | struct dlm_user_args *ua; | ||
166 | unsigned int waiting = 0; | ||
167 | uint64_t xid = 0; | ||
168 | |||
169 | if (lkb->lkb_flags & DLM_IFL_USER) { | ||
170 | ua = (struct dlm_user_args *) lkb->lkb_astparam; | ||
171 | if (ua) | ||
172 | xid = ua->xid; | ||
173 | } | ||
174 | |||
175 | if (lkb->lkb_timestamp) | ||
176 | waiting = jiffies_to_msecs(jiffies - lkb->lkb_timestamp); | ||
177 | |||
178 | /* id nodeid remid pid xid exflags flags sts grmode rqmode time_ms | ||
179 | r_nodeid r_len r_name */ | ||
180 | |||
181 | seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %u %u %d \"%s\"\n", | ||
182 | lkb->lkb_id, | ||
183 | lkb->lkb_nodeid, | ||
184 | lkb->lkb_remid, | ||
185 | lkb->lkb_ownpid, | ||
186 | (unsigned long long)xid, | ||
187 | lkb->lkb_exflags, | ||
188 | lkb->lkb_flags, | ||
189 | lkb->lkb_status, | ||
190 | lkb->lkb_grmode, | ||
191 | lkb->lkb_rqmode, | ||
192 | waiting, | ||
193 | r->res_nodeid, | ||
194 | r->res_length, | ||
195 | r->res_name); | ||
196 | } | ||
197 | |||
198 | static int print_locks(struct dlm_rsb *r, struct seq_file *s) | ||
199 | { | ||
200 | struct dlm_lkb *lkb; | ||
201 | |||
202 | lock_rsb(r); | ||
203 | |||
204 | list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) | ||
205 | print_lock(s, lkb, r); | ||
206 | |||
207 | list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) | ||
208 | print_lock(s, lkb, r); | ||
209 | |||
210 | list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) | ||
211 | print_lock(s, lkb, r); | ||
212 | |||
213 | unlock_rsb(r); | ||
154 | return 0; | 214 | return 0; |
155 | } | 215 | } |
156 | 216 | ||
@@ -166,6 +226,9 @@ static int rsb_iter_next(struct rsb_iter *ri) | |||
166 | read_lock(&ls->ls_rsbtbl[i].lock); | 226 | read_lock(&ls->ls_rsbtbl[i].lock); |
167 | if (!list_empty(&ls->ls_rsbtbl[i].list)) { | 227 | if (!list_empty(&ls->ls_rsbtbl[i].list)) { |
168 | ri->next = ls->ls_rsbtbl[i].list.next; | 228 | ri->next = ls->ls_rsbtbl[i].list.next; |
229 | ri->rsb = list_entry(ri->next, struct dlm_rsb, | ||
230 | res_hashchain); | ||
231 | dlm_hold_rsb(ri->rsb); | ||
169 | read_unlock(&ls->ls_rsbtbl[i].lock); | 232 | read_unlock(&ls->ls_rsbtbl[i].lock); |
170 | break; | 233 | break; |
171 | } | 234 | } |
@@ -176,6 +239,7 @@ static int rsb_iter_next(struct rsb_iter *ri) | |||
176 | if (ri->entry >= ls->ls_rsbtbl_size) | 239 | if (ri->entry >= ls->ls_rsbtbl_size) |
177 | return 1; | 240 | return 1; |
178 | } else { | 241 | } else { |
242 | struct dlm_rsb *old = ri->rsb; | ||
179 | i = ri->entry; | 243 | i = ri->entry; |
180 | read_lock(&ls->ls_rsbtbl[i].lock); | 244 | read_lock(&ls->ls_rsbtbl[i].lock); |
181 | ri->next = ri->next->next; | 245 | ri->next = ri->next->next; |
@@ -184,11 +248,14 @@ static int rsb_iter_next(struct rsb_iter *ri) | |||
184 | ri->next = NULL; | 248 | ri->next = NULL; |
185 | ri->entry++; | 249 | ri->entry++; |
186 | read_unlock(&ls->ls_rsbtbl[i].lock); | 250 | read_unlock(&ls->ls_rsbtbl[i].lock); |
251 | dlm_put_rsb(old); | ||
187 | goto top; | 252 | goto top; |
188 | } | 253 | } |
254 | ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); | ||
255 | dlm_hold_rsb(ri->rsb); | ||
189 | read_unlock(&ls->ls_rsbtbl[i].lock); | 256 | read_unlock(&ls->ls_rsbtbl[i].lock); |
257 | dlm_put_rsb(old); | ||
190 | } | 258 | } |
191 | ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); | ||
192 | 259 | ||
193 | return 0; | 260 | return 0; |
194 | } | 261 | } |
@@ -202,7 +269,7 @@ static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls) | |||
202 | { | 269 | { |
203 | struct rsb_iter *ri; | 270 | struct rsb_iter *ri; |
204 | 271 | ||
205 | ri = kmalloc(sizeof *ri, GFP_KERNEL); | 272 | ri = kzalloc(sizeof *ri, GFP_KERNEL); |
206 | if (!ri) | 273 | if (!ri) |
207 | return NULL; | 274 | return NULL; |
208 | 275 | ||
@@ -260,7 +327,17 @@ static int rsb_seq_show(struct seq_file *file, void *iter_ptr) | |||
260 | { | 327 | { |
261 | struct rsb_iter *ri = iter_ptr; | 328 | struct rsb_iter *ri = iter_ptr; |
262 | 329 | ||
263 | print_resource(ri->rsb, file); | 330 | if (ri->locks) { |
331 | if (ri->header) { | ||
332 | seq_printf(file, "id nodeid remid pid xid exflags flags " | ||
333 | "sts grmode rqmode time_ms r_nodeid " | ||
334 | "r_len r_name\n"); | ||
335 | ri->header = 0; | ||
336 | } | ||
337 | print_locks(ri->rsb, file); | ||
338 | } else { | ||
339 | print_resource(ri->rsb, file); | ||
340 | } | ||
264 | 341 | ||
265 | return 0; | 342 | return 0; |
266 | } | 343 | } |
@@ -296,6 +373,83 @@ static const struct file_operations rsb_fops = { | |||
296 | }; | 373 | }; |
297 | 374 | ||
298 | /* | 375 | /* |
376 | * Dump state in compact per-lock listing | ||
377 | */ | ||
378 | |||
379 | static struct rsb_iter *locks_iter_init(struct dlm_ls *ls, loff_t *pos) | ||
380 | { | ||
381 | struct rsb_iter *ri; | ||
382 | |||
383 | ri = kzalloc(sizeof *ri, GFP_KERNEL); | ||
384 | if (!ri) | ||
385 | return NULL; | ||
386 | |||
387 | ri->ls = ls; | ||
388 | ri->entry = 0; | ||
389 | ri->next = NULL; | ||
390 | ri->locks = 1; | ||
391 | |||
392 | if (*pos == 0) | ||
393 | ri->header = 1; | ||
394 | |||
395 | if (rsb_iter_next(ri)) { | ||
396 | rsb_iter_free(ri); | ||
397 | return NULL; | ||
398 | } | ||
399 | |||
400 | return ri; | ||
401 | } | ||
402 | |||
403 | static void *locks_seq_start(struct seq_file *file, loff_t *pos) | ||
404 | { | ||
405 | struct rsb_iter *ri; | ||
406 | loff_t n = *pos; | ||
407 | |||
408 | ri = locks_iter_init(file->private, pos); | ||
409 | if (!ri) | ||
410 | return NULL; | ||
411 | |||
412 | while (n--) { | ||
413 | if (rsb_iter_next(ri)) { | ||
414 | rsb_iter_free(ri); | ||
415 | return NULL; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | return ri; | ||
420 | } | ||
421 | |||
422 | static struct seq_operations locks_seq_ops = { | ||
423 | .start = locks_seq_start, | ||
424 | .next = rsb_seq_next, | ||
425 | .stop = rsb_seq_stop, | ||
426 | .show = rsb_seq_show, | ||
427 | }; | ||
428 | |||
429 | static int locks_open(struct inode *inode, struct file *file) | ||
430 | { | ||
431 | struct seq_file *seq; | ||
432 | int ret; | ||
433 | |||
434 | ret = seq_open(file, &locks_seq_ops); | ||
435 | if (ret) | ||
436 | return ret; | ||
437 | |||
438 | seq = file->private_data; | ||
439 | seq->private = inode->i_private; | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static const struct file_operations locks_fops = { | ||
445 | .owner = THIS_MODULE, | ||
446 | .open = locks_open, | ||
447 | .read = seq_read, | ||
448 | .llseek = seq_lseek, | ||
449 | .release = seq_release | ||
450 | }; | ||
451 | |||
452 | /* | ||
299 | * dump lkb's on the ls_waiters list | 453 | * dump lkb's on the ls_waiters list |
300 | */ | 454 | */ |
301 | 455 | ||
@@ -362,6 +516,20 @@ int dlm_create_debug_file(struct dlm_ls *ls) | |||
362 | return -ENOMEM; | 516 | return -ENOMEM; |
363 | } | 517 | } |
364 | 518 | ||
519 | memset(name, 0, sizeof(name)); | ||
520 | snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_locks", ls->ls_name); | ||
521 | |||
522 | ls->ls_debug_locks_dentry = debugfs_create_file(name, | ||
523 | S_IFREG | S_IRUGO, | ||
524 | dlm_root, | ||
525 | ls, | ||
526 | &locks_fops); | ||
527 | if (!ls->ls_debug_locks_dentry) { | ||
528 | debugfs_remove(ls->ls_debug_waiters_dentry); | ||
529 | debugfs_remove(ls->ls_debug_rsb_dentry); | ||
530 | return -ENOMEM; | ||
531 | } | ||
532 | |||
365 | return 0; | 533 | return 0; |
366 | } | 534 | } |
367 | 535 | ||
@@ -371,6 +539,8 @@ void dlm_delete_debug_file(struct dlm_ls *ls) | |||
371 | debugfs_remove(ls->ls_debug_rsb_dentry); | 539 | debugfs_remove(ls->ls_debug_rsb_dentry); |
372 | if (ls->ls_debug_waiters_dentry) | 540 | if (ls->ls_debug_waiters_dentry) |
373 | debugfs_remove(ls->ls_debug_waiters_dentry); | 541 | debugfs_remove(ls->ls_debug_waiters_dentry); |
542 | if (ls->ls_debug_locks_dentry) | ||
543 | debugfs_remove(ls->ls_debug_locks_dentry); | ||
374 | } | 544 | } |
375 | 545 | ||
376 | int dlm_register_debugfs(void) | 546 | int dlm_register_debugfs(void) |