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[22]; /* NFSv3 call counts ([0] == 22) */
24 static unsigned int cltv3info[22]; /* 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
54 * 5 noncached non-directories
55 * 6 noncached directories
59 static const char * nfsv2name[18] = {
60 "null", "getattr", "setattr", "root", "lookup", "readlink",
61 "read", "wrcache", "write", "create", "remove", "rename",
62 "link", "symlink", "mkdir", "rmdir", "readdir", "fsstat"
65 static const char * nfsv3name[22] = {
66 "null", "getattr", "setattr", "lookup", "access", "readlink",
67 "read", "write", "create", "mkdir", "symlink", "mknod",
68 "remove", "rmdir", "rename", "link", "readdir", "readdirplus",
69 "fsstat", "fsinfo", "pathconf", "commit"
72 typedef struct statinfo {
75 unsigned int * valptr;
77 /* Filled in by parse_statfile */
81 static statinfo svcinfo[] = {
82 { "net", 4, svcnetinfo },
83 { "rpc", 5, svcrpcinfo },
84 { "rc", 8, svcrcinfo }, /* including fh_* */
85 { "proc2", 19, svcv2info },
86 { "proc3", 23, svcv3info },
90 static statinfo cltinfo[] = {
91 { "net", 4, cltnetinfo },
92 { "rpc", 3, cltrpcinfo },
93 { "proc2", 19, cltv2info },
94 { "proc3", 23, cltv3info },
98 static void print_numbers(const char *, unsigned int *,
100 static void print_callstats(const char *, const char **,
101 unsigned int *, unsigned int);
102 static int parse_statfile(const char *, struct statinfo *);
104 #define PRNT_CALLS 0x0001
105 #define PRNT_RPC 0x0002
106 #define PRNT_NET 0x0004
107 #define PRNT_FH 0x0008
108 #define PRNT_RC 0x0010
109 #define PRNT_ALL 0xffff
112 main(int argc, char **argv)
120 while ((c = getopt(argc, argv, "acno:rsz")) != -1) {
129 opt_prt |= PRNT_CALLS;
132 if (!strcmp(optarg, "nfs"))
133 opt_prt |= PRNT_CALLS;
134 else if (!strcmp(optarg, "rpc"))
136 else if (!strcmp(optarg, "net"))
138 else if (!strcmp(optarg, "rc"))
140 else if (!strcmp(optarg, "fh"))
143 fprintf(stderr, "nfsstat: unknown category: "
155 fprintf(stderr, "nfsstat: zeroing of nfs statistics "
156 "not yet supported\n");
162 opt_srv = opt_clt = 1;
165 if (!(opt_srv + opt_clt))
166 opt_srv = opt_clt = 1;
168 opt_prt = PRNT_CALLS + PRNT_RPC;
169 if ((opt_prt & (PRNT_FH|PRNT_RC)) && !opt_srv) {
171 "You requested file handle or request cache "
172 "statistics while using the -c option.\n"
173 "This information is available only for the NFS "
177 if ((opt_srv && !parse_statfile(NFSSVCSTAT, svcinfo))
178 || (opt_clt && !parse_statfile(NFSCLTSTAT, cltinfo)))
182 if (opt_prt & PRNT_NET) {
184 "Server packet stats:\n"
185 "packets udp tcp tcpconn\n",
189 if (opt_prt & PRNT_RPC) {
191 "Server rpc stats:\n"
192 "calls badcalls badauth badclnt xdrcall\n",
196 if (opt_prt & PRNT_RC) {
198 "Server reply cache:\n"
199 "hits misses nocache\n",
203 if (opt_prt & PRNT_FH) {
205 "Server file handle cache:\n"
206 "lookup anon ncachendir ncachedir stale\n",
209 if (opt_prt & PRNT_CALLS) {
212 nfsv2name, svcv2info + 1, 18
217 nfsv3name, svcv3info + 1, 22
223 if (opt_prt & PRNT_NET) {
225 "Client packet stats:\n"
226 "packets udp tcp tcpconn\n",
230 if (opt_prt & PRNT_RPC) {
232 "Client rpc stats:\n"
233 "calls retrans authrefrsh\n",
237 if (opt_prt & PRNT_CALLS) {
240 nfsv2name, cltv2info + 1, 18
245 nfsv3name, cltv3info + 1, 22
254 print_numbers(const char *hdr, unsigned int *info, unsigned int nr)
259 for (i = 0; i < nr; i++)
260 printf("%s%-8d", i? " " : "", info[i]);
265 print_callstats(const char *hdr, const char **names,
266 unsigned int *info, unsigned int nr)
272 for (i = 0, total = 0; i < nr; i++)
276 for (i = 0; i < nr; i += 6) {
277 for (j = 0; j < 6 && i + j < nr; j++)
278 printf("%-11s", names[i+j]);
280 for (j = 0; j < 6 && i + j < nr; j++)
281 printf("%-6d %2d%% ",
282 info[i+j], 100 * info[i+j] / total);
289 parse_statfile(const char *name, struct statinfo *statp)
291 char buffer[4096], *next;
294 /* Being unable to read e.g. the nfsd stats file shouldn't
295 * be a fatal error -- it usually means the module isn't loaded.
297 if ((fp = fopen(name, "r")) == NULL) {
298 fprintf(stderr, "Warning: %s: %m\n", name);
302 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
304 char *sp, *line = buffer;
307 if ((next = strchr(line, '\n')) != NULL)
309 if (!(sp = strtok(line, " \t")))
311 for (ip = statp; ip->tag; ip++) {
312 if (!strcmp(sp, ip->tag))
319 for (i = 0; i < cnt; i++) {
320 if (!(sp = strtok(NULL, " \t")))
322 ip->valptr[i] = atoi(sp);