Print this page
    
5513 KM_NORMALPRI should be documented in kmem_alloc(9f) and kmem_cache_create(9f) man pages
14465 Present KM_NOSLEEP_LAZY as documented interface
Change-Id: I002ec28ddf390650f1fcba1ca94f6abfdb241439
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/nfs/nfs_auth.c
          +++ new/usr/src/uts/common/fs/nfs/nfs_auth.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]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright (c) 2015 by Delphix. All rights reserved.
  25   25   * Copyright (c) 2015 Joyent, Inc.  All rights reserved.
  26   26   * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
  27   27   */
  28   28  
  29   29  #include <sys/param.h>
  30   30  #include <sys/errno.h>
  31   31  #include <sys/vfs.h>
  32   32  #include <sys/vnode.h>
  33   33  #include <sys/cred.h>
  34   34  #include <sys/cmn_err.h>
  35   35  #include <sys/systm.h>
  36   36  #include <sys/kmem.h>
  37   37  #include <sys/pathname.h>
  38   38  #include <sys/utsname.h>
  39   39  #include <sys/debug.h>
  40   40  #include <sys/door.h>
  41   41  #include <sys/sdt.h>
  42   42  #include <sys/thread.h>
  43   43  #include <sys/avl.h>
  44   44  
  45   45  #include <rpc/types.h>
  46   46  #include <rpc/auth.h>
  47   47  #include <rpc/clnt.h>
  48   48  
  49   49  #include <nfs/nfs.h>
  50   50  #include <nfs/export.h>
  51   51  #include <nfs/nfs_clnt.h>
  52   52  #include <nfs/auth.h>
  53   53  
  54   54  static struct kmem_cache *exi_cache_handle;
  55   55  static void exi_cache_reclaim(void *);
  56   56  static void exi_cache_reclaim_zone(nfs_globals_t *);
  57   57  static void exi_cache_trim(struct exportinfo *exi);
  58   58  
  59   59  extern pri_t minclsyspri;
  60   60  
  61   61  /* NFS auth cache statistics */
  62   62  volatile uint_t nfsauth_cache_hit;
  63   63  volatile uint_t nfsauth_cache_miss;
  64   64  volatile uint_t nfsauth_cache_refresh;
  65   65  volatile uint_t nfsauth_cache_reclaim;
  66   66  volatile uint_t exi_cache_auth_reclaim_failed;
  67   67  volatile uint_t exi_cache_clnt_reclaim_failed;
  68   68  
  69   69  /*
  70   70   * The lifetime of an auth cache entry:
  71   71   * ------------------------------------
  72   72   *
  73   73   * An auth cache entry is created with both the auth_time
  74   74   * and auth_freshness times set to the current time.
  75   75   *
  76   76   * Upon every client access which results in a hit, the
  77   77   * auth_time will be updated.
  78   78   *
  79   79   * If a client access determines that the auth_freshness
  80   80   * indicates that the entry is STALE, then it will be
  81   81   * refreshed. Note that this will explicitly reset
  82   82   * auth_time.
  83   83   *
  84   84   * When the REFRESH successfully occurs, then the
  85   85   * auth_freshness is updated.
  86   86   *
  87   87   * There are two ways for an entry to leave the cache:
  88   88   *
  89   89   * 1) Purged by an action on the export (remove or changed)
  90   90   * 2) Memory backpressure from the kernel (check against NFSAUTH_CACHE_TRIM)
  91   91   *
  92   92   * For 2) we check the timeout value against auth_time.
  93   93   */
  94   94  
  95   95  /*
  96   96   * Number of seconds until we mark for refresh an auth cache entry.
  97   97   */
  98   98  #define NFSAUTH_CACHE_REFRESH 600
  99   99  
 100  100  /*
 101  101   * Number of idle seconds until we yield to backpressure
 102  102   * to trim a cache entry.
 103  103   */
 104  104  #define NFSAUTH_CACHE_TRIM 3600
 105  105  
 106  106  /*
 107  107   * While we could encapuslate the exi_list inside the
 108  108   * exi structure, we can't do that for the auth_list.
 109  109   * So, to keep things looking clean, we keep them both
 110  110   * in these external lists.
 111  111   */
 112  112  typedef struct refreshq_exi_node {
 113  113          struct exportinfo       *ren_exi;
 114  114          list_t                  ren_authlist;
 115  115          list_node_t             ren_node;
 116  116  } refreshq_exi_node_t;
 117  117  
 118  118  typedef struct refreshq_auth_node {
 119  119          struct auth_cache       *ran_auth;
 120  120          char                    *ran_netid;
 121  121          list_node_t             ran_node;
 122  122  } refreshq_auth_node_t;
 123  123  
 124  124  /*
 125  125   * Used to manipulate things on the refreshq_queue.  Note that the refresh
 126  126   * thread will effectively pop a node off of the queue, at which point it
 127  127   * will no longer need to hold the mutex.
 128  128   */
 129  129  static kmutex_t refreshq_lock;
 130  130  static list_t refreshq_queue;
 131  131  static kcondvar_t refreshq_cv;
 132  132  
 133  133  /*
 134  134   * If there is ever a problem with loading the module, then nfsauth_fini()
 135  135   * needs to be called to remove state.  In that event, since the refreshq
 136  136   * thread has been started, they need to work together to get rid of state.
 137  137   */
 138  138  typedef enum nfsauth_refreshq_thread_state {
 139  139          REFRESHQ_THREAD_RUNNING,
 140  140          REFRESHQ_THREAD_FINI_REQ,
 141  141          REFRESHQ_THREAD_HALTED,
 142  142          REFRESHQ_THREAD_NEED_CREATE
 143  143  } nfsauth_refreshq_thread_state_t;
 144  144  
 145  145  typedef struct nfsauth_globals {
 146  146          kmutex_t        mountd_lock;
 147  147          door_handle_t   mountd_dh;
 148  148  
 149  149          /*
 150  150           * Used to manipulate things on the refreshq_queue.  Note that the
 151  151           * refresh thread will effectively pop a node off of the queue,
 152  152           * at which point it will no longer need to hold the mutex.
 153  153           */
 154  154          kmutex_t        refreshq_lock;
 155  155          list_t          refreshq_queue;
 156  156          kcondvar_t      refreshq_cv;
 157  157  
 158  158          /*
 159  159           * A list_t would be overkill.  These are auth_cache entries which are
 160  160           * no longer linked to an exi.  It should be the case that all of their
 161  161           * states are NFS_AUTH_INVALID, i.e., the only way to be put on this
 162  162           * list is iff their state indicated that they had been placed on the
 163  163           * refreshq_queue.
 164  164           *
 165  165           * Note that while there is no link from the exi or back to the exi,
 166  166           * the exi can not go away until these entries are harvested.
 167  167           */
 168  168          struct auth_cache               *refreshq_dead_entries;
 169  169          nfsauth_refreshq_thread_state_t refreshq_thread_state;
 170  170  
 171  171  } nfsauth_globals_t;
 172  172  
 173  173  static void nfsauth_free_node(struct auth_cache *);
 174  174  static void nfsauth_refresh_thread(nfsauth_globals_t *);
 175  175  
 176  176  static int nfsauth_cache_compar(const void *, const void *);
 177  177  
 178  178  static nfsauth_globals_t *
 179  179  nfsauth_get_zg(void)
 180  180  {
 181  181          nfs_globals_t *ng = nfs_srv_getzg();
 182  182          nfsauth_globals_t *nag = ng->nfs_auth;
 183  183          ASSERT(nag != NULL);
 184  184          return (nag);
 185  185  }
 186  186  
 187  187  void
 188  188  mountd_args(uint_t did)
 189  189  {
 190  190          nfsauth_globals_t *nag;
 191  191  
 192  192          nag = nfsauth_get_zg();
 193  193          mutex_enter(&nag->mountd_lock);
 194  194          if (nag->mountd_dh != NULL)
 195  195                  door_ki_rele(nag->mountd_dh);
 196  196          nag->mountd_dh = door_ki_lookup(did);
 197  197          mutex_exit(&nag->mountd_lock);
 198  198  }
 199  199  
 200  200  void
 201  201  nfsauth_init(void)
 202  202  {
 203  203          exi_cache_handle = kmem_cache_create("exi_cache_handle",
 204  204              sizeof (struct auth_cache), 0, NULL, NULL,
 205  205              exi_cache_reclaim, NULL, NULL, 0);
 206  206  }
 207  207  
 208  208  void
 209  209  nfsauth_fini(void)
 210  210  {
 211  211          kmem_cache_destroy(exi_cache_handle);
 212  212  }
 213  213  
 214  214  void
 215  215  nfsauth_zone_init(nfs_globals_t *ng)
 216  216  {
 217  217          nfsauth_globals_t *nag;
 218  218  
 219  219          nag = kmem_zalloc(sizeof (*nag), KM_SLEEP);
 220  220  
 221  221          /*
 222  222           * mountd can be restarted by smf(5).  We need to make sure
 223  223           * the updated door handle will safely make it to mountd_dh.
 224  224           */
 225  225          mutex_init(&nag->mountd_lock, NULL, MUTEX_DEFAULT, NULL);
 226  226          mutex_init(&nag->refreshq_lock, NULL, MUTEX_DEFAULT, NULL);
 227  227          list_create(&nag->refreshq_queue, sizeof (refreshq_exi_node_t),
 228  228              offsetof(refreshq_exi_node_t, ren_node));
 229  229          cv_init(&nag->refreshq_cv, NULL, CV_DEFAULT, NULL);
 230  230          nag->refreshq_thread_state = REFRESHQ_THREAD_NEED_CREATE;
 231  231  
 232  232          ng->nfs_auth = nag;
 233  233  }
 234  234  
 235  235  void
 236  236  nfsauth_zone_shutdown(nfs_globals_t *ng)
 237  237  {
 238  238          refreshq_exi_node_t     *ren;
 239  239          nfsauth_globals_t       *nag = ng->nfs_auth;
 240  240  
 241  241          /* Prevent the nfsauth_refresh_thread from getting new work */
 242  242          mutex_enter(&nag->refreshq_lock);
 243  243          if (nag->refreshq_thread_state == REFRESHQ_THREAD_RUNNING) {
 244  244                  nag->refreshq_thread_state = REFRESHQ_THREAD_FINI_REQ;
 245  245                  cv_broadcast(&nag->refreshq_cv);
 246  246  
 247  247                  /* Wait for nfsauth_refresh_thread() to exit */
 248  248                  while (nag->refreshq_thread_state != REFRESHQ_THREAD_HALTED)
 249  249                          cv_wait(&nag->refreshq_cv, &nag->refreshq_lock);
 250  250          }
 251  251          mutex_exit(&nag->refreshq_lock);
 252  252  
 253  253          /*
 254  254           * Walk the exi_list and in turn, walk the auth_lists and free all
 255  255           * lists.  In addition, free INVALID auth_cache entries.
 256  256           */
 257  257          while ((ren = list_remove_head(&nag->refreshq_queue))) {
 258  258                  refreshq_auth_node_t *ran;
 259  259  
 260  260                  while ((ran = list_remove_head(&ren->ren_authlist)) != NULL) {
 261  261                          struct auth_cache *p = ran->ran_auth;
 262  262                          if (p->auth_state == NFS_AUTH_INVALID)
 263  263                                  nfsauth_free_node(p);
 264  264                          strfree(ran->ran_netid);
 265  265                          kmem_free(ran, sizeof (*ran));
 266  266                  }
 267  267  
 268  268                  list_destroy(&ren->ren_authlist);
 269  269                  exi_rele(ren->ren_exi);
 270  270                  kmem_free(ren, sizeof (*ren));
 271  271          }
 272  272  }
 273  273  
 274  274  void
 275  275  nfsauth_zone_fini(nfs_globals_t *ng)
 276  276  {
 277  277          nfsauth_globals_t *nag = ng->nfs_auth;
 278  278  
 279  279          ng->nfs_auth = NULL;
 280  280  
 281  281          list_destroy(&nag->refreshq_queue);
 282  282          cv_destroy(&nag->refreshq_cv);
 283  283          mutex_destroy(&nag->refreshq_lock);
 284  284          mutex_destroy(&nag->mountd_lock);
 285  285          /* Extra cleanup. */
 286  286          if (nag->mountd_dh != NULL)
 287  287                  door_ki_rele(nag->mountd_dh);
 288  288          kmem_free(nag, sizeof (*nag));
 289  289  }
 290  290  
 291  291  /*
 292  292   * Convert the address in a netbuf to
 293  293   * a hash index for the auth_cache table.
 294  294   */
 295  295  static int
 296  296  hash(struct netbuf *a)
 297  297  {
 298  298          int i, h = 0;
 299  299  
 300  300          for (i = 0; i < a->len; i++)
 301  301                  h ^= a->buf[i];
 302  302  
 303  303          return (h & (AUTH_TABLESIZE - 1));
 304  304  }
 305  305  
 306  306  /*
 307  307   * Mask out the components of an
 308  308   * address that do not identify
 309  309   * a host. For socket addresses the
 310  310   * masking gets rid of the port number.
 311  311   */
 312  312  static void
 313  313  addrmask(struct netbuf *addr, struct netbuf *mask)
 314  314  {
 315  315          int i;
 316  316  
 317  317          for (i = 0; i < addr->len; i++)
 318  318                  addr->buf[i] &= mask->buf[i];
 319  319  }
 320  320  
 321  321  /*
 322  322   * nfsauth4_access is used for NFS V4 auth checking. Besides doing
 323  323   * the common nfsauth_access(), it will check if the client can
 324  324   * have a limited access to this vnode even if the security flavor
 325  325   * used does not meet the policy.
 326  326   */
 327  327  int
 328  328  nfsauth4_access(struct exportinfo *exi, vnode_t *vp, struct svc_req *req,
 329  329      cred_t *cr, uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids)
 330  330  {
 331  331          int access;
 332  332  
 333  333          access = nfsauth_access(exi, req, cr, uid, gid, ngids, gids);
 334  334  
 335  335          /*
 336  336           * There are cases that the server needs to allow the client
 337  337           * to have a limited view.
 338  338           *
 339  339           * e.g.
 340  340           * /export is shared as "sec=sys,rw=dfs-test-4,sec=krb5,rw"
 341  341           * /export/home is shared as "sec=sys,rw"
 342  342           *
 343  343           * When the client mounts /export with sec=sys, the client
 344  344           * would get a limited view with RO access on /export to see
 345  345           * "home" only because the client is allowed to access
 346  346           * /export/home with auth_sys.
 347  347           */
 348  348          if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) {
 349  349                  /*
 350  350                   * Allow ro permission with LIMITED view if there is a
 351  351                   * sub-dir exported under vp.
 352  352                   */
 353  353                  if (has_visible(exi, vp))
 354  354                          return (NFSAUTH_LIMITED);
 355  355          }
 356  356  
 357  357          return (access);
 358  358  }
 359  359  
 360  360  static void
 361  361  sys_log(const char *msg)
 362  362  {
 363  363          static time_t   tstamp = 0;
 364  364          time_t          now;
 365  365  
 366  366          /*
 367  367           * msg is shown (at most) once per minute
 368  368           */
 369  369          now = gethrestime_sec();
 370  370          if ((tstamp + 60) < now) {
 371  371                  tstamp = now;
 372  372                  cmn_err(CE_WARN, msg);
 373  373          }
 374  374  }
 375  375  
 376  376  /*
 377  377   * Callup to the mountd to get access information in the kernel.
 378  378   */
 379  379  static bool_t
 380  380  nfsauth_retrieve(nfsauth_globals_t *nag, struct exportinfo *exi,
 381  381      char *req_netid, int flavor, struct netbuf *addr, int *access,
 382  382      cred_t *clnt_cred, uid_t *srv_uid, gid_t *srv_gid, uint_t *srv_gids_cnt,
 383  383      gid_t **srv_gids)
 384  384  {
 385  385          varg_t                    varg = {0};
 386  386          nfsauth_res_t             res = {0};
 387  387          XDR                       xdrs;
 388  388          size_t                    absz;
 389  389          caddr_t                   abuf;
 390  390          int                       last = 0;
 391  391          door_arg_t                da;
 392  392          door_info_t               di;
 393  393          door_handle_t             dh;
 394  394          uint_t                    ntries = 0;
 395  395  
 396  396          /*
 397  397           * No entry in the cache for this client/flavor
 398  398           * so we need to call the nfsauth service in the
 399  399           * mount daemon.
 400  400           */
 401  401  
 402  402          varg.vers = V_PROTO;
 403  403          varg.arg_u.arg.cmd = NFSAUTH_ACCESS;
 404  404          varg.arg_u.arg.areq.req_client.n_len = addr->len;
 405  405          varg.arg_u.arg.areq.req_client.n_bytes = addr->buf;
 406  406          varg.arg_u.arg.areq.req_netid = req_netid;
 407  407          varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path;
 408  408          varg.arg_u.arg.areq.req_flavor = flavor;
 409  409          varg.arg_u.arg.areq.req_clnt_uid = crgetuid(clnt_cred);
 410  410          varg.arg_u.arg.areq.req_clnt_gid = crgetgid(clnt_cred);
 411  411          varg.arg_u.arg.areq.req_clnt_gids.len = crgetngroups(clnt_cred);
 412  412          varg.arg_u.arg.areq.req_clnt_gids.val = (gid_t *)crgetgroups(clnt_cred);
 413  413  
 414  414          DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg);
 415  415  
 416  416          /*
 417  417           * Setup the XDR stream for encoding the arguments. Notice that
 418  418           * in addition to the args having variable fields (req_netid and
 419  419           * req_path), the argument data structure is itself versioned,
 420  420           * so we need to make sure we can size the arguments buffer
 421  421           * appropriately to encode all the args. If we can't get sizing
 422  422           * info _or_ properly encode the arguments, there's really no
 423  423           * point in continuting, so we fail the request.
 424  424           */
 425  425          if ((absz = xdr_sizeof(xdr_varg, &varg)) == 0) {
 426  426                  *access = NFSAUTH_DENIED;
 427  427                  return (FALSE);
 428  428          }
 429  429  
 430  430          abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP);
 431  431          xdrmem_create(&xdrs, abuf, absz, XDR_ENCODE);
 432  432          if (!xdr_varg(&xdrs, &varg)) {
 433  433                  XDR_DESTROY(&xdrs);
 434  434                  goto fail;
 435  435          }
 436  436          XDR_DESTROY(&xdrs);
 437  437  
 438  438          /*
 439  439           * Prepare the door arguments
 440  440           *
 441  441           * We don't know the size of the message the daemon
 442  442           * will pass back to us.  By setting rbuf to NULL,
 443  443           * we force the door code to allocate a buf of the
 444  444           * appropriate size.  We must set rsize > 0, however,
 445  445           * else the door code acts as if no response was
 446  446           * expected and doesn't pass the data to us.
 447  447           */
 448  448          da.data_ptr = (char *)abuf;
 449  449          da.data_size = absz;
 450  450          da.desc_ptr = NULL;
 451  451          da.desc_num = 0;
 452  452          da.rbuf = NULL;
 453  453          da.rsize = 1;
 454  454  
 455  455  retry:
 456  456          mutex_enter(&nag->mountd_lock);
 457  457          dh = nag->mountd_dh;
 458  458          if (dh != NULL)
 459  459                  door_ki_hold(dh);
 460  460          mutex_exit(&nag->mountd_lock);
 461  461  
 462  462          if (dh == NULL) {
 463  463                  /*
 464  464                   * The rendezvous point has not been established yet!
 465  465                   * This could mean that either mountd(1m) has not yet
 466  466                   * been started or that _this_ routine nuked the door
 467  467                   * handle after receiving an EINTR for a REVOKED door.
 468  468                   *
 469  469                   * Returning NFSAUTH_DROP will cause the NFS client
 470  470                   * to retransmit the request, so let's try to be more
 471  471                   * rescillient and attempt for ntries before we bail.
 472  472                   */
 473  473                  if (++ntries % NFSAUTH_DR_TRYCNT) {
 474  474                          delay(hz);
 475  475                          goto retry;
 476  476                  }
 477  477  
 478  478                  kmem_free(abuf, absz);
 479  479  
 480  480                  sys_log("nfsauth: mountd has not established door");
 481  481                  *access = NFSAUTH_DROP;
 482  482                  return (FALSE);
 483  483          }
 484  484  
 485  485          ntries = 0;
 486  486  
 487  487          /*
 488  488           * Now that we've got what we need, place the call.
 489  489           */
 490  490          switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) {
 491  491          case 0:                         /* Success */
 492  492                  door_ki_rele(dh);
 493  493  
 494  494                  if (da.data_ptr == NULL && da.data_size == 0) {
 495  495                          /*
 496  496                           * The door_return that contained the data
 497  497                           * failed! We're here because of the 2nd
 498  498                           * door_return (w/o data) such that we can
 499  499                           * get control of the thread (and exit
 500  500                           * gracefully).
 501  501                           */
 502  502                          DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil,
 503  503                              door_arg_t *, &da);
 504  504                          goto fail;
 505  505                  }
 506  506  
 507  507                  break;
 508  508  
 509  509          case EAGAIN:
 510  510                  /*
 511  511                   * Server out of resources; back off for a bit
 512  512                   */
 513  513                  door_ki_rele(dh);
 514  514                  delay(hz);
 515  515                  goto retry;
 516  516                  /* NOTREACHED */
 517  517  
 518  518          case EINTR:
 519  519                  if (!door_ki_info(dh, &di)) {
 520  520                          door_ki_rele(dh);
 521  521  
 522  522                          if (di.di_attributes & DOOR_REVOKED) {
 523  523                                  /*
 524  524                                   * The server barfed and revoked
 525  525                                   * the (existing) door on us; we
 526  526                                   * want to wait to give smf(5) a
 527  527                                   * chance to restart mountd(1m)
 528  528                                   * and establish a new door handle.
 529  529                                   */
 530  530                                  mutex_enter(&nag->mountd_lock);
 531  531                                  if (dh == nag->mountd_dh) {
 532  532                                          door_ki_rele(nag->mountd_dh);
 533  533                                          nag->mountd_dh = NULL;
 534  534                                  }
 535  535                                  mutex_exit(&nag->mountd_lock);
 536  536                                  delay(hz);
 537  537                                  goto retry;
 538  538                          }
 539  539                          /*
 540  540                           * If the door was _not_ revoked on us,
 541  541                           * then more than likely we took an INTR,
 542  542                           * so we need to fail the operation.
 543  543                           */
 544  544                          goto fail;
 545  545                  }
 546  546                  /*
 547  547                   * The only failure that can occur from getting
 548  548                   * the door info is EINVAL, so we let the code
 549  549                   * below handle it.
 550  550                   */
 551  551                  /* FALLTHROUGH */
 552  552  
 553  553          case EBADF:
 554  554          case EINVAL:
 555  555          default:
 556  556                  /*
 557  557                   * If we have a stale door handle, give smf a last
 558  558                   * chance to start it by sleeping for a little bit.
 559  559                   * If we're still hosed, we'll fail the call.
 560  560                   *
 561  561                   * Since we're going to reacquire the door handle
 562  562                   * upon the retry, we opt to sleep for a bit and
 563  563                   * _not_ to clear mountd_dh. If mountd restarted
 564  564                   * and was able to set mountd_dh, we should see
 565  565                   * the new instance; if not, we won't get caught
 566  566                   * up in the retry/DELAY loop.
 567  567                   */
 568  568                  door_ki_rele(dh);
 569  569                  if (!last) {
 570  570                          delay(hz);
 571  571                          last++;
 572  572                          goto retry;
 573  573                  }
 574  574                  sys_log("nfsauth: stale mountd door handle");
 575  575                  goto fail;
 576  576          }
 577  577  
 578  578          ASSERT(da.rbuf != NULL);
 579  579  
 580  580          /*
 581  581           * No door errors encountered; setup the XDR stream for decoding
 582  582           * the results. If we fail to decode the results, we've got no
 583  583           * other recourse than to fail the request.
 584  584           */
 585  585          xdrmem_create(&xdrs, da.rbuf, da.rsize, XDR_DECODE);
 586  586          if (!xdr_nfsauth_res(&xdrs, &res)) {
 587  587                  xdr_free(xdr_nfsauth_res, (char *)&res);
 588  588                  XDR_DESTROY(&xdrs);
 589  589                  kmem_free(da.rbuf, da.rsize);
 590  590                  goto fail;
 591  591          }
 592  592          XDR_DESTROY(&xdrs);
 593  593          kmem_free(da.rbuf, da.rsize);
 594  594  
 595  595          DTRACE_PROBE1(nfsserv__func__nfsauth__results, nfsauth_res_t *, &res);
 596  596          switch (res.stat) {
 597  597                  case NFSAUTH_DR_OKAY:
 598  598                          *access = res.ares.auth_perm;
 599  599                          *srv_uid = res.ares.auth_srv_uid;
 600  600                          *srv_gid = res.ares.auth_srv_gid;
 601  601  
 602  602                          if ((*srv_gids_cnt = res.ares.auth_srv_gids.len) != 0) {
 603  603                                  *srv_gids = kmem_alloc(*srv_gids_cnt *
 604  604                                      sizeof (gid_t), KM_SLEEP);
 605  605                                  bcopy(res.ares.auth_srv_gids.val, *srv_gids,
 606  606                                      *srv_gids_cnt * sizeof (gid_t));
 607  607                          } else {
 608  608                                  *srv_gids = NULL;
 609  609                          }
 610  610  
 611  611                          break;
 612  612  
 613  613                  case NFSAUTH_DR_EFAIL:
 614  614                  case NFSAUTH_DR_DECERR:
 615  615                  case NFSAUTH_DR_BADCMD:
 616  616                  default:
 617  617                          xdr_free(xdr_nfsauth_res, (char *)&res);
 618  618  fail:
 619  619                          *access = NFSAUTH_DENIED;
 620  620                          kmem_free(abuf, absz);
 621  621                          return (FALSE);
 622  622                          /* NOTREACHED */
 623  623          }
 624  624  
 625  625          xdr_free(xdr_nfsauth_res, (char *)&res);
 626  626          kmem_free(abuf, absz);
 627  627  
 628  628          return (TRUE);
 629  629  }
 630  630  
 631  631  static void
 632  632  nfsauth_refresh_thread(nfsauth_globals_t *nag)
 633  633  {
 634  634          refreshq_exi_node_t     *ren;
 635  635          refreshq_auth_node_t    *ran;
 636  636  
 637  637          struct exportinfo       *exi;
 638  638  
 639  639          int                     access;
 640  640          bool_t                  retrieval;
 641  641  
 642  642          callb_cpr_t             cprinfo;
 643  643  
 644  644          CALLB_CPR_INIT(&cprinfo, &nag->refreshq_lock, callb_generic_cpr,
 645  645              "nfsauth_refresh");
 646  646  
 647  647          for (;;) {
 648  648                  mutex_enter(&nag->refreshq_lock);
 649  649                  if (nag->refreshq_thread_state != REFRESHQ_THREAD_RUNNING) {
 650  650                          /* Keep the hold on the lock! */
 651  651                          break;
 652  652                  }
 653  653  
 654  654                  ren = list_remove_head(&nag->refreshq_queue);
 655  655                  if (ren == NULL) {
 656  656                          CALLB_CPR_SAFE_BEGIN(&cprinfo);
 657  657                          cv_wait(&nag->refreshq_cv, &nag->refreshq_lock);
 658  658                          CALLB_CPR_SAFE_END(&cprinfo, &nag->refreshq_lock);
 659  659                          mutex_exit(&nag->refreshq_lock);
 660  660                          continue;
 661  661                  }
 662  662                  mutex_exit(&nag->refreshq_lock);
 663  663  
 664  664                  exi = ren->ren_exi;
 665  665                  ASSERT(exi != NULL);
 666  666  
 667  667                  /*
 668  668                   * Since the ren was removed from the refreshq_queue above,
 669  669                   * this is the only thread aware about the ren existence, so we
 670  670                   * have the exclusive ownership of it and we do not need to
 671  671                   * protect it by any lock.
 672  672                   */
 673  673                  while ((ran = list_remove_head(&ren->ren_authlist))) {
 674  674                          uid_t uid;
 675  675                          gid_t gid;
 676  676                          uint_t ngids;
 677  677                          gid_t *gids;
 678  678                          struct auth_cache *p = ran->ran_auth;
 679  679                          char *netid = ran->ran_netid;
 680  680  
 681  681                          ASSERT(p != NULL);
 682  682                          ASSERT(netid != NULL);
 683  683  
 684  684                          kmem_free(ran, sizeof (refreshq_auth_node_t));
 685  685  
 686  686                          mutex_enter(&p->auth_lock);
 687  687  
 688  688                          /*
 689  689                           * Once the entry goes INVALID, it can not change
 690  690                           * state.
 691  691                           *
 692  692                           * No need to refresh entries also in a case we are
 693  693                           * just shutting down.
 694  694                           *
 695  695                           * In general, there is no need to hold the
 696  696                           * refreshq_lock to test the refreshq_thread_state.  We
 697  697                           * do hold it at other places because there is some
 698  698                           * related thread synchronization (or some other tasks)
 699  699                           * close to the refreshq_thread_state check.
 700  700                           *
 701  701                           * The check for the refreshq_thread_state value here
 702  702                           * is purely advisory to allow the faster
 703  703                           * nfsauth_refresh_thread() shutdown.  In a case we
 704  704                           * will miss such advisory, nothing catastrophic
 705  705                           * happens: we will just spin longer here before the
 706  706                           * shutdown.
 707  707                           */
 708  708                          if (p->auth_state == NFS_AUTH_INVALID ||
 709  709                              nag->refreshq_thread_state !=
 710  710                              REFRESHQ_THREAD_RUNNING) {
 711  711                                  mutex_exit(&p->auth_lock);
 712  712  
 713  713                                  if (p->auth_state == NFS_AUTH_INVALID)
 714  714                                          nfsauth_free_node(p);
 715  715  
 716  716                                  strfree(netid);
 717  717  
 718  718                                  continue;
 719  719                          }
 720  720  
 721  721                          /*
 722  722                           * Make sure the state is valid.  Note that once we
 723  723                           * change the state to NFS_AUTH_REFRESHING, no other
 724  724                           * thread will be able to work on this entry.
 725  725                           */
 726  726                          ASSERT(p->auth_state == NFS_AUTH_STALE);
 727  727  
 728  728                          p->auth_state = NFS_AUTH_REFRESHING;
 729  729                          mutex_exit(&p->auth_lock);
 730  730  
 731  731                          DTRACE_PROBE2(nfsauth__debug__cache__refresh,
 732  732                              struct exportinfo *, exi,
 733  733                              struct auth_cache *, p);
 734  734  
 735  735                          /*
 736  736                           * The first caching of the access rights
 737  737                           * is done with the netid pulled out of the
 738  738                           * request from the client. All subsequent
 739  739                           * users of the cache may or may not have
 740  740                           * the same netid. It doesn't matter. So
 741  741                           * when we refresh, we simply use the netid
 742  742                           * of the request which triggered the
 743  743                           * refresh attempt.
 744  744                           */
 745  745                          retrieval = nfsauth_retrieve(nag, exi, netid,
 746  746                              p->auth_flavor, &p->auth_clnt->authc_addr, &access,
 747  747                              p->auth_clnt_cred, &uid, &gid, &ngids, &gids);
 748  748  
 749  749                          /*
 750  750                           * This can only be set in one other place
 751  751                           * and the state has to be NFS_AUTH_FRESH.
 752  752                           */
 753  753                          strfree(netid);
 754  754  
 755  755                          mutex_enter(&p->auth_lock);
 756  756                          if (p->auth_state == NFS_AUTH_INVALID) {
 757  757                                  mutex_exit(&p->auth_lock);
 758  758                                  nfsauth_free_node(p);
 759  759                                  if (retrieval == TRUE)
 760  760                                          kmem_free(gids, ngids * sizeof (gid_t));
 761  761                          } else {
 762  762                                  /*
 763  763                                   * If we got an error, do not reset the
 764  764                                   * time. This will cause the next access
 765  765                                   * check for the client to reschedule this
 766  766                                   * node.
 767  767                                   */
 768  768                                  if (retrieval == TRUE) {
 769  769                                          p->auth_access = access;
 770  770  
 771  771                                          p->auth_srv_uid = uid;
 772  772                                          p->auth_srv_gid = gid;
 773  773                                          kmem_free(p->auth_srv_gids,
 774  774                                              p->auth_srv_ngids * sizeof (gid_t));
 775  775                                          p->auth_srv_ngids = ngids;
 776  776                                          p->auth_srv_gids = gids;
 777  777  
 778  778                                          p->auth_freshness = gethrestime_sec();
 779  779                                  }
 780  780                                  p->auth_state = NFS_AUTH_FRESH;
 781  781  
 782  782                                  cv_broadcast(&p->auth_cv);
 783  783                                  mutex_exit(&p->auth_lock);
 784  784                          }
 785  785                  }
 786  786  
 787  787                  list_destroy(&ren->ren_authlist);
 788  788                  exi_rele(ren->ren_exi);
 789  789                  kmem_free(ren, sizeof (refreshq_exi_node_t));
 790  790          }
 791  791  
 792  792          nag->refreshq_thread_state = REFRESHQ_THREAD_HALTED;
 793  793          cv_broadcast(&nag->refreshq_cv);
 794  794          CALLB_CPR_EXIT(&cprinfo);
 795  795          DTRACE_PROBE(nfsauth__nfsauth__refresh__thread__exit);
 796  796          zthread_exit();
 797  797  }
 798  798  
 799  799  int
 800  800  nfsauth_cache_clnt_compar(const void *v1, const void *v2)
 801  801  {
 802  802          int c;
 803  803  
 804  804          const struct auth_cache_clnt *a1 = (const struct auth_cache_clnt *)v1;
 805  805          const struct auth_cache_clnt *a2 = (const struct auth_cache_clnt *)v2;
 806  806  
 807  807          if (a1->authc_addr.len < a2->authc_addr.len)
 808  808                  return (-1);
 809  809          if (a1->authc_addr.len > a2->authc_addr.len)
 810  810                  return (1);
 811  811  
 812  812          c = memcmp(a1->authc_addr.buf, a2->authc_addr.buf, a1->authc_addr.len);
 813  813          if (c < 0)
 814  814                  return (-1);
 815  815          if (c > 0)
 816  816                  return (1);
 817  817  
 818  818          return (0);
 819  819  }
 820  820  
 821  821  static int
 822  822  nfsauth_cache_compar(const void *v1, const void *v2)
 823  823  {
 824  824          int c;
 825  825  
 826  826          const struct auth_cache *a1 = (const struct auth_cache *)v1;
 827  827          const struct auth_cache *a2 = (const struct auth_cache *)v2;
 828  828  
 829  829          if (a1->auth_flavor < a2->auth_flavor)
 830  830                  return (-1);
 831  831          if (a1->auth_flavor > a2->auth_flavor)
 832  832                  return (1);
 833  833  
 834  834          if (crgetuid(a1->auth_clnt_cred) < crgetuid(a2->auth_clnt_cred))
 835  835                  return (-1);
 836  836          if (crgetuid(a1->auth_clnt_cred) > crgetuid(a2->auth_clnt_cred))
 837  837                  return (1);
 838  838  
 839  839          if (crgetgid(a1->auth_clnt_cred) < crgetgid(a2->auth_clnt_cred))
 840  840                  return (-1);
 841  841          if (crgetgid(a1->auth_clnt_cred) > crgetgid(a2->auth_clnt_cred))
 842  842                  return (1);
 843  843  
 844  844          if (crgetngroups(a1->auth_clnt_cred) < crgetngroups(a2->auth_clnt_cred))
 845  845                  return (-1);
 846  846          if (crgetngroups(a1->auth_clnt_cred) > crgetngroups(a2->auth_clnt_cred))
 847  847                  return (1);
 848  848  
 849  849          c = memcmp(crgetgroups(a1->auth_clnt_cred),
 850  850              crgetgroups(a2->auth_clnt_cred), crgetngroups(a1->auth_clnt_cred));
 851  851          if (c < 0)
 852  852                  return (-1);
 853  853          if (c > 0)
 854  854                  return (1);
 855  855  
 856  856          return (0);
 857  857  }
 858  858  
 859  859  /*
 860  860   * Get the access information from the cache or callup to the mountd
 861  861   * to get and cache the access information in the kernel.
 862  862   */
 863  863  static int
 864  864  nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor,
 865  865      cred_t *cr, uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids)
 866  866  {
 867  867          nfsauth_globals_t       *nag;
 868  868          struct netbuf           *taddrmask;
 869  869          struct netbuf           addr;   /* temporary copy of client's address */
 870  870          const struct netbuf     *claddr;
 871  871          avl_tree_t              *tree;
 872  872          struct auth_cache       ac;     /* used as a template for avl_find() */
 873  873          struct auth_cache_clnt  *c;
 874  874          struct auth_cache_clnt  acc;    /* used as a template for avl_find() */
 875  875          struct auth_cache       *p = NULL;
 876  876          int                     access;
 877  877  
 878  878          uid_t                   tmpuid;
 879  879          gid_t                   tmpgid;
 880  880          uint_t                  tmpngids;
 881  881          gid_t                   *tmpgids;
 882  882  
 883  883          avl_index_t             where;  /* used for avl_find()/avl_insert() */
 884  884  
 885  885          ASSERT(cr != NULL);
 886  886  
 887  887          ASSERT3P(curzone->zone_id, ==, exi->exi_zoneid);
 888  888          nag = nfsauth_get_zg();
 889  889  
 890  890          /*
 891  891           * Now check whether this client already
 892  892           * has an entry for this flavor in the cache
 893  893           * for this export.
 894  894           * Get the caller's address, mask off the
 895  895           * parts of the address that do not identify
 896  896           * the host (port number, etc), and then hash
 897  897           * it to find the chain of cache entries.
 898  898           */
 899  899  
 900  900          claddr = svc_getrpccaller(req->rq_xprt);
 901  901          addr = *claddr;
 902  902          if (claddr->len != 0) {
 903  903                  addr.buf = kmem_alloc(addr.maxlen, KM_SLEEP);
 904  904                  bcopy(claddr->buf, addr.buf, claddr->len);
 905  905          } else {
 906  906                  addr.buf = NULL;
 907  907          }
 908  908  
 909  909          SVC_GETADDRMASK(req->rq_xprt, SVC_TATTR_ADDRMASK, (void **)&taddrmask);
 910  910          ASSERT(taddrmask != NULL);
 911  911          addrmask(&addr, taddrmask);
 912  912  
 913  913          acc.authc_addr = addr;
 914  914  
  
    | 
      ↓ open down ↓ | 
    914 lines elided | 
    
      ↑ open up ↑ | 
  
 915  915          tree = exi->exi_cache[hash(&addr)];
 916  916  
 917  917          rw_enter(&exi->exi_cache_lock, RW_READER);
 918  918          c = (struct auth_cache_clnt *)avl_find(tree, &acc, NULL);
 919  919  
 920  920          if (c == NULL) {
 921  921                  struct auth_cache_clnt *nc;
 922  922  
 923  923                  rw_exit(&exi->exi_cache_lock);
 924  924  
 925      -                nc = kmem_alloc(sizeof (*nc), KM_NOSLEEP | KM_NORMALPRI);
      925 +                nc = kmem_alloc(sizeof (*nc), KM_NOSLEEP_LAZY);
 926  926                  if (nc == NULL)
 927  927                          goto retrieve;
 928  928  
 929  929                  /*
 930  930                   * Initialize the new auth_cache_clnt
 931  931                   */
 932  932                  nc->authc_addr = addr;
 933      -                nc->authc_addr.buf = kmem_alloc(addr.maxlen,
 934      -                    KM_NOSLEEP | KM_NORMALPRI);
      933 +                nc->authc_addr.buf = kmem_alloc(addr.maxlen, KM_NOSLEEP_LAZY);
 935  934                  if (addr.maxlen != 0 && nc->authc_addr.buf == NULL) {
 936  935                          kmem_free(nc, sizeof (*nc));
 937  936                          goto retrieve;
 938  937                  }
 939  938                  bcopy(addr.buf, nc->authc_addr.buf, addr.len);
 940  939                  rw_init(&nc->authc_lock, NULL, RW_DEFAULT, NULL);
 941  940                  avl_create(&nc->authc_tree, nfsauth_cache_compar,
 942  941                      sizeof (struct auth_cache),
 943  942                      offsetof(struct auth_cache, auth_link));
 944  943  
 945  944                  rw_enter(&exi->exi_cache_lock, RW_WRITER);
 946  945                  c = (struct auth_cache_clnt *)avl_find(tree, &acc, &where);
 947  946                  if (c == NULL) {
 948  947                          avl_insert(tree, nc, where);
 949  948                          rw_downgrade(&exi->exi_cache_lock);
 950  949                          c = nc;
 951  950                  } else {
 952  951                          rw_downgrade(&exi->exi_cache_lock);
 953  952  
 954  953                          avl_destroy(&nc->authc_tree);
 955  954                          rw_destroy(&nc->authc_lock);
 956  955                          kmem_free(nc->authc_addr.buf, nc->authc_addr.maxlen);
 957  956                          kmem_free(nc, sizeof (*nc));
 958  957                  }
 959  958          }
 960  959  
 961  960          ASSERT(c != NULL);
 962  961  
 963  962          rw_enter(&c->authc_lock, RW_READER);
 964  963  
  
    | 
      ↓ open down ↓ | 
    20 lines elided | 
    
      ↑ open up ↑ | 
  
 965  964          ac.auth_flavor = flavor;
 966  965          ac.auth_clnt_cred = cr;
 967  966  
 968  967          p = (struct auth_cache *)avl_find(&c->authc_tree, &ac, NULL);
 969  968  
 970  969          if (p == NULL) {
 971  970                  struct auth_cache *np;
 972  971  
 973  972                  rw_exit(&c->authc_lock);
 974  973  
 975      -                np = kmem_cache_alloc(exi_cache_handle,
 976      -                    KM_NOSLEEP | KM_NORMALPRI);
      974 +                np = kmem_cache_alloc(exi_cache_handle, KM_NOSLEEP_LAZY);
 977  975                  if (np == NULL) {
 978  976                          rw_exit(&exi->exi_cache_lock);
 979  977                          goto retrieve;
 980  978                  }
 981  979  
 982  980                  /*
 983  981                   * Initialize the new auth_cache
 984  982                   */
 985  983                  np->auth_clnt = c;
 986  984                  np->auth_flavor = flavor;
 987  985                  np->auth_clnt_cred = crdup(cr);
 988  986                  np->auth_srv_ngids = 0;
 989  987                  np->auth_srv_gids = NULL;
 990  988                  np->auth_time = np->auth_freshness = gethrestime_sec();
 991  989                  np->auth_state = NFS_AUTH_NEW;
 992  990                  mutex_init(&np->auth_lock, NULL, MUTEX_DEFAULT, NULL);
 993  991                  cv_init(&np->auth_cv, NULL, CV_DEFAULT, NULL);
 994  992  
 995  993                  rw_enter(&c->authc_lock, RW_WRITER);
 996  994                  rw_exit(&exi->exi_cache_lock);
 997  995  
 998  996                  p = (struct auth_cache *)avl_find(&c->authc_tree, &ac, &where);
 999  997                  if (p == NULL) {
1000  998                          avl_insert(&c->authc_tree, np, where);
1001  999                          rw_downgrade(&c->authc_lock);
1002 1000                          p = np;
1003 1001                  } else {
1004 1002                          rw_downgrade(&c->authc_lock);
1005 1003  
1006 1004                          cv_destroy(&np->auth_cv);
1007 1005                          mutex_destroy(&np->auth_lock);
1008 1006                          crfree(np->auth_clnt_cred);
1009 1007                          kmem_cache_free(exi_cache_handle, np);
1010 1008                  }
1011 1009          } else {
1012 1010                  rw_exit(&exi->exi_cache_lock);
1013 1011          }
1014 1012  
1015 1013          mutex_enter(&p->auth_lock);
1016 1014          rw_exit(&c->authc_lock);
1017 1015  
1018 1016          /*
1019 1017           * If the entry is in the WAITING state then some other thread is just
1020 1018           * retrieving the required info.  The entry was either NEW, or the list
1021 1019           * of client's supplemental groups is going to be changed (either by
1022 1020           * this thread, or by some other thread).  We need to wait until the
1023 1021           * nfsauth_retrieve() is done.
1024 1022           */
1025 1023          while (p->auth_state == NFS_AUTH_WAITING)
1026 1024                  cv_wait(&p->auth_cv, &p->auth_lock);
1027 1025  
1028 1026          /*
1029 1027           * Here the entry cannot be in WAITING or INVALID state.
1030 1028           */
1031 1029          ASSERT(p->auth_state != NFS_AUTH_WAITING);
1032 1030          ASSERT(p->auth_state != NFS_AUTH_INVALID);
1033 1031  
1034 1032          /*
1035 1033           * If the cache entry is not valid yet, we need to retrieve the
1036 1034           * info ourselves.
1037 1035           */
1038 1036          if (p->auth_state == NFS_AUTH_NEW) {
1039 1037                  bool_t res;
1040 1038                  /*
1041 1039                   * NFS_AUTH_NEW is the default output auth_state value in a
1042 1040                   * case we failed somewhere below.
1043 1041                   */
1044 1042                  auth_state_t state = NFS_AUTH_NEW;
1045 1043  
1046 1044                  p->auth_state = NFS_AUTH_WAITING;
1047 1045                  mutex_exit(&p->auth_lock);
1048 1046                  kmem_free(addr.buf, addr.maxlen);
1049 1047                  addr = p->auth_clnt->authc_addr;
1050 1048  
1051 1049                  atomic_inc_uint(&nfsauth_cache_miss);
1052 1050  
1053 1051                  res = nfsauth_retrieve(nag, exi, svc_getnetid(req->rq_xprt),
1054 1052                      flavor, &addr, &access, cr, &tmpuid, &tmpgid, &tmpngids,
1055 1053                      &tmpgids);
1056 1054  
1057 1055                  p->auth_access = access;
1058 1056                  p->auth_time = p->auth_freshness = gethrestime_sec();
1059 1057  
1060 1058                  if (res == TRUE) {
1061 1059                          if (uid != NULL)
1062 1060                                  *uid = tmpuid;
1063 1061                          if (gid != NULL)
  
    | 
      ↓ open down ↓ | 
    77 lines elided | 
    
      ↑ open up ↑ | 
  
1064 1062                                  *gid = tmpgid;
1065 1063                          if (ngids != NULL && gids != NULL) {
1066 1064                                  *ngids = tmpngids;
1067 1065                                  *gids = tmpgids;
1068 1066  
1069 1067                                  /*
1070 1068                                   * We need a copy of gids for the
1071 1069                                   * auth_cache entry
1072 1070                                   */
1073 1071                                  tmpgids = kmem_alloc(tmpngids * sizeof (gid_t),
1074      -                                    KM_NOSLEEP | KM_NORMALPRI);
     1072 +                                    KM_NOSLEEP_LAZY);
1075 1073                                  if (tmpgids != NULL)
1076 1074                                          bcopy(*gids, tmpgids,
1077 1075                                              tmpngids * sizeof (gid_t));
1078 1076                          }
1079 1077  
1080 1078                          if (tmpgids != NULL || tmpngids == 0) {
1081 1079                                  p->auth_srv_uid = tmpuid;
1082 1080                                  p->auth_srv_gid = tmpgid;
1083 1081                                  p->auth_srv_ngids = tmpngids;
1084 1082                                  p->auth_srv_gids = tmpgids;
1085 1083  
1086 1084                                  state = NFS_AUTH_FRESH;
1087 1085                          }
1088 1086                  }
1089 1087  
1090 1088                  /*
1091 1089                   * Set the auth_state and notify waiters.
1092 1090                   */
1093 1091                  mutex_enter(&p->auth_lock);
1094 1092                  p->auth_state = state;
1095 1093                  cv_broadcast(&p->auth_cv);
1096 1094                  mutex_exit(&p->auth_lock);
1097 1095          } else {
1098 1096                  uint_t nach;
1099 1097                  time_t refresh;
1100 1098  
1101 1099                  refresh = gethrestime_sec() - p->auth_freshness;
1102 1100  
1103 1101                  p->auth_time = gethrestime_sec();
1104 1102  
1105 1103                  if (uid != NULL)
1106 1104                          *uid = p->auth_srv_uid;
1107 1105                  if (gid != NULL)
1108 1106                          *gid = p->auth_srv_gid;
1109 1107                  if (ngids != NULL && gids != NULL) {
1110 1108                          if ((*ngids = p->auth_srv_ngids) != 0) {
1111 1109                                  size_t sz = *ngids * sizeof (gid_t);
1112 1110                                  *gids = kmem_alloc(sz, KM_SLEEP);
1113 1111                                  bcopy(p->auth_srv_gids, *gids, sz);
1114 1112                          } else {
1115 1113                                  *gids = NULL;
1116 1114                          }
1117 1115                  }
1118 1116  
1119 1117                  access = p->auth_access;
1120 1118  
1121 1119                  if ((refresh > NFSAUTH_CACHE_REFRESH) &&
1122 1120                      p->auth_state == NFS_AUTH_FRESH) {
1123 1121                          refreshq_auth_node_t *ran;
1124 1122                          uint_t nacr;
1125 1123  
1126 1124                          p->auth_state = NFS_AUTH_STALE;
1127 1125                          mutex_exit(&p->auth_lock);
1128 1126  
1129 1127                          nacr = atomic_inc_uint_nv(&nfsauth_cache_refresh);
1130 1128                          DTRACE_PROBE3(nfsauth__debug__cache__stale,
1131 1129                              struct exportinfo *, exi,
1132 1130                              struct auth_cache *, p,
1133 1131                              uint_t, nacr);
1134 1132  
1135 1133                          ran = kmem_alloc(sizeof (refreshq_auth_node_t),
1136 1134                              KM_SLEEP);
1137 1135                          ran->ran_auth = p;
1138 1136                          ran->ran_netid = strdup(svc_getnetid(req->rq_xprt));
1139 1137  
1140 1138                          mutex_enter(&nag->refreshq_lock);
1141 1139  
1142 1140                          if (nag->refreshq_thread_state ==
1143 1141                              REFRESHQ_THREAD_NEED_CREATE) {
1144 1142                                  /* Launch nfsauth refresh thread */
1145 1143                                  nag->refreshq_thread_state =
1146 1144                                      REFRESHQ_THREAD_RUNNING;
1147 1145                                  (void) zthread_create(NULL, 0,
1148 1146                                      nfsauth_refresh_thread, nag, 0,
1149 1147                                      minclsyspri);
1150 1148                          }
1151 1149  
1152 1150                          /*
1153 1151                           * We should not add a work queue item if the thread
1154 1152                           * is not accepting them.
1155 1153                           */
1156 1154                          if (nag->refreshq_thread_state ==
1157 1155                              REFRESHQ_THREAD_RUNNING) {
1158 1156                                  refreshq_exi_node_t *ren;
1159 1157  
1160 1158                                  /*
1161 1159                                   * Is there an existing exi_list?
1162 1160                                   */
1163 1161                                  for (ren = list_head(&nag->refreshq_queue);
1164 1162                                      ren != NULL;
1165 1163                                      ren = list_next(&nag->refreshq_queue,
1166 1164                                      ren)) {
1167 1165                                          if (ren->ren_exi == exi) {
1168 1166                                                  list_insert_tail(
1169 1167                                                      &ren->ren_authlist, ran);
1170 1168                                                  break;
1171 1169                                          }
1172 1170                                  }
1173 1171  
1174 1172                                  if (ren == NULL) {
1175 1173                                          ren = kmem_alloc(
1176 1174                                              sizeof (refreshq_exi_node_t),
1177 1175                                              KM_SLEEP);
1178 1176  
1179 1177                                          exi_hold(exi);
1180 1178                                          ren->ren_exi = exi;
1181 1179  
1182 1180                                          list_create(&ren->ren_authlist,
1183 1181                                              sizeof (refreshq_auth_node_t),
1184 1182                                              offsetof(refreshq_auth_node_t,
1185 1183                                              ran_node));
1186 1184  
1187 1185                                          list_insert_tail(&ren->ren_authlist,
1188 1186                                              ran);
1189 1187                                          list_insert_tail(&nag->refreshq_queue,
1190 1188                                              ren);
1191 1189                                  }
1192 1190  
1193 1191                                  cv_broadcast(&nag->refreshq_cv);
1194 1192                          } else {
1195 1193                                  strfree(ran->ran_netid);
1196 1194                                  kmem_free(ran, sizeof (refreshq_auth_node_t));
1197 1195                          }
1198 1196  
1199 1197                          mutex_exit(&nag->refreshq_lock);
1200 1198                  } else {
1201 1199                          mutex_exit(&p->auth_lock);
1202 1200                  }
1203 1201  
1204 1202                  nach = atomic_inc_uint_nv(&nfsauth_cache_hit);
1205 1203                  DTRACE_PROBE2(nfsauth__debug__cache__hit,
1206 1204                      uint_t, nach,
1207 1205                      time_t, refresh);
1208 1206  
1209 1207                  kmem_free(addr.buf, addr.maxlen);
1210 1208          }
1211 1209  
1212 1210          return (access);
1213 1211  
1214 1212  retrieve:
1215 1213  
1216 1214          /*
1217 1215           * Retrieve the required data without caching.
1218 1216           */
1219 1217  
1220 1218          ASSERT(p == NULL);
1221 1219  
1222 1220          atomic_inc_uint(&nfsauth_cache_miss);
1223 1221  
1224 1222          if (nfsauth_retrieve(nag, exi, svc_getnetid(req->rq_xprt), flavor,
1225 1223              &addr, &access, cr, &tmpuid, &tmpgid, &tmpngids, &tmpgids)) {
1226 1224                  if (uid != NULL)
1227 1225                          *uid = tmpuid;
1228 1226                  if (gid != NULL)
1229 1227                          *gid = tmpgid;
1230 1228                  if (ngids != NULL && gids != NULL) {
1231 1229                          *ngids = tmpngids;
1232 1230                          *gids = tmpgids;
1233 1231                  } else {
1234 1232                          kmem_free(tmpgids, tmpngids * sizeof (gid_t));
1235 1233                  }
1236 1234          }
1237 1235  
1238 1236          kmem_free(addr.buf, addr.maxlen);
1239 1237  
1240 1238          return (access);
1241 1239  }
1242 1240  
1243 1241  /*
1244 1242   * Check if the requesting client has access to the filesystem with
1245 1243   * a given nfs flavor number which is an explicitly shared flavor.
1246 1244   */
1247 1245  int
1248 1246  nfsauth4_secinfo_access(struct exportinfo *exi, struct svc_req *req,
1249 1247      int flavor, int perm, cred_t *cr)
1250 1248  {
1251 1249          int access;
1252 1250  
1253 1251          if (! (perm & M_4SEC_EXPORTED)) {
1254 1252                  return (NFSAUTH_DENIED);
1255 1253          }
1256 1254  
1257 1255          /*
1258 1256           * Optimize if there are no lists
1259 1257           */
1260 1258          if ((perm & (M_ROOT | M_NONE | M_MAP)) == 0) {
1261 1259                  perm &= ~M_4SEC_EXPORTED;
1262 1260                  if (perm == M_RO)
1263 1261                          return (NFSAUTH_RO);
1264 1262                  if (perm == M_RW)
1265 1263                          return (NFSAUTH_RW);
1266 1264          }
1267 1265  
1268 1266          access = nfsauth_cache_get(exi, req, flavor, cr, NULL, NULL, NULL,
1269 1267              NULL);
1270 1268  
1271 1269          return (access);
1272 1270  }
1273 1271  
1274 1272  int
1275 1273  nfsauth_access(struct exportinfo *exi, struct svc_req *req, cred_t *cr,
1276 1274      uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids)
1277 1275  {
1278 1276          int access, mapaccess;
1279 1277          struct secinfo *sp;
1280 1278          int i, flavor, perm;
1281 1279          int authnone_entry = -1;
1282 1280  
1283 1281          /*
1284 1282           * By default root is mapped to anonymous user.
1285 1283           * This might get overriden later in nfsauth_cache_get().
1286 1284           */
1287 1285          if (crgetuid(cr) == 0) {
1288 1286                  if (uid != NULL)
1289 1287                          *uid = exi->exi_export.ex_anon;
1290 1288                  if (gid != NULL)
1291 1289                          *gid = exi->exi_export.ex_anon;
1292 1290          } else {
1293 1291                  if (uid != NULL)
1294 1292                          *uid = crgetuid(cr);
1295 1293                  if (gid != NULL)
1296 1294                          *gid = crgetgid(cr);
1297 1295          }
1298 1296  
1299 1297          if (ngids != NULL)
1300 1298                  *ngids = 0;
1301 1299          if (gids != NULL)
1302 1300                  *gids = NULL;
1303 1301  
1304 1302          /*
1305 1303           *  Get the nfs flavor number from xprt.
1306 1304           */
1307 1305          flavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
1308 1306  
1309 1307          /*
1310 1308           * First check the access restrictions on the filesystem.  If
1311 1309           * there are no lists associated with this flavor then there's no
1312 1310           * need to make an expensive call to the nfsauth service or to
1313 1311           * cache anything.
1314 1312           */
1315 1313  
1316 1314          sp = exi->exi_export.ex_secinfo;
1317 1315          for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
1318 1316                  if (flavor != sp[i].s_secinfo.sc_nfsnum) {
1319 1317                          if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE)
1320 1318                                  authnone_entry = i;
1321 1319                          continue;
1322 1320                  }
1323 1321                  break;
1324 1322          }
1325 1323  
1326 1324          mapaccess = 0;
1327 1325  
1328 1326          if (i >= exi->exi_export.ex_seccnt) {
1329 1327                  /*
1330 1328                   * Flavor not found, but use AUTH_NONE if it exists
1331 1329                   */
1332 1330                  if (authnone_entry == -1)
1333 1331                          return (NFSAUTH_DENIED);
1334 1332                  flavor = AUTH_NONE;
1335 1333                  mapaccess = NFSAUTH_MAPNONE;
1336 1334                  i = authnone_entry;
1337 1335          }
1338 1336  
1339 1337          /*
1340 1338           * If the flavor is in the ex_secinfo list, but not an explicitly
1341 1339           * shared flavor by the user, it is a result of the nfsv4 server
1342 1340           * namespace setup. We will grant an RO permission similar for
1343 1341           * a pseudo node except that this node is a shared one.
1344 1342           *
1345 1343           * e.g. flavor in (flavor) indicates that it is not explictly
1346 1344           *      shared by the user:
1347 1345           *
1348 1346           *              /       (sys, krb5)
1349 1347           *              |
1350 1348           *              export  #share -o sec=sys (krb5)
1351 1349           *              |
1352 1350           *              secure  #share -o sec=krb5
1353 1351           *
1354 1352           *      In this case, when a krb5 request coming in to access
1355 1353           *      /export, RO permission is granted.
1356 1354           */
1357 1355          if (!(sp[i].s_flags & M_4SEC_EXPORTED))
1358 1356                  return (mapaccess | NFSAUTH_RO);
1359 1357  
1360 1358          /*
1361 1359           * Optimize if there are no lists.
1362 1360           * We cannot optimize for AUTH_SYS with NGRPS (16) supplemental groups.
1363 1361           */
1364 1362          perm = sp[i].s_flags;
1365 1363          if ((perm & (M_ROOT | M_NONE | M_MAP)) == 0 && (ngroups_max <= NGRPS ||
1366 1364              flavor != AUTH_SYS || crgetngroups(cr) < NGRPS)) {
1367 1365                  perm &= ~M_4SEC_EXPORTED;
1368 1366                  if (perm == M_RO)
1369 1367                          return (mapaccess | NFSAUTH_RO);
1370 1368                  if (perm == M_RW)
1371 1369                          return (mapaccess | NFSAUTH_RW);
1372 1370          }
1373 1371  
1374 1372          access = nfsauth_cache_get(exi, req, flavor, cr, uid, gid, ngids, gids);
1375 1373  
1376 1374          /*
1377 1375           * For both NFSAUTH_DENIED and NFSAUTH_WRONGSEC we do not care about
1378 1376           * the supplemental groups.
1379 1377           */
1380 1378          if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) {
1381 1379                  if (ngids != NULL && gids != NULL) {
1382 1380                          kmem_free(*gids, *ngids * sizeof (gid_t));
1383 1381                          *ngids = 0;
1384 1382                          *gids = NULL;
1385 1383                  }
1386 1384          }
1387 1385  
1388 1386          /*
1389 1387           * Client's security flavor doesn't match with "ro" or
1390 1388           * "rw" list. Try again using AUTH_NONE if present.
1391 1389           */
1392 1390          if ((access & NFSAUTH_WRONGSEC) && (flavor != AUTH_NONE)) {
1393 1391                  /*
1394 1392                   * Have we already encountered AUTH_NONE ?
1395 1393                   */
1396 1394                  if (authnone_entry != -1) {
1397 1395                          mapaccess = NFSAUTH_MAPNONE;
1398 1396                          access = nfsauth_cache_get(exi, req, AUTH_NONE, cr,
1399 1397                              NULL, NULL, NULL, NULL);
1400 1398                  } else {
1401 1399                          /*
1402 1400                           * Check for AUTH_NONE presence.
1403 1401                           */
1404 1402                          for (; i < exi->exi_export.ex_seccnt; i++) {
1405 1403                                  if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) {
1406 1404                                          mapaccess = NFSAUTH_MAPNONE;
1407 1405                                          access = nfsauth_cache_get(exi, req,
1408 1406                                              AUTH_NONE, cr, NULL, NULL, NULL,
1409 1407                                              NULL);
1410 1408                                          break;
1411 1409                                  }
1412 1410                          }
1413 1411                  }
1414 1412          }
1415 1413  
1416 1414          if (access & NFSAUTH_DENIED)
1417 1415                  access = NFSAUTH_DENIED;
1418 1416  
1419 1417          return (access | mapaccess);
1420 1418  }
1421 1419  
1422 1420  static void
1423 1421  nfsauth_free_clnt_node(struct auth_cache_clnt *p)
1424 1422  {
1425 1423          void *cookie = NULL;
1426 1424          struct auth_cache *node;
1427 1425  
1428 1426          while ((node = avl_destroy_nodes(&p->authc_tree, &cookie)) != NULL)
1429 1427                  nfsauth_free_node(node);
1430 1428          avl_destroy(&p->authc_tree);
1431 1429  
1432 1430          kmem_free(p->authc_addr.buf, p->authc_addr.maxlen);
1433 1431          rw_destroy(&p->authc_lock);
1434 1432  
1435 1433          kmem_free(p, sizeof (*p));
1436 1434  }
1437 1435  
1438 1436  static void
1439 1437  nfsauth_free_node(struct auth_cache *p)
1440 1438  {
1441 1439          crfree(p->auth_clnt_cred);
1442 1440          kmem_free(p->auth_srv_gids, p->auth_srv_ngids * sizeof (gid_t));
1443 1441          mutex_destroy(&p->auth_lock);
1444 1442          cv_destroy(&p->auth_cv);
1445 1443          kmem_cache_free(exi_cache_handle, p);
1446 1444  }
1447 1445  
1448 1446  /*
1449 1447   * Free the nfsauth cache for a given export
1450 1448   */
1451 1449  void
1452 1450  nfsauth_cache_free(struct exportinfo *exi)
1453 1451  {
1454 1452          int i;
1455 1453  
1456 1454          /*
1457 1455           * The only way we got here was with an exi_rele, which means that no
1458 1456           * auth cache entry is being refreshed.
1459 1457           */
1460 1458  
1461 1459          for (i = 0; i < AUTH_TABLESIZE; i++) {
1462 1460                  avl_tree_t *tree = exi->exi_cache[i];
1463 1461                  void *cookie = NULL;
1464 1462                  struct auth_cache_clnt *node;
1465 1463  
1466 1464                  while ((node = avl_destroy_nodes(tree, &cookie)) != NULL)
1467 1465                          nfsauth_free_clnt_node(node);
1468 1466          }
1469 1467  }
1470 1468  
1471 1469  /*
1472 1470   * Called by the kernel memory allocator when memory is low.
1473 1471   * Free unused cache entries. If that's not enough, the VM system
1474 1472   * will call again for some more.
1475 1473   *
1476 1474   * This needs to operate on all zones, so we take a reader lock
1477 1475   * on the list of zones and walk the list.  This is OK here
1478 1476   * becuase exi_cache_trim doesn't block or cause new objects
1479 1477   * to be allocated (basically just frees lots of stuff).
1480 1478   * Use care if nfssrv_globals_rwl is taken as reader in any
1481 1479   * other cases because it will block nfs_server_zone_init
1482 1480   * and nfs_server_zone_fini, which enter as writer.
1483 1481   */
1484 1482  /*ARGSUSED*/
1485 1483  void
1486 1484  exi_cache_reclaim(void *cdrarg)
1487 1485  {
1488 1486          nfs_globals_t *ng;
1489 1487  
1490 1488          rw_enter(&nfssrv_globals_rwl, RW_READER);
1491 1489  
1492 1490          ng = list_head(&nfssrv_globals_list);
1493 1491          while (ng != NULL) {
1494 1492                  exi_cache_reclaim_zone(ng);
1495 1493                  ng = list_next(&nfssrv_globals_list, ng);
1496 1494          }
1497 1495  
1498 1496          rw_exit(&nfssrv_globals_rwl);
1499 1497  }
1500 1498  
1501 1499  static void
1502 1500  exi_cache_reclaim_zone(nfs_globals_t *ng)
1503 1501  {
1504 1502          int i;
1505 1503          struct exportinfo *exi;
1506 1504          nfs_export_t *ne = ng->nfs_export;
1507 1505  
1508 1506          rw_enter(&ne->exported_lock, RW_READER);
1509 1507  
1510 1508          for (i = 0; i < EXPTABLESIZE; i++) {
1511 1509                  for (exi = ne->exptable[i]; exi; exi = exi->fid_hash.next)
1512 1510                          exi_cache_trim(exi);
1513 1511          }
1514 1512  
1515 1513          rw_exit(&ne->exported_lock);
1516 1514  
1517 1515          atomic_inc_uint(&nfsauth_cache_reclaim);
1518 1516  }
1519 1517  
1520 1518  static void
1521 1519  exi_cache_trim(struct exportinfo *exi)
1522 1520  {
1523 1521          struct auth_cache_clnt *c;
1524 1522          struct auth_cache_clnt *nextc;
1525 1523          struct auth_cache *p;
1526 1524          struct auth_cache *next;
1527 1525          int i;
1528 1526          time_t stale_time;
1529 1527          avl_tree_t *tree;
1530 1528  
1531 1529          for (i = 0; i < AUTH_TABLESIZE; i++) {
1532 1530                  tree = exi->exi_cache[i];
1533 1531                  stale_time = gethrestime_sec() - NFSAUTH_CACHE_TRIM;
1534 1532                  rw_enter(&exi->exi_cache_lock, RW_READER);
1535 1533  
1536 1534                  /*
1537 1535                   * Free entries that have not been
1538 1536                   * used for NFSAUTH_CACHE_TRIM seconds.
1539 1537                   */
1540 1538                  for (c = avl_first(tree); c != NULL; c = AVL_NEXT(tree, c)) {
1541 1539                          /*
1542 1540                           * We are being called by the kmem subsystem to reclaim
1543 1541                           * memory so don't block if we can't get the lock.
1544 1542                           */
1545 1543                          if (rw_tryenter(&c->authc_lock, RW_WRITER) == 0) {
1546 1544                                  exi_cache_auth_reclaim_failed++;
1547 1545                                  rw_exit(&exi->exi_cache_lock);
1548 1546                                  return;
1549 1547                          }
1550 1548  
1551 1549                          for (p = avl_first(&c->authc_tree); p != NULL;
1552 1550                              p = next) {
1553 1551                                  next = AVL_NEXT(&c->authc_tree, p);
1554 1552  
1555 1553                                  ASSERT(p->auth_state != NFS_AUTH_INVALID);
1556 1554  
1557 1555                                  mutex_enter(&p->auth_lock);
1558 1556  
1559 1557                                  /*
1560 1558                                   * We won't trim recently used and/or WAITING
1561 1559                                   * entries.
1562 1560                                   */
1563 1561                                  if (p->auth_time > stale_time ||
1564 1562                                      p->auth_state == NFS_AUTH_WAITING) {
1565 1563                                          mutex_exit(&p->auth_lock);
1566 1564                                          continue;
1567 1565                                  }
1568 1566  
1569 1567                                  DTRACE_PROBE1(nfsauth__debug__trim__state,
1570 1568                                      auth_state_t, p->auth_state);
1571 1569  
1572 1570                                  /*
1573 1571                                   * STALE and REFRESHING entries needs to be
1574 1572                                   * marked INVALID only because they are
1575 1573                                   * referenced by some other structures or
1576 1574                                   * threads.  They will be freed later.
1577 1575                                   */
1578 1576                                  if (p->auth_state == NFS_AUTH_STALE ||
1579 1577                                      p->auth_state == NFS_AUTH_REFRESHING) {
1580 1578                                          p->auth_state = NFS_AUTH_INVALID;
1581 1579                                          mutex_exit(&p->auth_lock);
1582 1580  
1583 1581                                          avl_remove(&c->authc_tree, p);
1584 1582                                  } else {
1585 1583                                          mutex_exit(&p->auth_lock);
1586 1584  
1587 1585                                          avl_remove(&c->authc_tree, p);
1588 1586                                          nfsauth_free_node(p);
1589 1587                                  }
1590 1588                          }
1591 1589                          rw_exit(&c->authc_lock);
1592 1590                  }
1593 1591  
1594 1592                  if (rw_tryupgrade(&exi->exi_cache_lock) == 0) {
1595 1593                          rw_exit(&exi->exi_cache_lock);
1596 1594                          exi_cache_clnt_reclaim_failed++;
1597 1595                          continue;
1598 1596                  }
1599 1597  
1600 1598                  for (c = avl_first(tree); c != NULL; c = nextc) {
1601 1599                          nextc = AVL_NEXT(tree, c);
1602 1600  
1603 1601                          if (avl_is_empty(&c->authc_tree) == B_FALSE)
1604 1602                                  continue;
1605 1603  
1606 1604                          avl_remove(tree, c);
1607 1605  
1608 1606                          nfsauth_free_clnt_node(c);
1609 1607                  }
1610 1608  
1611 1609                  rw_exit(&exi->exi_cache_lock);
1612 1610          }
1613 1611  }
  
    | 
      ↓ open down ↓ | 
    529 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX