2 * nfsstat.c Output NFS statistics
4 * Copyright (C) 1995-2005 Olaf Kirch <okir@suse.de>
9 #define NFSSVCSTAT "/proc/net/rpc/nfsd"
10 #define NFSCLTSTAT "/proc/net/rpc/nfs"
12 #define MOUNTSFILE "/proc/mounts"
24 static unsigned int svcv2info[20]; /* NFSv2 call counts ([0] == 18) */
25 static unsigned int cltv2info[20]; /* NFSv2 call counts ([0] == 18) */
26 static unsigned int svcv3info[24]; /* NFSv3 call counts ([0] == 22) */
27 static unsigned int cltv3info[24]; /* NFSv3 call counts ([0] == 22) */
28 static unsigned int svcv4info[4]; /* NFSv4 call counts ([0] == 2) */
29 static unsigned int cltv4info[34]; /* NFSv4 call counts ([0] == 32) */
30 static unsigned int svcnetinfo[5]; /* 0 # of received packets
35 static unsigned int cltnetinfo[5]; /* 0 # of received packets
41 static unsigned int svcrpcinfo[6]; /* 0 total # of RPC calls
42 * 1 total # of bad calls
44 * 3 authentication failed
47 static unsigned int cltrpcinfo[4]; /* 0 total # of RPC calls
48 * 1 retransmitted calls
52 static unsigned int svcrcinfo[9]; /* 0 repcache hits
55 * (for pre-2.4 kernels:)
58 * 5 noncached non-directories
59 * 6 noncached directories
63 static unsigned int svcfhinfo[7]; /* (for kernels >= 2.4.0)
67 * 3 noncached directories
68 * 4 noncached non-directories
69 * leave hole to relocate stale for order
73 static const char * nfsv2name[18] = {
74 "null", "getattr", "setattr", "root", "lookup", "readlink",
75 "read", "wrcache", "write", "create", "remove", "rename",
76 "link", "symlink", "mkdir", "rmdir", "readdir", "fsstat"
79 static const char * nfsv3name[22] = {
80 "null", "getattr", "setattr", "lookup", "access", "readlink",
81 "read", "write", "create", "mkdir", "symlink", "mknod",
82 "remove", "rmdir", "rename", "link", "readdir", "readdirplus",
83 "fsstat", "fsinfo", "pathconf", "commit"
86 static const char * nfssvrv4name[2] = {
91 static const char * nfscltv4name[32] = {
92 "null", "read", "write", "commit", "open", "open_conf",
93 "open_noat", "open_dgrd", "close", "setattr", "fsinfo", "renew",
94 "setclntid", "confirm", "lock",
95 "lockt", "locku", "access", "getattr", "lookup", "lookup_root",
96 "remove", "rename", "link", "symlink", "create", "pathconf",
97 "statfs", "readlink", "readdir", "server_caps", "delegreturn",
100 typedef struct statinfo {
103 unsigned int * valptr;
106 #define STRUCTSIZE(x) sizeof(x)/sizeof(*x)
108 static statinfo svcinfo[] = {
109 { "net", STRUCTSIZE(svcnetinfo), svcnetinfo },
110 { "rpc", STRUCTSIZE(svcrpcinfo), svcrpcinfo },
111 { "rc", STRUCTSIZE(svcrcinfo), svcrcinfo },
112 { "fh", STRUCTSIZE(svcfhinfo), svcfhinfo },
113 { "proc2", STRUCTSIZE(svcv2info), svcv2info },
114 { "proc3", STRUCTSIZE(svcv3info), svcv3info },
115 { "proc4", STRUCTSIZE(svcv4info), svcv4info },
119 static statinfo cltinfo[] = {
120 { "net", STRUCTSIZE(cltnetinfo), cltnetinfo },
121 { "rpc", STRUCTSIZE(cltrpcinfo), cltrpcinfo },
122 { "proc2", STRUCTSIZE(cltv2info), cltv2info },
123 { "proc3", STRUCTSIZE(cltv3info), cltv3info },
124 { "proc4", STRUCTSIZE(cltv4info), cltv4info },
128 static void print_numbers(const char *, unsigned int *,
130 static void print_callstats(const char *, const char **,
131 unsigned int *, unsigned int);
132 static int parse_statfile(const char *, struct statinfo *);
134 static statinfo *get_stat_info(const char *, struct statinfo *);
136 static int mounts(const char *);
138 #define PRNT_CALLS 0x0001
139 #define PRNT_RPC 0x0002
140 #define PRNT_NET 0x0004
141 #define PRNT_FH 0x0008
142 #define PRNT_RC 0x0010
143 #define PRNT_AUTO 0x1000
144 #define PRNT_V2 0x2000
145 #define PRNT_V3 0x4000
146 #define PRNT_V4 0x8000
147 #define PRNT_ALL 0x0fff
155 void usage(char *name)
157 printf("Usage: %s [OPTION]...\n\
159 -m, --mounted\t\tShow statistics on mounted NFS filesystems\n\
160 -c, --client\t\tShow NFS client statistics\n\
161 -s, --server\t\tShow NFS server statistics\n\
162 -2\t\t\tShow NFS version 2 statistics\n\
163 -3\t\t\tShow NFS version 3 statistics\n\
164 -4\t\t\tShow NFS version 4 statistics\n\
165 -o [facility]\t\tShow statistics on particular facilities.\n\
166 nfs\tNFS protocol information\n\
167 rpc\tGeneral RPC information\n\
168 net\tNetwork layer statistics\n\
169 fh\t\tUsage information on the server's file handle cache\n\
170 rc\t\tUsage information on the server's request reply cache\n\
171 all\tSelect all of the above\n\
172 -v, --verbose, --all\tSame as '-o all'\n\
173 -r, --rpc\t\tShow RPC statistics\n\
174 -n, --nfs\t\tShow NFS statistics\n\
175 --version\t\tShow program version\n\
176 --help\t\tWhat you just did\n\
181 static struct option longopts[] =
183 { "acl", 0, 0, 'a' },
184 { "all", 0, 0, 'v' },
185 { "auto", 0, 0, '\3' },
186 { "client", 0, 0, 'c' },
187 { "mounts", 0, 0, 'm' },
188 { "nfs", 0, 0, 'n' },
189 { "rpc", 0, 0, 'r' },
190 { "server", 0, 0, 's' },
191 { "verbose", 0, 0, 'v' },
192 { "zero", 0, 0, 'z' },
193 { "help", 0, 0, '\1' },
194 { "version", 0, 0, '\2' },
199 main(int argc, char **argv)
210 if ((progname = strrchr(argv[0], '/')))
215 while ((c = getopt_long(argc, argv, "234acmno:vrsz\1\2", longopts, NULL)) != EOF) {
218 fprintf(stderr, "nfsstat: nfs acls are not yet supported.\n");
224 opt_prt |= PRNT_CALLS;
227 if (!strcmp(optarg, "nfs"))
228 opt_prt |= PRNT_CALLS;
229 else if (!strcmp(optarg, "rpc"))
231 else if (!strcmp(optarg, "net"))
233 else if (!strcmp(optarg, "rc"))
235 else if (!strcmp(optarg, "fh"))
237 else if (!strcmp(optarg, "all"))
238 opt_prt |= PRNT_CALLS | PRNT_RPC | PRNT_NET | PRNT_RC | PRNT_FH;
240 fprintf(stderr, "nfsstat: unknown category: "
248 opt_prt |= versions[c - '2'];
254 opt_prt |= PRNT_AUTO;
263 fprintf(stderr, "nfsstat: zeroing of nfs statistics "
264 "not yet supported\n");
267 return mounts(MOUNTSFILE);
272 fprintf(stdout, "nfsstat: " VERSION "\n");
275 printf("Try `%s --help' for more information.\n", progname);
281 opt_srv = opt_clt = 1;
284 if (!(opt_srv + opt_clt))
285 opt_srv = opt_clt = 1;
286 if (!(opt_prt & 0xfff)) {
287 opt_prt |= PRNT_CALLS + PRNT_RPC;
289 if (!(opt_prt & 0xe000)) {
290 opt_prt |= PRNT_AUTO;
292 if ((opt_prt & (PRNT_FH|PRNT_RC)) && !opt_srv) {
294 "You requested file handle or request cache "
295 "statistics while using the -c option.\n"
296 "This information is available only for the NFS "
301 srv_info = parse_statfile(NFSSVCSTAT, svcinfo);
302 if (srv_info == 0 && opt_clt == 0) {
303 fprintf(stderr, "Warning: No Server Stats (%s: %m).\n", NFSSVCSTAT);
311 clt_info = parse_statfile(NFSCLTSTAT, cltinfo);
312 if (opt_srv == 0 && clt_info == 0) {
313 fprintf(stderr, "Warning: No Client Stats (%s: %m).\n", NFSCLTSTAT);
321 if (opt_prt & PRNT_NET) {
323 "Server packet stats:\n"
324 "packets udp tcp tcpconn\n",
329 if (opt_prt & PRNT_RPC) {
331 "Server rpc stats:\n"
332 "calls badcalls badauth badclnt xdrcall\n",
337 if (opt_prt & PRNT_RC) {
339 "Server reply cache:\n"
340 "hits misses nocache\n",
347 * 2.2 puts all fh-related info after the 'rc' header
348 * 2.4 puts all fh-related info after the 'fh' header, but relocates
349 * 'stale' to the start and swaps dir and nondir :-(
350 * We preseve the 2.2 order
352 if (opt_prt & PRNT_FH) {
353 if (get_stat_info("fh", svcinfo)) { /* >= 2.4 */
354 int t = svcfhinfo[3];
355 svcfhinfo[3]=svcfhinfo[4];
358 svcfhinfo[5]=svcfhinfo[0]; /* relocate 'stale' */
361 "Server file handle cache:\n"
362 "lookup anon ncachedir ncachedir stale\n",
366 "Server file handle cache:\n"
367 "lookup anon ncachedir ncachedir stale\n",
371 if (opt_prt & PRNT_CALLS) {
372 if ((opt_prt & PRNT_V2) || ((opt_prt & PRNT_AUTO) && svcv2info[0] && svcv2info[svcv2info[0]+1] != svcv2info[0]))
375 nfsv2name, svcv2info + 1, sizeof(nfsv2name)/sizeof(char *)
377 if ((opt_prt & PRNT_V3) || ((opt_prt & PRNT_AUTO) && svcv3info[0] && svcv3info[svcv3info[0]+1] != svcv3info[0]))
380 nfsv3name, svcv3info + 1, sizeof(nfsv3name)/sizeof(char *)
382 if ((opt_prt & PRNT_V4) || ((opt_prt & PRNT_AUTO) && svcv4info[0] && svcv4info[svcv4info[0]+1] != svcv4info[0]))
385 nfssvrv4name, svcv4info + 1, sizeof(nfssvrv4name)/sizeof(char *)
391 if (opt_prt & PRNT_NET) {
393 "Client packet stats:\n"
394 "packets udp tcp tcpconn\n",
399 if (opt_prt & PRNT_RPC) {
401 "Client rpc stats:\n"
402 "calls retrans authrefrsh\n",
407 if (opt_prt & PRNT_CALLS) {
408 if ((opt_prt & PRNT_V2) || ((opt_prt & PRNT_AUTO) && cltv2info[0] && cltv2info[cltv2info[0]+1] != cltv2info[0]))
411 nfsv2name, cltv2info + 1, sizeof(nfsv2name)/sizeof(char *)
413 if ((opt_prt & PRNT_V3) || ((opt_prt & PRNT_AUTO) && cltv3info[0] && cltv3info[cltv3info[0]+1] != cltv3info[0]))
416 nfsv3name, cltv3info + 1, sizeof(nfsv3name)/sizeof(char *)
418 if ((opt_prt & PRNT_V4) || ((opt_prt & PRNT_AUTO) && cltv4info[0] && cltv4info[cltv4info[0]+1] != cltv4info[0]))
421 nfscltv4name, cltv4info + 1, sizeof(nfscltv4name)/sizeof(char *)
430 get_stat_info(const char *sp, struct statinfo *statp)
434 for (ip = statp; ip->tag; ip++) {
435 if (!strcmp(sp, ip->tag))
443 print_numbers(const char *hdr, unsigned int *info, unsigned int nr)
448 for (i = 0; i < nr; i++)
449 printf("%s%-8d", i? " " : "", info[i]);
454 print_callstats(const char *hdr, const char **names,
455 unsigned int *info, unsigned int nr)
457 unsigned long long total;
458 unsigned long long pct;
462 for (i = 0, total = 0; i < nr; i++)
466 for (i = 0; i < nr; i += 6) {
467 for (j = 0; j < 6 && i + j < nr; j++)
468 printf("%-13s", names[i+j]);
470 for (j = 0; j < 6 && i + j < nr; j++) {
471 pct = ((unsigned long long) info[i+j]*100)/total;
472 printf("%-8d%3llu%% ", info[i+j], pct);
481 parse_statfile(const char *name, struct statinfo *statp)
483 char buffer[4096], *next;
486 /* Being unable to read e.g. the nfsd stats file shouldn't
487 * be a fatal error -- it usually means the module isn't loaded.
489 if ((fp = fopen(name, "r")) == NULL) {
490 // fprintf(stderr, "Warning: %s: %m\n", name);
494 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
496 char *sp, *line = buffer;
498 unsigned int total = 0;
500 if ((next = strchr(line, '\n')) != NULL)
502 if (!(sp = strtok(line, " \t")))
505 ip = get_stat_info(sp, statp);
511 for (i = 0; i < cnt; i++) {
512 if (!(sp = strtok(NULL, " \t")))
514 ip->valptr[i] = atoi(sp);
515 total += ip->valptr[i];
517 ip->valptr[i] = total;
525 mounts(const char *name)
527 char buffer[4096], *next;
530 /* Being unable to read e.g. the nfsd stats file shouldn't
531 * be a fatal error -- it usually means the module isn't loaded.
533 if ((fp = fopen(name, "r")) == NULL) {
534 fprintf(stderr, "Warning: %s: %m\n", name);
538 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
540 char *device, *mount, *type, *flags;
542 if ((next = strchr(line, '\n')) != NULL)
545 if (!(device = strtok(line, " \t")))
548 if (!(mount = strtok(NULL, " \t")))
551 if (!(type = strtok(NULL, " \t")))
554 if (strcmp(type, "nfs")) {
558 if (!(flags = strtok(NULL, " \t")))
561 printf("%s from %s\n", mount, device);
562 printf(" Flags:\t%s\n", flags);