2 * nfsstat.c Output NFS statistics
4 * Copyright (C) 1995, 1996, 1999 Olaf Kirch <okir@monad.swb.de>
9 #define NFSSVCSTAT "/proc/net/rpc/nfsd"
10 #define NFSCLTSTAT "/proc/net/rpc/nfs"
12 #define MOUNTSFILE "/proc/mounts"
23 static unsigned int svcv2info[19]; /* NFSv2 call counts ([0] == 18) */
24 static unsigned int cltv2info[19]; /* NFSv2 call counts ([0] == 18) */
25 static unsigned int svcv3info[23]; /* NFSv3 call counts ([0] == 22) */
26 static unsigned int cltv3info[23]; /* NFSv3 call counts ([0] == 22) */
27 static unsigned int svcnetinfo[4]; /* 0 # of received packets
32 static unsigned int cltnetinfo[4]; /* 0 # of received packets
38 static unsigned int svcrpcinfo[5]; /* 0 total # of RPC calls
39 * 1 total # of bad calls
41 * 3 authentication failed
44 static unsigned int cltrpcinfo[3]; /* 0 total # of RPC calls
45 * 1 retransmitted calls
49 static unsigned int svcrcinfo[8]; /* 0 repcache hits
52 * (for pre-2.4 kernels:)
55 * 5 noncached non-directories
56 * 6 noncached directories
60 static unsigned int svcfhinfo[6]; /* (for kernels >= 2.4.0)
64 * 3 noncached directories
65 * 4 noncached non-directories
66 * leave hole to relocate stale for order
70 static const char * nfsv2name[18] = {
71 "null", "getattr", "setattr", "root", "lookup", "readlink",
72 "read", "wrcache", "write", "create", "remove", "rename",
73 "link", "symlink", "mkdir", "rmdir", "readdir", "fsstat"
76 static const char * nfsv3name[22] = {
77 "null", "getattr", "setattr", "lookup", "access", "readlink",
78 "read", "write", "create", "mkdir", "symlink", "mknod",
79 "remove", "rmdir", "rename", "link", "readdir", "readdirplus",
80 "fsstat", "fsinfo", "pathconf", "commit"
83 typedef struct statinfo {
86 unsigned int * valptr;
89 static statinfo svcinfo[] = {
90 { "net", 4, svcnetinfo },
91 { "rpc", 5, svcrpcinfo },
92 { "rc", 8, svcrcinfo },
93 { "fh", 5, svcfhinfo },
94 { "proc2", 19, svcv2info },
95 { "proc3", 23, svcv3info },
99 static statinfo cltinfo[] = {
100 { "net", 4, cltnetinfo },
101 { "rpc", 3, cltrpcinfo },
102 { "proc2", 19, cltv2info },
103 { "proc3", 23, cltv3info },
107 static void print_numbers(const char *, unsigned int *,
109 static void print_callstats(const char *, const char **,
110 unsigned int *, unsigned int);
111 static int parse_statfile(const char *, struct statinfo *);
113 static statinfo *get_stat_info(const char *, struct statinfo *);
115 static int mounts(const char *);
117 #define PRNT_CALLS 0x0001
118 #define PRNT_RPC 0x0002
119 #define PRNT_NET 0x0004
120 #define PRNT_FH 0x0008
121 #define PRNT_RC 0x0010
122 #define PRNT_ALL 0xffff
125 main(int argc, char **argv)
135 while ((c = getopt(argc, argv, "acmno:rsz")) != -1) {
144 opt_prt |= PRNT_CALLS;
147 if (!strcmp(optarg, "nfs"))
148 opt_prt |= PRNT_CALLS;
149 else if (!strcmp(optarg, "rpc"))
151 else if (!strcmp(optarg, "net"))
153 else if (!strcmp(optarg, "rc"))
155 else if (!strcmp(optarg, "fh"))
158 fprintf(stderr, "nfsstat: unknown category: "
170 fprintf(stderr, "nfsstat: zeroing of nfs statistics "
171 "not yet supported\n");
174 return mounts(MOUNTSFILE);
179 opt_srv = opt_clt = 1;
182 if (!(opt_srv + opt_clt))
183 opt_srv = opt_clt = 1;
185 opt_prt = PRNT_CALLS + PRNT_RPC;
186 if ((opt_prt & (PRNT_FH|PRNT_RC)) && !opt_srv) {
188 "You requested file handle or request cache "
189 "statistics while using the -c option.\n"
190 "This information is available only for the NFS "
195 srv_info = parse_statfile(NFSSVCSTAT, svcinfo);
196 if (srv_info == 0 && opt_clt == 0) {
197 fprintf(stderr, "Warning: No Server Stats (%s: %m).\n", NFSSVCSTAT);
205 clt_info = parse_statfile(NFSCLTSTAT, cltinfo);
206 if (opt_srv == 0 && clt_info == 0) {
207 fprintf(stderr, "Warning: No Client Stats (%s: %m).\n", NFSCLTSTAT);
215 if (opt_prt & PRNT_NET) {
217 "Server packet stats:\n"
218 "packets udp tcp tcpconn\n",
222 if (opt_prt & PRNT_RPC) {
224 "Server rpc stats:\n"
225 "calls badcalls badauth badclnt xdrcall\n",
229 if (opt_prt & PRNT_RC) {
231 "Server reply cache:\n"
232 "hits misses nocache\n",
238 * 2.2 puts all fh-related info after the 'rc' header
239 * 2.4 puts all fh-related info after the 'fh' header, but relocates
240 * 'stale' to the start and swaps dir and nondir :-(
241 * We preseve the 2.2 order
243 if (opt_prt & PRNT_FH) {
244 if (get_stat_info("fh", svcinfo)) { /* >= 2.4 */
245 int t = svcfhinfo[3];
246 svcfhinfo[3]=svcfhinfo[4];
249 svcfhinfo[5]=svcfhinfo[0]; /* relocate 'stale' */
252 "Server file handle cache:\n"
253 "lookup anon ncachedir ncachedir stale\n",
257 "Server file handle cache:\n"
258 "lookup anon ncachedir ncachedir stale\n",
261 if (opt_prt & PRNT_CALLS) {
264 nfsv2name, svcv2info + 1, 18
269 nfsv3name, svcv3info + 1, 22
275 if (opt_prt & PRNT_NET) {
277 "Client packet stats:\n"
278 "packets udp tcp tcpconn\n",
282 if (opt_prt & PRNT_RPC) {
284 "Client rpc stats:\n"
285 "calls retrans authrefrsh\n",
289 if (opt_prt & PRNT_CALLS) {
292 nfsv2name, cltv2info + 1, 18
297 nfsv3name, cltv3info + 1, 22
306 get_stat_info(const char *sp, struct statinfo *statp)
310 for (ip = statp; ip->tag; ip++) {
311 if (!strcmp(sp, ip->tag))
319 print_numbers(const char *hdr, unsigned int *info, unsigned int nr)
324 for (i = 0; i < nr; i++)
325 printf("%s%-8d", i? " " : "", info[i]);
330 print_callstats(const char *hdr, const char **names,
331 unsigned int *info, unsigned int nr)
333 unsigned long long total;
334 unsigned long long pct;
338 for (i = 0, total = 0; i < nr; i++)
342 for (i = 0; i < nr; i += 6) {
343 for (j = 0; j < 6 && i + j < nr; j++)
344 printf("%-11s", names[i+j]);
346 for (j = 0; j < 6 && i + j < nr; j++) {
347 pct = ((unsigned long long) info[i+j]*100)/total;
348 printf("%-6d %2llu%% ", info[i+j], pct);
357 parse_statfile(const char *name, struct statinfo *statp)
359 char buffer[4096], *next;
362 /* Being unable to read e.g. the nfsd stats file shouldn't
363 * be a fatal error -- it usually means the module isn't loaded.
365 if ((fp = fopen(name, "r")) == NULL) {
366 // fprintf(stderr, "Warning: %s: %m\n", name);
370 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
372 char *sp, *line = buffer;
375 if ((next = strchr(line, '\n')) != NULL)
377 if (!(sp = strtok(line, " \t")))
380 ip = get_stat_info(sp, statp);
386 for (i = 0; i < cnt; i++) {
387 if (!(sp = strtok(NULL, " \t")))
389 ip->valptr[i] = atoi(sp);
398 mounts(const char *name)
400 char buffer[4096], *next;
403 /* Being unable to read e.g. the nfsd stats file shouldn't
404 * be a fatal error -- it usually means the module isn't loaded.
406 if ((fp = fopen(name, "r")) == NULL) {
407 fprintf(stderr, "Warning: %s: %m\n", name);
411 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
413 char *device, *mount, *type, *flags;
415 if ((next = strchr(line, '\n')) != NULL)
418 if (!(device = strtok(line, " \t")))
421 if (!(mount = strtok(NULL, " \t")))
424 if (!(type = strtok(NULL, " \t")))
427 if (strcmp(type, "nfs")) {
431 if (!(flags = strtok(NULL, " \t")))
434 printf("%s from %s\n", mount, device);
435 printf(" Flags:\t%s\n", flags);