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]
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
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>
59 #include <nfs/nfs_clnt.h>
60 #include <nfs/nfs_sec.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
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
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 */
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 "*************************************";
178 (void) setlocale(LC_ALL
, "");
179 (void) textdomain(TEXT_DOMAIN
);
181 while ((c
= getopt(argc
, argv
, "cnrsmzav:T:")) != EOF
) {
200 fail(0, "Must be root for z flag\n");
207 vflag
= atoi(optarg
);
208 if ((vflag
< 2) || (vflag
> 4))
209 fail(0, "Invalid version number\n");
214 timestamp_fmt
= UDATE
;
215 else if (*optarg
== 'd')
216 timestamp_fmt
= DDATE
;
229 if (((argc
- optind
) > 0) && !mflag
) {
231 interval
= safe_strtoi(argv
[optind
], "invalid interval");
233 fail(0, "invalid interval\n");
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");
243 if ((argc
- optind
) > 0)
247 * no count number was set, so we will loop infinitely
248 * at interval specified
252 stats_timer(interval
);
255 if (cflag
|| rflag
|| sflag
|| zflag
|| nflag
|| aflag
|| vflag
)
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
];
262 fail(0, "Please fully qualify your pathname "
263 "with a leading '/'");
267 if (argc
- optind
> 0)
268 fprintf(stderr
, "Only the first 50 paths "
269 "will be searched for\n");
278 if (timestamp_fmt
!= NODATE
)
279 print_timestamp(timestamp_fmt
);
282 (rpc_clts_server_kstat
== NULL
||
283 nfs_server_v4_kstat
== NULL
)) {
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
))
293 if (nflag
|| (!rflag
&& !nflag
&& !aflag
))
294 sn_print(zflag
, vflag
);
295 if (aflag
|| (!rflag
&& !nflag
&& !aflag
))
296 sa_print(zflag
, vflag
);
299 (rpc_clts_client_kstat
== NULL
||
300 nfs_client_kstat
== NULL
)) {
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
))
308 if (nflag
|| (!rflag
&& !nflag
&& !aflag
))
309 cn_print(zflag
, vflag
);
310 if (aflag
|| (!rflag
&& !nflag
&& !aflag
))
311 ca_print(zflag
, vflag
);
318 printf("%s\n", split_line
);
322 } while ((--count
> 0) || go_forever
);
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
);
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
);
394 getstats_rfsproc(int ver
)
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
);
414 getstats_rfsreq(int ver
)
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
);
433 getstats_aclproc(void)
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
);
448 getstats_aclreq(void)
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
);
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
);
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");
545 req_width(kstat_t
*req
, int field_width
)
547 int i
, nreq
, per
, len
;
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
)
565 per
= (int)(knp
[i
].value
.ui64
* 100 / tot
);
568 (void) sprintf(fixlen
, "%" PRIu64
" %d%%",
569 knp
[i
].value
.ui64
, per
);
570 len
= strlen(fixlen
) + 1;
571 if (field_width
< len
)
574 return (field_width
);
578 stat_width(kstat_t
*req
, int field_width
)
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
)
591 (void) sprintf(fixlen
, "%" PRIu64
, knp
[i
].value
.ui64
);
592 len
= strlen(fixlen
) + 1;
593 if (field_width
< len
)
596 return (field_width
);
604 field_width
= getstats_rpc();
605 if (field_width
== 0)
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
);
622 field_width
= getstats_rpc();
623 if (field_width
== 0)
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
);
635 cn_print(int zflag
, int vflag
)
639 field_width
= getstats_nfs();
640 if (field_width
== 0)
644 nfsstat_kstat_sum(nfs_client_kstat
, nfs4_client_kstat
,
646 stat_print("\nClient nfs:", ksum_kstat
, &old_ksum_kstat
.kst
,
650 if (vflag
== 2 || vflag
== 3) {
651 stat_print("\nClient nfs:", nfs_client_kstat
,
652 &old_nfs_client_kstat
.kst
, field_width
, zflag
);
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,
672 if (vflag
== 4 || vflag
== 0) {
673 field_width
= getstats_rfsreq(4);
674 req_print_v4(rfsreqcnt_v4_kstat
, &old_rfsreqcnt_v4_kstat
.kst
,
680 sn_print(int zflag
, int vflag
)
684 field_width
= getstats_nfs();
685 if (field_width
== 0)
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
,
723 ca_print(int zflag
, int vflag
)
727 field_width
= getstats_aclreq();
728 if (field_width
== 0)
731 printf("\nClient nfs_acl:\n");
733 if (vflag
== 2 || vflag
== 0) {
734 req_print(aclreqcnt_v2_kstat
, &old_aclreqcnt_v2_kstat
.kst
, 2,
738 if (vflag
== 3 || vflag
== 0) {
739 req_print(aclreqcnt_v3_kstat
, &old_aclreqcnt_v3_kstat
.kst
,
740 3, field_width
, zflag
);
745 sa_print(int zflag
, int vflag
)
749 field_width
= getstats_aclproc();
750 if (field_width
== 0)
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))
769 req_print(kstat_t
*req
, kstat_t
*req_old
, int ver
, int field_width
,
772 int i
, j
, nreq
, per
, ncolumns
;
773 uint64_t tot
, old_tot
;
777 kstat_named_t
*knp_old
;
782 if (field_width
== 0)
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
));
795 if (knp_old
== NULL
) {
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
;
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
);
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
);
820 per
= (int)(knp
[j
].value
.ui64
* 100 / tot
);
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
);
832 for (i
= 0; i
< req
->ks_ndata
; i
++)
833 knp
[i
].value
.ui64
= 0;
836 nfsstat_kstat_copy(req
, req_old
, 1);
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).
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
;
858 kstat_named_t
*kptr_old
;
863 if (field_width
== 0)
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
) {
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
;
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
);
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
);
905 per
= (int)(knp
[j
].value
.ui64
* 100 / tot
);
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
);
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
);
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
);
928 per
= (int)(knp
[j
].value
.ui64
* 100 / tot_ops
);
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
);
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);
946 nfsstat_kstat_copy(req
, req_old
, 0);
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
;
956 kstat_named_t
*knp_old
;
961 if (field_width
== 0)
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
);
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
);
990 for (i
= 0; i
< req
->ks_ndata
; i
++)
991 knp
[i
].value
.ui64
= 0;
995 nfsstat_kstat_copy(req
, req_old
, 1);
997 nfsstat_kstat_copy(req
, req_old
, 0);
1001 nfsstat_kstat_sum(kstat_t
*kstat1
, kstat_t
*kstat2
, kstat_t
*sum
)
1004 kstat_named_t
*knp1
, *knp2
, *knpsum
;
1005 if (kstat1
== NULL
|| kstat2
== NULL
)
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
1023 char my_dir
[MAXPATHLEN
];
1030 * Print the mount table info
1037 struct myrec
*list
, *mrp
, *pmrp
;
1042 struct mntinfo_kstat mik
;
1043 int transport_flag
= 0;
1046 char *timer_name
[] = {
1053 mt
= fopen(MNTTAB
, "r");
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)
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
) {
1074 for (path_count
= 0; path
[path_count
] != NULL
;
1076 if (strcmp(path
[path_count
], m
.mnt_mountp
)
1086 if ((mrp
= malloc(sizeof (struct myrec
))) == 0) {
1087 fprintf(stderr
, "nfsstat: not enough memory\n");
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");
1105 (void) strcpy(mrp
->ig_path
, m
.mnt_mountp
);
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");
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)
1131 pmrp
->next
= mrp
->next
;
1137 for (ksp
= kc
->kc_chain
; ksp
; ksp
= ksp
->ks_next
) {
1140 if (ksp
->ks_type
!= KSTAT_TYPE_RAW
)
1142 if (strcmp(ksp
->ks_module
, "nfs") != 0)
1144 if (strcmp(ksp
->ks_name
, "mntinfo") != 0)
1147 for (mrp
= list
; mrp
; mrp
= mrp
->next
) {
1148 if ((mrp
->my_fsid
& MAXMIN
) == ksp
->ks_instance
)
1154 if (safe_kstat_read(kc
, ksp
, &mik
) == -1)
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",
1169 printf(" Flags: vers=%u,proto=%s",
1170 mik
.mik_vers
, mik
.mik_proto
);
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
;
1183 printf(",sec=%s", flavor
);
1185 printf(",sec#=%d", mik
.mik_secmod
);
1187 printf(",%s", (mik
.mik_flags
& MI_HARD
) ? "hard" : "soft");
1188 if (mik
.mik_flags
& MI_PRINTED
)
1190 printf(",%s", (mik
.mik_flags
& MI_INT
) ? "intr" : "nointr");
1191 if (mik
.mik_flags
& MI_DOWN
)
1193 if (mik
.mik_flags
& MI_NOAC
)
1195 if (mik
.mik_flags
& MI_NOCTO
)
1197 if (mik
.mik_flags
& MI_DYNAMIC
)
1199 if (mik
.mik_flags
& MI_LLOCK
)
1201 if (mik
.mik_flags
& MI_GRPID
)
1203 if (mik
.mik_flags
& MI_RPCTIMESYNC
)
1204 printf(",rpctimesync");
1205 if (mik
.mik_flags
& MI_LINK
)
1207 if (mik
.mik_flags
& MI_SYMLINK
)
1209 if (mik
.mik_vers
< NFS_V4
&& mik
.mik_flags
& MI_READDIRONLY
)
1210 printf(",readdironly");
1211 if (mik
.mik_flags
& MI_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
,
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",
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
++) {
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",
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
, ','))
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
);
1265 static char *mntopts
[] = { MNTOPT_IGNORE
, MNTOPT_DEV
, NULL
};
1270 * Return 1 if "ignore" appears in the options string
1285 while (*opts
!= '\0') {
1286 if (getsubopt(&opts
, mntopts
, &value
) == IGNORE
) {
1299 fprintf(stderr
, "Usage: nfsstat [-cnrsza [-v version] "
1300 "[-T d|u] [interval [count]]\n");
1301 fprintf(stderr
, "Usage: nfsstat -m [pathname..]\n");
1306 fail(int do_perror
, char *message
, ...)
1310 va_start(args
, message
);
1311 fprintf(stderr
, "nfsstat: ");
1312 vfprintf(stderr
, message
, args
);
1315 fprintf(stderr
, ": %s", strerror(errno
));
1316 fprintf(stderr
, "\n");
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
);
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
,
1342 return (kstat_chain_id
);
1346 stats_timer(int interval
)
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
));
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;
1377 if ((timer_settime(t_id
, 0, &time_struct
, NULL
)) != 0) {
1378 fail(1, "Setting timer failed");
1388 nfsstat_kstat_copy(kstat_t
*src
, kstat_t
*dst
, int fr
)
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
);
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.
1410 safe_zalloc(void **ptr
, uint_t size
, int free_first
)
1413 fail(1, "invalid pointer");
1414 if (free_first
&& *ptr
!= NULL
)
1416 if ((*ptr
= (void *)malloc(size
)) == NULL
)
1417 fail(1, "malloc failed");
1418 (void) memset(*ptr
, 0, size
);
1422 safe_strtoi(char const *val
, char *errmsg
)
1427 tmp
= strtol(val
, &end
, 10);
1428 if (*end
!= '\0' || errno
)
1429 fail(0, "%s %s", errmsg
, val
);