1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /* LINTLIBRARY */
23 /* PROTOLIB1 */
24
25 /*
26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 /*
31 * nfsstat: Network File System statistics
32 *
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <kvm.h>
43 #include <kstat.h>
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <sys/t_lock.h>
47 #include <sys/tiuser.h>
48 #include <sys/statvfs.h>
49 #include <sys/mntent.h>
50 #include <sys/mnttab.h>
51 #include <sys/sysmacros.h>
52 #include <sys/mkdev.h>
53 #include <rpc/types.h>
54 #include <rpc/xdr.h>
55 #include <rpc/auth.h>
56 #include <rpc/clnt.h>
57 #include <nfs/nfs.h>
58 #include <nfs/nfs_clnt.h>
59 #include <nfs/nfs_sec.h>
60 #include <inttypes.h>
61 #include <signal.h>
62 #include <time.h>
63 #include <sys/time.h>
64 #include <strings.h>
65 #include <ctype.h>
66 #include <locale.h>
67
68 #include "statcommon.h"
69
70 static kstat_ctl_t *kc = NULL; /* libkstat cookie */
71 static kstat_t *rpc_clts_client_kstat, *rpc_clts_server_kstat;
72 static kstat_t *rpc_cots_client_kstat, *rpc_cots_server_kstat;
73 static kstat_t *rpc_rdma_client_kstat, *rpc_rdma_server_kstat;
74 static kstat_t *nfs_client_kstat, *nfs_server_v2_kstat, *nfs_server_v3_kstat;
75 static kstat_t *nfs4_client_kstat, *nfs_server_v4_kstat;
76 static kstat_t *rfsproccnt_v2_kstat, *rfsproccnt_v3_kstat, *rfsproccnt_v4_kstat;
77 static kstat_t *rfsreqcnt_v2_kstat, *rfsreqcnt_v3_kstat, *rfsreqcnt_v4_kstat;
78 static kstat_t *aclproccnt_v2_kstat, *aclproccnt_v3_kstat;
79 static kstat_t *aclreqcnt_v2_kstat, *aclreqcnt_v3_kstat;
80 static kstat_t *ksum_kstat;
81
82 static void handle_sig(int);
83 static int getstats_rpc(void);
84 static int getstats_nfs(void);
85 static int getstats_rfsproc(int);
86 static int getstats_rfsreq(int);
87 static int getstats_aclproc(void);
88 static int getstats_aclreq(void);
89 static void putstats(void);
90 static void setup(void);
91 static void cr_print(int);
92 static void sr_print(int);
93 static void cn_print(int, int);
94 static void sn_print(int, int);
95 static void ca_print(int, int);
96 static void sa_print(int, int);
97 static void req_print(kstat_t *, kstat_t *, int, int, int);
98 static void req_print_v4(kstat_t *, kstat_t *, int, int);
99 static void stat_print(const char *, kstat_t *, kstat_t *, int, int);
100 static void nfsstat_kstat_sum(kstat_t *, kstat_t *, kstat_t *);
101 static void stats_timer(int);
102 static void safe_zalloc(void **, uint_t, int);
103 static int safe_strtoi(char const *, char *);
104
105
106 static void nfsstat_kstat_copy(kstat_t *, kstat_t *, int);
107 static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
108 static kid_t safe_kstat_write(kstat_ctl_t *, kstat_t *, void *);
109
110 static void usage(void);
111 static void mi_print(void);
112 static int ignore(char *);
113 static int interval; /* interval between stats */
114 static int count; /* number of iterations the stat is printed */
115 #define MAX_COLUMNS 80
116 #define MAX_PATHS 50 /* max paths that can be taken by -m */
117
118 /*
119 * MI4_MIRRORMOUNT is canonically defined in nfs4_clnt.h, but we cannot
120 * include that file here. Same with MI4_REFERRAL.
121 */
122 #define MI4_MIRRORMOUNT 0x4000
123 #define MI4_REFERRAL 0x8000
124 #define NFS_V4 4
125
126 static int req_width(kstat_t *, int);
127 static int stat_width(kstat_t *, int);
128 static char *path [MAX_PATHS] = {NULL}; /* array to store the multiple paths */
129
130 /*
131 * Struct holds the previous kstat values so
132 * we can compute deltas when using the -i flag
133 */
134 typedef struct old_kstat
135 {
136 kstat_t kst;
137 int tot;
138 } old_kstat_t;
139
140 static old_kstat_t old_rpc_clts_client_kstat, old_rpc_clts_server_kstat;
141 static old_kstat_t old_rpc_cots_client_kstat, old_rpc_cots_server_kstat;
142 static old_kstat_t old_rpc_rdma_client_kstat, old_rpc_rdma_server_kstat;
143 static old_kstat_t old_nfs_client_kstat, old_nfs_server_v2_kstat;
144 static old_kstat_t old_nfs_server_v3_kstat, old_ksum_kstat;
145 static old_kstat_t old_nfs4_client_kstat, old_nfs_server_v4_kstat;
146 static old_kstat_t old_rfsproccnt_v2_kstat, old_rfsproccnt_v3_kstat;
147 static old_kstat_t old_rfsproccnt_v4_kstat, old_rfsreqcnt_v2_kstat;
148 static old_kstat_t old_rfsreqcnt_v3_kstat, old_rfsreqcnt_v4_kstat;
149 static old_kstat_t old_aclproccnt_v2_kstat, old_aclproccnt_v3_kstat;
150 static old_kstat_t old_aclreqcnt_v2_kstat, old_aclreqcnt_v3_kstat;
151
152 static uint_t timestamp_fmt = NODATE;
153
154 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
155 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't */
156 #endif
157
158 int
main(int argc,char * argv[])159 main(int argc, char *argv[])
160 {
161 int c, go_forever, j;
162 int cflag = 0; /* client stats */
163 int sflag = 0; /* server stats */
164 int nflag = 0; /* nfs stats */
165 int rflag = 0; /* rpc stats */
166 int mflag = 0; /* mount table stats */
167 int aflag = 0; /* print acl statistics */
168 int vflag = 0; /* version specified, 0 specifies all */
169 int zflag = 0; /* zero stats after printing */
170 char *split_line = "*******************************************"
171 "*************************************";
172
173 interval = 0;
174 count = 0;
175 go_forever = 0;
176
177 (void) setlocale(LC_ALL, "");
178 (void) textdomain(TEXT_DOMAIN);
179
180 while ((c = getopt(argc, argv, "cnrsmzav:T:")) != EOF) {
181 switch (c) {
182 case 'c':
183 cflag++;
184 break;
185 case 'n':
186 nflag++;
187 break;
188 case 'r':
189 rflag++;
190 break;
191 case 's':
192 sflag++;
193 break;
194 case 'm':
195 mflag++;
196 break;
197 case 'z':
198 if (geteuid())
199 fail(0, "Must be root for z flag\n");
200 zflag++;
201 break;
202 case 'a':
203 aflag++;
204 break;
205 case 'v':
206 vflag = atoi(optarg);
207 if ((vflag < 2) || (vflag > 4))
208 fail(0, "Invalid version number\n");
209 break;
210 case 'T':
211 if (optarg) {
212 if (*optarg == 'u')
213 timestamp_fmt = UDATE;
214 else if (*optarg == 'd')
215 timestamp_fmt = DDATE;
216 else
217 usage();
218 } else {
219 usage();
220 }
221 break;
222 case '?':
223 default:
224 usage();
225 }
226 }
227
228 if (((argc - optind) > 0) && !mflag) {
229
230 interval = safe_strtoi(argv[optind], "invalid interval");
231 if (interval < 1)
232 fail(0, "invalid interval\n");
233 optind++;
234
235 if ((argc - optind) > 0) {
236 count = safe_strtoi(argv[optind], "invalid count");
237 if ((count <= 0) || (count == NULL))
238 fail(0, "invalid count\n");
239 }
240 optind++;
241
242 if ((argc - optind) > 0)
243 usage();
244
245 /*
246 * no count number was set, so we will loop infinitely
247 * at interval specified
248 */
249 if (!count)
250 go_forever = 1;
251 stats_timer(interval);
252 } else if (mflag) {
253
254 if (cflag || rflag || sflag || zflag || nflag || aflag || vflag)
255 fail(0,
256 "The -m flag may not be used with any other flags");
257
258 for (j = 0; (argc - optind > 0) && (j < (MAX_PATHS - 1)); j++) {
259 path[j] = argv[optind];
260 if (*path[j] != '/')
261 fail(0, "Please fully qualify your pathname "
262 "with a leading '/'");
263 optind++;
264 }
265 path[j] = NULL;
266 if (argc - optind > 0)
267 fprintf(stderr, "Only the first 50 paths "
268 "will be searched for\n");
269 }
270
271 setup();
272
273 do {
274 if (mflag) {
275 mi_print();
276 } else {
277 if (timestamp_fmt != NODATE)
278 print_timestamp(timestamp_fmt);
279
280 if (sflag &&
281 (rpc_clts_server_kstat == NULL ||
282 nfs_server_v4_kstat == NULL)) {
283 fprintf(stderr,
284 "nfsstat: kernel is not configured with "
285 "the server nfs and rpc code.\n");
286 }
287
288 /* if s and nothing else, all 3 prints are called */
289 if (sflag || (!sflag && !cflag)) {
290 if (rflag || (!rflag && !nflag && !aflag))
291 sr_print(zflag);
292 if (nflag || (!rflag && !nflag && !aflag))
293 sn_print(zflag, vflag);
294 if (aflag || (!rflag && !nflag && !aflag))
295 sa_print(zflag, vflag);
296 }
297 if (cflag &&
298 (rpc_clts_client_kstat == NULL ||
299 nfs_client_kstat == NULL)) {
300 fprintf(stderr,
301 "nfsstat: kernel is not configured with"
302 " the client nfs and rpc code.\n");
303 }
304 if (cflag || (!sflag && !cflag)) {
305 if (rflag || (!rflag && !nflag && !aflag))
306 cr_print(zflag);
307 if (nflag || (!rflag && !nflag && !aflag))
308 cn_print(zflag, vflag);
309 if (aflag || (!rflag && !nflag && !aflag))
310 ca_print(zflag, vflag);
311 }
312 }
313
314 if (zflag)
315 putstats();
316 if (interval)
317 printf("%s\n", split_line);
318
319 if (interval > 0)
320 (void) pause();
321 } while ((--count > 0) || go_forever);
322
323 kstat_close(kc);
324 free(ksum_kstat);
325 return (0);
326 }
327
328
329 static int
getstats_rpc(void)330 getstats_rpc(void)
331 {
332 int field_width = 0;
333
334 if (rpc_clts_client_kstat != NULL) {
335 safe_kstat_read(kc, rpc_clts_client_kstat, NULL);
336 field_width = stat_width(rpc_clts_client_kstat, field_width);
337 }
338
339 if (rpc_cots_client_kstat != NULL) {
340 safe_kstat_read(kc, rpc_cots_client_kstat, NULL);
341 field_width = stat_width(rpc_cots_client_kstat, field_width);
342 }
343
344 if (rpc_rdma_client_kstat != NULL) {
345 safe_kstat_read(kc, rpc_rdma_client_kstat, NULL);
346 field_width = stat_width(rpc_rdma_client_kstat, field_width);
347 }
348
349 if (rpc_clts_server_kstat != NULL) {
350 safe_kstat_read(kc, rpc_clts_server_kstat, NULL);
351 field_width = stat_width(rpc_clts_server_kstat, field_width);
352 }
353 if (rpc_cots_server_kstat != NULL) {
354 safe_kstat_read(kc, rpc_cots_server_kstat, NULL);
355 field_width = stat_width(rpc_cots_server_kstat, field_width);
356 }
357 if (rpc_rdma_server_kstat != NULL) {
358 safe_kstat_read(kc, rpc_rdma_server_kstat, NULL);
359 field_width = stat_width(rpc_rdma_server_kstat, field_width);
360 }
361 return (field_width);
362 }
363
364 static int
getstats_nfs(void)365 getstats_nfs(void)
366 {
367 int field_width = 0;
368
369 if (nfs_client_kstat != NULL) {
370 safe_kstat_read(kc, nfs_client_kstat, NULL);
371 field_width = stat_width(nfs_client_kstat, field_width);
372 }
373 if (nfs4_client_kstat != NULL) {
374 safe_kstat_read(kc, nfs4_client_kstat, NULL);
375 field_width = stat_width(nfs4_client_kstat, field_width);
376 }
377 if (nfs_server_v2_kstat != NULL) {
378 safe_kstat_read(kc, nfs_server_v2_kstat, NULL);
379 field_width = stat_width(nfs_server_v2_kstat, field_width);
380 }
381 if (nfs_server_v3_kstat != NULL) {
382 safe_kstat_read(kc, nfs_server_v3_kstat, NULL);
383 field_width = stat_width(nfs_server_v3_kstat, field_width);
384 }
385 if (nfs_server_v4_kstat != NULL) {
386 safe_kstat_read(kc, nfs_server_v4_kstat, NULL);
387 field_width = stat_width(nfs_server_v4_kstat, field_width);
388 }
389 return (field_width);
390 }
391
392 static int
getstats_rfsproc(int ver)393 getstats_rfsproc(int ver)
394 {
395 int field_width = 0;
396
397 if ((ver == 2) && (rfsproccnt_v2_kstat != NULL)) {
398 safe_kstat_read(kc, rfsproccnt_v2_kstat, NULL);
399 field_width = req_width(rfsproccnt_v2_kstat, field_width);
400 }
401 if ((ver == 3) && (rfsproccnt_v3_kstat != NULL)) {
402 safe_kstat_read(kc, rfsproccnt_v3_kstat, NULL);
403 field_width = req_width(rfsproccnt_v3_kstat, field_width);
404 }
405 if ((ver == 4) && (rfsproccnt_v4_kstat != NULL)) {
406 safe_kstat_read(kc, rfsproccnt_v4_kstat, NULL);
407 field_width = req_width(rfsproccnt_v4_kstat, field_width);
408 }
409 return (field_width);
410 }
411
412 static int
getstats_rfsreq(int ver)413 getstats_rfsreq(int ver)
414 {
415 int field_width = 0;
416 if ((ver == 2) && (rfsreqcnt_v2_kstat != NULL)) {
417 safe_kstat_read(kc, rfsreqcnt_v2_kstat, NULL);
418 field_width = req_width(rfsreqcnt_v2_kstat, field_width);
419 }
420 if ((ver == 3) && (rfsreqcnt_v3_kstat != NULL)) {
421 safe_kstat_read(kc, rfsreqcnt_v3_kstat, NULL);
422 field_width = req_width(rfsreqcnt_v3_kstat, field_width);
423 }
424 if ((ver == 4) && (rfsreqcnt_v4_kstat != NULL)) {
425 safe_kstat_read(kc, rfsreqcnt_v4_kstat, NULL);
426 field_width = req_width(rfsreqcnt_v4_kstat, field_width);
427 }
428 return (field_width);
429 }
430
431 static int
getstats_aclproc(void)432 getstats_aclproc(void)
433 {
434 int field_width = 0;
435 if (aclproccnt_v2_kstat != NULL) {
436 safe_kstat_read(kc, aclproccnt_v2_kstat, NULL);
437 field_width = req_width(aclproccnt_v2_kstat, field_width);
438 }
439 if (aclproccnt_v3_kstat != NULL) {
440 safe_kstat_read(kc, aclproccnt_v3_kstat, NULL);
441 field_width = req_width(aclproccnt_v3_kstat, field_width);
442 }
443 return (field_width);
444 }
445
446 static int
getstats_aclreq(void)447 getstats_aclreq(void)
448 {
449 int field_width = 0;
450 if (aclreqcnt_v2_kstat != NULL) {
451 safe_kstat_read(kc, aclreqcnt_v2_kstat, NULL);
452 field_width = req_width(aclreqcnt_v2_kstat, field_width);
453 }
454 if (aclreqcnt_v3_kstat != NULL) {
455 safe_kstat_read(kc, aclreqcnt_v3_kstat, NULL);
456 field_width = req_width(aclreqcnt_v3_kstat, field_width);
457 }
458 return (field_width);
459 }
460
461 static void
putstats(void)462 putstats(void)
463 {
464 if (rpc_clts_client_kstat != NULL)
465 safe_kstat_write(kc, rpc_clts_client_kstat, NULL);
466 if (rpc_cots_client_kstat != NULL)
467 safe_kstat_write(kc, rpc_cots_client_kstat, NULL);
468 if (rpc_rdma_client_kstat != NULL)
469 safe_kstat_write(kc, rpc_rdma_client_kstat, NULL);
470 if (nfs_client_kstat != NULL)
471 safe_kstat_write(kc, nfs_client_kstat, NULL);
472 if (nfs4_client_kstat != NULL)
473 safe_kstat_write(kc, nfs4_client_kstat, NULL);
474 if (rpc_clts_server_kstat != NULL)
475 safe_kstat_write(kc, rpc_clts_server_kstat, NULL);
476 if (rpc_cots_server_kstat != NULL)
477 safe_kstat_write(kc, rpc_cots_server_kstat, NULL);
478 if (rpc_rdma_server_kstat != NULL)
479 safe_kstat_write(kc, rpc_rdma_server_kstat, NULL);
480 if (nfs_server_v2_kstat != NULL)
481 safe_kstat_write(kc, nfs_server_v2_kstat, NULL);
482 if (nfs_server_v3_kstat != NULL)
483 safe_kstat_write(kc, nfs_server_v3_kstat, NULL);
484 if (nfs_server_v4_kstat != NULL)
485 safe_kstat_write(kc, nfs_server_v4_kstat, NULL);
486 if (rfsproccnt_v2_kstat != NULL)
487 safe_kstat_write(kc, rfsproccnt_v2_kstat, NULL);
488 if (rfsproccnt_v3_kstat != NULL)
489 safe_kstat_write(kc, rfsproccnt_v3_kstat, NULL);
490 if (rfsproccnt_v4_kstat != NULL)
491 safe_kstat_write(kc, rfsproccnt_v4_kstat, NULL);
492 if (rfsreqcnt_v2_kstat != NULL)
493 safe_kstat_write(kc, rfsreqcnt_v2_kstat, NULL);
494 if (rfsreqcnt_v3_kstat != NULL)
495 safe_kstat_write(kc, rfsreqcnt_v3_kstat, NULL);
496 if (rfsreqcnt_v4_kstat != NULL)
497 safe_kstat_write(kc, rfsreqcnt_v4_kstat, NULL);
498 if (aclproccnt_v2_kstat != NULL)
499 safe_kstat_write(kc, aclproccnt_v2_kstat, NULL);
500 if (aclproccnt_v3_kstat != NULL)
501 safe_kstat_write(kc, aclproccnt_v3_kstat, NULL);
502 if (aclreqcnt_v2_kstat != NULL)
503 safe_kstat_write(kc, aclreqcnt_v2_kstat, NULL);
504 if (aclreqcnt_v3_kstat != NULL)
505 safe_kstat_write(kc, aclreqcnt_v3_kstat, NULL);
506 }
507
508 static void
setup(void)509 setup(void)
510 {
511 if ((kc = kstat_open()) == NULL)
512 fail(1, "kstat_open(): can't open /dev/kstat");
513
514 /* alloc space for our temporary kstat */
515 safe_zalloc((void **)&ksum_kstat, sizeof (kstat_t), 0);
516 rpc_clts_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_client");
517 rpc_clts_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_server");
518 rpc_cots_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_client");
519 rpc_cots_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_server");
520 rpc_rdma_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_client");
521 rpc_rdma_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_server");
522 nfs_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs_client");
523 nfs4_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs4_client");
524 nfs_server_v2_kstat = kstat_lookup(kc, "nfs", 2, "nfs_server");
525 nfs_server_v3_kstat = kstat_lookup(kc, "nfs", 3, "nfs_server");
526 nfs_server_v4_kstat = kstat_lookup(kc, "nfs", 4, "nfs_server");
527 rfsproccnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v2");
528 rfsproccnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v3");
529 rfsproccnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v4");
530 rfsreqcnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v2");
531 rfsreqcnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v3");
532 rfsreqcnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v4");
533 aclproccnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v2");
534 aclproccnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v3");
535 aclreqcnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v2");
536 aclreqcnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v3");
537 if (rpc_clts_client_kstat == NULL && rpc_cots_server_kstat == NULL &&
538 rfsproccnt_v2_kstat == NULL && rfsreqcnt_v3_kstat == NULL)
539 fail(0, "Multiple kstat lookups failed."
540 "Your kernel module may not be loaded\n");
541 }
542
543 static int
req_width(kstat_t * req,int field_width)544 req_width(kstat_t *req, int field_width)
545 {
546 int i, nreq, per, len;
547 char fixlen[128];
548 kstat_named_t *knp;
549 uint64_t tot;
550
551 tot = 0;
552 knp = KSTAT_NAMED_PTR(req);
553 for (i = 0; i < req->ks_ndata; i++)
554 tot += knp[i].value.ui64;
555
556 knp = kstat_data_lookup(req, "null");
557 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req));
558
559 for (i = 0; i < nreq; i++) {
560 len = strlen(knp[i].name) + 1;
561 if (field_width < len)
562 field_width = len;
563 if (tot)
564 per = (int)(knp[i].value.ui64 * 100 / tot);
565 else
566 per = 0;
567 (void) sprintf(fixlen, "%" PRIu64 " %d%%",
568 knp[i].value.ui64, per);
569 len = strlen(fixlen) + 1;
570 if (field_width < len)
571 field_width = len;
572 }
573 return (field_width);
574 }
575
576 static int
stat_width(kstat_t * req,int field_width)577 stat_width(kstat_t *req, int field_width)
578 {
579 int i, nreq, len;
580 char fixlen[128];
581 kstat_named_t *knp;
582
583 knp = KSTAT_NAMED_PTR(req);
584 nreq = req->ks_ndata;
585
586 for (i = 0; i < nreq; i++) {
587 len = strlen(knp[i].name) + 1;
588 if (field_width < len)
589 field_width = len;
590 (void) sprintf(fixlen, "%" PRIu64, knp[i].value.ui64);
591 len = strlen(fixlen) + 1;
592 if (field_width < len)
593 field_width = len;
594 }
595 return (field_width);
596 }
597
598 static void
cr_print(int zflag)599 cr_print(int zflag)
600 {
601 int field_width;
602
603 field_width = getstats_rpc();
604 if (field_width == 0)
605 return;
606
607 stat_print("\nClient rpc:\nConnection oriented:",
608 rpc_cots_client_kstat,
609 &old_rpc_cots_client_kstat.kst, field_width, zflag);
610 stat_print("Connectionless:", rpc_clts_client_kstat,
611 &old_rpc_clts_client_kstat.kst, field_width, zflag);
612 stat_print("RDMA based:", rpc_rdma_client_kstat,
613 &old_rpc_rdma_client_kstat.kst, field_width, zflag);
614 }
615
616 static void
sr_print(int zflag)617 sr_print(int zflag)
618 {
619 int field_width;
620
621 field_width = getstats_rpc();
622 if (field_width == 0)
623 return;
624
625 stat_print("\nServer rpc:\nConnection oriented:", rpc_cots_server_kstat,
626 &old_rpc_cots_server_kstat.kst, field_width, zflag);
627 stat_print("Connectionless:", rpc_clts_server_kstat,
628 &old_rpc_clts_server_kstat.kst, field_width, zflag);
629 stat_print("RDMA based:", rpc_rdma_server_kstat,
630 &old_rpc_rdma_server_kstat.kst, field_width, zflag);
631 }
632
633 static void
cn_print(int zflag,int vflag)634 cn_print(int zflag, int vflag)
635 {
636 int field_width;
637
638 field_width = getstats_nfs();
639 if (field_width == 0)
640 return;
641
642 if (vflag == 0) {
643 nfsstat_kstat_sum(nfs_client_kstat, nfs4_client_kstat,
644 ksum_kstat);
645 stat_print("\nClient nfs:", ksum_kstat, &old_ksum_kstat.kst,
646 field_width, zflag);
647 }
648
649 if (vflag == 2 || vflag == 3) {
650 stat_print("\nClient nfs:", nfs_client_kstat,
651 &old_nfs_client_kstat.kst, field_width, zflag);
652 }
653
654 if (vflag == 4) {
655 stat_print("\nClient nfs:", nfs4_client_kstat,
656 &old_nfs4_client_kstat.kst, field_width, zflag);
657 }
658
659 if (vflag == 2 || vflag == 0) {
660 field_width = getstats_rfsreq(2);
661 req_print(rfsreqcnt_v2_kstat, &old_rfsreqcnt_v2_kstat.kst,
662 2, field_width, zflag);
663 }
664
665 if (vflag == 3 || vflag == 0) {
666 field_width = getstats_rfsreq(3);
667 req_print(rfsreqcnt_v3_kstat, &old_rfsreqcnt_v3_kstat.kst, 3,
668 field_width, zflag);
669 }
670
671 if (vflag == 4 || vflag == 0) {
672 field_width = getstats_rfsreq(4);
673 req_print_v4(rfsreqcnt_v4_kstat, &old_rfsreqcnt_v4_kstat.kst,
674 field_width, zflag);
675 }
676 }
677
678 static void
sn_print(int zflag,int vflag)679 sn_print(int zflag, int vflag)
680 {
681 int field_width;
682
683 field_width = getstats_nfs();
684 if (field_width == 0)
685 return;
686
687 if (vflag == 2 || vflag == 0) {
688 stat_print("\nServer NFSv2:", nfs_server_v2_kstat,
689 &old_nfs_server_v2_kstat.kst, field_width, zflag);
690 }
691
692 if (vflag == 3 || vflag == 0) {
693 stat_print("\nServer NFSv3:", nfs_server_v3_kstat,
694 &old_nfs_server_v3_kstat.kst, field_width, zflag);
695 }
696
697 if (vflag == 4 || vflag == 0) {
698 stat_print("\nServer NFSv4:", nfs_server_v4_kstat,
699 &old_nfs_server_v4_kstat.kst, field_width, zflag);
700 }
701
702 if (vflag == 2 || vflag == 0) {
703 field_width = getstats_rfsproc(2);
704 req_print(rfsproccnt_v2_kstat, &old_rfsproccnt_v2_kstat.kst,
705 2, field_width, zflag);
706 }
707
708 if (vflag == 3 || vflag == 0) {
709 field_width = getstats_rfsproc(3);
710 req_print(rfsproccnt_v3_kstat, &old_rfsproccnt_v3_kstat.kst,
711 3, field_width, zflag);
712 }
713
714 if (vflag == 4 || vflag == 0) {
715 field_width = getstats_rfsproc(4);
716 req_print_v4(rfsproccnt_v4_kstat, &old_rfsproccnt_v4_kstat.kst,
717 field_width, zflag);
718 }
719 }
720
721 static void
ca_print(int zflag,int vflag)722 ca_print(int zflag, int vflag)
723 {
724 int field_width;
725
726 field_width = getstats_aclreq();
727 if (field_width == 0)
728 return;
729
730 printf("\nClient nfs_acl:\n");
731
732 if (vflag == 2 || vflag == 0) {
733 req_print(aclreqcnt_v2_kstat, &old_aclreqcnt_v2_kstat.kst, 2,
734 field_width, zflag);
735 }
736
737 if (vflag == 3 || vflag == 0) {
738 req_print(aclreqcnt_v3_kstat, &old_aclreqcnt_v3_kstat.kst,
739 3, field_width, zflag);
740 }
741 }
742
743 static void
sa_print(int zflag,int vflag)744 sa_print(int zflag, int vflag)
745 {
746 int field_width;
747
748 field_width = getstats_aclproc();
749 if (field_width == 0)
750 return;
751
752 printf("\nServer nfs_acl:\n");
753
754 if (vflag == 2 || vflag == 0) {
755 req_print(aclproccnt_v2_kstat, &old_aclproccnt_v2_kstat.kst,
756 2, field_width, zflag);
757 }
758
759 if (vflag == 3 || vflag == 0) {
760 req_print(aclproccnt_v3_kstat, &old_aclproccnt_v3_kstat.kst,
761 3, field_width, zflag);
762 }
763 }
764
765 #define MIN(a, b) ((a) < (b) ? (a) : (b))
766
767 static void
req_print(kstat_t * req,kstat_t * req_old,int ver,int field_width,int zflag)768 req_print(kstat_t *req, kstat_t *req_old, int ver, int field_width,
769 int zflag)
770 {
771 int i, j, nreq, per, ncolumns;
772 uint64_t tot, old_tot;
773 char fixlen[128];
774 kstat_named_t *knp;
775 kstat_named_t *kptr;
776 kstat_named_t *knp_old;
777
778 if (req == NULL)
779 return;
780
781 if (field_width == 0)
782 return;
783
784 ncolumns = (MAX_COLUMNS -1)/field_width;
785 knp = kstat_data_lookup(req, "null");
786 knp_old = KSTAT_NAMED_PTR(req_old);
787
788 kptr = KSTAT_NAMED_PTR(req);
789 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req));
790
791 tot = 0;
792 old_tot = 0;
793
794 if (knp_old == NULL) {
795 old_tot = 0;
796 }
797
798 for (i = 0; i < req->ks_ndata; i++)
799 tot += kptr[i].value.ui64;
800
801 if (interval && knp_old != NULL) {
802 for (i = 0; i < req_old->ks_ndata; i++)
803 old_tot += knp_old[i].value.ui64;
804 tot -= old_tot;
805 }
806
807 printf("Version %d: (%" PRIu64 " calls)\n", ver, tot);
808
809 for (i = 0; i < nreq; i += ncolumns) {
810 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
811 printf("%-*s", field_width, knp[j].name);
812 }
813 printf("\n");
814 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
815 if (tot && interval && knp_old != NULL)
816 per = (int)((knp[j].value.ui64 -
817 knp_old[j].value.ui64) * 100 / tot);
818 else if (tot)
819 per = (int)(knp[j].value.ui64 * 100 / tot);
820 else
821 per = 0;
822 (void) sprintf(fixlen, "%" PRIu64 " %d%% ",
823 ((interval && knp_old != NULL) ?
824 (knp[j].value.ui64 - knp_old[j].value.ui64)
825 : knp[j].value.ui64), per);
826 printf("%-*s", field_width, fixlen);
827 }
828 printf("\n");
829 }
830 if (zflag) {
831 for (i = 0; i < req->ks_ndata; i++)
832 knp[i].value.ui64 = 0;
833 }
834 if (knp_old != NULL)
835 nfsstat_kstat_copy(req, req_old, 1);
836 else
837 nfsstat_kstat_copy(req, req_old, 0);
838 }
839
840 /*
841 * Separate version of the req_print() to deal with V4 and its use of
842 * procedures and operations. It looks odd to have the counts for
843 * both of those lumped into the same set of statistics so this
844 * function (copy of req_print() does the separation and titles).
845 */
846
847 #define COUNT 2
848
849 static void
req_print_v4(kstat_t * req,kstat_t * req_old,int field_width,int zflag)850 req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag)
851 {
852 int i, j, nreq, per, ncolumns;
853 uint64_t tot, tot_ops, old_tot, old_tot_ops;
854 char fixlen[128];
855 kstat_named_t *kptr;
856 kstat_named_t *knp;
857 kstat_named_t *kptr_old;
858
859 if (req == NULL)
860 return;
861
862 if (field_width == 0)
863 return;
864
865 ncolumns = (MAX_COLUMNS)/field_width;
866 kptr = KSTAT_NAMED_PTR(req);
867 kptr_old = KSTAT_NAMED_PTR(req_old);
868
869 if (kptr_old == NULL) {
870 old_tot_ops = 0;
871 old_tot = 0;
872 } else {
873 old_tot = kptr_old[0].value.ui64 + kptr_old[1].value.ui64;
874 for (i = 2, old_tot_ops = 0; i < req_old->ks_ndata; i++)
875 old_tot_ops += kptr_old[i].value.ui64;
876 }
877
878 /* Count the number of operations sent */
879 for (i = 2, tot_ops = 0; i < req->ks_ndata; i++)
880 tot_ops += kptr[i].value.ui64;
881 /* For v4 NULL/COMPOUND are the only procedures */
882 tot = kptr[0].value.ui64 + kptr[1].value.ui64;
883
884 if (interval) {
885 tot -= old_tot;
886 tot_ops -= old_tot_ops;
887 }
888
889 printf("Version 4: (%" PRIu64 " calls)\n", tot);
890
891 knp = kstat_data_lookup(req, "null");
892 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req));
893
894 for (i = 0; i < COUNT; i += ncolumns) {
895 for (j = i; j < MIN(i + ncolumns, 2); j++) {
896 printf("%-*s", field_width, knp[j].name);
897 }
898 printf("\n");
899 for (j = i; j < MIN(i + ncolumns, 2); j++) {
900 if (tot && interval && kptr_old != NULL)
901 per = (int)((knp[j].value.ui64 -
902 kptr_old[j].value.ui64) * 100 / tot);
903 else if (tot)
904 per = (int)(knp[j].value.ui64 * 100 / tot);
905 else
906 per = 0;
907 (void) sprintf(fixlen, "%" PRIu64 " %d%% ",
908 ((interval && kptr_old != NULL) ?
909 (knp[j].value.ui64 - kptr_old[j].value.ui64)
910 : knp[j].value.ui64), per);
911 printf("%-*s", field_width, fixlen);
912 }
913 printf("\n");
914 }
915
916 printf("Version 4: (%" PRIu64 " operations)\n", tot_ops);
917 for (i = 2; i < nreq; i += ncolumns) {
918 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
919 printf("%-*s", field_width, knp[j].name);
920 }
921 printf("\n");
922 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
923 if (tot_ops && interval && kptr_old != NULL)
924 per = (int)((knp[j].value.ui64 -
925 kptr_old[j].value.ui64) * 100 / tot_ops);
926 else if (tot_ops)
927 per = (int)(knp[j].value.ui64 * 100 / tot_ops);
928 else
929 per = 0;
930 (void) sprintf(fixlen, "%" PRIu64 " %d%% ",
931 ((interval && kptr_old != NULL) ?
932 (knp[j].value.ui64 - kptr_old[j].value.ui64)
933 : knp[j].value.ui64), per);
934 printf("%-*s", field_width, fixlen);
935 }
936 printf("\n");
937 }
938 if (zflag) {
939 for (i = 0; i < req->ks_ndata; i++)
940 kptr[i].value.ui64 = 0;
941 }
942 if (kptr_old != NULL)
943 nfsstat_kstat_copy(req, req_old, 1);
944 else
945 nfsstat_kstat_copy(req, req_old, 0);
946 }
947
948 static void
stat_print(const char * title_string,kstat_t * req,kstat_t * req_old,int field_width,int zflag)949 stat_print(const char *title_string, kstat_t *req, kstat_t *req_old,
950 int field_width, int zflag)
951 {
952 int i, j, nreq, ncolumns;
953 char fixlen[128];
954 kstat_named_t *knp;
955 kstat_named_t *knp_old;
956
957 if (req == NULL)
958 return;
959
960 if (field_width == 0)
961 return;
962
963 printf("%s\n", title_string);
964 ncolumns = (MAX_COLUMNS -1)/field_width;
965
966 /* MEANS knp = (kstat_named_t *)req->ks_data */
967 knp = KSTAT_NAMED_PTR(req);
968 nreq = req->ks_ndata;
969 knp_old = KSTAT_NAMED_PTR(req_old);
970
971 for (i = 0; i < nreq; i += ncolumns) {
972 /* prints out the titles of the columns */
973 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
974 printf("%-*s", field_width, knp[j].name);
975 }
976 printf("\n");
977 /* prints out the stat numbers */
978 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
979 (void) sprintf(fixlen, "%" PRIu64 " ",
980 (interval && knp_old != NULL) ?
981 (knp[j].value.ui64 - knp_old[j].value.ui64)
982 : knp[j].value.ui64);
983 printf("%-*s", field_width, fixlen);
984 }
985 printf("\n");
986
987 }
988 if (zflag) {
989 for (i = 0; i < req->ks_ndata; i++)
990 knp[i].value.ui64 = 0;
991 }
992
993 if (knp_old != NULL)
994 nfsstat_kstat_copy(req, req_old, 1);
995 else
996 nfsstat_kstat_copy(req, req_old, 0);
997 }
998
999 static void
nfsstat_kstat_sum(kstat_t * kstat1,kstat_t * kstat2,kstat_t * sum)1000 nfsstat_kstat_sum(kstat_t *kstat1, kstat_t *kstat2, kstat_t *sum)
1001 {
1002 int i;
1003 kstat_named_t *knp1, *knp2, *knpsum;
1004 if (kstat1 == NULL || kstat2 == NULL)
1005 return;
1006
1007 knp1 = KSTAT_NAMED_PTR(kstat1);
1008 knp2 = KSTAT_NAMED_PTR(kstat2);
1009 if (sum->ks_data == NULL)
1010 nfsstat_kstat_copy(kstat1, sum, 0);
1011 knpsum = KSTAT_NAMED_PTR(sum);
1012
1013 for (i = 0; i < (kstat1->ks_ndata); i++)
1014 knpsum[i].value.ui64 = knp1[i].value.ui64 + knp2[i].value.ui64;
1015 }
1016
1017 /*
1018 * my_dir and my_path could be pointers
1019 */
1020 struct myrec {
1021 ulong_t my_fsid;
1022 char my_dir[MAXPATHLEN];
1023 char *my_path;
1024 char *ig_path;
1025 struct myrec *next;
1026 };
1027
1028 /*
1029 * Print the mount table info
1030 */
1031 static void
mi_print(void)1032 mi_print(void)
1033 {
1034 FILE *mt;
1035 struct extmnttab m;
1036 struct myrec *list, *mrp, *pmrp;
1037 char *flavor;
1038 int ignored = 0;
1039 seconfig_t nfs_sec;
1040 kstat_t *ksp;
1041 struct mntinfo_kstat mik;
1042 int transport_flag = 0;
1043 int path_count;
1044 int found;
1045 char *timer_name[] = {
1046 "Lookups",
1047 "Reads",
1048 "Writes",
1049 "All"
1050 };
1051
1052 mt = fopen(MNTTAB, "r");
1053 if (mt == NULL) {
1054 perror(MNTTAB);
1055 exit(0);
1056 }
1057
1058 list = NULL;
1059 resetmnttab(mt);
1060
1061 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) {
1062 /* ignore non "nfs" and save the "ignore" entries */
1063 if (strcmp(m.mnt_fstype, MNTTYPE_NFS) != 0)
1064 continue;
1065 /*
1066 * Check to see here if user gave a path(s) to
1067 * only show the mount point they wanted
1068 * Iterate through the list of paths the user gave and see
1069 * if any of them match our current nfs mount
1070 */
1071 if (path[0] != NULL) {
1072 found = 0;
1073 for (path_count = 0; path[path_count] != NULL;
1074 path_count++) {
1075 if (strcmp(path[path_count], m.mnt_mountp)
1076 == 0) {
1077 found = 1;
1078 break;
1079 }
1080 }
1081 if (!found)
1082 continue;
1083 }
1084
1085 if ((mrp = malloc(sizeof (struct myrec))) == 0) {
1086 fprintf(stderr, "nfsstat: not enough memory\n");
1087 exit(1);
1088 }
1089 mrp->my_fsid = makedev(m.mnt_major, m.mnt_minor);
1090 if (ignore(m.mnt_mntopts)) {
1091 /*
1092 * ignored entries cannot be ignored for this
1093 * option. We have to display the info for this
1094 * nfs mount. The ignore is an indication
1095 * that the actual mount point is different and
1096 * something is in between the nfs mount.
1097 * So save the mount point now
1098 */
1099 if ((mrp->ig_path = malloc(
1100 strlen(m.mnt_mountp) + 1)) == 0) {
1101 fprintf(stderr, "nfsstat: not enough memory\n");
1102 exit(1);
1103 }
1104 (void) strcpy(mrp->ig_path, m.mnt_mountp);
1105 ignored++;
1106 } else {
1107 mrp->ig_path = 0;
1108 (void) strcpy(mrp->my_dir, m.mnt_mountp);
1109 }
1110 if ((mrp->my_path = strdup(m.mnt_special)) == NULL) {
1111 fprintf(stderr, "nfsstat: not enough memory\n");
1112 exit(1);
1113 }
1114 mrp->next = list;
1115 list = mrp;
1116 }
1117
1118 /*
1119 * If something got ignored, go to the beginning of the mnttab
1120 * and look for the cachefs entries since they are the one
1121 * causing this. The mount point saved for the ignored entries
1122 * is matched against the special to get the actual mount point.
1123 * We are interested in the acutal mount point so that the output
1124 * look nice too.
1125 */
1126 if (ignored) {
1127 rewind(mt);
1128 resetmnttab(mt);
1129 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) {
1130
1131 /* ignore non "cachefs" */
1132 if (strcmp(m.mnt_fstype, MNTTYPE_CACHEFS) != 0)
1133 continue;
1134
1135 for (mrp = list; mrp; mrp = mrp->next) {
1136 if (mrp->ig_path == 0)
1137 continue;
1138 if (strcmp(mrp->ig_path, m.mnt_special) == 0) {
1139 mrp->ig_path = 0;
1140 (void) strcpy(mrp->my_dir,
1141 m.mnt_mountp);
1142 }
1143 }
1144 }
1145 /*
1146 * Now ignored entries which do not have
1147 * the my_dir initialized are really ignored; This never
1148 * happens unless the mnttab is corrupted.
1149 */
1150 for (pmrp = 0, mrp = list; mrp; mrp = mrp->next) {
1151 if (mrp->ig_path == 0)
1152 pmrp = mrp;
1153 else if (pmrp)
1154 pmrp->next = mrp->next;
1155 else
1156 list = mrp->next;
1157 }
1158 }
1159
1160 (void) fclose(mt);
1161
1162
1163 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1164 int i;
1165
1166 if (ksp->ks_type != KSTAT_TYPE_RAW)
1167 continue;
1168 if (strcmp(ksp->ks_module, "nfs") != 0)
1169 continue;
1170 if (strcmp(ksp->ks_name, "mntinfo") != 0)
1171 continue;
1172
1173 for (mrp = list; mrp; mrp = mrp->next) {
1174 if ((mrp->my_fsid & MAXMIN) == ksp->ks_instance)
1175 break;
1176 }
1177 if (mrp == 0)
1178 continue;
1179
1180 if (safe_kstat_read(kc, ksp, &mik) == -1)
1181 continue;
1182
1183 printf("%s from %s\n", mrp->my_dir, mrp->my_path);
1184
1185 /*
1186 * for printing rdma transport and provider string.
1187 * This way we avoid modifying the kernel mntinfo_kstat
1188 * struct for protofmly.
1189 */
1190 if (strcmp(mik.mik_proto, "ibtf") == 0) {
1191 printf(" Flags: vers=%u,proto=rdma",
1192 mik.mik_vers);
1193 transport_flag = 1;
1194 } else {
1195 printf(" Flags: vers=%u,proto=%s",
1196 mik.mik_vers, mik.mik_proto);
1197 transport_flag = 0;
1198 }
1199
1200 /*
1201 * get the secmode name from /etc/nfssec.conf.
1202 */
1203 if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) {
1204 flavor = nfs_sec.sc_name;
1205 } else
1206 flavor = NULL;
1207
1208 if (flavor != NULL)
1209 printf(",sec=%s", flavor);
1210 else
1211 printf(",sec#=%d", mik.mik_secmod);
1212
1213 printf(",%s", (mik.mik_flags & MI_HARD) ? "hard" : "soft");
1214 if (mik.mik_flags & MI_PRINTED)
1215 printf(",printed");
1216 printf(",%s", (mik.mik_flags & MI_INT) ? "intr" : "nointr");
1217 if (mik.mik_flags & MI_DOWN)
1218 printf(",down");
1219 if (mik.mik_flags & MI_NOAC)
1220 printf(",noac");
1221 if (mik.mik_flags & MI_NOCTO)
1222 printf(",nocto");
1223 if (mik.mik_flags & MI_DYNAMIC)
1224 printf(",dynamic");
1225 if (mik.mik_flags & MI_LLOCK)
1226 printf(",llock");
1227 if (mik.mik_flags & MI_GRPID)
1228 printf(",grpid");
1229 if (mik.mik_flags & MI_RPCTIMESYNC)
1230 printf(",rpctimesync");
1231 if (mik.mik_flags & MI_LINK)
1232 printf(",link");
1233 if (mik.mik_flags & MI_SYMLINK)
1234 printf(",symlink");
1235 if (mik.mik_vers < NFS_V4 && mik.mik_flags & MI_READDIRONLY)
1236 printf(",readdironly");
1237 if (mik.mik_flags & MI_ACL)
1238 printf(",acl");
1239 if (mik.mik_flags & MI_DIRECTIO)
1240 printf(",forcedirectio");
1241
1242 if (mik.mik_vers >= NFS_V4) {
1243 if (mik.mik_flags & MI4_MIRRORMOUNT)
1244 printf(",mirrormount");
1245 if (mik.mik_flags & MI4_REFERRAL)
1246 printf(",referral");
1247 }
1248
1249 printf(",rsize=%d,wsize=%d,retrans=%d,timeo=%d",
1250 mik.mik_curread, mik.mik_curwrite, mik.mik_retrans,
1251 mik.mik_timeo);
1252 printf("\n");
1253 printf(" Attr cache: acregmin=%d,acregmax=%d"
1254 ",acdirmin=%d,acdirmax=%d\n", mik.mik_acregmin,
1255 mik.mik_acregmax, mik.mik_acdirmin, mik.mik_acdirmax);
1256
1257 if (transport_flag) {
1258 printf(" Transport: proto=rdma, plugin=%s\n",
1259 mik.mik_proto);
1260 }
1261
1262 #define srtt_to_ms(x) x, (x * 2 + x / 2)
1263 #define dev_to_ms(x) x, (x * 5)
1264
1265 for (i = 0; i < NFS_CALLTYPES + 1; i++) {
1266 int j;
1267
1268 j = (i == NFS_CALLTYPES ? i - 1 : i);
1269 if (mik.mik_timers[j].srtt ||
1270 mik.mik_timers[j].rtxcur) {
1271 printf(" %s: srtt=%d (%dms), "
1272 "dev=%d (%dms), cur=%u (%ums)\n",
1273 timer_name[i],
1274 srtt_to_ms(mik.mik_timers[i].srtt),
1275 dev_to_ms(mik.mik_timers[i].deviate),
1276 mik.mik_timers[i].rtxcur,
1277 mik.mik_timers[i].rtxcur * 20);
1278 }
1279 }
1280
1281 if (strchr(mrp->my_path, ','))
1282 printf(
1283 " Failover: noresponse=%d,failover=%d,"
1284 "remap=%d,currserver=%s\n",
1285 mik.mik_noresponse, mik.mik_failover,
1286 mik.mik_remap, mik.mik_curserver);
1287 printf("\n");
1288 }
1289 }
1290
1291 static char *mntopts[] = { MNTOPT_IGNORE, MNTOPT_DEV, NULL };
1292 #define IGNORE 0
1293 #define DEV 1
1294
1295 /*
1296 * Return 1 if "ignore" appears in the options string
1297 */
1298 static int
ignore(char * opts)1299 ignore(char *opts)
1300 {
1301 char *value;
1302 char *s;
1303
1304 if (opts == NULL)
1305 return (0);
1306 s = strdup(opts);
1307 if (s == NULL)
1308 return (0);
1309 opts = s;
1310
1311 while (*opts != '\0') {
1312 if (getsubopt(&opts, mntopts, &value) == IGNORE) {
1313 free(s);
1314 return (1);
1315 }
1316 }
1317
1318 free(s);
1319 return (0);
1320 }
1321
1322 void
usage(void)1323 usage(void)
1324 {
1325 fprintf(stderr, "Usage: nfsstat [-cnrsza [-v version] "
1326 "[-T d|u] [interval [count]]\n");
1327 fprintf(stderr, "Usage: nfsstat -m [pathname..]\n");
1328 exit(1);
1329 }
1330
1331 void
fail(int do_perror,char * message,...)1332 fail(int do_perror, char *message, ...)
1333 {
1334 va_list args;
1335
1336 va_start(args, message);
1337 fprintf(stderr, "nfsstat: ");
1338 vfprintf(stderr, message, args);
1339 va_end(args);
1340 if (do_perror)
1341 fprintf(stderr, ": %s", strerror(errno));
1342 fprintf(stderr, "\n");
1343 exit(1);
1344 }
1345
1346 kid_t
safe_kstat_read(kstat_ctl_t * kc,kstat_t * ksp,void * data)1347 safe_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data)
1348 {
1349 kid_t kstat_chain_id = kstat_read(kc, ksp, data);
1350
1351 if (kstat_chain_id == -1)
1352 fail(1, "kstat_read(%x, '%s') failed", kc, ksp->ks_name);
1353 return (kstat_chain_id);
1354 }
1355
1356 kid_t
safe_kstat_write(kstat_ctl_t * kc,kstat_t * ksp,void * data)1357 safe_kstat_write(kstat_ctl_t *kc, kstat_t *ksp, void *data)
1358 {
1359 kid_t kstat_chain_id = 0;
1360
1361 if (ksp->ks_data != NULL) {
1362 kstat_chain_id = kstat_write(kc, ksp, data);
1363
1364 if (kstat_chain_id == -1)
1365 fail(1, "kstat_write(%x, '%s') failed", kc,
1366 ksp->ks_name);
1367 }
1368 return (kstat_chain_id);
1369 }
1370
1371 void
stats_timer(int interval)1372 stats_timer(int interval)
1373 {
1374 timer_t t_id;
1375 itimerspec_t time_struct;
1376 struct sigevent sig_struct;
1377 struct sigaction act;
1378
1379 bzero(&sig_struct, sizeof (struct sigevent));
1380 bzero(&act, sizeof (struct sigaction));
1381
1382 /* Create timer */
1383 sig_struct.sigev_notify = SIGEV_SIGNAL;
1384 sig_struct.sigev_signo = SIGUSR1;
1385 sig_struct.sigev_value.sival_int = 0;
1386
1387 if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) {
1388 fail(1, "Timer creation failed");
1389 }
1390
1391 act.sa_handler = handle_sig;
1392
1393 if (sigaction(SIGUSR1, &act, NULL) != 0) {
1394 fail(1, "Could not set up signal handler");
1395 }
1396
1397 time_struct.it_value.tv_sec = interval;
1398 time_struct.it_value.tv_nsec = 0;
1399 time_struct.it_interval.tv_sec = interval;
1400 time_struct.it_interval.tv_nsec = 0;
1401
1402 /* Arm timer */
1403 if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) {
1404 fail(1, "Setting timer failed");
1405 }
1406 }
1407
1408 void
handle_sig(int x)1409 handle_sig(int x)
1410 {
1411 }
1412
1413 static void
nfsstat_kstat_copy(kstat_t * src,kstat_t * dst,int fr)1414 nfsstat_kstat_copy(kstat_t *src, kstat_t *dst, int fr)
1415 {
1416
1417 if (fr)
1418 free(dst->ks_data);
1419
1420 *dst = *src;
1421
1422 if (src->ks_data != NULL) {
1423 safe_zalloc(&dst->ks_data, src->ks_data_size, 0);
1424 (void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size);
1425 } else {
1426 dst->ks_data = NULL;
1427 dst->ks_data_size = 0;
1428 }
1429 }
1430
1431 /*
1432 * "Safe" allocators - if we return we're guaranteed to have the desired space
1433 * allocated and zero-filled. We exit via fail if we can't get the space.
1434 */
1435 void
safe_zalloc(void ** ptr,uint_t size,int free_first)1436 safe_zalloc(void **ptr, uint_t size, int free_first)
1437 {
1438 if (ptr == NULL)
1439 fail(1, "invalid pointer");
1440 if (free_first && *ptr != NULL)
1441 free(*ptr);
1442 if ((*ptr = (void *)malloc(size)) == NULL)
1443 fail(1, "malloc failed");
1444 (void) memset(*ptr, 0, size);
1445 }
1446
1447 static int
safe_strtoi(char const * val,char * errmsg)1448 safe_strtoi(char const *val, char *errmsg)
1449 {
1450 char *end;
1451 long tmp;
1452 errno = 0;
1453 tmp = strtol(val, &end, 10);
1454 if (*end != '\0' || errno)
1455 fail(0, "%s %s", errmsg, val);
1456 return ((int)tmp);
1457 }
1458