6198 Let's EOL cachefs
[illumos-gate.git] / usr / src / cmd / fs.d / nfs / nfsstat / nfsstat.c
blob64381da71e903fa8e863fc6dad266438f74caabc
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 /* LINTLIBRARY */
23 /* PROTOLIB1 */
26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
32 * nfsstat: Network File System statistics
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <kvm.h>
44 #include <kstat.h>
45 #include <sys/param.h>
46 #include <sys/types.h>
47 #include <sys/t_lock.h>
48 #include <sys/tiuser.h>
49 #include <sys/statvfs.h>
50 #include <sys/mntent.h>
51 #include <sys/mnttab.h>
52 #include <sys/sysmacros.h>
53 #include <sys/mkdev.h>
54 #include <rpc/types.h>
55 #include <rpc/xdr.h>
56 #include <rpc/auth.h>
57 #include <rpc/clnt.h>
58 #include <nfs/nfs.h>
59 #include <nfs/nfs_clnt.h>
60 #include <nfs/nfs_sec.h>
61 #include <inttypes.h>
62 #include <signal.h>
63 #include <time.h>
64 #include <sys/time.h>
65 #include <strings.h>
66 #include <ctype.h>
67 #include <locale.h>
69 #include "statcommon.h"
71 static kstat_ctl_t *kc = NULL; /* libkstat cookie */
72 static kstat_t *rpc_clts_client_kstat, *rpc_clts_server_kstat;
73 static kstat_t *rpc_cots_client_kstat, *rpc_cots_server_kstat;
74 static kstat_t *rpc_rdma_client_kstat, *rpc_rdma_server_kstat;
75 static kstat_t *nfs_client_kstat, *nfs_server_v2_kstat, *nfs_server_v3_kstat;
76 static kstat_t *nfs4_client_kstat, *nfs_server_v4_kstat;
77 static kstat_t *rfsproccnt_v2_kstat, *rfsproccnt_v3_kstat, *rfsproccnt_v4_kstat;
78 static kstat_t *rfsreqcnt_v2_kstat, *rfsreqcnt_v3_kstat, *rfsreqcnt_v4_kstat;
79 static kstat_t *aclproccnt_v2_kstat, *aclproccnt_v3_kstat;
80 static kstat_t *aclreqcnt_v2_kstat, *aclreqcnt_v3_kstat;
81 static kstat_t *ksum_kstat;
83 static void handle_sig(int);
84 static int getstats_rpc(void);
85 static int getstats_nfs(void);
86 static int getstats_rfsproc(int);
87 static int getstats_rfsreq(int);
88 static int getstats_aclproc(void);
89 static int getstats_aclreq(void);
90 static void putstats(void);
91 static void setup(void);
92 static void cr_print(int);
93 static void sr_print(int);
94 static void cn_print(int, int);
95 static void sn_print(int, int);
96 static void ca_print(int, int);
97 static void sa_print(int, int);
98 static void req_print(kstat_t *, kstat_t *, int, int, int);
99 static void req_print_v4(kstat_t *, kstat_t *, int, int);
100 static void stat_print(const char *, kstat_t *, kstat_t *, int, int);
101 static void nfsstat_kstat_sum(kstat_t *, kstat_t *, kstat_t *);
102 static void stats_timer(int);
103 static void safe_zalloc(void **, uint_t, int);
104 static int safe_strtoi(char const *, char *);
107 static void nfsstat_kstat_copy(kstat_t *, kstat_t *, int);
108 static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
109 static kid_t safe_kstat_write(kstat_ctl_t *, kstat_t *, void *);
111 static void usage(void);
112 static void mi_print(void);
113 static int ignore(char *);
114 static int interval; /* interval between stats */
115 static int count; /* number of iterations the stat is printed */
116 #define MAX_COLUMNS 80
117 #define MAX_PATHS 50 /* max paths that can be taken by -m */
120 * MI4_MIRRORMOUNT is canonically defined in nfs4_clnt.h, but we cannot
121 * include that file here. Same with MI4_REFERRAL.
123 #define MI4_MIRRORMOUNT 0x4000
124 #define MI4_REFERRAL 0x8000
125 #define NFS_V4 4
127 static int req_width(kstat_t *, int);
128 static int stat_width(kstat_t *, int);
129 static char *path [MAX_PATHS] = {NULL}; /* array to store the multiple paths */
132 * Struct holds the previous kstat values so
133 * we can compute deltas when using the -i flag
135 typedef struct old_kstat
137 kstat_t kst;
138 int tot;
139 } old_kstat_t;
141 static old_kstat_t old_rpc_clts_client_kstat, old_rpc_clts_server_kstat;
142 static old_kstat_t old_rpc_cots_client_kstat, old_rpc_cots_server_kstat;
143 static old_kstat_t old_rpc_rdma_client_kstat, old_rpc_rdma_server_kstat;
144 static old_kstat_t old_nfs_client_kstat, old_nfs_server_v2_kstat;
145 static old_kstat_t old_nfs_server_v3_kstat, old_ksum_kstat;
146 static old_kstat_t old_nfs4_client_kstat, old_nfs_server_v4_kstat;
147 static old_kstat_t old_rfsproccnt_v2_kstat, old_rfsproccnt_v3_kstat;
148 static old_kstat_t old_rfsproccnt_v4_kstat, old_rfsreqcnt_v2_kstat;
149 static old_kstat_t old_rfsreqcnt_v3_kstat, old_rfsreqcnt_v4_kstat;
150 static old_kstat_t old_aclproccnt_v2_kstat, old_aclproccnt_v3_kstat;
151 static old_kstat_t old_aclreqcnt_v2_kstat, old_aclreqcnt_v3_kstat;
153 static uint_t timestamp_fmt = NODATE;
155 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
156 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't */
157 #endif
160 main(int argc, char *argv[])
162 int c, go_forever, j;
163 int cflag = 0; /* client stats */
164 int sflag = 0; /* server stats */
165 int nflag = 0; /* nfs stats */
166 int rflag = 0; /* rpc stats */
167 int mflag = 0; /* mount table stats */
168 int aflag = 0; /* print acl statistics */
169 int vflag = 0; /* version specified, 0 specifies all */
170 int zflag = 0; /* zero stats after printing */
171 char *split_line = "*******************************************"
172 "*************************************";
174 interval = 0;
175 count = 0;
176 go_forever = 0;
178 (void) setlocale(LC_ALL, "");
179 (void) textdomain(TEXT_DOMAIN);
181 while ((c = getopt(argc, argv, "cnrsmzav:T:")) != EOF) {
182 switch (c) {
183 case 'c':
184 cflag++;
185 break;
186 case 'n':
187 nflag++;
188 break;
189 case 'r':
190 rflag++;
191 break;
192 case 's':
193 sflag++;
194 break;
195 case 'm':
196 mflag++;
197 break;
198 case 'z':
199 if (geteuid())
200 fail(0, "Must be root for z flag\n");
201 zflag++;
202 break;
203 case 'a':
204 aflag++;
205 break;
206 case 'v':
207 vflag = atoi(optarg);
208 if ((vflag < 2) || (vflag > 4))
209 fail(0, "Invalid version number\n");
210 break;
211 case 'T':
212 if (optarg) {
213 if (*optarg == 'u')
214 timestamp_fmt = UDATE;
215 else if (*optarg == 'd')
216 timestamp_fmt = DDATE;
217 else
218 usage();
219 } else {
220 usage();
222 break;
223 case '?':
224 default:
225 usage();
229 if (((argc - optind) > 0) && !mflag) {
231 interval = safe_strtoi(argv[optind], "invalid interval");
232 if (interval < 1)
233 fail(0, "invalid interval\n");
234 optind++;
236 if ((argc - optind) > 0) {
237 count = safe_strtoi(argv[optind], "invalid count");
238 if ((count <= 0) || (count == NULL))
239 fail(0, "invalid count\n");
241 optind++;
243 if ((argc - optind) > 0)
244 usage();
247 * no count number was set, so we will loop infinitely
248 * at interval specified
250 if (!count)
251 go_forever = 1;
252 stats_timer(interval);
253 } else if (mflag) {
255 if (cflag || rflag || sflag || zflag || nflag || aflag || vflag)
256 fail(0,
257 "The -m flag may not be used with any other flags");
259 for (j = 0; (argc - optind > 0) && (j < (MAX_PATHS - 1)); j++) {
260 path[j] = argv[optind];
261 if (*path[j] != '/')
262 fail(0, "Please fully qualify your pathname "
263 "with a leading '/'");
264 optind++;
266 path[j] = NULL;
267 if (argc - optind > 0)
268 fprintf(stderr, "Only the first 50 paths "
269 "will be searched for\n");
272 setup();
274 do {
275 if (mflag) {
276 mi_print();
277 } else {
278 if (timestamp_fmt != NODATE)
279 print_timestamp(timestamp_fmt);
281 if (sflag &&
282 (rpc_clts_server_kstat == NULL ||
283 nfs_server_v4_kstat == NULL)) {
284 fprintf(stderr,
285 "nfsstat: kernel is not configured with "
286 "the server nfs and rpc code.\n");
289 /* if s and nothing else, all 3 prints are called */
290 if (sflag || (!sflag && !cflag)) {
291 if (rflag || (!rflag && !nflag && !aflag))
292 sr_print(zflag);
293 if (nflag || (!rflag && !nflag && !aflag))
294 sn_print(zflag, vflag);
295 if (aflag || (!rflag && !nflag && !aflag))
296 sa_print(zflag, vflag);
298 if (cflag &&
299 (rpc_clts_client_kstat == NULL ||
300 nfs_client_kstat == NULL)) {
301 fprintf(stderr,
302 "nfsstat: kernel is not configured with"
303 " the client nfs and rpc code.\n");
305 if (cflag || (!sflag && !cflag)) {
306 if (rflag || (!rflag && !nflag && !aflag))
307 cr_print(zflag);
308 if (nflag || (!rflag && !nflag && !aflag))
309 cn_print(zflag, vflag);
310 if (aflag || (!rflag && !nflag && !aflag))
311 ca_print(zflag, vflag);
315 if (zflag)
316 putstats();
317 if (interval)
318 printf("%s\n", split_line);
320 if (interval > 0)
321 (void) pause();
322 } while ((--count > 0) || go_forever);
324 kstat_close(kc);
325 free(ksum_kstat);
326 return (0);
330 static int
331 getstats_rpc(void)
333 int field_width = 0;
335 if (rpc_clts_client_kstat != NULL) {
336 safe_kstat_read(kc, rpc_clts_client_kstat, NULL);
337 field_width = stat_width(rpc_clts_client_kstat, field_width);
340 if (rpc_cots_client_kstat != NULL) {
341 safe_kstat_read(kc, rpc_cots_client_kstat, NULL);
342 field_width = stat_width(rpc_cots_client_kstat, field_width);
345 if (rpc_rdma_client_kstat != NULL) {
346 safe_kstat_read(kc, rpc_rdma_client_kstat, NULL);
347 field_width = stat_width(rpc_rdma_client_kstat, field_width);
350 if (rpc_clts_server_kstat != NULL) {
351 safe_kstat_read(kc, rpc_clts_server_kstat, NULL);
352 field_width = stat_width(rpc_clts_server_kstat, field_width);
354 if (rpc_cots_server_kstat != NULL) {
355 safe_kstat_read(kc, rpc_cots_server_kstat, NULL);
356 field_width = stat_width(rpc_cots_server_kstat, field_width);
358 if (rpc_rdma_server_kstat != NULL) {
359 safe_kstat_read(kc, rpc_rdma_server_kstat, NULL);
360 field_width = stat_width(rpc_rdma_server_kstat, field_width);
362 return (field_width);
365 static int
366 getstats_nfs(void)
368 int field_width = 0;
370 if (nfs_client_kstat != NULL) {
371 safe_kstat_read(kc, nfs_client_kstat, NULL);
372 field_width = stat_width(nfs_client_kstat, field_width);
374 if (nfs4_client_kstat != NULL) {
375 safe_kstat_read(kc, nfs4_client_kstat, NULL);
376 field_width = stat_width(nfs4_client_kstat, field_width);
378 if (nfs_server_v2_kstat != NULL) {
379 safe_kstat_read(kc, nfs_server_v2_kstat, NULL);
380 field_width = stat_width(nfs_server_v2_kstat, field_width);
382 if (nfs_server_v3_kstat != NULL) {
383 safe_kstat_read(kc, nfs_server_v3_kstat, NULL);
384 field_width = stat_width(nfs_server_v3_kstat, field_width);
386 if (nfs_server_v4_kstat != NULL) {
387 safe_kstat_read(kc, nfs_server_v4_kstat, NULL);
388 field_width = stat_width(nfs_server_v4_kstat, field_width);
390 return (field_width);
393 static int
394 getstats_rfsproc(int ver)
396 int field_width = 0;
398 if ((ver == 2) && (rfsproccnt_v2_kstat != NULL)) {
399 safe_kstat_read(kc, rfsproccnt_v2_kstat, NULL);
400 field_width = req_width(rfsproccnt_v2_kstat, field_width);
402 if ((ver == 3) && (rfsproccnt_v3_kstat != NULL)) {
403 safe_kstat_read(kc, rfsproccnt_v3_kstat, NULL);
404 field_width = req_width(rfsproccnt_v3_kstat, field_width);
406 if ((ver == 4) && (rfsproccnt_v4_kstat != NULL)) {
407 safe_kstat_read(kc, rfsproccnt_v4_kstat, NULL);
408 field_width = req_width(rfsproccnt_v4_kstat, field_width);
410 return (field_width);
413 static int
414 getstats_rfsreq(int ver)
416 int field_width = 0;
417 if ((ver == 2) && (rfsreqcnt_v2_kstat != NULL)) {
418 safe_kstat_read(kc, rfsreqcnt_v2_kstat, NULL);
419 field_width = req_width(rfsreqcnt_v2_kstat, field_width);
421 if ((ver == 3) && (rfsreqcnt_v3_kstat != NULL)) {
422 safe_kstat_read(kc, rfsreqcnt_v3_kstat, NULL);
423 field_width = req_width(rfsreqcnt_v3_kstat, field_width);
425 if ((ver == 4) && (rfsreqcnt_v4_kstat != NULL)) {
426 safe_kstat_read(kc, rfsreqcnt_v4_kstat, NULL);
427 field_width = req_width(rfsreqcnt_v4_kstat, field_width);
429 return (field_width);
432 static int
433 getstats_aclproc(void)
435 int field_width = 0;
436 if (aclproccnt_v2_kstat != NULL) {
437 safe_kstat_read(kc, aclproccnt_v2_kstat, NULL);
438 field_width = req_width(aclproccnt_v2_kstat, field_width);
440 if (aclproccnt_v3_kstat != NULL) {
441 safe_kstat_read(kc, aclproccnt_v3_kstat, NULL);
442 field_width = req_width(aclproccnt_v3_kstat, field_width);
444 return (field_width);
447 static int
448 getstats_aclreq(void)
450 int field_width = 0;
451 if (aclreqcnt_v2_kstat != NULL) {
452 safe_kstat_read(kc, aclreqcnt_v2_kstat, NULL);
453 field_width = req_width(aclreqcnt_v2_kstat, field_width);
455 if (aclreqcnt_v3_kstat != NULL) {
456 safe_kstat_read(kc, aclreqcnt_v3_kstat, NULL);
457 field_width = req_width(aclreqcnt_v3_kstat, field_width);
459 return (field_width);
462 static void
463 putstats(void)
465 if (rpc_clts_client_kstat != NULL)
466 safe_kstat_write(kc, rpc_clts_client_kstat, NULL);
467 if (rpc_cots_client_kstat != NULL)
468 safe_kstat_write(kc, rpc_cots_client_kstat, NULL);
469 if (rpc_rdma_client_kstat != NULL)
470 safe_kstat_write(kc, rpc_rdma_client_kstat, NULL);
471 if (nfs_client_kstat != NULL)
472 safe_kstat_write(kc, nfs_client_kstat, NULL);
473 if (nfs4_client_kstat != NULL)
474 safe_kstat_write(kc, nfs4_client_kstat, NULL);
475 if (rpc_clts_server_kstat != NULL)
476 safe_kstat_write(kc, rpc_clts_server_kstat, NULL);
477 if (rpc_cots_server_kstat != NULL)
478 safe_kstat_write(kc, rpc_cots_server_kstat, NULL);
479 if (rpc_rdma_server_kstat != NULL)
480 safe_kstat_write(kc, rpc_rdma_server_kstat, NULL);
481 if (nfs_server_v2_kstat != NULL)
482 safe_kstat_write(kc, nfs_server_v2_kstat, NULL);
483 if (nfs_server_v3_kstat != NULL)
484 safe_kstat_write(kc, nfs_server_v3_kstat, NULL);
485 if (nfs_server_v4_kstat != NULL)
486 safe_kstat_write(kc, nfs_server_v4_kstat, NULL);
487 if (rfsproccnt_v2_kstat != NULL)
488 safe_kstat_write(kc, rfsproccnt_v2_kstat, NULL);
489 if (rfsproccnt_v3_kstat != NULL)
490 safe_kstat_write(kc, rfsproccnt_v3_kstat, NULL);
491 if (rfsproccnt_v4_kstat != NULL)
492 safe_kstat_write(kc, rfsproccnt_v4_kstat, NULL);
493 if (rfsreqcnt_v2_kstat != NULL)
494 safe_kstat_write(kc, rfsreqcnt_v2_kstat, NULL);
495 if (rfsreqcnt_v3_kstat != NULL)
496 safe_kstat_write(kc, rfsreqcnt_v3_kstat, NULL);
497 if (rfsreqcnt_v4_kstat != NULL)
498 safe_kstat_write(kc, rfsreqcnt_v4_kstat, NULL);
499 if (aclproccnt_v2_kstat != NULL)
500 safe_kstat_write(kc, aclproccnt_v2_kstat, NULL);
501 if (aclproccnt_v3_kstat != NULL)
502 safe_kstat_write(kc, aclproccnt_v3_kstat, NULL);
503 if (aclreqcnt_v2_kstat != NULL)
504 safe_kstat_write(kc, aclreqcnt_v2_kstat, NULL);
505 if (aclreqcnt_v3_kstat != NULL)
506 safe_kstat_write(kc, aclreqcnt_v3_kstat, NULL);
509 static void
510 setup(void)
512 if ((kc = kstat_open()) == NULL)
513 fail(1, "kstat_open(): can't open /dev/kstat");
515 /* alloc space for our temporary kstat */
516 safe_zalloc((void **)&ksum_kstat, sizeof (kstat_t), 0);
517 rpc_clts_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_client");
518 rpc_clts_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_server");
519 rpc_cots_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_client");
520 rpc_cots_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_server");
521 rpc_rdma_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_client");
522 rpc_rdma_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_server");
523 nfs_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs_client");
524 nfs4_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs4_client");
525 nfs_server_v2_kstat = kstat_lookup(kc, "nfs", 2, "nfs_server");
526 nfs_server_v3_kstat = kstat_lookup(kc, "nfs", 3, "nfs_server");
527 nfs_server_v4_kstat = kstat_lookup(kc, "nfs", 4, "nfs_server");
528 rfsproccnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v2");
529 rfsproccnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v3");
530 rfsproccnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v4");
531 rfsreqcnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v2");
532 rfsreqcnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v3");
533 rfsreqcnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v4");
534 aclproccnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v2");
535 aclproccnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v3");
536 aclreqcnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v2");
537 aclreqcnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v3");
538 if (rpc_clts_client_kstat == NULL && rpc_cots_server_kstat == NULL &&
539 rfsproccnt_v2_kstat == NULL && rfsreqcnt_v3_kstat == NULL)
540 fail(0, "Multiple kstat lookups failed."
541 "Your kernel module may not be loaded\n");
544 static int
545 req_width(kstat_t *req, int field_width)
547 int i, nreq, per, len;
548 char fixlen[128];
549 kstat_named_t *knp;
550 uint64_t tot;
552 tot = 0;
553 knp = KSTAT_NAMED_PTR(req);
554 for (i = 0; i < req->ks_ndata; i++)
555 tot += knp[i].value.ui64;
557 knp = kstat_data_lookup(req, "null");
558 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req));
560 for (i = 0; i < nreq; i++) {
561 len = strlen(knp[i].name) + 1;
562 if (field_width < len)
563 field_width = len;
564 if (tot)
565 per = (int)(knp[i].value.ui64 * 100 / tot);
566 else
567 per = 0;
568 (void) sprintf(fixlen, "%" PRIu64 " %d%%",
569 knp[i].value.ui64, per);
570 len = strlen(fixlen) + 1;
571 if (field_width < len)
572 field_width = len;
574 return (field_width);
577 static int
578 stat_width(kstat_t *req, int field_width)
580 int i, nreq, len;
581 char fixlen[128];
582 kstat_named_t *knp;
584 knp = KSTAT_NAMED_PTR(req);
585 nreq = req->ks_ndata;
587 for (i = 0; i < nreq; i++) {
588 len = strlen(knp[i].name) + 1;
589 if (field_width < len)
590 field_width = len;
591 (void) sprintf(fixlen, "%" PRIu64, knp[i].value.ui64);
592 len = strlen(fixlen) + 1;
593 if (field_width < len)
594 field_width = len;
596 return (field_width);
599 static void
600 cr_print(int zflag)
602 int field_width;
604 field_width = getstats_rpc();
605 if (field_width == 0)
606 return;
608 stat_print("\nClient rpc:\nConnection oriented:",
609 rpc_cots_client_kstat,
610 &old_rpc_cots_client_kstat.kst, field_width, zflag);
611 stat_print("Connectionless:", rpc_clts_client_kstat,
612 &old_rpc_clts_client_kstat.kst, field_width, zflag);
613 stat_print("RDMA based:", rpc_rdma_client_kstat,
614 &old_rpc_rdma_client_kstat.kst, field_width, zflag);
617 static void
618 sr_print(int zflag)
620 int field_width;
622 field_width = getstats_rpc();
623 if (field_width == 0)
624 return;
626 stat_print("\nServer rpc:\nConnection oriented:", rpc_cots_server_kstat,
627 &old_rpc_cots_server_kstat.kst, field_width, zflag);
628 stat_print("Connectionless:", rpc_clts_server_kstat,
629 &old_rpc_clts_server_kstat.kst, field_width, zflag);
630 stat_print("RDMA based:", rpc_rdma_server_kstat,
631 &old_rpc_rdma_server_kstat.kst, field_width, zflag);
634 static void
635 cn_print(int zflag, int vflag)
637 int field_width;
639 field_width = getstats_nfs();
640 if (field_width == 0)
641 return;
643 if (vflag == 0) {
644 nfsstat_kstat_sum(nfs_client_kstat, nfs4_client_kstat,
645 ksum_kstat);
646 stat_print("\nClient nfs:", ksum_kstat, &old_ksum_kstat.kst,
647 field_width, zflag);
650 if (vflag == 2 || vflag == 3) {
651 stat_print("\nClient nfs:", nfs_client_kstat,
652 &old_nfs_client_kstat.kst, field_width, zflag);
655 if (vflag == 4) {
656 stat_print("\nClient nfs:", nfs4_client_kstat,
657 &old_nfs4_client_kstat.kst, field_width, zflag);
660 if (vflag == 2 || vflag == 0) {
661 field_width = getstats_rfsreq(2);
662 req_print(rfsreqcnt_v2_kstat, &old_rfsreqcnt_v2_kstat.kst,
663 2, field_width, zflag);
666 if (vflag == 3 || vflag == 0) {
667 field_width = getstats_rfsreq(3);
668 req_print(rfsreqcnt_v3_kstat, &old_rfsreqcnt_v3_kstat.kst, 3,
669 field_width, zflag);
672 if (vflag == 4 || vflag == 0) {
673 field_width = getstats_rfsreq(4);
674 req_print_v4(rfsreqcnt_v4_kstat, &old_rfsreqcnt_v4_kstat.kst,
675 field_width, zflag);
679 static void
680 sn_print(int zflag, int vflag)
682 int field_width;
684 field_width = getstats_nfs();
685 if (field_width == 0)
686 return;
688 if (vflag == 2 || vflag == 0) {
689 stat_print("\nServer NFSv2:", nfs_server_v2_kstat,
690 &old_nfs_server_v2_kstat.kst, field_width, zflag);
693 if (vflag == 3 || vflag == 0) {
694 stat_print("\nServer NFSv3:", nfs_server_v3_kstat,
695 &old_nfs_server_v3_kstat.kst, field_width, zflag);
698 if (vflag == 4 || vflag == 0) {
699 stat_print("\nServer NFSv4:", nfs_server_v4_kstat,
700 &old_nfs_server_v4_kstat.kst, field_width, zflag);
703 if (vflag == 2 || vflag == 0) {
704 field_width = getstats_rfsproc(2);
705 req_print(rfsproccnt_v2_kstat, &old_rfsproccnt_v2_kstat.kst,
706 2, field_width, zflag);
709 if (vflag == 3 || vflag == 0) {
710 field_width = getstats_rfsproc(3);
711 req_print(rfsproccnt_v3_kstat, &old_rfsproccnt_v3_kstat.kst,
712 3, field_width, zflag);
715 if (vflag == 4 || vflag == 0) {
716 field_width = getstats_rfsproc(4);
717 req_print_v4(rfsproccnt_v4_kstat, &old_rfsproccnt_v4_kstat.kst,
718 field_width, zflag);
722 static void
723 ca_print(int zflag, int vflag)
725 int field_width;
727 field_width = getstats_aclreq();
728 if (field_width == 0)
729 return;
731 printf("\nClient nfs_acl:\n");
733 if (vflag == 2 || vflag == 0) {
734 req_print(aclreqcnt_v2_kstat, &old_aclreqcnt_v2_kstat.kst, 2,
735 field_width, zflag);
738 if (vflag == 3 || vflag == 0) {
739 req_print(aclreqcnt_v3_kstat, &old_aclreqcnt_v3_kstat.kst,
740 3, field_width, zflag);
744 static void
745 sa_print(int zflag, int vflag)
747 int field_width;
749 field_width = getstats_aclproc();
750 if (field_width == 0)
751 return;
753 printf("\nServer nfs_acl:\n");
755 if (vflag == 2 || vflag == 0) {
756 req_print(aclproccnt_v2_kstat, &old_aclproccnt_v2_kstat.kst,
757 2, field_width, zflag);
760 if (vflag == 3 || vflag == 0) {
761 req_print(aclproccnt_v3_kstat, &old_aclproccnt_v3_kstat.kst,
762 3, field_width, zflag);
766 #define MIN(a, b) ((a) < (b) ? (a) : (b))
768 static void
769 req_print(kstat_t *req, kstat_t *req_old, int ver, int field_width,
770 int zflag)
772 int i, j, nreq, per, ncolumns;
773 uint64_t tot, old_tot;
774 char fixlen[128];
775 kstat_named_t *knp;
776 kstat_named_t *kptr;
777 kstat_named_t *knp_old;
779 if (req == NULL)
780 return;
782 if (field_width == 0)
783 return;
785 ncolumns = (MAX_COLUMNS -1)/field_width;
786 knp = kstat_data_lookup(req, "null");
787 knp_old = KSTAT_NAMED_PTR(req_old);
789 kptr = KSTAT_NAMED_PTR(req);
790 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req));
792 tot = 0;
793 old_tot = 0;
795 if (knp_old == NULL) {
796 old_tot = 0;
799 for (i = 0; i < req->ks_ndata; i++)
800 tot += kptr[i].value.ui64;
802 if (interval && knp_old != NULL) {
803 for (i = 0; i < req_old->ks_ndata; i++)
804 old_tot += knp_old[i].value.ui64;
805 tot -= old_tot;
808 printf("Version %d: (%" PRIu64 " calls)\n", ver, tot);
810 for (i = 0; i < nreq; i += ncolumns) {
811 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
812 printf("%-*s", field_width, knp[j].name);
814 printf("\n");
815 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
816 if (tot && interval && knp_old != NULL)
817 per = (int)((knp[j].value.ui64 -
818 knp_old[j].value.ui64) * 100 / tot);
819 else if (tot)
820 per = (int)(knp[j].value.ui64 * 100 / tot);
821 else
822 per = 0;
823 (void) sprintf(fixlen, "%" PRIu64 " %d%% ",
824 ((interval && knp_old != NULL) ?
825 (knp[j].value.ui64 - knp_old[j].value.ui64)
826 : knp[j].value.ui64), per);
827 printf("%-*s", field_width, fixlen);
829 printf("\n");
831 if (zflag) {
832 for (i = 0; i < req->ks_ndata; i++)
833 knp[i].value.ui64 = 0;
835 if (knp_old != NULL)
836 nfsstat_kstat_copy(req, req_old, 1);
837 else
838 nfsstat_kstat_copy(req, req_old, 0);
842 * Separate version of the req_print() to deal with V4 and its use of
843 * procedures and operations. It looks odd to have the counts for
844 * both of those lumped into the same set of statistics so this
845 * function (copy of req_print() does the separation and titles).
848 #define COUNT 2
850 static void
851 req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag)
853 int i, j, nreq, per, ncolumns;
854 uint64_t tot, tot_ops, old_tot, old_tot_ops;
855 char fixlen[128];
856 kstat_named_t *kptr;
857 kstat_named_t *knp;
858 kstat_named_t *kptr_old;
860 if (req == NULL)
861 return;
863 if (field_width == 0)
864 return;
866 ncolumns = (MAX_COLUMNS)/field_width;
867 kptr = KSTAT_NAMED_PTR(req);
868 kptr_old = KSTAT_NAMED_PTR(req_old);
870 if (kptr_old == NULL) {
871 old_tot_ops = 0;
872 old_tot = 0;
873 } else {
874 old_tot = kptr_old[0].value.ui64 + kptr_old[1].value.ui64;
875 for (i = 2, old_tot_ops = 0; i < req_old->ks_ndata; i++)
876 old_tot_ops += kptr_old[i].value.ui64;
879 /* Count the number of operations sent */
880 for (i = 2, tot_ops = 0; i < req->ks_ndata; i++)
881 tot_ops += kptr[i].value.ui64;
882 /* For v4 NULL/COMPOUND are the only procedures */
883 tot = kptr[0].value.ui64 + kptr[1].value.ui64;
885 if (interval) {
886 tot -= old_tot;
887 tot_ops -= old_tot_ops;
890 printf("Version 4: (%" PRIu64 " calls)\n", tot);
892 knp = kstat_data_lookup(req, "null");
893 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req));
895 for (i = 0; i < COUNT; i += ncolumns) {
896 for (j = i; j < MIN(i + ncolumns, 2); j++) {
897 printf("%-*s", field_width, knp[j].name);
899 printf("\n");
900 for (j = i; j < MIN(i + ncolumns, 2); j++) {
901 if (tot && interval && kptr_old != NULL)
902 per = (int)((knp[j].value.ui64 -
903 kptr_old[j].value.ui64) * 100 / tot);
904 else if (tot)
905 per = (int)(knp[j].value.ui64 * 100 / tot);
906 else
907 per = 0;
908 (void) sprintf(fixlen, "%" PRIu64 " %d%% ",
909 ((interval && kptr_old != NULL) ?
910 (knp[j].value.ui64 - kptr_old[j].value.ui64)
911 : knp[j].value.ui64), per);
912 printf("%-*s", field_width, fixlen);
914 printf("\n");
917 printf("Version 4: (%" PRIu64 " operations)\n", tot_ops);
918 for (i = 2; i < nreq; i += ncolumns) {
919 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
920 printf("%-*s", field_width, knp[j].name);
922 printf("\n");
923 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
924 if (tot_ops && interval && kptr_old != NULL)
925 per = (int)((knp[j].value.ui64 -
926 kptr_old[j].value.ui64) * 100 / tot_ops);
927 else if (tot_ops)
928 per = (int)(knp[j].value.ui64 * 100 / tot_ops);
929 else
930 per = 0;
931 (void) sprintf(fixlen, "%" PRIu64 " %d%% ",
932 ((interval && kptr_old != NULL) ?
933 (knp[j].value.ui64 - kptr_old[j].value.ui64)
934 : knp[j].value.ui64), per);
935 printf("%-*s", field_width, fixlen);
937 printf("\n");
939 if (zflag) {
940 for (i = 0; i < req->ks_ndata; i++)
941 kptr[i].value.ui64 = 0;
943 if (kptr_old != NULL)
944 nfsstat_kstat_copy(req, req_old, 1);
945 else
946 nfsstat_kstat_copy(req, req_old, 0);
949 static void
950 stat_print(const char *title_string, kstat_t *req, kstat_t *req_old,
951 int field_width, int zflag)
953 int i, j, nreq, ncolumns;
954 char fixlen[128];
955 kstat_named_t *knp;
956 kstat_named_t *knp_old;
958 if (req == NULL)
959 return;
961 if (field_width == 0)
962 return;
964 printf("%s\n", title_string);
965 ncolumns = (MAX_COLUMNS -1)/field_width;
967 /* MEANS knp = (kstat_named_t *)req->ks_data */
968 knp = KSTAT_NAMED_PTR(req);
969 nreq = req->ks_ndata;
970 knp_old = KSTAT_NAMED_PTR(req_old);
972 for (i = 0; i < nreq; i += ncolumns) {
973 /* prints out the titles of the columns */
974 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
975 printf("%-*s", field_width, knp[j].name);
977 printf("\n");
978 /* prints out the stat numbers */
979 for (j = i; j < MIN(i + ncolumns, nreq); j++) {
980 (void) sprintf(fixlen, "%" PRIu64 " ",
981 (interval && knp_old != NULL) ?
982 (knp[j].value.ui64 - knp_old[j].value.ui64)
983 : knp[j].value.ui64);
984 printf("%-*s", field_width, fixlen);
986 printf("\n");
989 if (zflag) {
990 for (i = 0; i < req->ks_ndata; i++)
991 knp[i].value.ui64 = 0;
994 if (knp_old != NULL)
995 nfsstat_kstat_copy(req, req_old, 1);
996 else
997 nfsstat_kstat_copy(req, req_old, 0);
1000 static void
1001 nfsstat_kstat_sum(kstat_t *kstat1, kstat_t *kstat2, kstat_t *sum)
1003 int i;
1004 kstat_named_t *knp1, *knp2, *knpsum;
1005 if (kstat1 == NULL || kstat2 == NULL)
1006 return;
1008 knp1 = KSTAT_NAMED_PTR(kstat1);
1009 knp2 = KSTAT_NAMED_PTR(kstat2);
1010 if (sum->ks_data == NULL)
1011 nfsstat_kstat_copy(kstat1, sum, 0);
1012 knpsum = KSTAT_NAMED_PTR(sum);
1014 for (i = 0; i < (kstat1->ks_ndata); i++)
1015 knpsum[i].value.ui64 = knp1[i].value.ui64 + knp2[i].value.ui64;
1019 * my_dir and my_path could be pointers
1021 struct myrec {
1022 ulong_t my_fsid;
1023 char my_dir[MAXPATHLEN];
1024 char *my_path;
1025 char *ig_path;
1026 struct myrec *next;
1030 * Print the mount table info
1032 static void
1033 mi_print(void)
1035 FILE *mt;
1036 struct extmnttab m;
1037 struct myrec *list, *mrp, *pmrp;
1038 char *flavor;
1039 int ignored = 0;
1040 seconfig_t nfs_sec;
1041 kstat_t *ksp;
1042 struct mntinfo_kstat mik;
1043 int transport_flag = 0;
1044 int path_count;
1045 int found;
1046 char *timer_name[] = {
1047 "Lookups",
1048 "Reads",
1049 "Writes",
1050 "All"
1053 mt = fopen(MNTTAB, "r");
1054 if (mt == NULL) {
1055 perror(MNTTAB);
1056 exit(0);
1059 list = NULL;
1060 resetmnttab(mt);
1062 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) {
1063 /* ignore non "nfs" and save the "ignore" entries */
1064 if (strcmp(m.mnt_fstype, MNTTYPE_NFS) != 0)
1065 continue;
1067 * Check to see here if user gave a path(s) to
1068 * only show the mount point they wanted
1069 * Iterate through the list of paths the user gave and see
1070 * if any of them match our current nfs mount
1072 if (path[0] != NULL) {
1073 found = 0;
1074 for (path_count = 0; path[path_count] != NULL;
1075 path_count++) {
1076 if (strcmp(path[path_count], m.mnt_mountp)
1077 == 0) {
1078 found = 1;
1079 break;
1082 if (!found)
1083 continue;
1086 if ((mrp = malloc(sizeof (struct myrec))) == 0) {
1087 fprintf(stderr, "nfsstat: not enough memory\n");
1088 exit(1);
1090 mrp->my_fsid = makedev(m.mnt_major, m.mnt_minor);
1091 if (ignore(m.mnt_mntopts)) {
1093 * ignored entries cannot be ignored for this
1094 * option. We have to display the info for this
1095 * nfs mount. The ignore is an indication
1096 * that the actual mount point is different and
1097 * something is in between the nfs mount.
1098 * So save the mount point now
1100 if ((mrp->ig_path = malloc(
1101 strlen(m.mnt_mountp) + 1)) == 0) {
1102 fprintf(stderr, "nfsstat: not enough memory\n");
1103 exit(1);
1105 (void) strcpy(mrp->ig_path, m.mnt_mountp);
1106 ignored++;
1107 } else {
1108 mrp->ig_path = 0;
1109 (void) strcpy(mrp->my_dir, m.mnt_mountp);
1111 if ((mrp->my_path = strdup(m.mnt_special)) == NULL) {
1112 fprintf(stderr, "nfsstat: not enough memory\n");
1113 exit(1);
1115 mrp->next = list;
1116 list = mrp;
1119 (void) fclose(mt);
1121 if (ignored) {
1123 * Now ignored entries which do not have
1124 * the my_dir initialized are really ignored; This never
1125 * happens unless the mnttab is corrupted.
1127 for (pmrp = 0, mrp = list; mrp; mrp = mrp->next) {
1128 if (mrp->ig_path == 0)
1129 pmrp = mrp;
1130 else if (pmrp)
1131 pmrp->next = mrp->next;
1132 else
1133 list = mrp->next;
1137 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1138 int i;
1140 if (ksp->ks_type != KSTAT_TYPE_RAW)
1141 continue;
1142 if (strcmp(ksp->ks_module, "nfs") != 0)
1143 continue;
1144 if (strcmp(ksp->ks_name, "mntinfo") != 0)
1145 continue;
1147 for (mrp = list; mrp; mrp = mrp->next) {
1148 if ((mrp->my_fsid & MAXMIN) == ksp->ks_instance)
1149 break;
1151 if (mrp == 0)
1152 continue;
1154 if (safe_kstat_read(kc, ksp, &mik) == -1)
1155 continue;
1157 printf("%s from %s\n", mrp->my_dir, mrp->my_path);
1160 * for printing rdma transport and provider string.
1161 * This way we avoid modifying the kernel mntinfo_kstat
1162 * struct for protofmly.
1164 if (strcmp(mik.mik_proto, "ibtf") == 0) {
1165 printf(" Flags: vers=%u,proto=rdma",
1166 mik.mik_vers);
1167 transport_flag = 1;
1168 } else {
1169 printf(" Flags: vers=%u,proto=%s",
1170 mik.mik_vers, mik.mik_proto);
1171 transport_flag = 0;
1175 * get the secmode name from /etc/nfssec.conf.
1177 if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) {
1178 flavor = nfs_sec.sc_name;
1179 } else
1180 flavor = NULL;
1182 if (flavor != NULL)
1183 printf(",sec=%s", flavor);
1184 else
1185 printf(",sec#=%d", mik.mik_secmod);
1187 printf(",%s", (mik.mik_flags & MI_HARD) ? "hard" : "soft");
1188 if (mik.mik_flags & MI_PRINTED)
1189 printf(",printed");
1190 printf(",%s", (mik.mik_flags & MI_INT) ? "intr" : "nointr");
1191 if (mik.mik_flags & MI_DOWN)
1192 printf(",down");
1193 if (mik.mik_flags & MI_NOAC)
1194 printf(",noac");
1195 if (mik.mik_flags & MI_NOCTO)
1196 printf(",nocto");
1197 if (mik.mik_flags & MI_DYNAMIC)
1198 printf(",dynamic");
1199 if (mik.mik_flags & MI_LLOCK)
1200 printf(",llock");
1201 if (mik.mik_flags & MI_GRPID)
1202 printf(",grpid");
1203 if (mik.mik_flags & MI_RPCTIMESYNC)
1204 printf(",rpctimesync");
1205 if (mik.mik_flags & MI_LINK)
1206 printf(",link");
1207 if (mik.mik_flags & MI_SYMLINK)
1208 printf(",symlink");
1209 if (mik.mik_vers < NFS_V4 && mik.mik_flags & MI_READDIRONLY)
1210 printf(",readdironly");
1211 if (mik.mik_flags & MI_ACL)
1212 printf(",acl");
1213 if (mik.mik_flags & MI_DIRECTIO)
1214 printf(",forcedirectio");
1216 if (mik.mik_vers >= NFS_V4) {
1217 if (mik.mik_flags & MI4_MIRRORMOUNT)
1218 printf(",mirrormount");
1219 if (mik.mik_flags & MI4_REFERRAL)
1220 printf(",referral");
1223 printf(",rsize=%d,wsize=%d,retrans=%d,timeo=%d",
1224 mik.mik_curread, mik.mik_curwrite, mik.mik_retrans,
1225 mik.mik_timeo);
1226 printf("\n");
1227 printf(" Attr cache: acregmin=%d,acregmax=%d"
1228 ",acdirmin=%d,acdirmax=%d\n", mik.mik_acregmin,
1229 mik.mik_acregmax, mik.mik_acdirmin, mik.mik_acdirmax);
1231 if (transport_flag) {
1232 printf(" Transport: proto=rdma, plugin=%s\n",
1233 mik.mik_proto);
1236 #define srtt_to_ms(x) x, (x * 2 + x / 2)
1237 #define dev_to_ms(x) x, (x * 5)
1239 for (i = 0; i < NFS_CALLTYPES + 1; i++) {
1240 int j;
1242 j = (i == NFS_CALLTYPES ? i - 1 : i);
1243 if (mik.mik_timers[j].srtt ||
1244 mik.mik_timers[j].rtxcur) {
1245 printf(" %s: srtt=%d (%dms), "
1246 "dev=%d (%dms), cur=%u (%ums)\n",
1247 timer_name[i],
1248 srtt_to_ms(mik.mik_timers[i].srtt),
1249 dev_to_ms(mik.mik_timers[i].deviate),
1250 mik.mik_timers[i].rtxcur,
1251 mik.mik_timers[i].rtxcur * 20);
1255 if (strchr(mrp->my_path, ','))
1256 printf(
1257 " Failover: noresponse=%d,failover=%d,"
1258 "remap=%d,currserver=%s\n",
1259 mik.mik_noresponse, mik.mik_failover,
1260 mik.mik_remap, mik.mik_curserver);
1261 printf("\n");
1265 static char *mntopts[] = { MNTOPT_IGNORE, MNTOPT_DEV, NULL };
1266 #define IGNORE 0
1267 #define DEV 1
1270 * Return 1 if "ignore" appears in the options string
1272 static int
1273 ignore(char *opts)
1275 char *value;
1276 char *s;
1278 if (opts == NULL)
1279 return (0);
1280 s = strdup(opts);
1281 if (s == NULL)
1282 return (0);
1283 opts = s;
1285 while (*opts != '\0') {
1286 if (getsubopt(&opts, mntopts, &value) == IGNORE) {
1287 free(s);
1288 return (1);
1292 free(s);
1293 return (0);
1296 void
1297 usage(void)
1299 fprintf(stderr, "Usage: nfsstat [-cnrsza [-v version] "
1300 "[-T d|u] [interval [count]]\n");
1301 fprintf(stderr, "Usage: nfsstat -m [pathname..]\n");
1302 exit(1);
1305 void
1306 fail(int do_perror, char *message, ...)
1308 va_list args;
1310 va_start(args, message);
1311 fprintf(stderr, "nfsstat: ");
1312 vfprintf(stderr, message, args);
1313 va_end(args);
1314 if (do_perror)
1315 fprintf(stderr, ": %s", strerror(errno));
1316 fprintf(stderr, "\n");
1317 exit(1);
1320 kid_t
1321 safe_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data)
1323 kid_t kstat_chain_id = kstat_read(kc, ksp, data);
1325 if (kstat_chain_id == -1)
1326 fail(1, "kstat_read(%x, '%s') failed", kc, ksp->ks_name);
1327 return (kstat_chain_id);
1330 kid_t
1331 safe_kstat_write(kstat_ctl_t *kc, kstat_t *ksp, void *data)
1333 kid_t kstat_chain_id = 0;
1335 if (ksp->ks_data != NULL) {
1336 kstat_chain_id = kstat_write(kc, ksp, data);
1338 if (kstat_chain_id == -1)
1339 fail(1, "kstat_write(%x, '%s') failed", kc,
1340 ksp->ks_name);
1342 return (kstat_chain_id);
1345 void
1346 stats_timer(int interval)
1348 timer_t t_id;
1349 itimerspec_t time_struct;
1350 struct sigevent sig_struct;
1351 struct sigaction act;
1353 bzero(&sig_struct, sizeof (struct sigevent));
1354 bzero(&act, sizeof (struct sigaction));
1356 /* Create timer */
1357 sig_struct.sigev_notify = SIGEV_SIGNAL;
1358 sig_struct.sigev_signo = SIGUSR1;
1359 sig_struct.sigev_value.sival_int = 0;
1361 if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) {
1362 fail(1, "Timer creation failed");
1365 act.sa_handler = handle_sig;
1367 if (sigaction(SIGUSR1, &act, NULL) != 0) {
1368 fail(1, "Could not set up signal handler");
1371 time_struct.it_value.tv_sec = interval;
1372 time_struct.it_value.tv_nsec = 0;
1373 time_struct.it_interval.tv_sec = interval;
1374 time_struct.it_interval.tv_nsec = 0;
1376 /* Arm timer */
1377 if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) {
1378 fail(1, "Setting timer failed");
1382 void
1383 handle_sig(int x)
1387 static void
1388 nfsstat_kstat_copy(kstat_t *src, kstat_t *dst, int fr)
1391 if (fr)
1392 free(dst->ks_data);
1394 *dst = *src;
1396 if (src->ks_data != NULL) {
1397 safe_zalloc(&dst->ks_data, src->ks_data_size, 0);
1398 (void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size);
1399 } else {
1400 dst->ks_data = NULL;
1401 dst->ks_data_size = 0;
1406 * "Safe" allocators - if we return we're guaranteed to have the desired space
1407 * allocated and zero-filled. We exit via fail if we can't get the space.
1409 void
1410 safe_zalloc(void **ptr, uint_t size, int free_first)
1412 if (ptr == NULL)
1413 fail(1, "invalid pointer");
1414 if (free_first && *ptr != NULL)
1415 free(*ptr);
1416 if ((*ptr = (void *)malloc(size)) == NULL)
1417 fail(1, "malloc failed");
1418 (void) memset(*ptr, 0, size);
1421 static int
1422 safe_strtoi(char const *val, char *errmsg)
1424 char *end;
1425 long tmp;
1426 errno = 0;
1427 tmp = strtol(val, &end, 10);
1428 if (*end != '\0' || errno)
1429 fail(0, "%s %s", errmsg, val);
1430 return ((int)tmp);