2 * nfsstat.c Output NFS statistics
4 * Copyright (C) 1995-2005 Olaf Kirch <okir@suse.de>
11 #define NFSSVCSTAT "/proc/net/rpc/nfsd"
12 #define NFSCLTSTAT "/proc/net/rpc/nfs"
14 #define MOUNTSFILE "/proc/mounts"
26 static unsigned int svcv2info[20]; /* NFSv2 call counts ([0] == 18) */
27 static unsigned int cltv2info[20]; /* NFSv2 call counts ([0] == 18) */
28 static unsigned int svcv3info[24]; /* NFSv3 call counts ([0] == 22) */
29 static unsigned int cltv3info[24]; /* NFSv3 call counts ([0] == 22) */
30 static unsigned int svcv4info[4]; /* NFSv4 call counts ([0] == 2) */
31 static unsigned int cltv4info[34]; /* NFSv4 call counts ([0] == 32) */
32 static unsigned int svcnetinfo[5]; /* 0 # of received packets
37 static unsigned int cltnetinfo[5]; /* 0 # of received packets
43 static unsigned int svcrpcinfo[6]; /* 0 total # of RPC calls
44 * 1 total # of bad calls
46 * 3 authentication failed
49 static unsigned int cltrpcinfo[4]; /* 0 total # of RPC calls
50 * 1 retransmitted calls
54 static unsigned int svcrcinfo[9]; /* 0 repcache hits
57 * (for pre-2.4 kernels:)
60 * 5 noncached non-directories
61 * 6 noncached directories
65 static unsigned int svcfhinfo[7]; /* (for kernels >= 2.4.0)
69 * 3 noncached directories
70 * 4 noncached non-directories
71 * leave hole to relocate stale for order
75 static const char * nfsv2name[18] = {
76 "null", "getattr", "setattr", "root", "lookup", "readlink",
77 "read", "wrcache", "write", "create", "remove", "rename",
78 "link", "symlink", "mkdir", "rmdir", "readdir", "fsstat"
81 static const char * nfsv3name[22] = {
82 "null", "getattr", "setattr", "lookup", "access", "readlink",
83 "read", "write", "create", "mkdir", "symlink", "mknod",
84 "remove", "rmdir", "rename", "link", "readdir", "readdirplus",
85 "fsstat", "fsinfo", "pathconf", "commit"
88 static const char * nfssvrv4name[2] = {
93 static const char * nfscltv4name[32] = {
94 "null", "read", "write", "commit", "open", "open_conf",
95 "open_noat", "open_dgrd", "close", "setattr", "fsinfo", "renew",
96 "setclntid", "confirm", "lock",
97 "lockt", "locku", "access", "getattr", "lookup", "lookup_root",
98 "remove", "rename", "link", "symlink", "create", "pathconf",
99 "statfs", "readlink", "readdir", "server_caps", "delegreturn",
102 typedef struct statinfo {
105 unsigned int * valptr;
108 #define STRUCTSIZE(x) sizeof(x)/sizeof(*x)
110 static statinfo svcinfo[] = {
111 { "net", STRUCTSIZE(svcnetinfo), svcnetinfo },
112 { "rpc", STRUCTSIZE(svcrpcinfo), svcrpcinfo },
113 { "rc", STRUCTSIZE(svcrcinfo), svcrcinfo },
114 { "fh", STRUCTSIZE(svcfhinfo), svcfhinfo },
115 { "proc2", STRUCTSIZE(svcv2info), svcv2info },
116 { "proc3", STRUCTSIZE(svcv3info), svcv3info },
117 { "proc4", STRUCTSIZE(svcv4info), svcv4info },
121 static statinfo cltinfo[] = {
122 { "net", STRUCTSIZE(cltnetinfo), cltnetinfo },
123 { "rpc", STRUCTSIZE(cltrpcinfo), cltrpcinfo },
124 { "proc2", STRUCTSIZE(cltv2info), cltv2info },
125 { "proc3", STRUCTSIZE(cltv3info), cltv3info },
126 { "proc4", STRUCTSIZE(cltv4info), cltv4info },
130 static void print_numbers(const char *, unsigned int *,
132 static void print_callstats(const char *, const char **,
133 unsigned int *, unsigned int);
134 static int parse_statfile(const char *, struct statinfo *);
136 static statinfo *get_stat_info(const char *, struct statinfo *);
138 static int mounts(const char *);
140 #define PRNT_CALLS 0x0001
141 #define PRNT_RPC 0x0002
142 #define PRNT_NET 0x0004
143 #define PRNT_FH 0x0008
144 #define PRNT_RC 0x0010
145 #define PRNT_AUTO 0x1000
146 #define PRNT_V2 0x2000
147 #define PRNT_V3 0x4000
148 #define PRNT_V4 0x8000
149 #define PRNT_ALL 0x0fff
157 void usage(char *name)
159 printf("Usage: %s [OPTION]...\n\
161 -m, --mounted\t\tShow statistics on mounted NFS filesystems\n\
162 -c, --client\t\tShow NFS client statistics\n\
163 -s, --server\t\tShow NFS server statistics\n\
164 -2\t\t\tShow NFS version 2 statistics\n\
165 -3\t\t\tShow NFS version 3 statistics\n\
166 -4\t\t\tShow NFS version 4 statistics\n\
167 -o [facility]\t\tShow statistics on particular facilities.\n\
168 nfs\tNFS protocol information\n\
169 rpc\tGeneral RPC information\n\
170 net\tNetwork layer statistics\n\
171 fh\t\tUsage information on the server's file handle cache\n\
172 rc\t\tUsage information on the server's request reply cache\n\
173 all\tSelect all of the above\n\
174 -v, --verbose, --all\tSame as '-o all'\n\
175 -r, --rpc\t\tShow RPC statistics\n\
176 -n, --nfs\t\tShow NFS statistics\n\
177 --version\t\tShow program version\n\
178 --help\t\tWhat you just did\n\
183 static struct option longopts[] =
185 { "acl", 0, 0, 'a' },
186 { "all", 0, 0, 'v' },
187 { "auto", 0, 0, '\3' },
188 { "client", 0, 0, 'c' },
189 { "mounts", 0, 0, 'm' },
190 { "nfs", 0, 0, 'n' },
191 { "rpc", 0, 0, 'r' },
192 { "server", 0, 0, 's' },
193 { "verbose", 0, 0, 'v' },
194 { "zero", 0, 0, 'z' },
195 { "help", 0, 0, '\1' },
196 { "version", 0, 0, '\2' },
201 main(int argc, char **argv)
212 if ((progname = strrchr(argv[0], '/')))
217 while ((c = getopt_long(argc, argv, "234acmno:vrsz\1\2", longopts, NULL)) != EOF) {
220 fprintf(stderr, "nfsstat: nfs acls are not yet supported.\n");
226 opt_prt |= PRNT_CALLS;
229 if (!strcmp(optarg, "nfs"))
230 opt_prt |= PRNT_CALLS;
231 else if (!strcmp(optarg, "rpc"))
233 else if (!strcmp(optarg, "net"))
235 else if (!strcmp(optarg, "rc"))
237 else if (!strcmp(optarg, "fh"))
239 else if (!strcmp(optarg, "all"))
240 opt_prt |= PRNT_CALLS | PRNT_RPC | PRNT_NET | PRNT_RC | PRNT_FH;
242 fprintf(stderr, "nfsstat: unknown category: "
250 opt_prt |= versions[c - '2'];
256 opt_prt |= PRNT_AUTO;
265 fprintf(stderr, "nfsstat: zeroing of nfs statistics "
266 "not yet supported\n");
269 return mounts(MOUNTSFILE);
274 fprintf(stdout, "nfsstat: " VERSION "\n");
277 printf("Try `%s --help' for more information.\n", progname);
283 opt_srv = opt_clt = 1;
286 if (!(opt_srv + opt_clt))
287 opt_srv = opt_clt = 1;
288 if (!(opt_prt & 0xfff)) {
289 opt_prt |= PRNT_CALLS + PRNT_RPC;
291 if (!(opt_prt & 0xe000)) {
292 opt_prt |= PRNT_AUTO;
294 if ((opt_prt & (PRNT_FH|PRNT_RC)) && !opt_srv) {
296 "You requested file handle or request cache "
297 "statistics while using the -c option.\n"
298 "This information is available only for the NFS "
303 srv_info = parse_statfile(NFSSVCSTAT, svcinfo);
304 if (srv_info == 0 && opt_clt == 0) {
305 fprintf(stderr, "Warning: No Server Stats (%s: %m).\n", NFSSVCSTAT);
313 clt_info = parse_statfile(NFSCLTSTAT, cltinfo);
314 if (opt_srv == 0 && clt_info == 0) {
315 fprintf(stderr, "Warning: No Client Stats (%s: %m).\n", NFSCLTSTAT);
323 if (opt_prt & PRNT_NET) {
325 "Server packet stats:\n"
326 "packets udp tcp tcpconn\n",
331 if (opt_prt & PRNT_RPC) {
333 "Server rpc stats:\n"
334 "calls badcalls badauth badclnt xdrcall\n",
339 if (opt_prt & PRNT_RC) {
341 "Server reply cache:\n"
342 "hits misses nocache\n",
349 * 2.2 puts all fh-related info after the 'rc' header
350 * 2.4 puts all fh-related info after the 'fh' header, but relocates
351 * 'stale' to the start and swaps dir and nondir :-(
352 * We preseve the 2.2 order
354 if (opt_prt & PRNT_FH) {
355 if (get_stat_info("fh", svcinfo)) { /* >= 2.4 */
356 int t = svcfhinfo[3];
357 svcfhinfo[3]=svcfhinfo[4];
360 svcfhinfo[5]=svcfhinfo[0]; /* relocate 'stale' */
363 "Server file handle cache:\n"
364 "lookup anon ncachedir ncachedir stale\n",
368 "Server file handle cache:\n"
369 "lookup anon ncachedir ncachedir stale\n",
373 if (opt_prt & PRNT_CALLS) {
374 if ((opt_prt & PRNT_V2) || ((opt_prt & PRNT_AUTO) && svcv2info[0] && svcv2info[svcv2info[0]+1] != svcv2info[0]))
377 nfsv2name, svcv2info + 1, sizeof(nfsv2name)/sizeof(char *)
379 if ((opt_prt & PRNT_V3) || ((opt_prt & PRNT_AUTO) && svcv3info[0] && svcv3info[svcv3info[0]+1] != svcv3info[0]))
382 nfsv3name, svcv3info + 1, sizeof(nfsv3name)/sizeof(char *)
384 if ((opt_prt & PRNT_V4) || ((opt_prt & PRNT_AUTO) && svcv4info[0] && svcv4info[svcv4info[0]+1] != svcv4info[0]))
387 nfssvrv4name, svcv4info + 1, sizeof(nfssvrv4name)/sizeof(char *)
393 if (opt_prt & PRNT_NET) {
395 "Client packet stats:\n"
396 "packets udp tcp tcpconn\n",
401 if (opt_prt & PRNT_RPC) {
403 "Client rpc stats:\n"
404 "calls retrans authrefrsh\n",
409 if (opt_prt & PRNT_CALLS) {
410 if ((opt_prt & PRNT_V2) || ((opt_prt & PRNT_AUTO) && cltv2info[0] && cltv2info[cltv2info[0]+1] != cltv2info[0]))
413 nfsv2name, cltv2info + 1, sizeof(nfsv2name)/sizeof(char *)
415 if ((opt_prt & PRNT_V3) || ((opt_prt & PRNT_AUTO) && cltv3info[0] && cltv3info[cltv3info[0]+1] != cltv3info[0]))
418 nfsv3name, cltv3info + 1, sizeof(nfsv3name)/sizeof(char *)
420 if ((opt_prt & PRNT_V4) || ((opt_prt & PRNT_AUTO) && cltv4info[0] && cltv4info[cltv4info[0]+1] != cltv4info[0]))
423 nfscltv4name, cltv4info + 1, sizeof(nfscltv4name)/sizeof(char *)
432 get_stat_info(const char *sp, struct statinfo *statp)
436 for (ip = statp; ip->tag; ip++) {
437 if (!strcmp(sp, ip->tag))
445 print_numbers(const char *hdr, unsigned int *info, unsigned int nr)
450 for (i = 0; i < nr; i++)
451 printf("%s%-8d", i? " " : "", info[i]);
456 print_callstats(const char *hdr, const char **names,
457 unsigned int *info, unsigned int nr)
459 unsigned long long total;
460 unsigned long long pct;
464 for (i = 0, total = 0; i < nr; i++)
468 for (i = 0; i < nr; i += 6) {
469 for (j = 0; j < 6 && i + j < nr; j++)
470 printf("%-13s", names[i+j]);
472 for (j = 0; j < 6 && i + j < nr; j++) {
473 pct = ((unsigned long long) info[i+j]*100)/total;
474 printf("%-8d%3llu%% ", info[i+j], pct);
483 parse_statfile(const char *name, struct statinfo *statp)
485 char buffer[4096], *next;
488 /* Being unable to read e.g. the nfsd stats file shouldn't
489 * be a fatal error -- it usually means the module isn't loaded.
491 if ((fp = fopen(name, "r")) == NULL) {
492 // fprintf(stderr, "Warning: %s: %m\n", name);
496 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
498 char *sp, *line = buffer;
500 unsigned int total = 0;
502 if ((next = strchr(line, '\n')) != NULL)
504 if (!(sp = strtok(line, " \t")))
507 ip = get_stat_info(sp, statp);
513 for (i = 0; i < cnt; i++) {
514 if (!(sp = strtok(NULL, " \t")))
516 ip->valptr[i] = atoi(sp);
517 total += ip->valptr[i];
519 ip->valptr[i] = total;
527 mounts(const char *name)
529 char buffer[4096], *next;
532 /* Being unable to read e.g. the nfsd stats file shouldn't
533 * be a fatal error -- it usually means the module isn't loaded.
535 if ((fp = fopen(name, "r")) == NULL) {
536 fprintf(stderr, "Warning: %s: %m\n", name);
540 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
542 char *device, *mount, *type, *flags;
544 if ((next = strchr(line, '\n')) != NULL)
547 if (!(device = strtok(line, " \t")))
550 if (!(mount = strtok(NULL, " \t")))
553 if (!(type = strtok(NULL, " \t")))
556 if (strcmp(type, "nfs")) {
560 if (!(flags = strtok(NULL, " \t")))
563 printf("%s from %s\n", mount, device);
564 printf(" Flags:\t%s\n", flags);