1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /****************************************************************************** |
3 | ******************************************************************************* |
4 | ** |
5 | ** Copyright (C) 2005-2009 Red Hat, Inc. All rights reserved. |
6 | ** |
7 | ** |
8 | ******************************************************************************* |
9 | ******************************************************************************/ |
10 | |
11 | #include <linux/pagemap.h> |
12 | #include <linux/seq_file.h> |
13 | #include <linux/init.h> |
14 | #include <linux/ctype.h> |
15 | #include <linux/debugfs.h> |
16 | #include <linux/slab.h> |
17 | |
18 | #include "dlm_internal.h" |
19 | #include "midcomms.h" |
20 | #include "lock.h" |
21 | #include "ast.h" |
22 | |
23 | #define DLM_DEBUG_BUF_LEN 4096 |
24 | static char debug_buf[DLM_DEBUG_BUF_LEN]; |
25 | static struct mutex debug_buf_lock; |
26 | |
27 | static struct dentry *dlm_root; |
28 | static struct dentry *dlm_comms; |
29 | |
30 | static char *print_lockmode(int mode) |
31 | { |
32 | switch (mode) { |
33 | case DLM_LOCK_IV: |
34 | return "--" ; |
35 | case DLM_LOCK_NL: |
36 | return "NL" ; |
37 | case DLM_LOCK_CR: |
38 | return "CR" ; |
39 | case DLM_LOCK_CW: |
40 | return "CW" ; |
41 | case DLM_LOCK_PR: |
42 | return "PR" ; |
43 | case DLM_LOCK_PW: |
44 | return "PW" ; |
45 | case DLM_LOCK_EX: |
46 | return "EX" ; |
47 | default: |
48 | return "??" ; |
49 | } |
50 | } |
51 | |
52 | static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, |
53 | struct dlm_rsb *res) |
54 | { |
55 | seq_printf(m: s, fmt: "%08x %s" , lkb->lkb_id, print_lockmode(mode: lkb->lkb_grmode)); |
56 | |
57 | if (lkb->lkb_status == DLM_LKSTS_CONVERT || |
58 | lkb->lkb_status == DLM_LKSTS_WAITING) |
59 | seq_printf(m: s, fmt: " (%s)" , print_lockmode(mode: lkb->lkb_rqmode)); |
60 | |
61 | if (lkb->lkb_nodeid) { |
62 | if (lkb->lkb_nodeid != res->res_nodeid) |
63 | seq_printf(m: s, fmt: " Remote: %3d %08x" , lkb->lkb_nodeid, |
64 | lkb->lkb_remid); |
65 | else |
66 | seq_printf(m: s, fmt: " Master: %08x" , lkb->lkb_remid); |
67 | } |
68 | |
69 | if (lkb->lkb_wait_type) |
70 | seq_printf(m: s, fmt: " wait_type: %d" , lkb->lkb_wait_type); |
71 | |
72 | seq_putc(m: s, c: '\n'); |
73 | } |
74 | |
75 | static void print_format1(struct dlm_rsb *res, struct seq_file *s) |
76 | { |
77 | struct dlm_lkb *lkb; |
78 | int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; |
79 | |
80 | lock_rsb(r: res); |
81 | |
82 | seq_printf(m: s, fmt: "\nResource %p Name (len=%d) \"" , res, res->res_length); |
83 | |
84 | for (i = 0; i < res->res_length; i++) { |
85 | if (isprint(res->res_name[i])) |
86 | seq_printf(m: s, fmt: "%c" , res->res_name[i]); |
87 | else |
88 | seq_printf(m: s, fmt: "%c" , '.'); |
89 | } |
90 | |
91 | if (res->res_nodeid > 0) |
92 | seq_printf(m: s, fmt: "\"\nLocal Copy, Master is node %d\n" , |
93 | res->res_nodeid); |
94 | else if (res->res_nodeid == 0) |
95 | seq_puts(m: s, s: "\"\nMaster Copy\n" ); |
96 | else if (res->res_nodeid == -1) |
97 | seq_printf(m: s, fmt: "\"\nLooking up master (lkid %x)\n" , |
98 | res->res_first_lkid); |
99 | else |
100 | seq_printf(m: s, fmt: "\"\nInvalid master %d\n" , res->res_nodeid); |
101 | if (seq_has_overflowed(m: s)) |
102 | goto out; |
103 | |
104 | /* Print the LVB: */ |
105 | if (res->res_lvbptr) { |
106 | seq_puts(m: s, s: "LVB: " ); |
107 | for (i = 0; i < lvblen; i++) { |
108 | if (i == lvblen / 2) |
109 | seq_puts(m: s, s: "\n " ); |
110 | seq_printf(m: s, fmt: "%02x " , |
111 | (unsigned char) res->res_lvbptr[i]); |
112 | } |
113 | if (rsb_flag(r: res, flag: RSB_VALNOTVALID)) |
114 | seq_puts(m: s, s: " (INVALID)" ); |
115 | seq_putc(m: s, c: '\n'); |
116 | if (seq_has_overflowed(m: s)) |
117 | goto out; |
118 | } |
119 | |
120 | root_list = !list_empty(head: &res->res_root_list); |
121 | recover_list = !list_empty(head: &res->res_recover_list); |
122 | |
123 | if (root_list || recover_list) { |
124 | seq_printf(m: s, fmt: "Recovery: root %d recover %d flags %lx count %d\n" , |
125 | root_list, recover_list, |
126 | res->res_flags, res->res_recover_locks_count); |
127 | } |
128 | |
129 | /* Print the locks attached to this resource */ |
130 | seq_puts(m: s, s: "Granted Queue\n" ); |
131 | list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) { |
132 | print_format1_lock(s, lkb, res); |
133 | if (seq_has_overflowed(m: s)) |
134 | goto out; |
135 | } |
136 | |
137 | seq_puts(m: s, s: "Conversion Queue\n" ); |
138 | list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) { |
139 | print_format1_lock(s, lkb, res); |
140 | if (seq_has_overflowed(m: s)) |
141 | goto out; |
142 | } |
143 | |
144 | seq_puts(m: s, s: "Waiting Queue\n" ); |
145 | list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) { |
146 | print_format1_lock(s, lkb, res); |
147 | if (seq_has_overflowed(m: s)) |
148 | goto out; |
149 | } |
150 | |
151 | if (list_empty(head: &res->res_lookup)) |
152 | goto out; |
153 | |
154 | seq_puts(m: s, s: "Lookup Queue\n" ); |
155 | list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) { |
156 | seq_printf(m: s, fmt: "%08x %s" , |
157 | lkb->lkb_id, print_lockmode(mode: lkb->lkb_rqmode)); |
158 | if (lkb->lkb_wait_type) |
159 | seq_printf(m: s, fmt: " wait_type: %d" , lkb->lkb_wait_type); |
160 | seq_putc(m: s, c: '\n'); |
161 | if (seq_has_overflowed(m: s)) |
162 | goto out; |
163 | } |
164 | out: |
165 | unlock_rsb(r: res); |
166 | } |
167 | |
168 | static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, |
169 | struct dlm_rsb *r) |
170 | { |
171 | u64 xid = 0; |
172 | u64 us; |
173 | |
174 | if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) { |
175 | if (lkb->lkb_ua) |
176 | xid = lkb->lkb_ua->xid; |
177 | } |
178 | |
179 | /* microseconds since lkb was added to current queue */ |
180 | us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_timestamp)); |
181 | |
182 | /* id nodeid remid pid xid exflags flags sts grmode rqmode time_us |
183 | r_nodeid r_len r_name */ |
184 | |
185 | seq_printf(m: s, fmt: "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n" , |
186 | lkb->lkb_id, |
187 | lkb->lkb_nodeid, |
188 | lkb->lkb_remid, |
189 | lkb->lkb_ownpid, |
190 | (unsigned long long)xid, |
191 | lkb->lkb_exflags, |
192 | dlm_iflags_val(lkb), |
193 | lkb->lkb_status, |
194 | lkb->lkb_grmode, |
195 | lkb->lkb_rqmode, |
196 | (unsigned long long)us, |
197 | r->res_nodeid, |
198 | r->res_length, |
199 | r->res_name); |
200 | } |
201 | |
202 | static void print_format2(struct dlm_rsb *r, struct seq_file *s) |
203 | { |
204 | struct dlm_lkb *lkb; |
205 | |
206 | lock_rsb(r); |
207 | |
208 | list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { |
209 | print_format2_lock(s, lkb, r); |
210 | if (seq_has_overflowed(m: s)) |
211 | goto out; |
212 | } |
213 | |
214 | list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) { |
215 | print_format2_lock(s, lkb, r); |
216 | if (seq_has_overflowed(m: s)) |
217 | goto out; |
218 | } |
219 | |
220 | list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) { |
221 | print_format2_lock(s, lkb, r); |
222 | if (seq_has_overflowed(m: s)) |
223 | goto out; |
224 | } |
225 | out: |
226 | unlock_rsb(r); |
227 | } |
228 | |
229 | static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb, |
230 | int rsb_lookup) |
231 | { |
232 | u64 xid = 0; |
233 | |
234 | if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) { |
235 | if (lkb->lkb_ua) |
236 | xid = lkb->lkb_ua->xid; |
237 | } |
238 | |
239 | seq_printf(m: s, fmt: "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n" , |
240 | lkb->lkb_id, |
241 | lkb->lkb_nodeid, |
242 | lkb->lkb_remid, |
243 | lkb->lkb_ownpid, |
244 | (unsigned long long)xid, |
245 | lkb->lkb_exflags, |
246 | dlm_iflags_val(lkb), |
247 | lkb->lkb_status, |
248 | lkb->lkb_grmode, |
249 | lkb->lkb_rqmode, |
250 | lkb->lkb_last_bast_mode, |
251 | rsb_lookup, |
252 | lkb->lkb_wait_type, |
253 | lkb->lkb_lvbseq, |
254 | (unsigned long long)ktime_to_ns(kt: lkb->lkb_timestamp), |
255 | (unsigned long long)ktime_to_ns(kt: lkb->lkb_last_bast_time)); |
256 | } |
257 | |
258 | static void print_format3(struct dlm_rsb *r, struct seq_file *s) |
259 | { |
260 | struct dlm_lkb *lkb; |
261 | int i, lvblen = r->res_ls->ls_lvblen; |
262 | int print_name = 1; |
263 | |
264 | lock_rsb(r); |
265 | |
266 | seq_printf(m: s, fmt: "rsb %p %d %x %lx %d %d %u %d " , |
267 | r, |
268 | r->res_nodeid, |
269 | r->res_first_lkid, |
270 | r->res_flags, |
271 | !list_empty(head: &r->res_root_list), |
272 | !list_empty(head: &r->res_recover_list), |
273 | r->res_recover_locks_count, |
274 | r->res_length); |
275 | if (seq_has_overflowed(m: s)) |
276 | goto out; |
277 | |
278 | for (i = 0; i < r->res_length; i++) { |
279 | if (!isascii(r->res_name[i]) || !isprint(r->res_name[i])) |
280 | print_name = 0; |
281 | } |
282 | |
283 | seq_puts(m: s, s: print_name ? "str " : "hex" ); |
284 | |
285 | for (i = 0; i < r->res_length; i++) { |
286 | if (print_name) |
287 | seq_printf(m: s, fmt: "%c" , r->res_name[i]); |
288 | else |
289 | seq_printf(m: s, fmt: " %02x" , (unsigned char)r->res_name[i]); |
290 | } |
291 | seq_putc(m: s, c: '\n'); |
292 | if (seq_has_overflowed(m: s)) |
293 | goto out; |
294 | |
295 | if (!r->res_lvbptr) |
296 | goto do_locks; |
297 | |
298 | seq_printf(m: s, fmt: "lvb %u %d" , r->res_lvbseq, lvblen); |
299 | |
300 | for (i = 0; i < lvblen; i++) |
301 | seq_printf(m: s, fmt: " %02x" , (unsigned char)r->res_lvbptr[i]); |
302 | seq_putc(m: s, c: '\n'); |
303 | if (seq_has_overflowed(m: s)) |
304 | goto out; |
305 | |
306 | do_locks: |
307 | list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { |
308 | print_format3_lock(s, lkb, rsb_lookup: 0); |
309 | if (seq_has_overflowed(m: s)) |
310 | goto out; |
311 | } |
312 | |
313 | list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) { |
314 | print_format3_lock(s, lkb, rsb_lookup: 0); |
315 | if (seq_has_overflowed(m: s)) |
316 | goto out; |
317 | } |
318 | |
319 | list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) { |
320 | print_format3_lock(s, lkb, rsb_lookup: 0); |
321 | if (seq_has_overflowed(m: s)) |
322 | goto out; |
323 | } |
324 | |
325 | list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) { |
326 | print_format3_lock(s, lkb, rsb_lookup: 1); |
327 | if (seq_has_overflowed(m: s)) |
328 | goto out; |
329 | } |
330 | out: |
331 | unlock_rsb(r); |
332 | } |
333 | |
334 | static void print_format4(struct dlm_rsb *r, struct seq_file *s) |
335 | { |
336 | int our_nodeid = dlm_our_nodeid(); |
337 | int print_name = 1; |
338 | int i; |
339 | |
340 | lock_rsb(r); |
341 | |
342 | seq_printf(m: s, fmt: "rsb %p %d %d %d %d %lu %lx %d " , |
343 | r, |
344 | r->res_nodeid, |
345 | r->res_master_nodeid, |
346 | r->res_dir_nodeid, |
347 | our_nodeid, |
348 | r->res_toss_time, |
349 | r->res_flags, |
350 | r->res_length); |
351 | |
352 | for (i = 0; i < r->res_length; i++) { |
353 | if (!isascii(r->res_name[i]) || !isprint(r->res_name[i])) |
354 | print_name = 0; |
355 | } |
356 | |
357 | seq_puts(m: s, s: print_name ? "str " : "hex" ); |
358 | |
359 | for (i = 0; i < r->res_length; i++) { |
360 | if (print_name) |
361 | seq_printf(m: s, fmt: "%c" , r->res_name[i]); |
362 | else |
363 | seq_printf(m: s, fmt: " %02x" , (unsigned char)r->res_name[i]); |
364 | } |
365 | seq_putc(m: s, c: '\n'); |
366 | unlock_rsb(r); |
367 | } |
368 | |
369 | static void print_format5_lock(struct seq_file *s, struct dlm_lkb *lkb) |
370 | { |
371 | struct dlm_callback *cb; |
372 | |
373 | /* lkb_id lkb_flags mode flags sb_status sb_flags */ |
374 | |
375 | spin_lock(lock: &lkb->lkb_cb_lock); |
376 | list_for_each_entry(cb, &lkb->lkb_callbacks, list) { |
377 | seq_printf(m: s, fmt: "%x %x %d %x %d %x\n" , |
378 | lkb->lkb_id, |
379 | dlm_iflags_val(lkb), |
380 | cb->mode, |
381 | cb->flags, |
382 | cb->sb_status, |
383 | cb->sb_flags); |
384 | } |
385 | spin_unlock(lock: &lkb->lkb_cb_lock); |
386 | } |
387 | |
388 | static void print_format5(struct dlm_rsb *r, struct seq_file *s) |
389 | { |
390 | struct dlm_lkb *lkb; |
391 | |
392 | lock_rsb(r); |
393 | |
394 | list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { |
395 | print_format5_lock(s, lkb); |
396 | if (seq_has_overflowed(m: s)) |
397 | goto out; |
398 | } |
399 | |
400 | list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) { |
401 | print_format5_lock(s, lkb); |
402 | if (seq_has_overflowed(m: s)) |
403 | goto out; |
404 | } |
405 | |
406 | list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) { |
407 | print_format5_lock(s, lkb); |
408 | if (seq_has_overflowed(m: s)) |
409 | goto out; |
410 | } |
411 | out: |
412 | unlock_rsb(r); |
413 | } |
414 | |
415 | struct rsbtbl_iter { |
416 | struct dlm_rsb *rsb; |
417 | unsigned bucket; |
418 | int format; |
419 | int ; |
420 | }; |
421 | |
422 | /* |
423 | * If the buffer is full, seq_printf can be called again, but it |
424 | * does nothing. So, the these printing routines periodically check |
425 | * seq_has_overflowed to avoid wasting too much time trying to print to |
426 | * a full buffer. |
427 | */ |
428 | |
429 | static int table_seq_show(struct seq_file *seq, void *iter_ptr) |
430 | { |
431 | struct rsbtbl_iter *ri = iter_ptr; |
432 | |
433 | switch (ri->format) { |
434 | case 1: |
435 | print_format1(res: ri->rsb, s: seq); |
436 | break; |
437 | case 2: |
438 | if (ri->header) { |
439 | seq_puts(m: seq, s: "id nodeid remid pid xid exflags flags sts grmode rqmode time_ms r_nodeid r_len r_name\n" ); |
440 | ri->header = 0; |
441 | } |
442 | print_format2(r: ri->rsb, s: seq); |
443 | break; |
444 | case 3: |
445 | if (ri->header) { |
446 | seq_puts(m: seq, s: "version rsb 1.1 lvb 1.1 lkb 1.1\n" ); |
447 | ri->header = 0; |
448 | } |
449 | print_format3(r: ri->rsb, s: seq); |
450 | break; |
451 | case 4: |
452 | if (ri->header) { |
453 | seq_puts(m: seq, s: "version 4 rsb 2\n" ); |
454 | ri->header = 0; |
455 | } |
456 | print_format4(r: ri->rsb, s: seq); |
457 | break; |
458 | case 5: |
459 | if (ri->header) { |
460 | seq_puts(m: seq, s: "lkb_id lkb_flags mode flags sb_status sb_flags\n" ); |
461 | ri->header = 0; |
462 | } |
463 | print_format5(r: ri->rsb, s: seq); |
464 | break; |
465 | } |
466 | |
467 | return 0; |
468 | } |
469 | |
470 | static const struct seq_operations format1_seq_ops; |
471 | static const struct seq_operations format2_seq_ops; |
472 | static const struct seq_operations format3_seq_ops; |
473 | static const struct seq_operations format4_seq_ops; |
474 | static const struct seq_operations format5_seq_ops; |
475 | |
476 | static void *table_seq_start(struct seq_file *seq, loff_t *pos) |
477 | { |
478 | struct rb_root *tree; |
479 | struct rb_node *node; |
480 | struct dlm_ls *ls = seq->private; |
481 | struct rsbtbl_iter *ri; |
482 | struct dlm_rsb *r; |
483 | loff_t n = *pos; |
484 | unsigned bucket, entry; |
485 | int toss = (seq->op == &format4_seq_ops); |
486 | |
487 | bucket = n >> 32; |
488 | entry = n & ((1LL << 32) - 1); |
489 | |
490 | if (bucket >= ls->ls_rsbtbl_size) |
491 | return NULL; |
492 | |
493 | ri = kzalloc(size: sizeof(*ri), GFP_NOFS); |
494 | if (!ri) |
495 | return NULL; |
496 | if (n == 0) |
497 | ri->header = 1; |
498 | if (seq->op == &format1_seq_ops) |
499 | ri->format = 1; |
500 | if (seq->op == &format2_seq_ops) |
501 | ri->format = 2; |
502 | if (seq->op == &format3_seq_ops) |
503 | ri->format = 3; |
504 | if (seq->op == &format4_seq_ops) |
505 | ri->format = 4; |
506 | if (seq->op == &format5_seq_ops) |
507 | ri->format = 5; |
508 | |
509 | tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep; |
510 | |
511 | spin_lock(lock: &ls->ls_rsbtbl[bucket].lock); |
512 | if (!RB_EMPTY_ROOT(tree)) { |
513 | for (node = rb_first(tree); node; node = rb_next(node)) { |
514 | r = rb_entry(node, struct dlm_rsb, res_hashnode); |
515 | if (!entry--) { |
516 | dlm_hold_rsb(r); |
517 | ri->rsb = r; |
518 | ri->bucket = bucket; |
519 | spin_unlock(lock: &ls->ls_rsbtbl[bucket].lock); |
520 | return ri; |
521 | } |
522 | } |
523 | } |
524 | spin_unlock(lock: &ls->ls_rsbtbl[bucket].lock); |
525 | |
526 | /* |
527 | * move to the first rsb in the next non-empty bucket |
528 | */ |
529 | |
530 | /* zero the entry */ |
531 | n &= ~((1LL << 32) - 1); |
532 | |
533 | while (1) { |
534 | bucket++; |
535 | n += 1LL << 32; |
536 | |
537 | if (bucket >= ls->ls_rsbtbl_size) { |
538 | kfree(objp: ri); |
539 | return NULL; |
540 | } |
541 | tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep; |
542 | |
543 | spin_lock(lock: &ls->ls_rsbtbl[bucket].lock); |
544 | if (!RB_EMPTY_ROOT(tree)) { |
545 | node = rb_first(tree); |
546 | r = rb_entry(node, struct dlm_rsb, res_hashnode); |
547 | dlm_hold_rsb(r); |
548 | ri->rsb = r; |
549 | ri->bucket = bucket; |
550 | spin_unlock(lock: &ls->ls_rsbtbl[bucket].lock); |
551 | *pos = n; |
552 | return ri; |
553 | } |
554 | spin_unlock(lock: &ls->ls_rsbtbl[bucket].lock); |
555 | } |
556 | } |
557 | |
558 | static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos) |
559 | { |
560 | struct dlm_ls *ls = seq->private; |
561 | struct rsbtbl_iter *ri = iter_ptr; |
562 | struct rb_root *tree; |
563 | struct rb_node *next; |
564 | struct dlm_rsb *r, *rp; |
565 | loff_t n = *pos; |
566 | unsigned bucket; |
567 | int toss = (seq->op == &format4_seq_ops); |
568 | |
569 | bucket = n >> 32; |
570 | |
571 | /* |
572 | * move to the next rsb in the same bucket |
573 | */ |
574 | |
575 | spin_lock(lock: &ls->ls_rsbtbl[bucket].lock); |
576 | rp = ri->rsb; |
577 | next = rb_next(&rp->res_hashnode); |
578 | |
579 | if (next) { |
580 | r = rb_entry(next, struct dlm_rsb, res_hashnode); |
581 | dlm_hold_rsb(r); |
582 | ri->rsb = r; |
583 | spin_unlock(lock: &ls->ls_rsbtbl[bucket].lock); |
584 | dlm_put_rsb(r: rp); |
585 | ++*pos; |
586 | return ri; |
587 | } |
588 | spin_unlock(lock: &ls->ls_rsbtbl[bucket].lock); |
589 | dlm_put_rsb(r: rp); |
590 | |
591 | /* |
592 | * move to the first rsb in the next non-empty bucket |
593 | */ |
594 | |
595 | /* zero the entry */ |
596 | n &= ~((1LL << 32) - 1); |
597 | |
598 | while (1) { |
599 | bucket++; |
600 | n += 1LL << 32; |
601 | |
602 | if (bucket >= ls->ls_rsbtbl_size) { |
603 | kfree(objp: ri); |
604 | ++*pos; |
605 | return NULL; |
606 | } |
607 | tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep; |
608 | |
609 | spin_lock(lock: &ls->ls_rsbtbl[bucket].lock); |
610 | if (!RB_EMPTY_ROOT(tree)) { |
611 | next = rb_first(tree); |
612 | r = rb_entry(next, struct dlm_rsb, res_hashnode); |
613 | dlm_hold_rsb(r); |
614 | ri->rsb = r; |
615 | ri->bucket = bucket; |
616 | spin_unlock(lock: &ls->ls_rsbtbl[bucket].lock); |
617 | *pos = n; |
618 | return ri; |
619 | } |
620 | spin_unlock(lock: &ls->ls_rsbtbl[bucket].lock); |
621 | } |
622 | } |
623 | |
624 | static void table_seq_stop(struct seq_file *seq, void *iter_ptr) |
625 | { |
626 | struct rsbtbl_iter *ri = iter_ptr; |
627 | |
628 | if (ri) { |
629 | dlm_put_rsb(r: ri->rsb); |
630 | kfree(objp: ri); |
631 | } |
632 | } |
633 | |
634 | static const struct seq_operations format1_seq_ops = { |
635 | .start = table_seq_start, |
636 | .next = table_seq_next, |
637 | .stop = table_seq_stop, |
638 | .show = table_seq_show, |
639 | }; |
640 | |
641 | static const struct seq_operations format2_seq_ops = { |
642 | .start = table_seq_start, |
643 | .next = table_seq_next, |
644 | .stop = table_seq_stop, |
645 | .show = table_seq_show, |
646 | }; |
647 | |
648 | static const struct seq_operations format3_seq_ops = { |
649 | .start = table_seq_start, |
650 | .next = table_seq_next, |
651 | .stop = table_seq_stop, |
652 | .show = table_seq_show, |
653 | }; |
654 | |
655 | static const struct seq_operations format4_seq_ops = { |
656 | .start = table_seq_start, |
657 | .next = table_seq_next, |
658 | .stop = table_seq_stop, |
659 | .show = table_seq_show, |
660 | }; |
661 | |
662 | static const struct seq_operations format5_seq_ops = { |
663 | .start = table_seq_start, |
664 | .next = table_seq_next, |
665 | .stop = table_seq_stop, |
666 | .show = table_seq_show, |
667 | }; |
668 | |
669 | static const struct file_operations format1_fops; |
670 | static const struct file_operations format2_fops; |
671 | static const struct file_operations format3_fops; |
672 | static const struct file_operations format4_fops; |
673 | static const struct file_operations format5_fops; |
674 | |
675 | static int table_open1(struct inode *inode, struct file *file) |
676 | { |
677 | struct seq_file *seq; |
678 | int ret; |
679 | |
680 | ret = seq_open(file, &format1_seq_ops); |
681 | if (ret) |
682 | return ret; |
683 | |
684 | seq = file->private_data; |
685 | seq->private = inode->i_private; /* the dlm_ls */ |
686 | return 0; |
687 | } |
688 | |
689 | static int table_open2(struct inode *inode, struct file *file) |
690 | { |
691 | struct seq_file *seq; |
692 | int ret; |
693 | |
694 | ret = seq_open(file, &format2_seq_ops); |
695 | if (ret) |
696 | return ret; |
697 | |
698 | seq = file->private_data; |
699 | seq->private = inode->i_private; /* the dlm_ls */ |
700 | return 0; |
701 | } |
702 | |
703 | static ssize_t table_write2(struct file *file, const char __user *user_buf, |
704 | size_t count, loff_t *ppos) |
705 | { |
706 | struct seq_file *seq = file->private_data; |
707 | int n, len, lkb_nodeid, lkb_status, error; |
708 | char name[DLM_RESNAME_MAXLEN + 1] = {}; |
709 | struct dlm_ls *ls = seq->private; |
710 | unsigned int lkb_flags; |
711 | char buf[256] = {}; |
712 | uint32_t lkb_id; |
713 | |
714 | if (copy_from_user(to: buf, from: user_buf, |
715 | min_t(size_t, sizeof(buf) - 1, count))) |
716 | return -EFAULT; |
717 | |
718 | n = sscanf(buf, "%x %" __stringify(DLM_RESNAME_MAXLEN) "s %x %d %d" , |
719 | &lkb_id, name, &lkb_flags, &lkb_nodeid, &lkb_status); |
720 | if (n != 5) |
721 | return -EINVAL; |
722 | |
723 | len = strnlen(p: name, DLM_RESNAME_MAXLEN); |
724 | error = dlm_debug_add_lkb(ls, lkb_id, name, len, lkb_nodeid: lkb_flags, |
725 | lkb_flags: lkb_nodeid, lkb_status); |
726 | if (error) |
727 | return error; |
728 | |
729 | return count; |
730 | } |
731 | |
732 | static int table_open3(struct inode *inode, struct file *file) |
733 | { |
734 | struct seq_file *seq; |
735 | int ret; |
736 | |
737 | ret = seq_open(file, &format3_seq_ops); |
738 | if (ret) |
739 | return ret; |
740 | |
741 | seq = file->private_data; |
742 | seq->private = inode->i_private; /* the dlm_ls */ |
743 | return 0; |
744 | } |
745 | |
746 | static int table_open4(struct inode *inode, struct file *file) |
747 | { |
748 | struct seq_file *seq; |
749 | int ret; |
750 | |
751 | ret = seq_open(file, &format5_seq_ops); |
752 | if (ret) |
753 | return ret; |
754 | |
755 | seq = file->private_data; |
756 | seq->private = inode->i_private; /* the dlm_ls */ |
757 | return 0; |
758 | } |
759 | |
760 | static int table_open5(struct inode *inode, struct file *file) |
761 | { |
762 | struct seq_file *seq; |
763 | int ret; |
764 | |
765 | ret = seq_open(file, &format5_seq_ops); |
766 | if (ret) |
767 | return ret; |
768 | |
769 | seq = file->private_data; |
770 | seq->private = inode->i_private; /* the dlm_ls */ |
771 | return 0; |
772 | } |
773 | |
774 | static const struct file_operations format1_fops = { |
775 | .owner = THIS_MODULE, |
776 | .open = table_open1, |
777 | .read = seq_read, |
778 | .llseek = seq_lseek, |
779 | .release = seq_release |
780 | }; |
781 | |
782 | static const struct file_operations format2_fops = { |
783 | .owner = THIS_MODULE, |
784 | .open = table_open2, |
785 | .read = seq_read, |
786 | .write = table_write2, |
787 | .llseek = seq_lseek, |
788 | .release = seq_release |
789 | }; |
790 | |
791 | static const struct file_operations format3_fops = { |
792 | .owner = THIS_MODULE, |
793 | .open = table_open3, |
794 | .read = seq_read, |
795 | .llseek = seq_lseek, |
796 | .release = seq_release |
797 | }; |
798 | |
799 | static const struct file_operations format4_fops = { |
800 | .owner = THIS_MODULE, |
801 | .open = table_open4, |
802 | .read = seq_read, |
803 | .llseek = seq_lseek, |
804 | .release = seq_release |
805 | }; |
806 | |
807 | static const struct file_operations format5_fops = { |
808 | .owner = THIS_MODULE, |
809 | .open = table_open5, |
810 | .read = seq_read, |
811 | .llseek = seq_lseek, |
812 | .release = seq_release |
813 | }; |
814 | |
815 | /* |
816 | * dump lkb's on the ls_waiters list |
817 | */ |
818 | static ssize_t waiters_read(struct file *file, char __user *userbuf, |
819 | size_t count, loff_t *ppos) |
820 | { |
821 | struct dlm_ls *ls = file->private_data; |
822 | struct dlm_lkb *lkb; |
823 | size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv; |
824 | |
825 | mutex_lock(&debug_buf_lock); |
826 | mutex_lock(&ls->ls_waiters_mutex); |
827 | memset(debug_buf, 0, sizeof(debug_buf)); |
828 | |
829 | list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) { |
830 | ret = snprintf(buf: debug_buf + pos, size: len - pos, fmt: "%x %d %d %s\n" , |
831 | lkb->lkb_id, lkb->lkb_wait_type, |
832 | lkb->lkb_nodeid, lkb->lkb_resource->res_name); |
833 | if (ret >= len - pos) |
834 | break; |
835 | pos += ret; |
836 | } |
837 | mutex_unlock(lock: &ls->ls_waiters_mutex); |
838 | |
839 | rv = simple_read_from_buffer(to: userbuf, count, ppos, from: debug_buf, available: pos); |
840 | mutex_unlock(lock: &debug_buf_lock); |
841 | return rv; |
842 | } |
843 | |
844 | static ssize_t waiters_write(struct file *file, const char __user *user_buf, |
845 | size_t count, loff_t *ppos) |
846 | { |
847 | struct dlm_ls *ls = file->private_data; |
848 | int mstype, to_nodeid; |
849 | char buf[128] = {}; |
850 | uint32_t lkb_id; |
851 | int n, error; |
852 | |
853 | if (copy_from_user(to: buf, from: user_buf, |
854 | min_t(size_t, sizeof(buf) - 1, count))) |
855 | return -EFAULT; |
856 | |
857 | n = sscanf(buf, "%x %d %d" , &lkb_id, &mstype, &to_nodeid); |
858 | if (n != 3) |
859 | return -EINVAL; |
860 | |
861 | error = dlm_debug_add_lkb_to_waiters(ls, lkb_id, mstype, to_nodeid); |
862 | if (error) |
863 | return error; |
864 | |
865 | return count; |
866 | } |
867 | |
868 | static const struct file_operations waiters_fops = { |
869 | .owner = THIS_MODULE, |
870 | .open = simple_open, |
871 | .read = waiters_read, |
872 | .write = waiters_write, |
873 | .llseek = default_llseek, |
874 | }; |
875 | |
876 | void dlm_delete_debug_file(struct dlm_ls *ls) |
877 | { |
878 | debugfs_remove(dentry: ls->ls_debug_rsb_dentry); |
879 | debugfs_remove(dentry: ls->ls_debug_waiters_dentry); |
880 | debugfs_remove(dentry: ls->ls_debug_locks_dentry); |
881 | debugfs_remove(dentry: ls->ls_debug_all_dentry); |
882 | debugfs_remove(dentry: ls->ls_debug_toss_dentry); |
883 | debugfs_remove(dentry: ls->ls_debug_queued_asts_dentry); |
884 | } |
885 | |
886 | static int dlm_state_show(struct seq_file *file, void *offset) |
887 | { |
888 | seq_printf(m: file, fmt: "%s\n" , dlm_midcomms_state(node: file->private)); |
889 | return 0; |
890 | } |
891 | DEFINE_SHOW_ATTRIBUTE(dlm_state); |
892 | |
893 | static int dlm_flags_show(struct seq_file *file, void *offset) |
894 | { |
895 | seq_printf(m: file, fmt: "%lu\n" , dlm_midcomms_flags(node: file->private)); |
896 | return 0; |
897 | } |
898 | DEFINE_SHOW_ATTRIBUTE(dlm_flags); |
899 | |
900 | static int dlm_send_queue_cnt_show(struct seq_file *file, void *offset) |
901 | { |
902 | seq_printf(m: file, fmt: "%d\n" , dlm_midcomms_send_queue_cnt(node: file->private)); |
903 | return 0; |
904 | } |
905 | DEFINE_SHOW_ATTRIBUTE(dlm_send_queue_cnt); |
906 | |
907 | static int dlm_version_show(struct seq_file *file, void *offset) |
908 | { |
909 | seq_printf(m: file, fmt: "0x%08x\n" , dlm_midcomms_version(node: file->private)); |
910 | return 0; |
911 | } |
912 | DEFINE_SHOW_ATTRIBUTE(dlm_version); |
913 | |
914 | static ssize_t dlm_rawmsg_write(struct file *fp, const char __user *user_buf, |
915 | size_t count, loff_t *ppos) |
916 | { |
917 | void *buf; |
918 | int ret; |
919 | |
920 | if (count > PAGE_SIZE || count < sizeof(struct dlm_header)) |
921 | return -EINVAL; |
922 | |
923 | buf = kmalloc(PAGE_SIZE, GFP_NOFS); |
924 | if (!buf) |
925 | return -ENOMEM; |
926 | |
927 | if (copy_from_user(to: buf, from: user_buf, n: count)) { |
928 | ret = -EFAULT; |
929 | goto out; |
930 | } |
931 | |
932 | ret = dlm_midcomms_rawmsg_send(node: fp->private_data, buf, buflen: count); |
933 | if (ret) |
934 | goto out; |
935 | |
936 | kfree(objp: buf); |
937 | return count; |
938 | |
939 | out: |
940 | kfree(objp: buf); |
941 | return ret; |
942 | } |
943 | |
944 | static const struct file_operations dlm_rawmsg_fops = { |
945 | .open = simple_open, |
946 | .write = dlm_rawmsg_write, |
947 | .llseek = no_llseek, |
948 | }; |
949 | |
950 | void *dlm_create_debug_comms_file(int nodeid, void *data) |
951 | { |
952 | struct dentry *d_node; |
953 | char name[256]; |
954 | |
955 | memset(name, 0, sizeof(name)); |
956 | snprintf(buf: name, size: 256, fmt: "%d" , nodeid); |
957 | |
958 | d_node = debugfs_create_dir(name, parent: dlm_comms); |
959 | debugfs_create_file(name: "state" , mode: 0444, parent: d_node, data, fops: &dlm_state_fops); |
960 | debugfs_create_file(name: "flags" , mode: 0444, parent: d_node, data, fops: &dlm_flags_fops); |
961 | debugfs_create_file(name: "send_queue_count" , mode: 0444, parent: d_node, data, |
962 | fops: &dlm_send_queue_cnt_fops); |
963 | debugfs_create_file(name: "version" , mode: 0444, parent: d_node, data, fops: &dlm_version_fops); |
964 | debugfs_create_file(name: "rawmsg" , mode: 0200, parent: d_node, data, fops: &dlm_rawmsg_fops); |
965 | |
966 | return d_node; |
967 | } |
968 | |
969 | void dlm_delete_debug_comms_file(void *ctx) |
970 | { |
971 | debugfs_remove(dentry: ctx); |
972 | } |
973 | |
974 | void dlm_create_debug_file(struct dlm_ls *ls) |
975 | { |
976 | /* Reserve enough space for the longest file name */ |
977 | char name[DLM_LOCKSPACE_LEN + sizeof("_queued_asts" )]; |
978 | |
979 | /* format 1 */ |
980 | |
981 | ls->ls_debug_rsb_dentry = debugfs_create_file(name: ls->ls_name, |
982 | S_IFREG | S_IRUGO, |
983 | parent: dlm_root, |
984 | data: ls, |
985 | fops: &format1_fops); |
986 | |
987 | /* format 2 */ |
988 | |
989 | snprintf(buf: name, size: sizeof(name), fmt: "%s_locks" , ls->ls_name); |
990 | |
991 | ls->ls_debug_locks_dentry = debugfs_create_file(name, |
992 | mode: 0644, |
993 | parent: dlm_root, |
994 | data: ls, |
995 | fops: &format2_fops); |
996 | |
997 | /* format 3 */ |
998 | |
999 | snprintf(buf: name, size: sizeof(name), fmt: "%s_all" , ls->ls_name); |
1000 | |
1001 | ls->ls_debug_all_dentry = debugfs_create_file(name, |
1002 | S_IFREG | S_IRUGO, |
1003 | parent: dlm_root, |
1004 | data: ls, |
1005 | fops: &format3_fops); |
1006 | |
1007 | /* format 4 */ |
1008 | |
1009 | snprintf(buf: name, size: sizeof(name), fmt: "%s_toss" , ls->ls_name); |
1010 | |
1011 | ls->ls_debug_toss_dentry = debugfs_create_file(name, |
1012 | S_IFREG | S_IRUGO, |
1013 | parent: dlm_root, |
1014 | data: ls, |
1015 | fops: &format4_fops); |
1016 | |
1017 | snprintf(buf: name, size: sizeof(name), fmt: "%s_waiters" , ls->ls_name); |
1018 | |
1019 | ls->ls_debug_waiters_dentry = debugfs_create_file(name, |
1020 | mode: 0644, |
1021 | parent: dlm_root, |
1022 | data: ls, |
1023 | fops: &waiters_fops); |
1024 | |
1025 | /* format 5 */ |
1026 | |
1027 | snprintf(buf: name, size: sizeof(name), fmt: "%s_queued_asts" , ls->ls_name); |
1028 | |
1029 | ls->ls_debug_queued_asts_dentry = debugfs_create_file(name, |
1030 | mode: 0644, |
1031 | parent: dlm_root, |
1032 | data: ls, |
1033 | fops: &format5_fops); |
1034 | } |
1035 | |
1036 | void __init dlm_register_debugfs(void) |
1037 | { |
1038 | mutex_init(&debug_buf_lock); |
1039 | dlm_root = debugfs_create_dir(name: "dlm" , NULL); |
1040 | dlm_comms = debugfs_create_dir(name: "comms" , parent: dlm_root); |
1041 | } |
1042 | |
1043 | void dlm_unregister_debugfs(void) |
1044 | { |
1045 | debugfs_remove(dentry: dlm_root); |
1046 | } |
1047 | |
1048 | |