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  	{
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  		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  	
(1) Event cond_true: Condition "mp != NULL", taking true branch.
582  		for (mp = mounts; mp != NULL; mp = mp->next) {
(2) Event cond_true: Condition "fd == mp->fd", taking true branch.
583  			if (fd == mp->fd)
(3) Event break: Breaking from loop.
584  				break;
(4) Event loop_end: Reached end of loop.
585  		}
(5) Event cond_false: Condition "mp == NULL", taking false branch.
586  		if (mp == NULL)
(6) Event if_end: End of if statement.
587  			return;
(7) Event cond_true: Condition "i < contended_count", taking true branch.
(11) Event loop_begin: Jumped back to beginning of loop.
(12) Event cond_true: Condition "i < contended_count", taking true branch.
(16) Event loop_begin: Jumped back to beginning of loop.
(17) Event cond_false: Condition "i < contended_count", taking false branch.
588  		for (i = 0; i < contended_count; i++) {
(8) Event cond_false: Condition "contended_blocks[i] == block", taking false branch.
(13) Event cond_false: Condition "contended_blocks[i] == block", taking false branch.
589  			if (contended_blocks[i] == block) {
590  				break;
(9) Event if_end: End of if statement.
(14) Event if_end: End of if statement.
591  			}
(10) Event loop: Jumping back to the beginning of the loop.
(15) Event loop: Jumping back to the beginning of the loop.
(18) Event loop_end: Reached end of loop.
592  		}
593  		sprintf(blk, "%"PRIu64, block);
(19) Event cond_true: Condition "i >= contended_count", taking true branch.
594  		if (i >= contended_count) {
595  			memset(contended_filenames[i], 0, PATH_MAX);
(20) Event fixed_size_dest: You might overrun the 4096-character fixed-size string "contended_filenames[i]" by copying "mp->dir" without checking the length.
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 	
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;
1429 		while ((ln = bufgets(fd, gbuf, &gnextpos, &gpos, &gmaxpos))) {
1430 			if (ln[0] == ' ' && ln[1] == ' ' && ln[2] == ' ')
1431 				continue;
1432 			if (ln[0] == 'G') {
1433 				/* Summary stuff------------------------------------ */
1434 				if (waiters_this_glock) {
1435 					total_glocks[locktype][tot_waiters] +=
1436 						waiters_this_glock;
1437 					total_glocks[locktype][has_waiter]++;
1438 				}
1439 				if (holders_this_glock_ex)
1440 					total_glocks[locktype][held_ex]++;
1441 				if (holders_this_glock_sh)
1442 					total_glocks[locktype][held_sh]++;
1443 				if (holders_this_glock_df)
1444 					total_glocks[locktype][held_df]++;
1445 				locktype = get_lock_type(ln);
1446 				p = ln + 6;
1447 				if (*p != 'U' || *(p + 1) != 'N')
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