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
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");
271 if (fp == NULL) {
272 perror("/proc/mounts");
273 return 1;
274 }
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
280 if (strcmp(mnt->mnt_type, "debugfs") == 0) {
281 if (debugfs == NULL)
282 debugfs = strdup(mnt->mnt_dir);
283 continue;
284 }
285 if (strcmp(mnt->mnt_type, "gfs2") != 0)
286 continue;
287
288 newmnt = calloc(1, sizeof(*newmnt) + devlen + 1 + dirlen + 1);
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);
297 newmnt->fd = open(newmnt->device, O_RDONLY);
298
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 }
305 if (read_superblock(newmnt->fd, &newmnt->sb) != 0) {
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 {
|
(1) Event cond_true: |
Condition "*nextpos == NULL", taking true branch. |
458 if (*nextpos == NULL) {
|
(2) Event tainted_data_argument: |
Calling function "read" taints parameter "*bigbuf". [Note: The source code implementation of the function has been overridden by a builtin model.] |
| Also see events: |
[parm_assign][return_tainted_data] |
459 *maxpos = read(fd, bigbuf, bufsize - 1);
460 bigbuf[bufsize - 1] = '\0';
|
(3) Event cond_false: |
Condition "*maxpos == 0", taking false branch. |
461 if (*maxpos == 0)
|
(4) Event if_end: |
End of if statement. |
462 return NULL;
463 *pos = bigbuf;
|
(6) Event if_fallthrough: |
Falling through to end of if statement. |
464 } else
|
(7) Event if_end: |
End of if statement. |
465 *pos = *nextpos;
466
467 *nextpos = memchr(*pos, '\n', (bigbuf + *maxpos) - *pos);
|
(8) Event cond_true: |
Condition "*nextpos", taking true branch. |
|
(9) Event cond_true: |
Condition "**nextpos == 10", taking true branch. |
|
(10) Event cond_true: |
Condition "*nextpos < bigbuf + (bufsize - 1)", taking true branch. |
|
(12) Event loop_begin: |
Jumped back to beginning of loop. |
|
(13) Event cond_true: |
Condition "*nextpos", taking true branch. |
|
(14) Event cond_true: |
Condition "**nextpos == 10", taking true branch. |
|
(15) Event cond_false: |
Condition "*nextpos < bigbuf + (bufsize - 1)", taking false branch. |
468 while (*nextpos && (**nextpos == '\n' || **nextpos == '\r') &&
469 *nextpos < bigbuf + (bufsize - 1)) {
470 **nextpos = '\0';
471 (*nextpos)++;
|
(11) Event loop: |
Jumping back to the beginning of the loop. |
|
(16) Event loop_end: |
Reached end of loop. |
472 }
|
(17) Event cond_true: |
Condition "*nextpos >= bigbuf + *maxpos", taking true branch. |
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 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 procname = str + 6;
917 p = strchr(procname, '\n');
918 if (p)
919 *p = '\0';
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], *p1, *p2;
936 const char *procname;
937
938 p1 = strchr(g_line, '/');
939 if (!p1)
940 return;
941 p1++;
942 p2 = strchr(p1, ' ');
943 if (!p2)
944 return;
945 memset(trgt_res_name, 0, sizeof(trgt_res_name));
946 memcpy(trgt_res_name, p1, p2 - p1);
947 sprintf(dlm_resid, "%8d%16s", locktype, trgt_res_name);
948 for (i = 0; i < dlmgrants; i++) {
949 /*
950 lkb_id n remid pid x e f s g rq u n ln res_name 1234567890123456
951 1100003 1 2ae0006 8954 0 0 0 2 5 -1 0 1 24 " 2 102ab"
952 2a20001 1 30d0001 8934 0 0 0 2 3 -1 0 1 24 " 5 102ab"
953 b0001 2 860001 8868 0 0 10000 2 3 -1 0 0 24 " 1 2"
954 2450001 2 1be0002 8962 0 0 10000 1 -1 5 12214 0 24 " 2 102ab"
955 */
956 p1 = strchr(dlmglines[i], '\"');
957 if (!p1)
958 continue;
959 p1++;
960 if (strncmp(dlm_resid, p1, 24))
961 continue;
962
963 sscanf(dlmglines[i], "%x %d %x %u %"SCNu64" %x %x %d %d %d %"SCNu64" "
964 "%u %d \"%24s\"\n",
965 &lkb_id, &lkbnodeid, &remid, &ownpid, &xid, &exflags,
966 &flags, &status, &grmode, &rqmode, &us, &nodeid,
967 &length, res_name);
968 if (status == 1) { /* Waiting */
969 if (!lkbnodeid)
970 procname = getprocname(ownpid);
971 else
972 procname = "";
973 if (summary)
974 print_it(NULL, " (", NULL);
975 else
976 print_it(NULL, " D: ", NULL);
977 print_it(NULL, "%s for %s, pid %d %s", NULL,
978 dlm_status(status), dlm_nodeid(lkbnodeid),
979 ownpid, procname);
980 if (summary)
981 print_it(NULL, ")", NULL);
982 } else if (grmode == 0) {
983 continue; /* ignore "D: Granted NL on node X" */
984 } else {
985 procname = getprocname(ownpid);
986 if (summary)
987 print_it(NULL, " (", NULL);
988 else
989 print_it(NULL, " D: ", NULL);
990 print_it(NULL, "%s %s on %s to pid %d %s", NULL,
991 dlm_status(status), dlm_grtype(grmode),
992 dlm_nodeid(lkbnodeid), ownpid, procname);
993 if (summary)
994 print_it(NULL, ")", NULL);
995 }
996 if (!summary)
997 eol(0);
998 }
999 }
1000
1001 static void print_call_trace(const char *hline)
1002 {
1003 char *p, *pid, tmp[32], stackfn[64], str[96];
1004 FILE *fp;
1005 int i;
1006
1007 p = strchr(hline, 'p');
1008 if (!p)
1009 return;
1010 pid = p + 2;
1011 p = strchr(pid, ' ');
1012 if (!p)
1013 return;
1014 memset(tmp, 0, sizeof(tmp));
1015 memcpy(tmp, pid, p - pid);
1016 sprintf(stackfn, "/proc/%s/stack", tmp);
1017 fp = fopen(stackfn, "rt");
1018 if (fp == NULL)
1019 return;
1020 for (i = 0; i < MAX_CALLTRACE_LINES; i++) {
1021 if (fgets(str, sizeof(str) - 1, fp) == NULL)
1022 break;
1023 if (strstr(str, "gfs2_glock_")) { /* skip lines we don't
1024 care about*/
1025 i--;
1026 continue;
1027 }
1028 p = strchr(str, '\n');
1029 if (p)
1030 *p = '\0';
1031 p = strchr(str, ']');
1032 if (p)
1033 p += 2;
1034 else
1035 p = str;
1036 print_it(NULL, " C: %s ", NULL, p);
1037 eol(0);
1038 }
1039 fclose(fp);
1040 }
1041
1042 static int is_ex(const char *hline)
1043 {
1044 if (strncmp(hline, " H: s:EX ", 9) == 0)
1045 return 1;
1046 return 0;
1047 }
1048
1049 static int has_holder_flag(const char *hline, char flag)
1050 {
1051 const char *p;
1052
1053 p = strchr(hline, 'f');
1054 if (p == NULL)
1055 return 0;
1056 p++;
1057 if (*p != ':')
1058 return 0;
1059 p++;
1060 while (*p != '\0') {
1061 if (*p == ' ')
1062 return 0;
1063 if (*p == flag)
1064 return 1;
1065 p++;
1066 }
1067 return 0;
1068 }
1069
1070 static int is_holder(const char *hline)
1071 {
1072 return has_holder_flag(hline, 'H');
1073 }
1074
1075 static int is_waiter(const char *hline)
1076 {
1077 return has_holder_flag(hline, 'W');
1078 }
1079
1080 static int get_lock_type(const char *str)
1081 {
1082 const char *p;
1083
|
(1) Event identity_transfer: |
Passing "str" as argument 1 to function "strchr", which returns an offset off that argument. |
|
(2) Event tainted_data_transitive: |
Calling function "strchr" with tainted argument "str" results in tainted data. |
|
(3) Event var_assign: |
Assigning: "p" = "strchr(str, 47)", which taints "p". |
| Also see events: |
[return_tainted_data] |
1084 p = strchr(str, '/');
1085 return (p ? (*(p - 1)) - '0' : 0);
1086 }
1087
1088 static long long get_demote_time(const char *str)
1089 {
1090 char *p;
1091 char tmp[80];
1092
1093 p = strchr(str, '/');
1094 if (p == NULL)
1095 return 0;
1096 p++;
1097 p = strchr(p, '/');
1098 if (p == NULL)
1099 return 0;
1100 p++;
1101 strncpy(tmp, p, 79);
1102 tmp[79] = '\0';
1103 p = strchr(tmp, ' ');
1104 if (p == NULL)
1105 return 0;
1106 *p = '\0';
1107 return atoll(tmp);
1108 }
1109
1110 static const char *pid_string(const char *str)
1111 {
1112 char *p;
1113 static char pidstr[80];
1114
1115 memset(pidstr, 0, sizeof(pidstr));
1116 p = strchr(str, 'p');
1117 if (p) {
1118 strncpy(pidstr, p + 2, sizeof(pidstr));
1119 pidstr[79] = '\0';
1120 p = strchr(pidstr, ']');
1121 if (p) {
1122 p++;
1123 *p = '\0';
1124 }
1125 }
1126 return pidstr;
1127 }
1128
1129 /* If this glock is relevant, return 0, else the reason it's irrelevant */
1130 static int irrelevant(const char *holder, const char *glockstr)
1131 {
1132 int lock_type = get_lock_type(glockstr);
1133
1134 /* Exclude shared and locks */
1135 if (!is_ex(holder))
1136 return 1;
1137 /* Exclude locks held at mount time: statfs*/
1138 if (strstr(holder, "init_per_node"))
1139 return 2;
1140 if (strstr(holder, "init_journal"))
1141 return 3;
1142 if (strstr(holder, "init_inodes"))
1143 return 4;
1144 if (strstr(holder, "fill_super"))
1145 return 5;
1146 if (lock_type == 9) /* Exclude journal locks */
1147 return 6;
1148 return 0;
1149 }
1150
1151 static const char *reason(int why)
1152 {
1153 const char *reasons[] = {"(N/A:------)", /* 0 */
1154 "(N/A:Not EX)", /* 1 */
1155 "(N/A:System)", /* 2 */
1156 "(N/A:journl)", /* 3 */
1157 "(N/A:System)", /* 4 */
1158 "(N/A:System)", /* 5 */
1159 "(N/A:Journl)"}; /* 6 */
1160
1161 return reasons[why];
1162 }
1163
1164 static void print_friendly_prefix(char one_glocks_lines[MAX_LINES][97])
1165 {
1166 int why = irrelevant(one_glocks_lines[1], one_glocks_lines[0]);
1167
1168 if (why)
1169 print_it(NULL, " U: %s ", NULL, reason(why));
1170 else
1171 print_it(NULL, " U: ", NULL);
1172 }
1173
1174 static void show_glock(char one_glocks_lines[MAX_LINES][97], int gline,
1175 const char *fsname, int dlmwaiters, int dlmgrants,
1176 int trace_dir_path, int prev_had_waiter, int flags,
1177 int summary)
1178 {
1179 int i, locktype = 0;
1180 char id[33], *p;
1181 char extras[80], prefix = '\0';
1182 long long demote_time = 0;
1183 const char *ltype[] = {"N/A", "non-disk", "inode", "rgrp", "meta",
1184 "i_open", "flock", "posix lock", "quota",
1185 "journal"};
1186
1187 if (termlines) {
1188 if (irrelevant(one_glocks_lines[1], one_glocks_lines[0]))
1189 COLORS_HELD;
1190 else
1191 COLORS_NORMAL;
1192 }
1193 if (!gline)
1194 return;
1195
1196 memset(extras, 0, sizeof(extras));
1197 p = strchr(one_glocks_lines[0], '/');
1198 memset(id, 0, sizeof(id));
1199
1200 if (p) {
1201 locktype = get_lock_type(one_glocks_lines[0]);
1202 demote_time = get_demote_time(one_glocks_lines[0]);
1203 p++;
1204 strncpy(id, p, sizeof(id) - 1);
1205 id[sizeof(id) - 1] = '\0';
1206 p = strchr(id, ' ');
1207 if (p)
1208 *p = '\0';
1209
1210 if (locktype != 2) {
1211 strncpy(extras, ltype[locktype], 79);
1212 extras[79] = '\0';
1213 } else {
1214 const char *i_type = show_details(id, fsname, 2,
1215 trace_dir_path);
1216 sprintf(extras, "%sinode", i_type);
1217 }
1218 }
1219 if (flags & DETAILS) {
1220 print_it(NULL, " %s ", NULL, one_glocks_lines[0]);
1221 print_it(NULL, "(%s)", NULL, extras);
1222 if (demote_time)
1223 print_it(NULL, " ** demote time is greater than 0 **",
1224 NULL);
1225 eol(0);
1226 if (dlmgrants)
1227 show_dlm_grants(locktype, one_glocks_lines[0],
1228 dlmgrants, 0);
1229 }
1230 if (flags & FRIENDLY) {
1231 print_friendly_prefix(one_glocks_lines);
1232 for (i = 1; i < gline; i++) {
1233 if (one_glocks_lines[i][0] == ' ' &&
1234 one_glocks_lines[i][1] == 'H' &&
1235 prefix != 'W')
1236 prefix = (is_holder(one_glocks_lines[i]) ?
1237 'H' : 'W');
1238 }
1239 print_it(NULL, " %c %-10.10s %-9.9s %s", NULL, prefix,
1240 extras, id, friendly_glock(one_glocks_lines[0],
1241 prefix));
1242 eol(0);
1243 }
1244 for (i = 1; i < gline; i++) {
1245 if (!show_reservations &&
1246 one_glocks_lines[i][0] == ' ' &&
1247 one_glocks_lines[i][2] == 'B' &&
1248 one_glocks_lines[i][3] == ':')
1249 continue;
1250
1251 if (flags & DETAILS) {
1252 print_it(NULL, " %-80.80s", NULL, one_glocks_lines[i]);
1253 eol(0);
1254 continue;
1255 }
1256 if ((flags & FRIENDLY) &&
1257 one_glocks_lines[i][1] == 'H')
1258 print_friendly_prefix(one_glocks_lines);
1259
1260 if (one_glocks_lines[i][0] == ' ' &&
1261 one_glocks_lines[i][1] == 'H') {
1262 print_it(NULL, " %c ---> %s pid %s ", NULL,
1263 prefix, (is_holder(one_glocks_lines[i]) ?
1264 "held by" : "waiting"),
1265 pid_string(one_glocks_lines[i]));
1266 if (demote_time)
1267 print_it(NULL, "** demote time is non-"
1268 "zero ** ", NULL);
1269 if (is_dlm_waiting(dlmwaiters, locktype, id)) {
1270 print_it(NULL, "***** DLM is in a "
1271 "comm wait for this lock "
1272 "***** ", NULL);
1273 }
1274 show_dlm_grants(locktype, one_glocks_lines[0],
1275 dlmgrants, 1);
1276 eol(0);
1277 print_call_trace(one_glocks_lines[i]);
1278 }
1279 }
1280 }
1281
1282 static int parse_dlm_waiters(FILE *dlm, const char *fsname)
1283 {
1284 int dlml = 0;
1285
1286 memset(dlmwlines, 0, sizeof(dlmwlines));
1287 while (fgets(dlmwlines[dlml], 80, dlm))
1288 dlml++;
1289
1290 return dlml;
1291 }
1292
1293 static int parse_dlm_grants(int dlmfd, const char *fsname)
1294 {
1295 int dlml = 0;
1296 char *dlmline;
1297
1298 memset(dlmglines, 0, sizeof(dlmglines));
1299 dnextpos = NULL;
1300 while ((dlmline = bufgets(dlmfd, dbuf, &dnextpos, &dpos, &dmaxpos))) {
1301 if (!this_lkb_requested(dlmline))
1302 continue;
1303 strncpy(dlmglines[dlml], dlmline, 96);
1304 dlmglines[dlml][96] = '\0';
1305 dlml++;
1306 if (dlml >= MAX_LINES)
1307 break;
1308 }
1309 return dlml;
1310 }
1311
1312 static void print_summary(int total_glocks[11][stypes], int dlmwaiters)
1313 {
1314 int i;
1315 int total_unlocked = 0;
1316 const struct {
1317 const char *name;
1318 const int width;
1319 } column[] = {
1320 { "unknown", 7 }, { "nondisk", 7}, { "inode", 8 }, { "rgrp", 7 },
1321 { "meta", 4 }, { "iopen", 7 }, { "flock", 7 }, { "p", 1 },
1322 { "quota", 5 }, { "jrnl", 4 }, { "Total", 8 }
1323 };
1324 const int ncols = sizeof(column) / sizeof(column[0]);
1325
1326 /* Print column headers */
1327 print_it(NULL, "S glocks ", NULL);
1328 for (i = 1; i < ncols; i++)
1329 if (i != 7 && i != 4) /* Ignore plock and meta */
1330 print_it(NULL, "%*s ", NULL, column[i].width, column[i].name);
1331 eol(0);
1332 print_it(NULL, "S --------- ", NULL);
1333 for (i = 1; i < ncols; i++)
1334 if (i != 7 && i != 4) /* Ignore plock and meta */
1335 print_it(NULL, "%*s ", NULL, column[i].width, "--------");
1336 eol(0);
1337
1338 /* Print rows */
1339 print_it(NULL, "S Unlocked: ", NULL);
1340 for (i = 1; i < (ncols - 1); i++) {
1341 if (i != 7 && i != 4) /* Ignore plock and meta */
1342 print_it(NULL, "%*d ", NULL, column[i].width,
1343 total_glocks[i][all] - total_glocks[i][locked]);
1344 total_unlocked += total_glocks[i][all] -
1345 total_glocks[i][locked];
1346 }
1347 print_it(NULL, "%*d ", NULL, column[i].width, total_unlocked);
1348 eol(0);
1349 print_it(NULL, "S Locked: ", NULL);
1350 for (i = 1; i < ncols; i++) {
1351 if (i != 7 && i != 4) /* Ignore plock and meta */
1352 print_it(NULL, "%*d ", NULL, column[i].width,
1353 total_glocks[i][locked]);
1354 total_glocks[10][locked] += total_glocks[i][locked];
1355 }
1356 eol(0);
1357 print_it(NULL, "S Total: ", NULL);
1358 for (i = 1; i < ncols; i++) {
1359 if (i != 7 && i != 4) /* Ignore plock and meta */
1360 print_it(NULL, "%*d ", NULL, column[i].width,
1361 total_glocks[i][all]);
1362 total_glocks[10][all] += total_glocks[i][all];
1363 }
1364 eol(0);
1365 print_it(NULL, "S", NULL);
1366 eol(0);
1367 print_it(NULL, "S Held EX: ", NULL);
1368 for (i = 1; i < ncols; i++) {
1369 if (i != 7 && i != 4) /* Ignore plock and meta */
1370 print_it(NULL, "%*d ", NULL, column[i].width,
1371 total_glocks[i][held_ex]);
1372 total_glocks[10][held_ex] += total_glocks[i][held_ex];
1373 }
1374 eol(0);
1375 print_it(NULL, "S Held SH: ", NULL);
1376 for (i = 1; i < ncols; i++) {
1377 if (i != 7 && i != 4) /* Ignore plock and meta */
1378 print_it(NULL, "%*d ", NULL, column[i].width,
1379 total_glocks[i][held_sh]);
1380 total_glocks[10][held_sh] += total_glocks[i][held_sh];
1381 }
1382 eol(0);
1383 print_it(NULL, "S Held DF: ", NULL);
1384 for (i = 1; i < ncols; i++) {
1385 if (i != 7 && i != 4) /* Ignore plock and meta */
1386 print_it(NULL, "%*d ", NULL, column[i].width,
1387 total_glocks[i][held_df]);
1388 total_glocks[10][held_df] += total_glocks[i][held_df];
1389 }
1390 eol(0);
1391 print_it(NULL, "S G Waiting: ", NULL);
1392 for (i = 1; i < ncols; i++) {
1393 if (i != 7 && i != 4) /* Ignore plock and meta */
1394 print_it(NULL, "%*d ", NULL, column[i].width,
1395 total_glocks[i][has_waiter]);
1396 total_glocks[10][has_waiter] += total_glocks[i][has_waiter];
1397 }
1398 eol(0);
1399 print_it(NULL, "S P Waiting: ", NULL);
1400 for (i = 1; i < ncols; i++) {
1401 if (i != 7 && i != 4) /* Ignore plock and meta */
1402 print_it(NULL, "%*d ", NULL, column[i].width,
1403 total_glocks[i][tot_waiters]);
1404 total_glocks[10][tot_waiters] += total_glocks[i][tot_waiters];
1405 }
1406 eol(0);
1407 print_it(NULL, "S DLM wait: %7d", NULL, dlmwaiters);
1408 eol(0);
1409 eol(0);
1410 }
1411
1412 /* flags = DETAILS || FRIENDLY or both */
1413 static void glock_details(int fd, const char *fsname, int dlmwaiters,
1414 int dlmgrants, int trace_dir_path, int show_held,
1415 int summary)
1416 {
1417 char *ln, *p;
1418 char one_glocks_lines[MAX_LINES][97];
1419 int gline = 0;
1420 int show_prev_glock = 0, prev_had_waiter = 0;
1421 int total_glocks[11][stypes], locktype = 0;
1422 int holders_this_glock_ex = 0;
1423 int holders_this_glock_sh = 0;
1424 int holders_this_glock_df = 0;
1425 int waiters_this_glock = 0;
1426
1427 memset(total_glocks, 0, sizeof(total_glocks));
1428 gnextpos = NULL;
|
(1) Event tainted_return_value: |
Function "bufgets" returns tainted data. [details] |
|
(2) Event var_assign: |
Assigning: "ln" = "bufgets(fd, gbuf, &gnextpos, &gpos, &gmaxpos)", which taints "ln". |
|
(3) Event cond_true: |
Condition "ln = bufgets(fd, gbuf, &gnextpos, &gpos, &gmaxpos)", taking true branch. |
| Also see events: |
[tainted_data_transitive][var_assign][tainted_data][remediation] |
1429 while ((ln = bufgets(fd, gbuf, &gnextpos, &gpos, &gmaxpos))) {
|
(4) Event cond_true: |
Condition "ln[0] == ' '", taking true branch. |
|
(5) Event cond_true: |
Condition "ln[1] == ' '", taking true branch. |
|
(6) Event cond_false: |
Condition "ln[2] == ' '", taking false branch. |
1430 if (ln[0] == ' ' && ln[1] == ' ' && ln[2] == ' ')
|
(7) Event if_end: |
End of if statement. |
1431 continue;
|
(8) Event cond_true: |
Condition "ln[0] == 'G'", taking true branch. |
1432 if (ln[0] == 'G') {
1433 /* Summary stuff------------------------------------ */
|
(9) Event cond_false: |
Condition "waiters_this_glock", taking false branch. |
1434 if (waiters_this_glock) {
1435 total_glocks[locktype][tot_waiters] +=
1436 waiters_this_glock;
1437 total_glocks[locktype][has_waiter]++;
|
(10) Event if_end: |
End of if statement. |
1438 }
|
(11) Event cond_false: |
Condition "holders_this_glock_ex", taking false branch. |
1439 if (holders_this_glock_ex)
|
(12) Event if_end: |
End of if statement. |
1440 total_glocks[locktype][held_ex]++;
|
(13) Event cond_false: |
Condition "holders_this_glock_sh", taking false branch. |
1441 if (holders_this_glock_sh)
|
(14) Event if_end: |
End of if statement. |
1442 total_glocks[locktype][held_sh]++;
|
(15) Event cond_false: |
Condition "holders_this_glock_df", taking false branch. |
1443 if (holders_this_glock_df)
|
(16) Event if_end: |
End of if statement. |
1444 total_glocks[locktype][held_df]++;
|
(17) Event tainted_data_transitive: |
Call to function "get_lock_type" with tainted argument "*ln" returns tainted data. [details] |
|
(18) Event var_assign: |
Assigning: "locktype" = "get_lock_type(ln)", which taints "locktype". |
| Also see events: |
[tainted_return_value][var_assign][tainted_data][remediation] |
1445 locktype = get_lock_type(ln);
1446 p = ln + 6;
|
(19) Event cond_true: |
Condition "*p != 'U'", taking true branch. |
1447 if (*p != 'U' || *(p + 1) != 'N')
|
(20) Event tainted_data: |
Using tainted variable "locktype" as an index into an array "total_glocks". |
|
(21) Event remediation: |
Ensure that tainted values are properly sanitized, by checking that their values are within a permissible range. |
| Also see events: |
[tainted_return_value][var_assign][tainted_data_transitive][var_assign] |
1448 total_glocks[locktype][locked]++;
1449 total_glocks[locktype][all]++;
1450 holders_this_glock_ex = 0;
1451 holders_this_glock_sh = 0;
1452 holders_this_glock_df = 0;
1453 waiters_this_glock = 0;
1454 /* Detail stuff------------------------------------- */
1455 if (show_prev_glock) {
1456 show_glock(one_glocks_lines, gline, fsname,
1457 dlmwaiters, dlmgrants,
1458 trace_dir_path, prev_had_waiter,
1459 DETAILS, summary);
1460 show_glock(one_glocks_lines, gline, fsname,
1461 dlmwaiters, dlmgrants,
1462 trace_dir_path, prev_had_waiter,
1463 FRIENDLY, summary);
1464 memset(one_glocks_lines, 0,
1465 sizeof(one_glocks_lines));
1466 show_prev_glock = 0;
1467 }
1468 prev_had_waiter = 0;
1469 gline = 0;
1470 if (this_glock_requested(ln))
1471 show_prev_glock = 1;
1472 } else if (ln[0] == ' ' && ln[1] == 'H') {
1473 char *flag = strchr(ln, 'f');
1474 char *mode = strchr(ln, 's');
1475
1476 /* Summary stuff------------------------------------ */
1477 while (flag) {
1478 flag++;
1479 switch (*flag) {
1480 case ':':
1481 break;
1482 case 'W':
1483 waiters_this_glock++;
1484 flag = NULL;
1485 break;
1486 case 'H':
1487 flag = NULL;
1488 if (mode == NULL)
1489 holders_this_glock_df++;
1490 else if (*(mode + 1) == ':' &&
1491 *(mode + 2) == 'E' &&
1492 *(mode + 3) == 'X')
1493 holders_this_glock_ex++;
1494 else if (*(mode + 1) == ':' &&
1495 *(mode + 2) == 'S' &&
1496 *(mode + 3) == 'H')
1497 holders_this_glock_sh++;
1498 else
1499 holders_this_glock_df++;
1500 break;
1501 case ' ':
1502 flag = NULL;
1503 break;
1504 default:
1505 break;
1506 };
1507 }
1508 /* Detail stuff------------------------------------- */
1509 if (!glocks) {
1510 int haswaiter = is_waiter(ln);
1511
1512 if (haswaiter) {
1513 show_prev_glock = 1;
1514 prev_had_waiter = 1;
1515 } else if (show_held && is_holder(ln) &&
1516 !is_iopen(one_glocks_lines[0])) {
1517 show_prev_glock = 1;
1518 } else if (!irrelevant(ln, one_glocks_lines[0])) {
1519 show_prev_glock = 1;
1520 }
1521 }
1522 }
1523 /* Detail stuff--------------------------------------------- */
1524 strncpy(one_glocks_lines[gline], ln, 96);
1525 one_glocks_lines[gline][96] = '\0';
1526 gline++;
1527 if (gline >= MAX_LINES)
1528 break;
1529 if (termlines && line >= termlines)
1530 break;
1531 }
1532 /* Detail stuff----------------------------------------------------- */
1533 if (show_prev_glock && gline < MAX_LINES &&
1534 (!termlines || line < termlines)) {
1535 show_glock(one_glocks_lines, gline, fsname, dlmwaiters,
1536 dlmgrants, trace_dir_path, prev_had_waiter,
1537 DETAILS, summary);
1538 show_glock(one_glocks_lines, gline, fsname, dlmwaiters,
1539 dlmgrants, trace_dir_path, prev_had_waiter,
1540 FRIENDLY, summary);
1541 }
1542 if (!summary || ((iters_done % summary) != 0))
1543 return;
1544
1545 print_summary(total_glocks, dlmwaiters);
1546 }
1547
1548 static void show_help(int help)
1549 {
1550 if (help == 1) {
1551 COLORS_NORMAL;
1552 eol(0);
1553 print_it(NULL, " Glock flags: ", NULL);
1554 eol(0);
1555 print_it(NULL, " l - Locked ", NULL);
1556 print_it(NULL, " r - Reply pending ", NULL);
1557 eol(0);
1558 print_it(NULL, " d - Demote pending ", NULL);
1559 print_it(NULL, " I - Initial ", NULL);
1560 eol(0);
1561 print_it(NULL, " D - Demote requested ", NULL);
1562 print_it(NULL, " F - Frozen ", NULL);
1563 eol(0);
1564 print_it(NULL, " p - Demote in progress ", NULL);
1565 print_it(NULL, " q - Queued holder ", NULL);
1566 eol(0);
1567 print_it(NULL, " y - Dirty data ", NULL);
1568 print_it(NULL, " L - LRU ", NULL);
1569 eol(0);
1570 print_it(NULL, " f - Flush ", NULL);
1571 print_it(NULL, " o - Object present ", NULL);
1572 eol(0);
1573 print_it(NULL, " i - Invalidating ", NULL);
1574 print_it(NULL, " b - Blocking request ", NULL);
1575 eol(0);
1576 } else if (help == 2) {
1577 COLORS_NORMAL;
1578 eol(0);
1579 print_it(NULL, " Holder flags: ", NULL);
1580 eol(0);
1581 print_it(NULL, " t - Try (non-blocking) ", NULL);
1582 print_it(NULL, " E - Exact lock ", NULL);
1583 eol(0);
1584 print_it(NULL, " T - Try with callback ", NULL);
1585 print_it(NULL, " c - No Cache lock ", NULL);
1586 eol(0);
1587 print_it(NULL, " e - No exp ", NULL);
1588 print_it(NULL, " H - Held (locked) ", NULL);
1589 eol(0);
1590 print_it(NULL, " A - Any lock ", NULL);
1591 print_it(NULL, " W - Waiting for lock ", NULL);
1592 eol(0);
1593 print_it(NULL, " p - Priority lock ", NULL);
1594 print_it(NULL, " a - Asynchronous lock ", NULL);
1595 eol(0);
1596 print_it(NULL, " F - First ", NULL);
1597 eol(0);
1598 }
1599 }
1600
1601 /* flags = DETAILS || FRIENDLY or both */
1602 static void parse_glocks_file(int fd, const char *fsname, int dlmwaiters,
1603 int dlmgrants, int trace_dir_path,
1604 int show_held, int help, int summary)
1605 {
1606 char fstitle[96], *fsdlm;
1607 char ctimestr[64];
1608 time_t t;
1609 int i;
1610
1611 tzset();
1612 t = time(NULL);
1613 strftime(ctimestr, 64, "%a %b %d %T %Y", localtime(&t));
1614 ctimestr[63] = '\0';
1615 memset(fstitle, 0, sizeof(fstitle));
1616 fsdlm = calloc(1, 105 + dlmwaiters);
1617 if (!fsdlm) {
1618 printf("Failed to allocate fsdlm\n");
1619 exit(-1);
1620 }
1621
1622 sprintf(fstitle, "@ %.22s %s ", fsname, ctimestr);
1623 if (dlmwaiters) {
1624 sprintf(fsdlm, "dlm: %s/%s/%s [", dlm_dirtbl_size,
1625 dlm_rsbtbl_size, dlm_lkbtbl_size);
1626 for (i = 0; i < dlmwaiters; i++)
1627 strcat(fsdlm, "*");
1628 for (; i < 10; i++)
1629 strcat(fsdlm, " ");
1630 strcat(fsdlm, "]");
1631 }
1632 attron(A_BOLD);
1633 print_it(NULL, "%s @%s %s", NULL, fstitle, hostname, fsdlm);
1634 free(fsdlm);
1635 eol(0);
1636 attroff(A_BOLD);
1637 glock_details(fd, fsname, dlmwaiters, dlmgrants, trace_dir_path,
1638 show_held, summary);
1639
1640 show_help(help);
1641 if (termlines)
1642 refresh();
1643 }
1644
1645 static void usage(void)
1646 {
1647 printf("Usage:\n");
1648 printf("glocktop [-i] [-d <delay sec>] [-n <iter>] [-sX] [-c] [-D] [-H] [-r] [-t]\n");
1649 printf("\n");
1650 printf("-i : Runs glocktop in interactive mode.\n");
1651 printf("-d : delay between refreshes, in seconds (default: %d).\n", REFRESH_TIME);
1652 printf("-n : stop after <iter> refreshes.\n");
1653 printf("-H : don't show Held glocks, even if not waited on, excluding "
1654 "iopen\n");
1655 printf("-r : show reservations when rgrp glocks are displayed\n");
1656 printf("-s : show glock summary information every X iterations\n");
1657 printf("-t : trace directory glocks back\n");
1658 printf("-D : don't show DLM lock status\n");
1659 printf("\n");
1660 fflush(stdout);
1661 exit(0);
1662 }
1663
1664 int main(int argc, char **argv)
1665 {
1666 int fd;
1667 DIR *dir = NULL;
1668 char *fn;
1669 struct dirent *dent;
1670 int retval;
1671 int refresh_time = REFRESH_TIME;
1672 fd_set readfds;
1673 char string[96];
1674 int ch, dlmwaiters = 0, dlmgrants = 0;
1675 int cont = TRUE, optchar;
1676 int trace_dir_path = 0;
1677 int show_held = 1, help = 0;
1678 int interactive = 0;
1679 int summary = 10;
1680 int nfds = STDIN_FILENO + 1;
1681
1682 prog_name = argv[0];
1683 memset(glock, 0, sizeof(glock));
1684 memset(contended_filenames, 0, sizeof(contended_filenames));
1685 memset(contended_blocks, 0, sizeof(contended_blocks));
1686 UpdateSize(0);
1687 /* decode command line arguments */
1688 while (cont) {
1689 optchar = getopt(argc, argv, "-d:Dn:rs:thHi");
1690
1691 switch (optchar) {
1692 case 'd':
1693 refresh_time = atoi(optarg);
1694 if (refresh_time < 1) {
1695 fprintf(stderr, "Error: delay %d too small; "
1696 "must be at least 1\n", refresh_time);
1697 exit(-1);
1698 }
1699 break;
1700 case 'D':
1701 print_dlm_grants = 0;
1702 break;
1703 case 'n':
1704 iterations = atoi(optarg);
1705 break;
1706 case 'r':
1707 show_reservations = 1;
1708 break;
1709 case 's':
1710 summary = atoi(optarg);
1711 break;
1712 case 't':
1713 trace_dir_path = 1;
1714 break;
1715 case 'h':
1716 usage();
1717 break;
1718 case 'H':
1719 show_held = 0; /* held, but not iopen held */
1720 break;
1721 case 'i':
1722 interactive = 1;
1723 break;
1724 case EOF:
1725 cont = FALSE;
1726 break;
1727 case 1:
1728 if (optarg && glocks < MAX_GLOCKS)
1729 glock[glocks++] = optarg;
1730 break;
1731
1732 default:
1733 fprintf(stderr, "unknown option: %c\n", optchar);
1734 exit(-1);
1735 };
1736 }
1737
1738 if (interactive) {
1739 printf("Initializing. Please wait...");
1740 fflush(stdout);
1741 }
1742 if (gethostname(hostname, sizeof(hostname))) {
1743 fprintf(stderr, "Error: unable to determine host name.\n");
1744 exit(-1);
1745 }
1746 if (parse_mounts())
1747 exit(-1);
1748
1749 if (interactive && (wind = initscr()) == NULL) {
1750 fprintf(stderr, "Error: unable to initialize screen.\n");
1751 exit(-1);
1752 }
1753
1754 if (interactive) {
1755 /* Do our initial screen stuff: */
1756 signal(SIGWINCH, UpdateSize); /* handle term resize signal */
1757 UpdateSize(0); /* update screen size based on term settings */
1758 clear(); /* don't use Erase */
1759 start_color();
1760 noecho();
1761 keypad(stdscr, TRUE);
1762 raw();
1763 curs_set(0);
1764 init_colors();
1765 } else {
1766 termlines = 0;
1767 }
1768 while (!gbuf) {
1769 gbuf = malloc(bufsize);
1770 if (gbuf) {
1771 /*printf("bufsize=%dK\n", bufsize / 1024);*/
1772 break;
1773 }
1774 bufsize /= 2;
1775 }
1776 while (!dbuf) {
1777 dbuf = malloc(bufsize);
1778 if (dbuf) {
1779 /*printf("bufsize=%dK\n", bufsize / 1024);*/
1780 break;
1781 }
1782 bufsize /= 2;
1783 }
1784
1785 while (!done) {
1786 struct timeval tv;
1787
1788 if (asprintf(&fn, "%s/gfs2/", debugfs) == -1) {
1789 perror(argv[0]);
1790 exit(-1);
1791 }
1792 dir = opendir(fn);
1793 free(fn);
1794
1795 if (!dir) {
1796 if (interactive) {
1797 refresh();
1798 endwin();
1799 }
1800 fprintf(stderr, "Unable to open gfs2 debugfs directory.\n");
1801 fprintf(stderr, "Check if debugfs and gfs2 are mounted.\n");
1802 exit(-1);
1803 }
1804 display_title_lines();
1805 while ((dent = readdir(dir))) {
1806 const char *fsname;
1807 char *dlm_fn;
1808 FILE *dlmf;
1809 int dlmfd;
1810
1811 if (!strcmp(dent->d_name, "."))
1812 continue;
1813 if (!strcmp(dent->d_name, ".."))
1814 continue;
1815
1816 fsname = strchr(dent->d_name, ':');
1817 if (fsname)
1818 fsname++;
1819 else
1820 fsname = dent->d_name;
1821
1822 if (asprintf(&dlm_fn, "%s/dlm/%s_waiters", debugfs, fsname) == -1) {
1823 perror("Failed to construct dlm waiters debugfs path");
1824 exit(-1);
1825 }
1826 dlmf = fopen(dlm_fn, "rt");
1827 if (dlmf) {
1828 dlmwaiters = parse_dlm_waiters(dlmf, fsname);
1829 fclose(dlmf);
1830 }
1831 free(dlm_fn);
1832
1833 if (print_dlm_grants) {
1834 if (asprintf(&dlm_fn, "%s/dlm/%s_locks", debugfs, fsname) == -1) {
1835 perror("Failed to construct dlm locks debugfs path");
1836 exit(-1);
1837 }
1838 dlmfd = open(dlm_fn, O_RDONLY);
1839 if (dlmfd > 0) {
1840 dlmgrants = parse_dlm_grants(dlmfd,
1841 fsname);
1842 close(dlmfd);
1843 }
1844 free(dlm_fn);
1845 }
1846
1847 if (asprintf(&fn, "%s/gfs2/%s/glocks", debugfs, dent->d_name) == -1) {
1848 perror(argv[0]);
1849 exit(-1);
1850 }
1851 fd = open(fn, O_RDONLY);
1852 if (fd < 0) {
1853 if (interactive) {
1854 refresh();
1855 endwin();
1856 }
1857 perror(fn);
1858 free(fn);
1859 exit(-1);
1860 }
1861 free(fn);
1862 parse_glocks_file(fd, fsname, dlmwaiters, dlmgrants,
1863 trace_dir_path, show_held, help,
1864 summary);
1865 close(fd);
1866 }
1867 closedir(dir);
1868 tv.tv_sec = refresh_time;
1869 tv.tv_usec = 0;
1870 FD_ZERO(&readfds);
1871 if (nfds != 0)
1872 FD_SET(STDIN_FILENO, &readfds);
1873 retval = select(nfds, &readfds, NULL, NULL, &tv);
1874 if (retval) {
1875 if (interactive)
1876 ch = getch();
1877 else
1878 ch = getchar();
1879 switch (ch) {
1880 case 0x1b: /* mount wheel? */
1881 case 0x03:
1882 case 'q':
1883 done = 1;
1884 break;
1885 case 'h':
1886 help = (help + 1) % 3;
1887 break;
1888 case 's':
1889 if (!interactive)
1890 break;
1891 move(1, 0);
1892 printw("Change delay from %d to: ",
1893 refresh_time);
1894 if (bobgets(string, 1, 25, 5, &ch) == 1)
1895 refresh_time = atoi(string);
1896 if (refresh_time < 1)
1897 refresh_time = 1;
1898 break;
1899 /* When we get EOF on stdin, remove it from the fd_set
1900 to avoid shorting out the select() */
1901 case EOF:
1902 nfds = 0;
1903 break;
1904 }
1905 }
1906 iters_done++;
1907 if (iterations && iters_done >= iterations)
1908 break;
1909 }
1910 free_mounts();
1911 free(gbuf);
1912 free(dbuf);
1913 free(debugfs);
1914 if (interactive) {
1915 refresh();
1916 endwin();
1917 }
1918 exit(0);
1919 }
1920