1 #include "clusterautoconfig.h"
2 /**
3 * glocktop.c - list/print the top GFS2 glock waiters
4 */
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <time.h>
13 #include <limits.h>
14 #include <sys/wait.h>
15 #include <sys/mount.h>
16 #include <dirent.h>
17 #include <curses.h>
18 #include <term.h>
19 #include <string.h>
20 #include <stdint.h>
21 #include <inttypes.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <libgfs2.h>
25
26 #define MAX_GLOCKS 20
27 #define MAX_LINES 6000
28 #define MAX_FILES 512
29 #define MAX_CALLTRACE_LINES 4
30 #define TITLE1 "glocktop - GFS2 glock monitor"
31 #define TITLE2 "Press <ctrl-c> or <escape> to exit"
32
33 #define COLOR_TITLE 1
34 #define COLOR_NORMAL 2
35 #define COLOR_INVERSE 3
36 #define COLOR_SPECIAL 4
37 #define COLOR_HIGHLIGHT 5
38 #define COLOR_OFFSETS 6
39 #define COLOR_CONTENTS 7
40 #define COLOR_HELD 8
41
42 /* init_pair(COLOR_TITLE, COLOR_BLACK, COLOR_CYAN);
43 init_pair(COLOR_INVERSE, COLOR_BLACK, COLOR_WHITE);
44 init_pair(COLOR_NORMAL, COLOR_WHITE, COLOR_BLACK);
45 init_pair(COLOR_SPECIAL, COLOR_MAGENTA, COLOR_WHITE);
46 init_pair(COLOR_HIGHLIGHT, COLOR_WHITE, COLOR_BLUE);
47 init_pair(COLOR_OFFSETS, COLOR_CYAN, COLOR_WHITE);
48 init_pair(COLOR_CONTENTS, COLOR_BLUE, COLOR_WHITE);
49 init_pair(COLOR_HELD, COLOR_CYAN, COLOR_BLACK);
50 */
51
52 #define STR_BLACK "[\033[0;30m]"
53 #define STR_RED "[\033[0;31m]"
54 #define STR_GREEN "[\033[0;32m]"
55 #define STR_YELLOW "[\033[0;33m]"
56 #define STR_BLUE "[\033[0;34m]"
57 #define STR_MAGENTA "[\033[0;35m]"
58 #define STR_CYAN "[\033[0;36m]"
59 #define STR_WHITE "[\033[0;37m]"
60
61 #define BOLD_WHITE "[\033[1;37m]"
62
63 #define BKG_CYAN "[\033[46m]"
64 #define BKG_WHITE "[\033[47m]"
65 #define BKG_BLUE "[\033[44m]"
66
67 #define REFRESH_TIME 30
68 #define COLORS_TITLE \
69 do { \
70 if (termlines) \
71 attrset(COLOR_PAIR(COLOR_TITLE)); \
72 else \
73 printf(BKG_CYAN); \
74 } while (0)
75 #define COLORS_NORMAL_BOLD \
76 do { \
77 if (termlines) { \
78 attrset(COLOR_PAIR(COLOR_NORMAL)); \
79 attron(A_BOLD); \
80 } else { \
81 printf(BOLD_WHITE); \
82 } \
83 } while (0)
84 #define COLORS_NORMAL \
85 do { \
86 if (termlines) { \
87 attrset(COLOR_PAIR(COLOR_NORMAL)); \
88 } else { \
89 printf(STR_WHITE); \
90 } \
91 } while (0)
92 #define COLORS_INVERSE_BOLD \
93 do { \
94 if (termlines) { \
95 attrset(COLOR_PAIR(COLOR_INVERSE)); \
96 attron(A_BOLD); \
97 } else { \
98 printf(BKG_WHITE); \
99 } \
100 } while (0)
101 #define COLORS_INVERSE \
102 do { \
103 if (termlines) { \
104 attrset(COLOR_PAIR(COLOR_INVERSE)); \
105 } else { \
106 printf(BKG_WHITE); \
107 } \
108 } while (0)
109 #define COLORS_HELD \
110 do { \
111 if (termlines) { \
112 attrset(COLOR_PAIR(COLOR_HELD)); \
113 } else { \
114 printf(STR_CYAN); \
115 } \
116 } while (0)
117 #define COLORS_HIGHLIGHT \
118 do { \
119 if (termlines) { \
120 attrset(COLOR_PAIR(COLOR_HIGHLIGHT)); \
121 } else { \
122 printf(BKG_BLUE); \
123 } \
124 } while (0)
125 #define DLM_DIRTBL "/sys/kernel/config/dlm/cluster/dirtbl_size"
126 #define DLM_RSBTBL "/sys/kernel/config/dlm/cluster/rsbtbl_size"
127 #define DLM_LKBTBL "/sys/kernel/config/dlm/cluster/lkbtbl_size"
128
129 #define GFS2_MAX_META_HEIGHT 10
130
131 #define DETAILS 0x00000001
132 #define FRIENDLY 0x00000002
133
134 enum summary_types {
135 all = 0,
136 locked = 1,
137 held_ex = 2,
138 held_sh = 3,
139 held_df = 4,
140 has_waiter = 5,
141 tot_waiters = 6,
142 stypes = 7,
143 };
144
145 static char *debugfs;
146 static int termcols = 80, termlines = 30, done = 0;
147 static unsigned glocks = 0;
148 static const char *termtype;
149 static WINDOW *wind;
150 static int bufsize = 4 * 1024 * 1024;
151 static char *glock[MAX_GLOCKS];
152 static int iterations = 0, show_reservations = 0, iters_done = 0;
153 struct mount_point {
154 struct mount_point *next;
155 char *device;
156 char *dir;
157 int fd;
158 struct lgfs2_sbd sb;
159 };
160 static struct mount_point *mounts;
161 static char dlmwlines[MAX_LINES][96]; /* waiters lines */
162 static char dlmglines[MAX_LINES][97]; /* granted lines */
163 static char contended_filenames[MAX_FILES][PATH_MAX];
164 static uint64_t contended_blocks[MAX_FILES];
165 static int contended_count = 0;
166 static int line = 0;
167 static const char *prog_name;
168 static char dlm_dirtbl_size[32], dlm_rsbtbl_size[32], dlm_lkbtbl_size[32];
169 static int bsize = 0;
170 static char print_dlm_grants = 1;
171 static char *gbuf = NULL; /* glocks buffer */
172 static char *gpos = NULL;
173 static char *gnextpos = NULL;
174 static int gmaxpos = 0;
175 static char *dbuf = NULL; /* dlm locks buffer */
176 static char *dpos = NULL;
177 static char *dnextpos = NULL;
178 static int dmaxpos = 0;
179 static char hostname[256];
180
181 /*
182 * init_colors
183 */
184 static void init_colors(void)
185 {
186 init_pair(COLOR_TITLE, COLOR_BLACK, COLOR_CYAN);
187 init_pair(COLOR_INVERSE, COLOR_BLACK, COLOR_WHITE);
188 init_pair(COLOR_NORMAL, COLOR_WHITE, COLOR_BLACK);
189 init_pair(COLOR_SPECIAL, COLOR_MAGENTA, COLOR_WHITE);
190 init_pair(COLOR_HIGHLIGHT, COLOR_WHITE, COLOR_BLUE);
191 init_pair(COLOR_OFFSETS, COLOR_CYAN, COLOR_WHITE);
192 init_pair(COLOR_CONTENTS, COLOR_BLUE, COLOR_WHITE);
193 init_pair(COLOR_HELD, COLOR_CYAN, COLOR_BLACK);
194 }
195
196 /*
197 * UpdateSize - screen size changed, so update it
198 */
199 static void UpdateSize(int sig)
200 {
201 static char term_buffer[2048];
202 int rc;
203
204 if (termlines) {
205 termlines = 30;
206 termtype = getenv("TERM");
207 if (termtype == NULL)
208 return;
209 rc=tgetent(term_buffer,termtype);
210 if (rc >= 0) {
211 termlines = tgetnum((char *)"li");
212 if (termlines < 10)
213 termlines = 30;
214 termcols = tgetnum((char *)"co");
215 if (termcols < 80)
216 termcols = 80;
217 } else
218 perror("Error: tgetent failed.");
219 termlines--; /* last line is number of lines -1 */
220 }
221 signal(SIGWINCH, UpdateSize);
222 }
223
|
(1) Event noescape: |
"read_superblock(int, struct lgfs2_sbd *)" does not free or save its parameter "fd". |
224 static int read_superblock(int fd, struct lgfs2_sbd *sdp)
225 {
226 ssize_t r;
227 char *buf;
228
229 ioctl(fd, BLKFLSBUF, 0);
230 buf = calloc(1, GFS2_BASIC_BLOCK);
231 if (buf == NULL) {
232 perror("Failed to read superblock");
233 return -1;
234 }
235 r = pread(fd, buf, GFS2_BASIC_BLOCK, GFS2_BASIC_BLOCK * GFS2_SB_ADDR);
236 if (r != GFS2_BASIC_BLOCK) {
237 perror("Failed to read superblock");
238 free(buf);
239 return -1;
240 }
241 lgfs2_sb_in(sdp, buf);
242 free(buf);
243
244 bsize = sdp->sd_bsize;
245 if (!bsize)
246 bsize = 4096;
247 return 0;
248 }
249
250 static void free_mounts(void)
251 {
252 struct mount_point *mntp = mounts;
253
254 while (mntp != NULL) {
255 struct mount_point *nextp = mntp->next;
256
257 close(mntp->fd);
258 free(mntp);
259 mntp = nextp;
260 }
261 mounts = NULL;
262 }
263
264 static int parse_mounts(void)
265 {
266 struct mount_point **mntp = &mounts;
267 struct mntent *mnt;
268 FILE *fp;
269
270 fp = setmntent("/proc/mounts", "r");
|
(1) Event path: |
Condition "fp == NULL", taking false branch. |
271 if (fp == NULL) {
272 perror("/proc/mounts");
273 return 1;
274 }
|
(2) Event path: |
Condition "(mnt = getmntent(fp)) != NULL", taking true branch. |
|
(6) Event path: |
Condition "(mnt = getmntent(fp)) != NULL", taking true branch. |
275 while ((mnt = getmntent(fp)) != NULL) {
276 size_t devlen = strlen(mnt->mnt_fsname);
277 size_t dirlen = strlen(mnt->mnt_dir);
278 struct mount_point *newmnt;
279
|
(3) Event path: |
Condition "strcmp(mnt->mnt_type, "debugfs") == 0", taking true branch. |
|
(7) Event path: |
Condition "strcmp(mnt->mnt_type, "debugfs") == 0", taking false branch. |
280 if (strcmp(mnt->mnt_type, "debugfs") == 0) {
|
(4) Event path: |
Condition "debugfs == NULL", taking true branch. |
281 if (debugfs == NULL)
282 debugfs = strdup(mnt->mnt_dir);
|
(5) Event path: |
Continuing loop. |
283 continue;
284 }
|
(8) Event path: |
Condition "strcmp(mnt->mnt_type, "gfs2") != 0", taking false branch. |
285 if (strcmp(mnt->mnt_type, "gfs2") != 0)
286 continue;
287
288 newmnt = calloc(1, sizeof(*newmnt) + devlen + 1 + dirlen + 1);
|
(9) Event path: |
Condition "newmnt == NULL", taking false branch. |
289 if (newmnt == NULL) {
290 perror("Failed to gather mount points");
291 return 1;
292 }
293 newmnt->device = (char *)(newmnt + 1);
294 newmnt->dir = newmnt->device + devlen + 1;
295 strcpy(newmnt->device, mnt->mnt_fsname);
296 strcpy(newmnt->dir, mnt->mnt_dir);
|
(10) Event open_fn: |
Returning handle opened by "open". [Note: The source code implementation of the function has been overridden by a user model.] |
|
(11) Event var_assign: |
Assigning: "newmnt->fd" = handle returned from "open(newmnt->device, 0)". |
| Also see events: |
[noescape][leaked_handle] |
297 newmnt->fd = open(newmnt->device, O_RDONLY);
298
|
(12) Event path: |
Condition "newmnt->fd < 0", taking false branch. |
299 if (newmnt->fd < 0) {
300 fprintf(stderr, "Failed to open gfs2 filesystem '%s': %s\n",
301 newmnt->device, strerror(errno));
302 free(newmnt);
303 continue;
304 }
|
(13) Event noescape: |
Resource "newmnt->fd" is not freed or pointed-to in "read_superblock". [details] |
|
(14) Event path: |
Condition "read_superblock(newmnt->fd, &newmnt->sb) != 0", taking true branch. |
| Also see events: |
[open_fn][var_assign][leaked_handle] |
305 if (read_superblock(newmnt->fd, &newmnt->sb) != 0) {
|
CID (unavailable; MK=43de2d8d348e1e8fe02621522e802897) (#1 of 1): Resource leak (RESOURCE_LEAK): |
|
(15) Event leaked_handle: |
Freeing "newmnt" without freeing its handle field "fd" leaks the handle. |
| Also see events: |
[open_fn][var_assign][noescape] |
306 free(newmnt);
307 continue;
308 }
309 *mntp = newmnt;
310 mntp = &newmnt->next;
311 }
312 endmntent(fp);
313 if (debugfs == NULL) {
314 debugfs = strdup("/sys/kernel/debug");
315 if (!debugfs || mount("debugfs", "/sys/kernel/debug", "debugfs", 0, NULL)) {
316 perror("debugfs not mounted and an attempt to mount it failed");
317 free(debugfs);
318 free_mounts();
319 return 1;
320 }
321 }
322 return 0;
323 }
324
325 /*
326 * display_title_lines
327 */
328 static void display_title_lines(void)
329 {
330 if (termlines) {
331 clear(); /* don't use Erase */
332 COLORS_TITLE;
333 attron(A_BOLD);
334 move(0, 0);
335 printw("%-80s", TITLE1);
336 move(termlines, 0);
337 printw("%-79s", TITLE2);
338 COLORS_NORMAL_BOLD;
339 move(1, 0);
340 } else {
341 printf("\n");
342 }
343 line = 1;
344 }
345
346 /*
347 * bobgets - get a string
348 * returns: 1 if user exited by hitting enter
349 * 0 if user exited by hitting escape
350 */
351 static int bobgets(char string[], int x, int y, int sz, int *ch)
352 {
353 int finished,runningy,rc;
354
355 if (!termlines)
356 return 0;
357 move(x,y);
358 finished=FALSE;
359 COLORS_INVERSE_BOLD;
360 move(x,y);
361 addstr(string);
362 move(x,y);
363 curs_set(2);
364 refresh();
365 runningy=y;
366 rc=0;
367 while (!finished) {
368 *ch = getch();
369
370 if(*ch < 0x0100 && isprint(*ch)) {
371 char *p=string+strlen(string); // end of the string
372
373 *(p+1)='\0';
374 string[runningy-y]=*ch;
375 runningy++;
376 move(x,y);
377 addstr(string);
378 if (runningy-y >= sz) {
379 rc=1;
380 *ch = KEY_RIGHT;
381 finished = TRUE;
382 }
383 }
384 else {
385 // special character, is it one we recognize?
386 switch(*ch)
387 {
388 case(KEY_ENTER):
389 case('\n'):
390 case('\r'):
391 rc=1;
392 finished=TRUE;
393 string[runningy-y] = '\0';
394 break;
395 case(KEY_CANCEL):
396 case(0x01B):
397 rc=0;
398 finished=TRUE;
399 break;
400 case(KEY_DC):
401 case(0x07F):
402 if (runningy>=y) {
403 char *p;
404 p = &string[runningy - y];
405 while (*p) {
406 *p = *(p + 1);
407 p++;
408 }
409 *p = '\0';
410 runningy--;
411 // remove the character from the string
412 move(x,y);
413 addstr(string);
414 COLORS_NORMAL_BOLD;
415 addstr(" ");
416 COLORS_INVERSE_BOLD;
417 runningy++;
418 }
419 break;
420 case(KEY_BACKSPACE):
421 if (runningy>y) {
422 char *p;
423
424 p = &string[runningy - y - 1];
425 while (*p) {
426 *p = *(p + 1);
427 p++;
428 }
429 *p='\0';
430 runningy--;
431 // remove the character from the string
432 move(x,y);
433 addstr(string);
434 COLORS_NORMAL_BOLD;
435 addstr(" ");
436 COLORS_INVERSE_BOLD;
437 }
438 break;
439 default:
440 move(0,70);
441 printw("%08x", *ch);
442 // ignore all other characters
443 break;
444 } // end switch on non-printable character
445 } // end non-printable character
446 move(line, runningy);
447 refresh();
448 } // while !finished
449 if (sz>0)
450 string[sz]='\0';
451 COLORS_NORMAL_BOLD;
452 return rc;
453 }/* bobgets */
454
455 static char *bufgets(int fd, char *bigbuf, char **nextpos, char **pos,
456 int *maxpos)
457 {
458 if (*nextpos == NULL) {
459 *maxpos = read(fd, bigbuf, bufsize - 1);
460 bigbuf[bufsize - 1] = '\0';
461 if (*maxpos == 0)
462 return NULL;
463 *pos = bigbuf;
464 } else
465 *pos = *nextpos;
466
467 *nextpos = memchr(*pos, '\n', (bigbuf + *maxpos) - *pos);
468 while (*nextpos && (**nextpos == '\n' || **nextpos == '\r') &&
469 *nextpos < bigbuf + (bufsize - 1)) {
470 **nextpos = '\0';
471 (*nextpos)++;
472 }
473 if (*nextpos >= bigbuf + *maxpos)
474 *nextpos = NULL;
475 return *pos;
476 }
477
478 static char *glock_number(const char *str)
479 {
480 const char *glockid;
481 char *p;
482 static char id[32];
483
484 glockid = strchr(str, '/');
485 if (glockid == NULL)
486 return NULL;
487 glockid++;
488 strncpy(id, glockid, sizeof(id));
489 id[31] = '\0';
490 p = strchr(id, ' ');
491 if (p)
492 *p = '\0';
493 return id;
494 }
495
496 static int this_glock_requested(const char *str)
497 {
498 const char *glockid;
499 int i;
500
501 if (!glocks)
502 return 0;
503
504 glockid = glock_number(str);
505 if (glockid == NULL)
506 return 0;
507 for (i = 0; i < glocks; i++)
508 if (!strcmp(glockid, glock[i]))
509 return 1;
510 return 0;
511 }
512
513 static int is_iopen(const char *str)
514 {
515 const char *p;
516
517 p = strchr(str, '/');
518 if (p == NULL)
519 return 0;
520 p--;
521 if (*p == '5')
522 return 1;
523 return 0;
524 }
525
526 static int this_lkb_requested(const char *str)
527 {
528 int i;
529
530 if (!glocks)
531 return 1;
532
533 for (i = 0; i < glocks; i++) {
534 if (strstr(str, glock[i]))
535 return 1;
536 }
537 return 0;
538 }
539
540 static void eol(int col) /* end of line */
541 {
542 if (termlines) {
543 line++;
544 move(line, col);
545 } else {
546 printf("\n");
547 for (; col > 0; col--)
548 printf(" ");
549 }
550 }
551
552 __attribute__((format(printf,2,4)))
553 static void print_it(const char *label, const char *fmt, const char *fmt2, ...)
554 {
555 va_list args;
556 char tmp_string[128];
557
558 if (!termlines || line < termlines) {
559 va_start(args, fmt2);
560 vsnprintf(tmp_string, 127, fmt, args);
561 tmp_string[127] = '\0';
562
563 if (termlines) {
564 printw("%s", tmp_string);
565 refresh();
566 } else {
567 printf("%s", tmp_string);
568 fflush(stdout);
569 }
570 }
571 va_end(args);
572 }
573
574 static void display_filename(int fd, uint64_t block, uint64_t *dirarray, int subdepth)
575 {
576 struct mount_point *mp;
577 int i, subs;
578 char blk[32];
579 DIR *dir = NULL;
580 struct dirent *dent;
581
582 for (mp = mounts; mp != NULL; mp = mp->next) {
583 if (fd == mp->fd)
584 break;
585 }
586 if (mp == NULL)
587 return;
588 for (i = 0; i < contended_count; i++) {
589 if (contended_blocks[i] == block) {
590 break;
591 }
592 }
593 sprintf(blk, "%"PRIu64, block);
594 if (i >= contended_count) {
595 memset(contended_filenames[i], 0, PATH_MAX);
596 strcat(contended_filenames[i], mp->dir);
597 for (subs = subdepth - 2; subs >= 0; subs--) {
598 dir = opendir(contended_filenames[i]);
599 while ((dent = readdir(dir))) {
600 if (dent->d_ino == dirarray[subs]) {
601 strcat(contended_filenames[i], "/");
602 strcat(contended_filenames[i],
603 dent->d_name);
604 break;
605 }
606 }
607 closedir(dir);
608 }
609 }
610
611 print_it(NULL, "%s", NULL, contended_filenames[i]);
612 eol(0);
613 }
614
615 static const char *show_inode(const char *id, int fd, uint64_t block)
616 {
617 struct lgfs2_inode *ip;
618 const char *inode_type = NULL;
619 struct lgfs2_sbd sbd = { .device_fd = fd, .sd_bsize = bsize };
620
621 ip = lgfs2_inode_read(&sbd, block);
622 if (S_ISDIR(ip->i_mode)) {
623 struct lgfs2_inode *parent;
624 uint64_t dirarray[256];
625 int subdepth = 0;
626
627 inode_type = "directory ";
628 dirarray[0] = block;
629 subdepth++;
630 /* Backtrack the directory to its source */
631 while (1) {
632 parent = lgfs2_lookupi(ip, "..", 2);
633 if (parent == NULL)
634 break;
635 /* Stop at the root inode */
636 if (ip->i_num.in_addr == parent->i_num.in_addr) {
637 lgfs2_inode_put(&parent);
638 break;
639 }
640 lgfs2_inode_put(&ip);
641 /* coverity[use_after_free:SUPPRESS] */
642 ip = parent;
643 dirarray[subdepth++] = parent->i_num.in_addr;
644 }
645 display_filename(fd, block, dirarray, subdepth);
646 } else if (S_ISREG(ip->i_mode)) {
647 inode_type = "file ";
648 } else if (S_ISLNK(ip->i_mode)) {
649 inode_type = "link ";
650 } else if (S_ISCHR(ip->i_mode)) {
651 inode_type = "char device ";
652 } else if (S_ISBLK(ip->i_mode)) {
653 inode_type = "block device ";
654 } else if (S_ISFIFO(ip->i_mode)) {
655 inode_type = "fifo ";
656 } else if (S_ISSOCK(ip->i_mode)) {
657 inode_type = "socket ";
658 } else
659 inode_type = "file? ";
660 lgfs2_inode_put(&ip);
661 return inode_type;
662 }
663
664 static const char *show_details(const char *id, const char *fsname, int btype,
665 int trace_dir_path)
666 {
667 uint64_t block = 0;
668 const char *blk_type = NULL;
669 struct mount_point *mp;
670 FILE *dlmf;
671
672 /* Figure out which mount point corresponds to this debugfs id */
673 for (mp = mounts; mp != NULL; mp = mp->next) {
674 char *p;
675
676 p = strchr(mp->sb.sd_locktable, ':');
677 if (!p)
678 continue;
679 p++;
680 if (!strcmp(p, fsname))
681 break;
682 }
683 if (mp == NULL)
684 return "unknown";
685 memset(dlm_dirtbl_size, 0, sizeof(dlm_dirtbl_size));
686 memset(dlm_rsbtbl_size, 0, sizeof(dlm_rsbtbl_size));
687 memset(dlm_lkbtbl_size, 0, sizeof(dlm_lkbtbl_size));
688 if (!strcmp(mp->sb.sd_lockproto, "lock_dlm")) {
689 char *sp;
690 char *p;
691
692 dlmf = fopen(DLM_DIRTBL, "rt");
693 if (dlmf) {
694 sp = fgets(dlm_dirtbl_size, sizeof(dlm_dirtbl_size), dlmf);
695 if (sp == NULL)
696 goto out_err;
697 p = strchr(dlm_dirtbl_size, '\n');
698 if (p)
699 *p = '\0';
700 fclose(dlmf);
701 } else {
702 strcpy(dlm_dirtbl_size, " ");
703 }
704 dlmf = fopen(DLM_RSBTBL, "rt");
705 if (dlmf) {
706 sp = fgets(dlm_rsbtbl_size, sizeof(dlm_rsbtbl_size), dlmf);
707 if (sp == NULL)
708 goto out_err;
709 p = strchr(dlm_rsbtbl_size, '\n');
710 if (p)
711 *p = '\0';
712 fclose(dlmf);
713 } else {
714 strcpy(dlm_rsbtbl_size, " ");
715 }
716 dlmf = fopen(DLM_LKBTBL, "rt");
717 if (dlmf) {
718 sp = fgets(dlm_lkbtbl_size, sizeof(dlm_lkbtbl_size), dlmf);
719 if (sp == NULL)
720 goto out_err;
721 p = strchr(dlm_lkbtbl_size, '\n');
722 if (p)
723 *p = '\0';
724 fclose(dlmf);
725 } else {
726 strcpy(dlm_lkbtbl_size, " ");
727 }
728 } else {
729 strcpy(dlm_dirtbl_size, "nolock");
730 strcpy(dlm_lkbtbl_size, "nolock");
731 strcpy(dlm_lkbtbl_size, "nolock");
732 }
733
734 /* Read the inode in so we can see its type. */
735 sscanf(id, "%"PRIx64, &block);
736 if (block) {
737 if (btype == 2)
738 if (trace_dir_path)
739 blk_type = show_inode(id, mp->fd, block);
740 else
741 blk_type = "";
742 else
743 blk_type = "";
744 }
745 return blk_type;
746 out_err:
747 fclose(dlmf);
748 return "error";
749 }
750
751 static int is_dlm_waiting(int dlmwaiters, int locktype, char *id)
752 {
753 int i;
754 int dlmid, wait_type, nodeid, type;
755 char locknum[32];
756
757 for (i = 0; i < dlmwaiters && i < 100; i++) {
758 sscanf(dlmwlines[i], "%x %d %d %d %s",
759 &dlmid, &wait_type, &nodeid, &type, locknum);
760 if ((type == locktype) && (!strcmp(locknum, id)))
761 return 1;
762 }
763 return 0;
764 }
765
766 static const char *friendly_state(const char *glock_line, const char *search)
767 {
768 const char *p;
769
770 p = strstr(glock_line, search);
771
772 if (p == NULL)
773 return "Dazed";
774
775 p += 2;
776 if (*p == 'E')
777 return "Exclusive";
778 else if (*p == 'S')
779 return "Shared";
780 else if (*p == 'U')
781 return "Unlocked";
782 else if (*p == 'D')
783 return "Deferred";
784 else
785 return "Confused";
786 }
787
788 static const char *friendly_gflags(const char *glock_line)
789 {
790 static char flagout[PATH_MAX];
791 const char *p;
792
793 memset(flagout, 0, sizeof(flagout));
794
795 p = strstr(glock_line, "f:");
796 if (!p)
797 return " ";
798 p += 2;
799 strcpy(flagout, "[");
800 while (*p != ' ') {
801 switch (*p) {
802 case 'l':
803 /*strcat(flagout, "Locked");*/
804 break;
805 case 'D':
806 strcat(flagout, "Demoting");
807 break;
808 case 'd':
809 strcat(flagout, "Demote pending");
810 break;
811 case 'p':
812 strcat(flagout, "Demote in progress");
813 break;
814 case 'y':
815 strcat(flagout, "Dirty");
816 break;
817 case 'f':
818 strcat(flagout, "Flush");
819 break;
820 case 'i':
821 strcat(flagout, "Invalidating");
822 break;
823 case 'r':
824 strcat(flagout, "Reply pending");
825 break;
826 case 'I':
827 /*strcat(flagout, "Initial");*/
828 break;
829 case 'F':
830 strcat(flagout, "Frozen");
831 break;
832 case 'q':
833 strcat(flagout, "Queued");
834 break;
835 case 'L':
836 strcat(flagout, "LRU");
837 break;
838 case 'o':
839 /*strcat(flagout, "Object present");*/
840 break;
841 case 'b':
842 strcat(flagout, "Blocking");
843 break;
844 default:
845 strcat(flagout, "Unknown");
846 break;
847 }
848 if ((strlen(flagout)) > 1 && (!strchr(" lIo", *(p + 1))))
849 strcat(flagout, ", ");
850 p++;
851 }
852 strcat(flagout, "]");
853 return flagout;
854 }
855
856 static const char *friendly_glock(const char *glock_line, char prefix)
857 {
858 static char gline[PATH_MAX];
859
860 if (prefix == 'W')
861 sprintf(gline, "Is:%s, Want:%s %s",
862 friendly_state(glock_line, "s:"),
863 friendly_state(glock_line, "t:"),
864 friendly_gflags(glock_line));
865 else
866 sprintf(gline, "Held:%s %s",
867 friendly_state(glock_line, "s:"),
868 friendly_gflags(glock_line));
869 return gline;
870 }
871
872 static const char *dlm_grtype(int grmode)
873 {
874 const char *dlm_types[8] = {"NL", "CR", "CW", "PR", "PW", "EX",
875 "NA", "NA"};
876
877 if (grmode < 0)
878 return "-1";
879 return dlm_types[grmode & 0x07];
880 }
881
882 static const char *dlm_status(int status)
883 {
884 const char *dlm_statuses[4] = {"Unknown", "Waiting", "Granted",
885 "Converting"};
886 if (status < 0)
887 return "unknown";
888 return dlm_statuses[status & 0x03];
889 }
890
891 static const char *dlm_nodeid(int lkbnodeid)
892 {
893 static char nodeid[16];
894
895 if (lkbnodeid == 0)
896 return "this node";
897 sprintf(nodeid, "node %d", lkbnodeid);
898 return nodeid;
899 }
900
901 static const char *getprocname(int ownpid)
902 {
903 char fn[1024];
904 static char str[80];
905 const char *procname;
906 FILE *fp;
907
908 sprintf(fn, "/proc/%d/status", ownpid);
909 fp = fopen(fn, "r");
910 if (fp == NULL)
911 return "ended";
912
913 if (fgets(str, 80, fp) != NULL) {
914 char *p;
915
916 p = strchr(str + 6, '\n');
917 if (p)
918 *p = '\0';
919 procname = str + 6;
920 } else
921 procname = "unknown";
922
923 fclose(fp);
924 return procname;
925 }
926
927 static void show_dlm_grants(int locktype, const char *g_line, int dlmgrants,
928 int summary)
929 {
930 int i;
931 char dlm_resid[75];
932 unsigned int lkb_id, lkbnodeid, remid, ownpid, exflags, flags, status;
933 unsigned int grmode, rqmode, nodeid, length;
934 uint64_t xid, us;
935 char trgt_res_name[64], res_name[64];
936 const char *p1, *p2;
937 const char *procname;
938
939 p1 = strchr(g_line, '/');
940 if (!p1)
941 return;
942 p1++;
943 p2 = strchr(p1, ' ');
944 if (!p2)
945 return;
946 memset(trgt_res_name, 0, sizeof(trgt_res_name));
947 memcpy(trgt_res_name, p1, p2 - p1);
948 sprintf(dlm_resid, "%8d%16s", locktype, trgt_res_name);
949 for (i = 0; i < dlmgrants; i++) {
950 /*
951 lkb_id n remid pid x e f s g rq u n ln res_name 1234567890123456
952 1100003 1 2ae0006 8954 0 0 0 2 5 -1 0 1 24 " 2 102ab"
953 2a20001 1 30d0001 8934 0 0 0 2 3 -1 0 1 24 " 5 102ab"
954 b0001 2 860001 8868 0 0 10000 2 3 -1 0 0 24 " 1 2"
955 2450001 2 1be0002 8962 0 0 10000 1 -1 5 12214 0 24 " 2 102ab"
956 */
957 p1 = strchr(dlmglines[i], '\"');
958 if (!p1)
959 continue;
960 p1++;
961 if (strncmp(dlm_resid, p1, 24))
962 continue;
963
964 sscanf(dlmglines[i], "%x %d %x %u %"SCNu64" %x %x %d %d %d %"SCNu64" "
965 "%u %d \"%24s\"\n",
966 &lkb_id, &lkbnodeid, &remid, &ownpid, &xid, &exflags,
967 &flags, &status, &grmode, &rqmode, &us, &nodeid,
968 &length, res_name);
969 if (status == 1) { /* Waiting */
970 if (!lkbnodeid)
971 procname = getprocname(ownpid);
972 else
973 procname = "";
974 if (summary)
975 print_it(NULL, " (", NULL);
976 else
977 print_it(NULL, " D: ", NULL);
978 print_it(NULL, "%s for %s, pid %d %s", NULL,
979 dlm_status(status), dlm_nodeid(lkbnodeid),
980 ownpid, procname);
981 if (summary)
982 print_it(NULL, ")", NULL);
983 } else if (grmode == 0) {
984 continue; /* ignore "D: Granted NL on node X" */
985 } else {
986 procname = getprocname(ownpid);
987 if (summary)
988 print_it(NULL, " (", NULL);
989 else
990 print_it(NULL, " D: ", NULL);
991 print_it(NULL, "%s %s on %s to pid %d %s", NULL,
992 dlm_status(status), dlm_grtype(grmode),
993 dlm_nodeid(lkbnodeid), ownpid, procname);
994 if (summary)
995 print_it(NULL, ")", NULL);
996 }
997 if (!summary)
998 eol(0);
999 }
1000 }
1001
1002 static void print_call_trace(char *hline)
1003 {
1004 char *p, *pid, tmp[32], stackfn[64], str[96];
1005 FILE *fp;
1006 int i;
1007
1008 p = strchr(hline, 'p');
1009 if (!p)
1010 return;
1011 pid = p + 2;
1012 p = strchr(pid, ' ');
1013 if (!p)
1014 return;
1015 memset(tmp, 0, sizeof(tmp));
1016 memcpy(tmp, pid, p - pid);
1017 sprintf(stackfn, "/proc/%s/stack", tmp);
1018 fp = fopen(stackfn, "rt");
1019 if (fp == NULL)
1020 return;
1021 for (i = 0; i < MAX_CALLTRACE_LINES; i++) {
1022 if (fgets(str, sizeof(str) - 1, fp) == NULL)
1023 break;
1024 if (strstr(str, "gfs2_glock_")) { /* skip lines we don't
1025 care about*/
1026 i--;
1027 continue;
1028 }
1029 p = strchr(str, '\n');
1030 if (p)
1031 *p = '\0';
1032 p = strchr(str, ']');
1033 if (p)
1034 p += 2;
1035 else
1036 p = str;
1037 print_it(NULL, " C: %s ", NULL, p);
1038 eol(0);
1039 }
1040 fclose(fp);
1041 }
1042
1043 static int is_ex(const char *hline)
1044 {
1045 if (strncmp(hline, " H: s:EX ", 9) == 0)
1046 return 1;
1047 return 0;
1048 }
1049
1050 static int has_holder_flag(const char *hline, char flag)
1051 {
1052 const char *p;
1053
1054 p = strchr(hline, 'f');
1055 if (p == NULL)
1056 return 0;
1057 p++;
1058 if (*p != ':')
1059 return 0;
1060 p++;
1061 while (*p != '\0') {
1062 if (*p == ' ')
1063 return 0;
1064 if (*p == flag)
1065 return 1;
1066 p++;
1067 }
1068 return 0;
1069 }
1070
1071 static int is_holder(const char *hline)
1072 {
1073 return has_holder_flag(hline, 'H');
1074 }
1075
1076 static int is_waiter(const char *hline)
1077 {
1078 return has_holder_flag(hline, 'W');
1079 }
1080
1081 static int get_lock_type(const char *str)
1082 {
1083 const char *p;
1084
1085 p = strchr(str, '/');
1086 return (p ? (*(p - 1)) - '0' : 0);
1087 }
1088
1089 static long long get_demote_time(char *str)
1090 {
1091 char *p;
1092 char tmp[80];
1093
1094 p = strchr(str, '/');
1095 if (p == NULL)
1096 return 0;
1097 p++;
1098 p = strchr(p, '/');
1099 if (p == NULL)
1100 return 0;
1101 p++;
1102 strncpy(tmp, p, 79);
1103 tmp[79] = '\0';
1104 p = strchr(tmp, ' ');
1105 if (p == NULL)
1106 return 0;
1107 *p = '\0';
1108 return atoll(tmp);
1109 }
1110
1111 static const char *pid_string(char *str)
1112 {
1113 char *p;
1114 static char pidstr[80];
1115
1116 memset(pidstr, 0, sizeof(pidstr));
1117 p = strchr(str, 'p');
1118 if (p) {
1119 strncpy(pidstr, p + 2, sizeof(pidstr));
1120 pidstr[79] = '\0';
1121 p = strchr(pidstr, ']');
1122 if (p) {
1123 p++;
1124 *p = '\0';
1125 }
1126 }
1127 return pidstr;
1128 }
1129
1130 /* If this glock is relevant, return 0, else the reason it's irrelevant */
1131 static int irrelevant(const char *holder, const char *glockstr)
1132 {
1133 int lock_type = get_lock_type(glockstr);
1134
1135 /* Exclude shared and locks */
1136 if (!is_ex(holder))
1137 return 1;
1138 /* Exclude locks held at mount time: statfs*/
1139 if (strstr(holder, "init_per_node"))
1140 return 2;
1141 if (strstr(holder, "init_journal"))
1142 return 3;
1143 if (strstr(holder, "init_inodes"))
1144 return 4;
1145 if (strstr(holder, "fill_super"))
1146 return 5;
1147 if (lock_type == 9) /* Exclude journal locks */
1148 return 6;
1149 return 0;
1150 }
1151
1152 static const char *reason(int why)
1153 {
1154 const char *reasons[] = {"(N/A:------)", /* 0 */
1155 "(N/A:Not EX)", /* 1 */
1156 "(N/A:System)", /* 2 */
1157 "(N/A:journl)", /* 3 */
1158 "(N/A:System)", /* 4 */
1159 "(N/A:System)", /* 5 */
1160 "(N/A:Journl)"}; /* 6 */
1161
1162 return reasons[why];
1163 }
1164
1165 static void print_friendly_prefix(char one_glocks_lines[MAX_LINES][97])
1166 {
1167 int why = irrelevant(one_glocks_lines[1], one_glocks_lines[0]);
1168
1169 if (why)
1170 print_it(NULL, " U: %s ", NULL, reason(why));
1171 else
1172 print_it(NULL, " U: ", NULL);
1173 }
1174
1175 static void show_glock(char one_glocks_lines[MAX_LINES][97], int gline,
1176 const char *fsname, int dlmwaiters, int dlmgrants,
1177 int trace_dir_path, int prev_had_waiter, int flags,
1178 int summary)
1179 {
1180 int i, locktype = 0;
1181 char id[33], *p;
1182 char extras[80], prefix = '\0';
1183 long long demote_time = 0;
1184 const char *ltype[] = {"N/A", "non-disk", "inode", "rgrp", "meta",
1185 "i_open", "flock", "posix lock", "quota",
1186 "journal"};
1187
1188 if (termlines) {
1189 if (irrelevant(one_glocks_lines[1], one_glocks_lines[0]))
1190 COLORS_HELD;
1191 else
1192 COLORS_NORMAL;
1193 }
1194 if (!gline)
1195 return;
1196
1197 memset(extras, 0, sizeof(extras));
1198 p = strchr(one_glocks_lines[0], '/');
1199 memset(id, 0, sizeof(id));
1200
1201 if (p) {
1202 locktype = get_lock_type(one_glocks_lines[0]);
1203 demote_time = get_demote_time(one_glocks_lines[0]);
1204 p++;
1205 strncpy(id, p, sizeof(id) - 1);
1206 id[sizeof(id) - 1] = '\0';
1207 p = strchr(id, ' ');
1208 if (p)
1209 *p = '\0';
1210
1211 if (locktype != 2) {
1212 strncpy(extras, ltype[locktype], 79);
1213 extras[79] = '\0';
1214 } else {
1215 const char *i_type = show_details(id, fsname, 2,
1216 trace_dir_path);
1217 sprintf(extras, "%sinode", i_type);
1218 }
1219 }
1220 if (flags & DETAILS) {
1221 print_it(NULL, " %s ", NULL, one_glocks_lines[0]);
1222 print_it(NULL, "(%s)", NULL, extras);
1223 if (demote_time)
1224 print_it(NULL, " ** demote time is greater than 0 **",
1225 NULL);
1226 eol(0);
1227 if (dlmgrants)
1228 show_dlm_grants(locktype, one_glocks_lines[0],
1229 dlmgrants, 0);
1230 }
1231 if (flags & FRIENDLY) {
1232 print_friendly_prefix(one_glocks_lines);
1233 for (i = 1; i < gline; i++) {
1234 if (one_glocks_lines[i][0] == ' ' &&
1235 one_glocks_lines[i][1] == 'H' &&
1236 prefix != 'W')
1237 prefix = (is_holder(one_glocks_lines[i]) ?
1238 'H' : 'W');
1239 }
1240 print_it(NULL, " %c %-10.10s %-9.9s %s", NULL, prefix,
1241 extras, id, friendly_glock(one_glocks_lines[0],
1242 prefix));
1243 eol(0);
1244 }
1245 for (i = 1; i < gline; i++) {
1246 if (!show_reservations &&
1247 one_glocks_lines[i][0] == ' ' &&
1248 one_glocks_lines[i][2] == 'B' &&
1249 one_glocks_lines[i][3] == ':')
1250 continue;
1251
1252 if (flags & DETAILS) {
1253 print_it(NULL, " %-80.80s", NULL, one_glocks_lines[i]);
1254 eol(0);
1255 continue;
1256 }
1257 if ((flags & FRIENDLY) &&
1258 one_glocks_lines[i][1] == 'H')
1259 print_friendly_prefix(one_glocks_lines);
1260
1261 if (one_glocks_lines[i][0] == ' ' &&
1262 one_glocks_lines[i][1] == 'H') {
1263 print_it(NULL, " %c ---> %s pid %s ", NULL,
1264 prefix, (is_holder(one_glocks_lines[i]) ?
1265 "held by" : "waiting"),
1266 pid_string(one_glocks_lines[i]));
1267 if (demote_time)
1268 print_it(NULL, "** demote time is non-"
1269 "zero ** ", NULL);
1270 if (is_dlm_waiting(dlmwaiters, locktype, id)) {
1271 print_it(NULL, "***** DLM is in a "
1272 "comm wait for this lock "
1273 "***** ", NULL);
1274 }
1275 show_dlm_grants(locktype, one_glocks_lines[0],
1276 dlmgrants, 1);
1277 eol(0);
1278 print_call_trace(one_glocks_lines[i]);
1279 }
1280 }
1281 }
1282
1283 static int parse_dlm_waiters(FILE *dlm, const char *fsname)
1284 {
1285 int dlml = 0;
1286
1287 memset(dlmwlines, 0, sizeof(dlmwlines));
1288 while (fgets(dlmwlines[dlml], 80, dlm))
1289 dlml++;
1290
1291 return dlml;
1292 }
1293
1294 static int parse_dlm_grants(int dlmfd, const char *fsname)
1295 {
1296 int dlml = 0;
1297 char *dlmline;
1298
1299 memset(dlmglines, 0, sizeof(dlmglines));
1300 dnextpos = NULL;
1301 while ((dlmline = bufgets(dlmfd, dbuf, &dnextpos, &dpos, &dmaxpos))) {
1302 if (!this_lkb_requested(dlmline))
1303 continue;
1304 strncpy(dlmglines[dlml], dlmline, 96);
1305 dlmglines[dlml][96] = '\0';
1306 dlml++;
1307 if (dlml >= MAX_LINES)
1308 break;
1309 }
1310 return dlml;
1311 }
1312
1313 static void print_summary(int total_glocks[11][stypes], int dlmwaiters)
1314 {
1315 int i;
1316 int total_unlocked = 0;
1317 const struct {
1318 const char *name;
1319 const int width;
1320 } column[] = {
1321 { "unknown", 7 }, { "nondisk", 7}, { "inode", 8 }, { "rgrp", 7 },
1322 { "meta", 4 }, { "iopen", 7 }, { "flock", 7 }, { "p", 1 },
1323 { "quota", 5 }, { "jrnl", 4 }, { "Total", 8 }
1324 };
1325 const int ncols = sizeof(column) / sizeof(column[0]);
1326
1327 /* Print column headers */
1328 print_it(NULL, "S glocks ", NULL);
1329 for (i = 1; i < ncols; i++)
1330 if (i != 7 && i != 4) /* Ignore plock and meta */
1331 print_it(NULL, "%*s ", NULL, column[i].width, column[i].name);
1332 eol(0);
1333 print_it(NULL, "S --------- ", NULL);
1334 for (i = 1; i < ncols; i++)
1335 if (i != 7 && i != 4) /* Ignore plock and meta */
1336 print_it(NULL, "%*s ", NULL, column[i].width, "--------");
1337 eol(0);
1338
1339 /* Print rows */
1340 print_it(NULL, "S Unlocked: ", NULL);
1341 for (i = 1; i < (ncols - 1); i++) {
1342 if (i != 7 && i != 4) /* Ignore plock and meta */
1343 print_it(NULL, "%*d ", NULL, column[i].width,
1344 total_glocks[i][all] - total_glocks[i][locked]);
1345 total_unlocked += total_glocks[i][all] -
1346 total_glocks[i][locked];
1347 }
1348 print_it(NULL, "%*d ", NULL, column[i].width, total_unlocked);
1349 eol(0);
1350 print_it(NULL, "S Locked: ", NULL);
1351 for (i = 1; i < ncols; i++) {
1352 if (i != 7 && i != 4) /* Ignore plock and meta */
1353 print_it(NULL, "%*d ", NULL, column[i].width,
1354 total_glocks[i][locked]);
1355 total_glocks[10][locked] += total_glocks[i][locked];
1356 }
1357 eol(0);
1358 print_it(NULL, "S Total: ", NULL);
1359 for (i = 1; i < ncols; i++) {
1360 if (i != 7 && i != 4) /* Ignore plock and meta */
1361 print_it(NULL, "%*d ", NULL, column[i].width,
1362 total_glocks[i][all]);
1363 total_glocks[10][all] += total_glocks[i][all];
1364 }
1365 eol(0);
1366 print_it(NULL, "S", NULL);
1367 eol(0);
1368 print_it(NULL, "S Held EX: ", NULL);
1369 for (i = 1; i < ncols; i++) {
1370 if (i != 7 && i != 4) /* Ignore plock and meta */
1371 print_it(NULL, "%*d ", NULL, column[i].width,
1372 total_glocks[i][held_ex]);
1373 total_glocks[10][held_ex] += total_glocks[i][held_ex];
1374 }
1375 eol(0);
1376 print_it(NULL, "S Held SH: ", NULL);
1377 for (i = 1; i < ncols; i++) {
1378 if (i != 7 && i != 4) /* Ignore plock and meta */
1379 print_it(NULL, "%*d ", NULL, column[i].width,
1380 total_glocks[i][held_sh]);
1381 total_glocks[10][held_sh] += total_glocks[i][held_sh];
1382 }
1383 eol(0);
1384 print_it(NULL, "S Held DF: ", NULL);
1385 for (i = 1; i < ncols; i++) {
1386 if (i != 7 && i != 4) /* Ignore plock and meta */
1387 print_it(NULL, "%*d ", NULL, column[i].width,
1388 total_glocks[i][held_df]);
1389 total_glocks[10][held_df] += total_glocks[i][held_df];
1390 }
1391 eol(0);
1392 print_it(NULL, "S G Waiting: ", NULL);
1393 for (i = 1; i < ncols; i++) {
1394 if (i != 7 && i != 4) /* Ignore plock and meta */
1395 print_it(NULL, "%*d ", NULL, column[i].width,
1396 total_glocks[i][has_waiter]);
1397 total_glocks[10][has_waiter] += total_glocks[i][has_waiter];
1398 }
1399 eol(0);
1400 print_it(NULL, "S P Waiting: ", NULL);
1401 for (i = 1; i < ncols; i++) {
1402 if (i != 7 && i != 4) /* Ignore plock and meta */
1403 print_it(NULL, "%*d ", NULL, column[i].width,
1404 total_glocks[i][tot_waiters]);
1405 total_glocks[10][tot_waiters] += total_glocks[i][tot_waiters];
1406 }
1407 eol(0);
1408 print_it(NULL, "S DLM wait: %7d", NULL, dlmwaiters);
1409 eol(0);
1410 eol(0);
1411 }
1412
1413 /* flags = DETAILS || FRIENDLY or both */
1414 static void glock_details(int fd, const char *fsname, int dlmwaiters,
1415 int dlmgrants, int trace_dir_path, int show_held,
1416 int summary)
1417 {
1418 char *ln, *p;
1419 char one_glocks_lines[MAX_LINES][97];
1420 int gline = 0;
1421 int show_prev_glock = 0, prev_had_waiter = 0;
1422 int total_glocks[11][stypes], locktype = 0;
1423 int holders_this_glock_ex = 0;
1424 int holders_this_glock_sh = 0;
1425 int holders_this_glock_df = 0;
1426 int waiters_this_glock = 0;
1427
1428 memset(total_glocks, 0, sizeof(total_glocks));
1429 gnextpos = NULL;
1430 while ((ln = bufgets(fd, gbuf, &gnextpos, &gpos, &gmaxpos))) {
1431 if (ln[0] == ' ' && ln[1] == ' ' && ln[2] == ' ')
1432 continue;
1433 if (ln[0] == 'G') {
1434 /* Summary stuff------------------------------------ */
1435 if (waiters_this_glock) {
1436 total_glocks[locktype][tot_waiters] +=
1437 waiters_this_glock;
1438 total_glocks[locktype][has_waiter]++;
1439 }
1440 if (holders_this_glock_ex)
1441 total_glocks[locktype][held_ex]++;
1442 if (holders_this_glock_sh)
1443 total_glocks[locktype][held_sh]++;
1444 if (holders_this_glock_df)
1445 total_glocks[locktype][held_df]++;
1446 locktype = get_lock_type(ln);
1447 p = ln + 6;
1448 if (*p != 'U' || *(p + 1) != 'N')
1449 total_glocks[locktype][locked]++;
1450 total_glocks[locktype][all]++;
1451 holders_this_glock_ex = 0;
1452 holders_this_glock_sh = 0;
1453 holders_this_glock_df = 0;
1454 waiters_this_glock = 0;
1455 /* Detail stuff------------------------------------- */
1456 if (show_prev_glock) {
1457 show_glock(one_glocks_lines, gline, fsname,
1458 dlmwaiters, dlmgrants,
1459 trace_dir_path, prev_had_waiter,
1460 DETAILS, summary);
1461 show_glock(one_glocks_lines, gline, fsname,
1462 dlmwaiters, dlmgrants,
1463 trace_dir_path, prev_had_waiter,
1464 FRIENDLY, summary);
1465 memset(one_glocks_lines, 0,
1466 sizeof(one_glocks_lines));
1467 show_prev_glock = 0;
1468 }
1469 prev_had_waiter = 0;
1470 gline = 0;
1471 if (this_glock_requested(ln))
1472 show_prev_glock = 1;
1473 } else if (ln[0] == ' ' && ln[1] == 'H') {
1474 char *flag = strchr(ln, 'f');
1475 char *mode = strchr(ln, 's');
1476
1477 /* Summary stuff------------------------------------ */
1478 while (flag) {
1479 flag++;
1480 switch (*flag) {
1481 case ':':
1482 break;
1483 case 'W':
1484 waiters_this_glock++;
1485 flag = NULL;
1486 break;
1487 case 'H':
1488 flag = NULL;
1489 if (mode == NULL)
1490 holders_this_glock_df++;
1491 else if (*(mode + 1) == ':' &&
1492 *(mode + 2) == 'E' &&
1493 *(mode + 3) == 'X')
1494 holders_this_glock_ex++;
1495 else if (*(mode + 1) == ':' &&
1496 *(mode + 2) == 'S' &&
1497 *(mode + 3) == 'H')
1498 holders_this_glock_sh++;
1499 else
1500 holders_this_glock_df++;
1501 break;
1502 case ' ':
1503 flag = NULL;
1504 break;
1505 default:
1506 break;
1507 };
1508 }
1509 /* Detail stuff------------------------------------- */
1510 if (!glocks) {
1511 int haswaiter = is_waiter(ln);
1512
1513 if (haswaiter) {
1514 show_prev_glock = 1;
1515 prev_had_waiter = 1;
1516 } else if (show_held && is_holder(ln) &&
1517 !is_iopen(one_glocks_lines[0])) {
1518 show_prev_glock = 1;
1519 } else if (!irrelevant(ln, one_glocks_lines[0])) {
1520 show_prev_glock = 1;
1521 }
1522 }
1523 }
1524 /* Detail stuff--------------------------------------------- */
1525 strncpy(one_glocks_lines[gline], ln, 96);
1526 one_glocks_lines[gline][96] = '\0';
1527 gline++;
1528 if (gline >= MAX_LINES)
1529 break;
1530 if (termlines && line >= termlines)
1531 break;
1532 }
1533 /* Detail stuff----------------------------------------------------- */
1534 if (show_prev_glock && gline < MAX_LINES &&
1535 (!termlines || line < termlines)) {
1536 show_glock(one_glocks_lines, gline, fsname, dlmwaiters,
1537 dlmgrants, trace_dir_path, prev_had_waiter,
1538 DETAILS, summary);
1539 show_glock(one_glocks_lines, gline, fsname, dlmwaiters,
1540 dlmgrants, trace_dir_path, prev_had_waiter,
1541 FRIENDLY, summary);
1542 }
1543 if (!summary || ((iters_done % summary) != 0))
1544 return;
1545
1546 print_summary(total_glocks, dlmwaiters);
1547 }
1548
1549 static void show_help(int help)
1550 {
1551 if (help == 1) {
1552 COLORS_NORMAL;
1553 eol(0);
1554 print_it(NULL, " Glock flags: ", NULL);
1555 eol(0);
1556 print_it(NULL, " l - Locked ", NULL);
1557 print_it(NULL, " r - Reply pending ", NULL);
1558 eol(0);
1559 print_it(NULL, " d - Demote pending ", NULL);
1560 print_it(NULL, " I - Initial ", NULL);
1561 eol(0);
1562 print_it(NULL, " D - Demote requested ", NULL);
1563 print_it(NULL, " F - Frozen ", NULL);
1564 eol(0);
1565 print_it(NULL, " p - Demote in progress ", NULL);
1566 print_it(NULL, " q - Queued holder ", NULL);
1567 eol(0);
1568 print_it(NULL, " y - Dirty data ", NULL);
1569 print_it(NULL, " L - LRU ", NULL);
1570 eol(0);
1571 print_it(NULL, " f - Flush ", NULL);
1572 print_it(NULL, " o - Object present ", NULL);
1573 eol(0);
1574 print_it(NULL, " i - Invalidating ", NULL);
1575 print_it(NULL, " b - Blocking request ", NULL);
1576 eol(0);
1577 } else if (help == 2) {
1578 COLORS_NORMAL;
1579 eol(0);
1580 print_it(NULL, " Holder flags: ", NULL);
1581 eol(0);
1582 print_it(NULL, " t - Try (non-blocking) ", NULL);
1583 print_it(NULL, " E - Exact lock ", NULL);
1584 eol(0);
1585 print_it(NULL, " T - Try with callback ", NULL);
1586 print_it(NULL, " c - No Cache lock ", NULL);
1587 eol(0);
1588 print_it(NULL, " e - No exp ", NULL);
1589 print_it(NULL, " H - Held (locked) ", NULL);
1590 eol(0);
1591 print_it(NULL, " A - Any lock ", NULL);
1592 print_it(NULL, " W - Waiting for lock ", NULL);
1593 eol(0);
1594 print_it(NULL, " p - Priority lock ", NULL);
1595 print_it(NULL, " a - Asynchronous lock ", NULL);
1596 eol(0);
1597 print_it(NULL, " F - First ", NULL);
1598 eol(0);
1599 }
1600 }
1601
1602 /* flags = DETAILS || FRIENDLY or both */
1603 static void parse_glocks_file(int fd, const char *fsname, int dlmwaiters,
1604 int dlmgrants, int trace_dir_path,
1605 int show_held, int help, int summary)
1606 {
1607 char fstitle[96], *fsdlm;
1608 char ctimestr[64];
1609 time_t t;
1610 int i;
1611
1612 tzset();
1613 t = time(NULL);
1614 strftime(ctimestr, 64, "%a %b %d %T %Y", localtime(&t));
1615 ctimestr[63] = '\0';
1616 memset(fstitle, 0, sizeof(fstitle));
1617 fsdlm = calloc(1, 105 + dlmwaiters);
1618 if (!fsdlm) {
1619 printf("Failed to allocate fsdlm\n");
1620 exit(-1);
1621 }
1622
1623 sprintf(fstitle, "@ %.22s %s ", fsname, ctimestr);
1624 if (dlmwaiters) {
1625 sprintf(fsdlm, "dlm: %s/%s/%s [", dlm_dirtbl_size,
1626 dlm_rsbtbl_size, dlm_lkbtbl_size);
1627 for (i = 0; i < dlmwaiters; i++)
1628 strcat(fsdlm, "*");
1629 for (; i < 10; i++)
1630 strcat(fsdlm, " ");
1631 strcat(fsdlm, "]");
1632 }
1633 attron(A_BOLD);
1634 print_it(NULL, "%s @%s %s", NULL, fstitle, hostname, fsdlm);
1635 free(fsdlm);
1636 eol(0);
1637 attroff(A_BOLD);
1638 glock_details(fd, fsname, dlmwaiters, dlmgrants, trace_dir_path,
1639 show_held, summary);
1640
1641 show_help(help);
1642 if (termlines)
1643 refresh();
1644 }
1645
1646 static void usage(void)
1647 {
1648 printf("Usage:\n");
1649 printf("glocktop [-i] [-d <delay sec>] [-n <iter>] [-sX] [-c] [-D] [-H] [-r] [-t]\n");
1650 printf("\n");
1651 printf("-i : Runs glocktop in interactive mode.\n");
1652 printf("-d : delay between refreshes, in seconds (default: %d).\n", REFRESH_TIME);
1653 printf("-n : stop after <iter> refreshes.\n");
1654 printf("-H : don't show Held glocks, even if not waited on, excluding "
1655 "iopen\n");
1656 printf("-r : show reservations when rgrp glocks are displayed\n");
1657 printf("-s : show glock summary information every X iterations\n");
1658 printf("-t : trace directory glocks back\n");
1659 printf("-D : don't show DLM lock status\n");
1660 printf("\n");
1661 fflush(stdout);
1662 exit(0);
1663 }
1664
1665 int main(int argc, char **argv)
1666 {
1667 int fd;
1668 DIR *dir = NULL;
1669 char *fn;
1670 struct dirent *dent;
1671 int retval;
1672 int refresh_time = REFRESH_TIME;
1673 fd_set readfds;
1674 char string[96];
1675 int ch, dlmwaiters = 0, dlmgrants = 0;
1676 int cont = TRUE, optchar;
1677 int trace_dir_path = 0;
1678 int show_held = 1, help = 0;
1679 int interactive = 0;
1680 int summary = 10;
1681 int nfds = STDIN_FILENO + 1;
1682
1683 prog_name = argv[0];
1684 memset(glock, 0, sizeof(glock));
1685 memset(contended_filenames, 0, sizeof(contended_filenames));
1686 memset(contended_blocks, 0, sizeof(contended_blocks));
1687 UpdateSize(0);
1688 /* decode command line arguments */
1689 while (cont) {
1690 optchar = getopt(argc, argv, "-d:Dn:rs:thHi");
1691
1692 switch (optchar) {
1693 case 'd':
1694 refresh_time = atoi(optarg);
1695 if (refresh_time < 1) {
1696 fprintf(stderr, "Error: delay %d too small; "
1697 "must be at least 1\n", refresh_time);
1698 exit(-1);
1699 }
1700 break;
1701 case 'D':
1702 print_dlm_grants = 0;
1703 break;
1704 case 'n':
1705 iterations = atoi(optarg);
1706 break;
1707 case 'r':
1708 show_reservations = 1;
1709 break;
1710 case 's':
1711 summary = atoi(optarg);
1712 break;
1713 case 't':
1714 trace_dir_path = 1;
1715 break;
1716 case 'h':
1717 usage();
1718 break;
1719 case 'H':
1720 show_held = 0; /* held, but not iopen held */
1721 break;
1722 case 'i':
1723 interactive = 1;
1724 break;
1725 case EOF:
1726 cont = FALSE;
1727 break;
1728 case 1:
1729 if (optarg && glocks < MAX_GLOCKS)
1730 glock[glocks++] = optarg;
1731 break;
1732
1733 default:
1734 fprintf(stderr, "unknown option: %c\n", optchar);
1735 exit(-1);
1736 };
1737 }
1738
1739 if (interactive) {
1740 printf("Initializing. Please wait...");
1741 fflush(stdout);
1742 }
1743 if (gethostname(hostname, sizeof(hostname))) {
1744 fprintf(stderr, "Error: unable to determine host name.\n");
1745 exit(-1);
1746 }
1747 if (parse_mounts())
1748 exit(-1);
1749
1750 if (interactive && (wind = initscr()) == NULL) {
1751 fprintf(stderr, "Error: unable to initialize screen.\n");
1752 exit(-1);
1753 }
1754
1755 if (interactive) {
1756 /* Do our initial screen stuff: */
1757 signal(SIGWINCH, UpdateSize); /* handle term resize signal */
1758 UpdateSize(0); /* update screen size based on term settings */
1759 clear(); /* don't use Erase */
1760 start_color();
1761 noecho();
1762 keypad(stdscr, TRUE);
1763 raw();
1764 curs_set(0);
1765 init_colors();
1766 } else {
1767 termlines = 0;
1768 }
1769 while (!gbuf) {
1770 gbuf = malloc(bufsize);
1771 if (gbuf) {
1772 /*printf("bufsize=%dK\n", bufsize / 1024);*/
1773 break;
1774 }
1775 bufsize /= 2;
1776 }
1777 while (!dbuf) {
1778 dbuf = malloc(bufsize);
1779 if (dbuf) {
1780 /*printf("bufsize=%dK\n", bufsize / 1024);*/
1781 break;
1782 }
1783 bufsize /= 2;
1784 }
1785
1786 while (!done) {
1787 struct timeval tv;
1788
1789 if (asprintf(&fn, "%s/gfs2/", debugfs) == -1) {
1790 perror(argv[0]);
1791 exit(-1);
1792 }
1793 dir = opendir(fn);
1794 free(fn);
1795
1796 if (!dir) {
1797 if (interactive) {
1798 refresh();
1799 endwin();
1800 }
1801 fprintf(stderr, "Unable to open gfs2 debugfs directory.\n");
1802 fprintf(stderr, "Check if debugfs and gfs2 are mounted.\n");
1803 exit(-1);
1804 }
1805 display_title_lines();
1806 while ((dent = readdir(dir))) {
1807 const char *fsname;
1808 char *dlm_fn;
1809 FILE *dlmf;
1810 int dlmfd;
1811
1812 if (!strcmp(dent->d_name, "."))
1813 continue;
1814 if (!strcmp(dent->d_name, ".."))
1815 continue;
1816
1817 fsname = strchr(dent->d_name, ':');
1818 if (fsname)
1819 fsname++;
1820 else
1821 fsname = dent->d_name;
1822
1823 if (asprintf(&dlm_fn, "%s/dlm/%s_waiters", debugfs, fsname) == -1) {
1824 perror("Failed to construct dlm waiters debugfs path");
1825 exit(-1);
1826 }
1827 dlmf = fopen(dlm_fn, "rt");
1828 if (dlmf) {
1829 dlmwaiters = parse_dlm_waiters(dlmf, fsname);
1830 fclose(dlmf);
1831 }
1832 free(dlm_fn);
1833
1834 if (print_dlm_grants) {
1835 if (asprintf(&dlm_fn, "%s/dlm/%s_locks", debugfs, fsname) == -1) {
1836 perror("Failed to construct dlm locks debugfs path");
1837 exit(-1);
1838 }
1839 dlmfd = open(dlm_fn, O_RDONLY);
1840 if (dlmfd > 0) {
1841 dlmgrants = parse_dlm_grants(dlmfd,
1842 fsname);
1843 close(dlmfd);
1844 }
1845 free(dlm_fn);
1846 }
1847
1848 if (asprintf(&fn, "%s/gfs2/%s/glocks", debugfs, dent->d_name) == -1) {
1849 perror(argv[0]);
1850 exit(-1);
1851 }
1852 fd = open(fn, O_RDONLY);
1853 if (fd < 0) {
1854 if (interactive) {
1855 refresh();
1856 endwin();
1857 }
1858 perror(fn);
1859 free(fn);
1860 exit(-1);
1861 }
1862 free(fn);
1863 parse_glocks_file(fd, fsname, dlmwaiters, dlmgrants,
1864 trace_dir_path, show_held, help,
1865 summary);
1866 close(fd);
1867 }
1868 closedir(dir);
1869 tv.tv_sec = refresh_time;
1870 tv.tv_usec = 0;
1871 FD_ZERO(&readfds);
1872 if (nfds != 0)
1873 FD_SET(STDIN_FILENO, &readfds);
1874 retval = select(nfds, &readfds, NULL, NULL, &tv);
1875 if (retval) {
1876 if (interactive)
1877 ch = getch();
1878 else
1879 ch = getchar();
1880 switch (ch) {
1881 case 0x1b: /* mount wheel? */
1882 case 0x03:
1883 case 'q':
1884 done = 1;
1885 break;
1886 case 'h':
1887 help = (help + 1) % 3;
1888 break;
1889 case 's':
1890 if (!interactive)
1891 break;
1892 move(1, 0);
1893 printw("Change delay from %d to: ",
1894 refresh_time);
1895 if (bobgets(string, 1, 25, 5, &ch) == 1)
1896 refresh_time = atoi(string);
1897 if (refresh_time < 1)
1898 refresh_time = 1;
1899 break;
1900 /* When we get EOF on stdin, remove it from the fd_set
1901 to avoid shorting out the select() */
1902 case EOF:
1903 nfds = 0;
1904 break;
1905 }
1906 }
1907 iters_done++;
1908 if (iterations && iters_done >= iterations)
1909 break;
1910 }
1911 free_mounts();
1912 free(gbuf);
1913 free(dbuf);
1914 free(debugfs);
1915 if (interactive) {
1916 refresh();
1917 endwin();
1918 }
1919 exit(0);
1920 }
1921