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