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)
130 while ((c = getopt(argc, argv, "acno:rsz")) != -1) {
139 opt_prt |= PRNT_CALLS;
142 if (!strcmp(optarg, "nfs"))
143 opt_prt |= PRNT_CALLS;
144 else if (!strcmp(optarg, "rpc"))
146 else if (!strcmp(optarg, "net"))
148 else if (!strcmp(optarg, "rc"))
150 else if (!strcmp(optarg, "fh"))
153 fprintf(stderr, "nfsstat: unknown category: "
165 fprintf(stderr, "nfsstat: zeroing of nfs statistics "
166 "not yet supported\n");
172 opt_srv = opt_clt = 1;
175 if (!(opt_srv + opt_clt))
176 opt_srv = opt_clt = 1;
178 opt_prt = PRNT_CALLS + PRNT_RPC;
179 if ((opt_prt & (PRNT_FH|PRNT_RC)) && !opt_srv) {
181 "You requested file handle or request cache "
182 "statistics while using the -c option.\n"
183 "This information is available only for the NFS "
187 if ((opt_srv && !parse_statfile(NFSSVCSTAT, svcinfo))
188 || (opt_clt && !parse_statfile(NFSCLTSTAT, cltinfo)))
192 if (opt_prt & PRNT_NET) {
194 "Server packet stats:\n"
195 "packets udp tcp tcpconn\n",
199 if (opt_prt & PRNT_RPC) {
201 "Server rpc stats:\n"
202 "calls badcalls badauth badclnt xdrcall\n",
206 if (opt_prt & PRNT_RC) {
208 "Server reply cache:\n"
209 "hits misses nocache\n",
215 * 2.2 puts all fh-related info after the 'rc' header
216 * 2.4 puts all fh-related info after the 'fh' header, but relocates
217 * 'stale' to the start and swaps dir and nondir :-(
218 * We preseve the 2.2 order
220 if (opt_prt & PRNT_FH) {
221 if (get_stat_info("fh", svcinfo)) { /* >= 2.4 */
222 int t = svcfhinfo[3];
223 svcfhinfo[3]=svcfhinfo[4];
226 svcfhinfo[5]=svcfhinfo[0]; /* relocate 'stale' */
229 "Server file handle cache:\n"
230 "lookup anon ncachedir ncachedir stale\n",
234 "Server file handle cache:\n"
235 "lookup anon ncachedir ncachedir stale\n",
238 if (opt_prt & PRNT_CALLS) {
241 nfsv2name, svcv2info + 1, 18
246 nfsv3name, svcv3info + 1, 22
252 if (opt_prt & PRNT_NET) {
254 "Client packet stats:\n"
255 "packets udp tcp tcpconn\n",
259 if (opt_prt & PRNT_RPC) {
261 "Client rpc stats:\n"
262 "calls retrans authrefrsh\n",
266 if (opt_prt & PRNT_CALLS) {
269 nfsv2name, cltv2info + 1, 18
274 nfsv3name, cltv3info + 1, 22
283 get_stat_info(const char *sp, struct statinfo *statp)
287 for (ip = statp; ip->tag; ip++) {
288 if (!strcmp(sp, ip->tag))
296 print_numbers(const char *hdr, unsigned int *info, unsigned int nr)
301 for (i = 0; i < nr; i++)
302 printf("%s%-8d", i? " " : "", info[i]);
307 print_callstats(const char *hdr, const char **names,
308 unsigned int *info, unsigned int nr)
314 for (i = 0, total = 0; i < nr; i++)
318 for (i = 0; i < nr; i += 6) {
319 for (j = 0; j < 6 && i + j < nr; j++)
320 printf("%-11s", names[i+j]);
322 for (j = 0; j < 6 && i + j < nr; j++)
323 printf("%-6d %2d%% ",
324 info[i+j], 100 * info[i+j] / total);
332 parse_statfile(const char *name, struct statinfo *statp)
334 char buffer[4096], *next;
337 /* Being unable to read e.g. the nfsd stats file shouldn't
338 * be a fatal error -- it usually means the module isn't loaded.
340 if ((fp = fopen(name, "r")) == NULL) {
341 fprintf(stderr, "Warning: %s: %m\n", name);
345 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
347 char *sp, *line = buffer;
350 if ((next = strchr(line, '\n')) != NULL)
352 if (!(sp = strtok(line, " \t")))
355 ip = get_stat_info(sp, statp);
361 for (i = 0; i < cnt; i++) {
362 if (!(sp = strtok(NULL, " \t")))
364 ip->valptr[i] = atoi(sp);