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"
21 static unsigned int svcv2info[19]; /* NFSv2 call counts ([0] == 18) */
22 static unsigned int cltv2info[19]; /* NFSv2 call counts ([0] == 18) */
23 static unsigned int svcv3info[23]; /* NFSv3 call counts ([0] == 22) */
24 static unsigned int cltv3info[23]; /* NFSv3 call counts ([0] == 22) */
25 static unsigned int svcnetinfo[4]; /* 0 # of received packets
30 static unsigned int cltnetinfo[4]; /* 0 # of received packets
36 static unsigned int svcrpcinfo[5]; /* 0 total # of RPC calls
37 * 1 total # of bad calls
39 * 3 authentication failed
42 static unsigned int cltrpcinfo[3]; /* 0 total # of RPC calls
43 * 1 retransmitted calls
47 static unsigned int svcrcinfo[8]; /* 0 repcache hits
50 * (for pre-2.4 kernels:)
53 * 5 noncached non-directories
54 * 6 noncached directories
58 static unsigned int svcfhinfo[6]; /* (for kernels >= 2.4.0)
62 * 3 noncached directories
63 * 4 noncached non-directories
64 * leave hole to relocate stale for order
68 static const char * nfsv2name[18] = {
69 "null", "getattr", "setattr", "root", "lookup", "readlink",
70 "read", "wrcache", "write", "create", "remove", "rename",
71 "link", "symlink", "mkdir", "rmdir", "readdir", "fsstat"
74 static const char * nfsv3name[22] = {
75 "null", "getattr", "setattr", "lookup", "access", "readlink",
76 "read", "write", "create", "mkdir", "symlink", "mknod",
77 "remove", "rmdir", "rename", "link", "readdir", "readdirplus",
78 "fsstat", "fsinfo", "pathconf", "commit"
81 typedef struct statinfo {
84 unsigned int * valptr;
87 static statinfo svcinfo[] = {
88 { "net", 4, svcnetinfo },
89 { "rpc", 5, svcrpcinfo },
90 { "rc", 8, svcrcinfo },
91 { "fh", 5, svcfhinfo },
92 { "proc2", 19, svcv2info },
93 { "proc3", 23, svcv3info },
97 static statinfo cltinfo[] = {
98 { "net", 4, cltnetinfo },
99 { "rpc", 3, cltrpcinfo },
100 { "proc2", 19, cltv2info },
101 { "proc3", 23, cltv3info },
105 static void print_numbers(const char *, unsigned int *,
107 static void print_callstats(const char *, const char **,
108 unsigned int *, unsigned int);
109 static int parse_statfile(const char *, struct statinfo *);
111 static statinfo *get_stat_info(const char *, struct statinfo *);
114 #define PRNT_CALLS 0x0001
115 #define PRNT_RPC 0x0002
116 #define PRNT_NET 0x0004
117 #define PRNT_FH 0x0008
118 #define PRNT_RC 0x0010
119 #define PRNT_ALL 0xffff
122 main(int argc, char **argv)
132 while ((c = getopt(argc, argv, "acno:rsz")) != -1) {
141 opt_prt |= PRNT_CALLS;
144 if (!strcmp(optarg, "nfs"))
145 opt_prt |= PRNT_CALLS;
146 else if (!strcmp(optarg, "rpc"))
148 else if (!strcmp(optarg, "net"))
150 else if (!strcmp(optarg, "rc"))
152 else if (!strcmp(optarg, "fh"))
155 fprintf(stderr, "nfsstat: unknown category: "
167 fprintf(stderr, "nfsstat: zeroing of nfs statistics "
168 "not yet supported\n");
174 opt_srv = opt_clt = 1;
177 if (!(opt_srv + opt_clt))
178 opt_srv = opt_clt = 1;
180 opt_prt = PRNT_CALLS + PRNT_RPC;
181 if ((opt_prt & (PRNT_FH|PRNT_RC)) && !opt_srv) {
183 "You requested file handle or request cache "
184 "statistics while using the -c option.\n"
185 "This information is available only for the NFS "
190 srv_info = parse_statfile(NFSSVCSTAT, svcinfo);
191 if (srv_info == 0 && opt_clt == 0) {
192 fprintf(stderr, "Warning: No Server Stats (%s: %m).\n", NFSSVCSTAT);
200 clt_info = parse_statfile(NFSCLTSTAT, cltinfo);
201 if (opt_srv == 0 && clt_info == 0) {
202 fprintf(stderr, "Warning: No Client Stats (%s: %m).\n", NFSCLTSTAT);
210 if (opt_prt & PRNT_NET) {
212 "Server packet stats:\n"
213 "packets udp tcp tcpconn\n",
217 if (opt_prt & PRNT_RPC) {
219 "Server rpc stats:\n"
220 "calls badcalls badauth badclnt xdrcall\n",
224 if (opt_prt & PRNT_RC) {
226 "Server reply cache:\n"
227 "hits misses nocache\n",
233 * 2.2 puts all fh-related info after the 'rc' header
234 * 2.4 puts all fh-related info after the 'fh' header, but relocates
235 * 'stale' to the start and swaps dir and nondir :-(
236 * We preseve the 2.2 order
238 if (opt_prt & PRNT_FH) {
239 if (get_stat_info("fh", svcinfo)) { /* >= 2.4 */
240 int t = svcfhinfo[3];
241 svcfhinfo[3]=svcfhinfo[4];
244 svcfhinfo[5]=svcfhinfo[0]; /* relocate 'stale' */
247 "Server file handle cache:\n"
248 "lookup anon ncachedir ncachedir stale\n",
252 "Server file handle cache:\n"
253 "lookup anon ncachedir ncachedir stale\n",
256 if (opt_prt & PRNT_CALLS) {
259 nfsv2name, svcv2info + 1, 18
264 nfsv3name, svcv3info + 1, 22
270 if (opt_prt & PRNT_NET) {
272 "Client packet stats:\n"
273 "packets udp tcp tcpconn\n",
277 if (opt_prt & PRNT_RPC) {
279 "Client rpc stats:\n"
280 "calls retrans authrefrsh\n",
284 if (opt_prt & PRNT_CALLS) {
287 nfsv2name, cltv2info + 1, 18
292 nfsv3name, cltv3info + 1, 22
301 get_stat_info(const char *sp, struct statinfo *statp)
305 for (ip = statp; ip->tag; ip++) {
306 if (!strcmp(sp, ip->tag))
314 print_numbers(const char *hdr, unsigned int *info, unsigned int nr)
319 for (i = 0; i < nr; i++)
320 printf("%s%-8d", i? " " : "", info[i]);
325 print_callstats(const char *hdr, const char **names,
326 unsigned int *info, unsigned int nr)
328 unsigned long long total;
329 unsigned long long pct;
333 for (i = 0, total = 0; i < nr; i++)
337 for (i = 0; i < nr; i += 6) {
338 for (j = 0; j < 6 && i + j < nr; j++)
339 printf("%-11s", names[i+j]);
341 for (j = 0; j < 6 && i + j < nr; j++) {
342 pct = ((unsigned long long) info[i+j]*100)/total;
343 printf("%-6d %2llu%% ", info[i+j], pct);
352 parse_statfile(const char *name, struct statinfo *statp)
354 char buffer[4096], *next;
357 /* Being unable to read e.g. the nfsd stats file shouldn't
358 * be a fatal error -- it usually means the module isn't loaded.
360 if ((fp = fopen(name, "r")) == NULL) {
361 // fprintf(stderr, "Warning: %s: %m\n", name);
365 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
367 char *sp, *line = buffer;
370 if ((next = strchr(line, '\n')) != NULL)
372 if (!(sp = strtok(line, " \t")))
375 ip = get_stat_info(sp, statp);
381 for (i = 0; i < cnt; i++) {
382 if (!(sp = strtok(NULL, " \t")))
384 ip->valptr[i] = atoi(sp);