| 1 | |
| 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(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
|
| 56 |
|
| 57 | if (lkb->lkb_status == DLM_LKSTS_CONVERT ||
|
| 58 | lkb->lkb_status == DLM_LKSTS_WAITING)
|
| 59 | seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
|
| 60 |
|
| 61 | if (lkb->lkb_nodeid) {
|
| 62 | if (lkb->lkb_nodeid != res->res_nodeid)
|
| 63 | seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
|
| 64 | lkb->lkb_remid);
|
| 65 | else
|
| 66 | seq_printf(s, " Master: %08x", lkb->lkb_remid);
|
| 67 | }
|
| 68 |
|
| 69 | if (lkb->lkb_wait_type)
|
| 70 | seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
|
| 71 |
|
| 72 | seq_putc(s, '\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(res);
|
| 81 |
|
| 82 | seq_printf(s, "\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(s, "%c", res->res_name[i]);
|
| 87 | else
|
| 88 | seq_printf(s, "%c", '.');
|
| 89 | }
|
| 90 |
|
| 91 | if (res->res_nodeid > 0)
|
| 92 | seq_printf(s, "\"\nLocal Copy, Master is node %d\n",
|
| 93 | res->res_nodeid);
|
| 94 | else if (res->res_nodeid == 0)
|
| 95 | seq_puts(s, "\"\nMaster Copy\n");
|
| 96 | else if (res->res_nodeid == -1)
|
| 97 | seq_printf(s, "\"\nLooking up master (lkid %x)\n",
|
| 98 | res->res_first_lkid);
|
| 99 | else
|
| 100 | seq_printf(s, "\"\nInvalid master %d\n", res->res_nodeid);
|
| 101 | if (seq_has_overflowed(s))
|
| 102 | goto out;
|
| 103 |
|
| 104 |
|
| 105 | if (res->res_lvbptr) {
|
| 106 | seq_puts(s, "LVB: ");
|
| 107 | for (i = 0; i < lvblen; i++) {
|
| 108 | if (i == lvblen / 2)
|
| 109 | seq_puts(s, "\n ");
|
| 110 | seq_printf(s, "%02x ",
|
| 111 | (unsigned char) res->res_lvbptr[i]);
|
| 112 | }
|
| 113 | if (rsb_flag(res, RSB_VALNOTVALID))
|
| 114 | seq_puts(s, " (INVALID)");
|
| 115 | seq_putc(s, '\n');
|
| 116 | if (seq_has_overflowed(s))
|
| 117 | goto out;
|
| 118 | }
|
| 119 |
|
| 120 | root_list = !list_empty(&res->res_root_list);
|
| 121 | recover_list = !list_empty(&res->res_recover_list);
|
| 122 |
|
| 123 | if (root_list || recover_list) {
|
| 124 | seq_printf(s, "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 |
|
| 130 | seq_puts(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(s))
|
| 134 | goto out;
|
| 135 | }
|
| 136 |
|
| 137 | seq_puts(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(s))
|
| 141 | goto out;
|
| 142 | }
|
| 143 |
|
| 144 | seq_puts(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(s))
|
| 148 | goto out;
|
| 149 | }
|
| 150 |
|
| 151 | if (list_empty(&res->res_lookup))
|
| 152 | goto out;
|
| 153 |
|
| 154 | seq_puts(s, "Lookup Queue\n");
|
| 155 | list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
|
| 156 | seq_printf(s, "%08x %s",
|
| 157 | lkb->lkb_id, print_lockmode(lkb->lkb_rqmode));
|
| 158 | if (lkb->lkb_wait_type)
|
| 159 | seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
|
| 160 | seq_putc(s, '\n');
|
| 161 | if (seq_has_overflowed(s))
|
| 162 | goto out;
|
| 163 | }
|
| 164 | out:
|
| 165 | unlock_rsb(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 |
|
| 180 | us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_timestamp));
|
| 181 |
|
| 182 | |
| 183 | r_nodeid r_len r_name
|
| 184 |
|
| 185 | seq_printf(s, "%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(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(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(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(s, "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_cb_mode,
|
| 251 | rsb_lookup,
|
| 252 | lkb->lkb_wait_type,
|
| 253 | lkb->lkb_lvbseq,
|
| 254 | (unsigned long long)ktime_to_ns(lkb->lkb_timestamp),
|
| 255 | (unsigned long long)ktime_to_ns(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(s, "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(&r->res_root_list),
|
| 272 | !list_empty(&r->res_recover_list),
|
| 273 | r->res_recover_locks_count,
|
| 274 | r->res_length);
|
| 275 | if (seq_has_overflowed(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(s, print_name ? "str " : "hex");
|
| 284 |
|
| 285 | for (i = 0; i < r->res_length; i++) {
|
| 286 | if (print_name)
|
| 287 | seq_printf(s, "%c", r->res_name[i]);
|
| 288 | else
|
| 289 | seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
|
| 290 | }
|
| 291 | seq_putc(s, '\n');
|
| 292 | if (seq_has_overflowed(s))
|
| 293 | goto out;
|
| 294 |
|
| 295 | if (!r->res_lvbptr)
|
| 296 | goto do_locks;
|
| 297 |
|
| 298 | seq_printf(s, "lvb %u %d", r->res_lvbseq, lvblen);
|
| 299 |
|
| 300 | for (i = 0; i < lvblen; i++)
|
| 301 | seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]);
|
| 302 | seq_putc(s, '\n');
|
| 303 | if (seq_has_overflowed(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, 0);
|
| 309 | if (seq_has_overflowed(s))
|
| 310 | goto out;
|
| 311 | }
|
| 312 |
|
| 313 | list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
|
| 314 | print_format3_lock(s, lkb, 0);
|
| 315 | if (seq_has_overflowed(s))
|
| 316 | goto out;
|
| 317 | }
|
| 318 |
|
| 319 | list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
|
| 320 | print_format3_lock(s, lkb, 0);
|
| 321 | if (seq_has_overflowed(s))
|
| 322 | goto out;
|
| 323 | }
|
| 324 |
|
| 325 | list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) {
|
| 326 | print_format3_lock(s, lkb, 1);
|
| 327 | if (seq_has_overflowed(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(s, "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(s, print_name ? "str " : "hex");
|
| 358 |
|
| 359 | for (i = 0; i < r->res_length; i++) {
|
| 360 | if (print_name)
|
| 361 | seq_printf(s, "%c", r->res_name[i]);
|
| 362 | else
|
| 363 | seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
|
| 364 | }
|
| 365 | seq_putc(s, '\n');
|
| 366 | unlock_rsb(r);
|
| 367 | }
|
| 368 |
|
| 369 | static const struct seq_operations format1_seq_ops;
|
| 370 | static const struct seq_operations format2_seq_ops;
|
| 371 | static const struct seq_operations format3_seq_ops;
|
| 372 | static const struct seq_operations format4_seq_ops;
|
| 373 |
|
| 374 | |
| 375 | * If the buffer is full, seq_printf can be called again, but it
|
| 376 | * does nothing. So, the these printing routines periodically check
|
| 377 | * seq_has_overflowed to avoid wasting too much time trying to print to
|
| 378 | * a full buffer.
|
| 379 |
|
| 380 |
|
| 381 | static int table_seq_show(struct seq_file *seq, void *iter_ptr)
|
| 382 | {
|
| 383 | struct dlm_rsb *rsb = list_entry(iter_ptr, struct dlm_rsb, res_slow_list);
|
| 384 |
|
| 385 | if (seq->op == &format1_seq_ops)
|
| 386 | print_format1(rsb, seq);
|
| 387 | else if (seq->op == &format2_seq_ops)
|
| 388 | print_format2(rsb, seq);
|
| 389 | else if (seq->op == &format3_seq_ops)
|
| 390 | print_format3(rsb, seq);
|
| 391 | else if (seq->op == &format4_seq_ops)
|
| 392 | print_format4(rsb, seq);
|
| 393 |
|
| 394 | return 0;
|
| 395 | }
|
| 396 |
|
| 397 | static void *table_seq_start(struct seq_file *seq, loff_t *pos)
|
| 398 | {
|
| 399 | struct dlm_ls *ls = seq->private;
|
| 400 | struct list_head *list;
|
| 401 |
|
| 402 | if (!*pos) {
|
| 403 | if (seq->op == &format2_seq_ops)
|
| 404 | seq_puts(seq, "id nodeid remid pid xid exflags flags sts grmode rqmode time_ms r_nodeid r_len r_name\n");
|
| 405 | else if (seq->op == &format3_seq_ops)
|
| 406 | seq_puts(seq, "rsb ptr nodeid first_lkid flags !root_list_empty !recover_list_empty recover_locks_count len\n");
|
| 407 | else if (seq->op == &format4_seq_ops)
|
| 408 | seq_puts(seq, "rsb ptr nodeid master_nodeid dir_nodeid our_nodeid toss_time flags len str|hex name\n");
|
| 409 | }
|
| 410 |
|
| 411 | if (seq->op == &format4_seq_ops)
|
| 412 | list = &ls->ls_slow_inactive;
|
| 413 | else
|
| 414 | list = &ls->ls_slow_active;
|
| 415 |
|
| 416 | read_lock_bh(&ls->ls_rsbtbl_lock);
|
| 417 | return seq_list_start(list, *pos);
|
| 418 | }
|
| 419 |
|
| 420 | static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
|
| 421 | {
|
| 422 | struct dlm_ls *ls = seq->private;
|
| 423 | struct list_head *list;
|
| 424 |
|
| 425 | if (seq->op == &format4_seq_ops)
|
| 426 | list = &ls->ls_slow_inactive;
|
| 427 | else
|
| 428 | list = &ls->ls_slow_active;
|
| 429 |
|
| 430 | return seq_list_next(iter_ptr, list, pos);
|
| 431 | }
|
| 432 |
|
| 433 | static void table_seq_stop(struct seq_file *seq, void *iter_ptr)
|
| 434 | {
|
| 435 | struct dlm_ls *ls = seq->private;
|
| 436 |
|
| 437 | read_unlock_bh(&ls->ls_rsbtbl_lock);
|
| 438 | }
|
| 439 |
|
| 440 | static const struct seq_operations format1_seq_ops = {
|
| 441 | .start = table_seq_start,
|
| 442 | .next = table_seq_next,
|
| 443 | .stop = table_seq_stop,
|
| 444 | .show = table_seq_show,
|
| 445 | };
|
| 446 |
|
| 447 | static const struct seq_operations format2_seq_ops = {
|
| 448 | .start = table_seq_start,
|
| 449 | .next = table_seq_next,
|
| 450 | .stop = table_seq_stop,
|
| 451 | .show = table_seq_show,
|
| 452 | };
|
| 453 |
|
| 454 | static const struct seq_operations format3_seq_ops = {
|
| 455 | .start = table_seq_start,
|
| 456 | .next = table_seq_next,
|
| 457 | .stop = table_seq_stop,
|
| 458 | .show = table_seq_show,
|
| 459 | };
|
| 460 |
|
| 461 | static const struct seq_operations format4_seq_ops = {
|
| 462 | .start = table_seq_start,
|
| 463 | .next = table_seq_next,
|
| 464 | .stop = table_seq_stop,
|
| 465 | .show = table_seq_show,
|
| 466 | };
|
| 467 |
|
| 468 | static const struct file_operations format1_fops;
|
| 469 | static const struct file_operations format2_fops;
|
| 470 | static const struct file_operations format3_fops;
|
| 471 | static const struct file_operations format4_fops;
|
| 472 |
|
| 473 | static int table_open1(struct inode *inode, struct file *file)
|
| 474 | {
|
| 475 | struct seq_file *seq;
|
| 476 | int ret;
|
| 477 |
|
| 478 | ret = seq_open(file, &format1_seq_ops);
|
| 479 | if (ret)
|
| 480 | return ret;
|
| 481 |
|
| 482 | seq = file->private_data;
|
| 483 | seq->private = inode->i_private;
|
| 484 | return 0;
|
| 485 | }
|
| 486 |
|
| 487 | static int table_open2(struct inode *inode, struct file *file)
|
| 488 | {
|
| 489 | struct seq_file *seq;
|
| 490 | int ret;
|
| 491 |
|
| 492 | ret = seq_open(file, &format2_seq_ops);
|
| 493 | if (ret)
|
| 494 | return ret;
|
| 495 |
|
| 496 | seq = file->private_data;
|
| 497 | seq->private = inode->i_private;
|
| 498 | return 0;
|
| 499 | }
|
| 500 |
|
| 501 | static ssize_t table_write2(struct file *file, const char __user *user_buf,
|
| 502 | size_t count, loff_t *ppos)
|
| 503 | {
|
| 504 | struct seq_file *seq = file->private_data;
|
| 505 | int n, len, lkb_nodeid, lkb_status, error;
|
| 506 | char name[DLM_RESNAME_MAXLEN + 1] = {};
|
| 507 | struct dlm_ls *ls = seq->private;
|
| 508 | unsigned int lkb_flags;
|
| 509 | char buf[256] = {};
|
| 510 | uint32_t lkb_id;
|
| 511 |
|
| 512 | if (copy_from_user(buf, user_buf,
|
| 513 | min_t(size_t, sizeof(buf) - 1, count)))
|
| 514 | return -EFAULT;
|
| 515 |
|
| 516 | n = sscanf(buf, "%x %" __stringify(DLM_RESNAME_MAXLEN) "s %x %d %d",
|
| 517 | &lkb_id, name, &lkb_flags, &lkb_nodeid, &lkb_status);
|
| 518 | if (n != 5)
|
| 519 | return -EINVAL;
|
| 520 |
|
| 521 | len = strnlen(name, DLM_RESNAME_MAXLEN);
|
| 522 | error = dlm_debug_add_lkb(ls, lkb_id, name, len, lkb_flags,
|
| 523 | lkb_nodeid, lkb_status);
|
| 524 | if (error)
|
| 525 | return error;
|
| 526 |
|
| 527 | return count;
|
| 528 | }
|
| 529 |
|
| 530 | static int table_open3(struct inode *inode, struct file *file)
|
| 531 | {
|
| 532 | struct seq_file *seq;
|
| 533 | int ret;
|
| 534 |
|
| 535 | ret = seq_open(file, &format3_seq_ops);
|
| 536 | if (ret)
|
| 537 | return ret;
|
| 538 |
|
| 539 | seq = file->private_data;
|
| 540 | seq->private = inode->i_private;
|
| 541 | return 0;
|
| 542 | }
|
| 543 |
|
| 544 | static int table_open4(struct inode *inode, struct file *file)
|
| 545 | {
|
| 546 | struct seq_file *seq;
|
| 547 | int ret;
|
| 548 |
|
| 549 | ret = seq_open(file, &format4_seq_ops);
|
| 550 | if (ret)
|
| 551 | return ret;
|
| 552 |
|
| 553 | seq = file->private_data;
|
| 554 | seq->private = inode->i_private;
|
| 555 | return 0;
|
| 556 | }
|
| 557 |
|
| 558 | static const struct file_operations format1_fops = {
|
| 559 | .owner = THIS_MODULE,
|
| 560 | .open = table_open1,
|
| 561 | .read = seq_read,
|
| 562 | .llseek = seq_lseek,
|
| 563 | .release = seq_release
|
| 564 | };
|
| 565 |
|
| 566 | static const struct file_operations format2_fops = {
|
| 567 | .owner = THIS_MODULE,
|
| 568 | .open = table_open2,
|
| 569 | .read = seq_read,
|
| 570 | .write = table_write2,
|
| 571 | .llseek = seq_lseek,
|
| 572 | .release = seq_release
|
| 573 | };
|
| 574 |
|
| 575 | static const struct file_operations format3_fops = {
|
| 576 | .owner = THIS_MODULE,
|
| 577 | .open = table_open3,
|
| 578 | .read = seq_read,
|
| 579 | .llseek = seq_lseek,
|
| 580 | .release = seq_release
|
| 581 | };
|
| 582 |
|
| 583 | static const struct file_operations format4_fops = {
|
| 584 | .owner = THIS_MODULE,
|
| 585 | .open = table_open4,
|
| 586 | .read = seq_read,
|
| 587 | .llseek = seq_lseek,
|
| 588 | .release = seq_release
|
| 589 | };
|
| 590 |
|
| 591 | |
| 592 | * dump lkb's on the ls_waiters list
|
| 593 |
|
| 594 | static ssize_t waiters_read(struct file *file, char __user *userbuf,
|
| 595 | size_t count, loff_t *ppos)
|
| 596 | {
|
| 597 | struct dlm_ls *ls = file->private_data;
|
| 598 | struct dlm_lkb *lkb;
|
| 599 | size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret;
|
| 600 | ssize_t rv;
|
| 601 |
|
| 602 | mutex_lock(&debug_buf_lock);
|
| 603 | ret = dlm_lock_recovery_try(ls);
|
| 604 | if (!ret) {
|
| 605 | rv = -EAGAIN;
|
| 606 | goto out;
|
| 607 | }
|
| 608 |
|
| 609 | spin_lock_bh(&ls->ls_waiters_lock);
|
| 610 | memset(debug_buf, 0, sizeof(debug_buf));
|
| 611 |
|
| 612 | list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
|
| 613 | ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n",
|
| 614 | lkb->lkb_id, lkb->lkb_wait_type,
|
| 615 | lkb->lkb_nodeid, lkb->lkb_resource->res_name);
|
| 616 | if (ret >= len - pos)
|
| 617 | break;
|
| 618 | pos += ret;
|
| 619 | }
|
| 620 | spin_unlock_bh(&ls->ls_waiters_lock);
|
| 621 | dlm_unlock_recovery(ls);
|
| 622 |
|
| 623 | rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);
|
| 624 | out:
|
| 625 | mutex_unlock(&debug_buf_lock);
|
| 626 | return rv;
|
| 627 | }
|
| 628 |
|
| 629 | static ssize_t waiters_write(struct file *file, const char __user *user_buf,
|
| 630 | size_t count, loff_t *ppos)
|
| 631 | {
|
| 632 | struct dlm_ls *ls = file->private_data;
|
| 633 | int mstype, to_nodeid;
|
| 634 | char buf[128] = {};
|
| 635 | uint32_t lkb_id;
|
| 636 | int n, error;
|
| 637 |
|
| 638 | if (copy_from_user(buf, user_buf,
|
| 639 | min_t(size_t, sizeof(buf) - 1, count)))
|
| 640 | return -EFAULT;
|
| 641 |
|
| 642 | n = sscanf(buf, "%x %d %d", &lkb_id, &mstype, &to_nodeid);
|
| 643 | if (n != 3)
|
| 644 | return -EINVAL;
|
| 645 |
|
| 646 | error = dlm_lock_recovery_try(ls);
|
| 647 | if (!error)
|
| 648 | return -EAGAIN;
|
| 649 |
|
| 650 | error = dlm_debug_add_lkb_to_waiters(ls, lkb_id, mstype, to_nodeid);
|
| 651 | dlm_unlock_recovery(ls);
|
| 652 | if (error)
|
| 653 | return error;
|
| 654 |
|
| 655 | return count;
|
| 656 | }
|
| 657 |
|
| 658 | static const struct file_operations waiters_fops = {
|
| 659 | .owner = THIS_MODULE,
|
| 660 | .open = simple_open,
|
| 661 | .read = waiters_read,
|
| 662 | .write = waiters_write,
|
| 663 | .llseek = default_llseek,
|
| 664 | };
|
| 665 |
|
| 666 | void dlm_delete_debug_file(struct dlm_ls *ls)
|
| 667 | {
|
| 668 | debugfs_remove(ls->ls_debug_rsb_dentry);
|
| 669 | debugfs_remove(ls->ls_debug_waiters_dentry);
|
| 670 | debugfs_remove(ls->ls_debug_locks_dentry);
|
| 671 | debugfs_remove(ls->ls_debug_all_dentry);
|
| 672 | debugfs_remove(ls->ls_debug_toss_dentry);
|
| 673 | debugfs_remove(ls->ls_debug_queued_asts_dentry);
|
| 674 | }
|
| 675 |
|
| 676 | static int dlm_state_show(struct seq_file *file, void *offset)
|
| 677 | {
|
| 678 | seq_printf(file, "%s\n", dlm_midcomms_state(file->private));
|
| 679 | return 0;
|
| 680 | }
|
| 681 | DEFINE_SHOW_ATTRIBUTE(dlm_state);
|
| 682 |
|
| 683 | static int dlm_flags_show(struct seq_file *file, void *offset)
|
| 684 | {
|
| 685 | seq_printf(file, "%lu\n", dlm_midcomms_flags(file->private));
|
| 686 | return 0;
|
| 687 | }
|
| 688 | DEFINE_SHOW_ATTRIBUTE(dlm_flags);
|
| 689 |
|
| 690 | static int dlm_send_queue_cnt_show(struct seq_file *file, void *offset)
|
| 691 | {
|
| 692 | seq_printf(file, "%d\n", dlm_midcomms_send_queue_cnt(file->private));
|
| 693 | return 0;
|
| 694 | }
|
| 695 | DEFINE_SHOW_ATTRIBUTE(dlm_send_queue_cnt);
|
| 696 |
|
| 697 | static int dlm_version_show(struct seq_file *file, void *offset)
|
| 698 | {
|
| 699 | seq_printf(file, "0x%08x\n", dlm_midcomms_version(file->private));
|
| 700 | return 0;
|
| 701 | }
|
| 702 | DEFINE_SHOW_ATTRIBUTE(dlm_version);
|
| 703 |
|
| 704 | static ssize_t dlm_rawmsg_write(struct file *fp, const char __user *user_buf,
|
| 705 | size_t count, loff_t *ppos)
|
| 706 | {
|
| 707 | void *buf;
|
| 708 | int ret;
|
| 709 |
|
| 710 | if (count > PAGE_SIZE || count < sizeof(struct dlm_header))
|
| 711 | return -EINVAL;
|
| 712 |
|
| 713 | buf = kmalloc(PAGE_SIZE, GFP_NOFS);
|
| 714 | if (!buf)
|
| 715 | return -ENOMEM;
|
| 716 |
|
| 717 | if (copy_from_user(buf, user_buf, count)) {
|
| 718 | ret = -EFAULT;
|
| 719 | goto out;
|
| 720 | }
|
| 721 |
|
| 722 | ret = dlm_midcomms_rawmsg_send(fp->private_data, buf, count);
|
| 723 | if (ret)
|
| 724 | goto out;
|
| 725 |
|
| 726 | kfree(buf);
|
| 727 | return count;
|
| 728 |
|
| 729 | out:
|
| 730 | kfree(buf);
|
| 731 | return ret;
|
| 732 | }
|
| 733 |
|
| 734 | static const struct file_operations dlm_rawmsg_fops = {
|
| 735 | .open = simple_open,
|
| 736 | .write = dlm_rawmsg_write,
|
| 737 | };
|
| 738 |
|
| 739 | void *dlm_create_debug_comms_file(int nodeid, void *data)
|
| 740 | {
|
| 741 | struct dentry *d_node;
|
| 742 | char name[256];
|
| 743 |
|
| 744 | memset(name, 0, sizeof(name));
|
| 745 | snprintf(name, 256, "%d", nodeid);
|
| 746 |
|
| 747 | d_node = debugfs_create_dir(name, dlm_comms);
|
| 748 | debugfs_create_file("state", 0444, d_node, data, &dlm_state_fops);
|
| 749 | debugfs_create_file("flags", 0444, d_node, data, &dlm_flags_fops);
|
| 750 | debugfs_create_file("send_queue_count", 0444, d_node, data,
|
| 751 | &dlm_send_queue_cnt_fops);
|
| 752 | debugfs_create_file("version", 0444, d_node, data, &dlm_version_fops);
|
| 753 | debugfs_create_file("rawmsg", 0200, d_node, data, &dlm_rawmsg_fops);
|
| 754 |
|
| 755 | return d_node;
|
| 756 | }
|
| 757 |
|
| 758 | void dlm_delete_debug_comms_file(void *ctx)
|
| 759 | {
|
| 760 | debugfs_remove(ctx);
|
| 761 | }
|
| 762 |
|
| 763 | void dlm_create_debug_file(struct dlm_ls *ls)
|
| 764 | {
|
| 765 |
|
| 766 | char name[DLM_LOCKSPACE_LEN + sizeof("_queued_asts")];
|
| 767 |
|
| 768 |
|
| 769 |
|
| 770 | ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,
|
| 771 | S_IFREG | S_IRUGO,
|
| 772 | dlm_root,
|
| 773 | ls,
|
| 774 | &format1_fops);
|
| 775 |
|
| 776 |
|
| 777 |
|
| 778 | snprintf(name, sizeof(name), "%s_locks", ls->ls_name);
|
| 779 |
|
| 780 | ls->ls_debug_locks_dentry = debugfs_create_file(name,
|
| 781 | 0644,
|
| 782 | dlm_root,
|
| 783 | ls,
|
| 784 | &format2_fops);
|
| 785 |
|
| 786 |
|
| 787 |
|
| 788 | snprintf(name, sizeof(name), "%s_all", ls->ls_name);
|
| 789 |
|
| 790 | ls->ls_debug_all_dentry = debugfs_create_file(name,
|
| 791 | S_IFREG | S_IRUGO,
|
| 792 | dlm_root,
|
| 793 | ls,
|
| 794 | &format3_fops);
|
| 795 |
|
| 796 |
|
| 797 |
|
| 798 | snprintf(name, sizeof(name), "%s_toss", ls->ls_name);
|
| 799 |
|
| 800 | ls->ls_debug_toss_dentry = debugfs_create_file(name,
|
| 801 | S_IFREG | S_IRUGO,
|
| 802 | dlm_root,
|
| 803 | ls,
|
| 804 | &format4_fops);
|
| 805 |
|
| 806 | snprintf(name, sizeof(name), "%s_waiters", ls->ls_name);
|
| 807 |
|
| 808 | ls->ls_debug_waiters_dentry = debugfs_create_file(name,
|
| 809 | 0644,
|
| 810 | dlm_root,
|
| 811 | ls,
|
| 812 | &waiters_fops);
|
| 813 | }
|
| 814 |
|
| 815 | void __init dlm_register_debugfs(void)
|
| 816 | {
|
| 817 | mutex_init(&debug_buf_lock);
|
| 818 | dlm_root = debugfs_create_dir("dlm", NULL);
|
| 819 | dlm_comms = debugfs_create_dir("comms", dlm_root);
|
| 820 | }
|
| 821 |
|
| 822 | void dlm_unregister_debugfs(void)
|
| 823 | {
|
| 824 | debugfs_remove(dlm_root);
|
| 825 | }
|
| 826 |
|