Print this page
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16

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
↓ open down ↓ 12 lines elided ↑ open up ↑
  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      - * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  24   23   * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
  25   24   * Copyright (c) 2015 by Delphix. All rights reserved.
  26   25   * Copyright (c) 2015 Joyent, Inc.  All rights reserved.
       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>
↓ open down ↓ 9 lines elided ↑ open up ↑
  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 +static void exi_cache_reclaim_zone(nfs_globals_t *);
  56   57  static void exi_cache_trim(struct exportinfo *exi);
  57   58  
  58   59  extern pri_t minclsyspri;
  59   60  
       61 +/* NFS auth cache statistics */
  60   62  volatile uint_t nfsauth_cache_hit;
  61   63  volatile uint_t nfsauth_cache_miss;
  62   64  volatile uint_t nfsauth_cache_refresh;
  63   65  volatile uint_t nfsauth_cache_reclaim;
  64   66  volatile uint_t exi_cache_auth_reclaim_failed;
  65   67  volatile uint_t exi_cache_clnt_reclaim_failed;
  66   68  
  67   69  /*
  68   70   * The lifetime of an auth cache entry:
  69   71   * ------------------------------------
↓ open down ↓ 43 lines elided ↑ open up ↑
 113  115          list_node_t             ren_node;
 114  116  } refreshq_exi_node_t;
 115  117  
 116  118  typedef struct refreshq_auth_node {
 117  119          struct auth_cache       *ran_auth;
 118  120          char                    *ran_netid;
 119  121          list_node_t             ran_node;
 120  122  } refreshq_auth_node_t;
 121  123  
 122  124  /*
 123      - * Used to manipulate things on the refreshq_queue.
 124      - * Note that the refresh thread will effectively
 125      - * pop a node off of the queue, at which point it
      125 + * Used to manipulate things on the refreshq_queue.  Note that the refresh
      126 + * thread will effectively pop a node off of the queue, at which point it
 126  127   * will no longer need to hold the mutex.
 127  128   */
 128  129  static kmutex_t refreshq_lock;
 129  130  static list_t refreshq_queue;
 130  131  static kcondvar_t refreshq_cv;
 131  132  
 132  133  /*
 133      - * If there is ever a problem with loading the
 134      - * module, then nfsauth_fini() needs to be called
 135      - * to remove state. In that event, since the
 136      - * refreshq thread has been started, they need to
 137      - * work together to get rid of state.
      134 + * If there is ever a problem with loading the module, then nfsauth_fini()
      135 + * needs to be called to remove state.  In that event, since the refreshq
      136 + * thread has been started, they need to work together to get rid of state.
 138  137   */
 139  138  typedef enum nfsauth_refreshq_thread_state {
 140  139          REFRESHQ_THREAD_RUNNING,
 141  140          REFRESHQ_THREAD_FINI_REQ,
 142      -        REFRESHQ_THREAD_HALTED
      141 +        REFRESHQ_THREAD_HALTED,
      142 +        REFRESHQ_THREAD_NEED_CREATE
 143  143  } nfsauth_refreshq_thread_state_t;
 144  144  
 145      -nfsauth_refreshq_thread_state_t
 146      -refreshq_thread_state = REFRESHQ_THREAD_HALTED;
      145 +typedef struct nfsauth_globals {
      146 +        kmutex_t        mountd_lock;
      147 +        door_handle_t   mountd_dh;
 147  148  
      149 +        /*
      150 +         * Used to manipulate things on the refreshq_queue.  Note that the
      151 +         * refresh thread will effectively pop a node off of the queue,
      152 +         * at which point it will no longer need to hold the mutex.
      153 +         */
      154 +        kmutex_t        refreshq_lock;
      155 +        list_t          refreshq_queue;
      156 +        kcondvar_t      refreshq_cv;
      157 +
      158 +        /*
      159 +         * A list_t would be overkill.  These are auth_cache entries which are
      160 +         * no longer linked to an exi.  It should be the case that all of their
      161 +         * states are NFS_AUTH_INVALID, i.e., the only way to be put on this
      162 +         * list is iff their state indicated that they had been placed on the
      163 +         * refreshq_queue.
      164 +         *
      165 +         * Note that while there is no link from the exi or back to the exi,
      166 +         * the exi can not go away until these entries are harvested.
      167 +         */
      168 +        struct auth_cache               *refreshq_dead_entries;
      169 +        nfsauth_refreshq_thread_state_t refreshq_thread_state;
      170 +
      171 +} nfsauth_globals_t;
      172 +
 148  173  static void nfsauth_free_node(struct auth_cache *);
 149      -static void nfsauth_refresh_thread(void);
      174 +static void nfsauth_refresh_thread(nfsauth_globals_t *);
 150  175  
 151  176  static int nfsauth_cache_compar(const void *, const void *);
 152  177  
 153      -/*
 154      - * mountd is a server-side only daemon. This will need to be
 155      - * revisited if the NFS server is ever made zones-aware.
 156      - */
 157      -kmutex_t        mountd_lock;
 158      -door_handle_t   mountd_dh;
      178 +static nfsauth_globals_t *
      179 +nfsauth_get_zg(void)
      180 +{
      181 +        nfs_globals_t *ng = nfs_srv_getzg();
      182 +        nfsauth_globals_t *nag = ng->nfs_auth;
      183 +        ASSERT(nag != NULL);
      184 +        return (nag);
      185 +}
 159  186  
 160  187  void
 161  188  mountd_args(uint_t did)
 162  189  {
 163      -        mutex_enter(&mountd_lock);
 164      -        if (mountd_dh != NULL)
 165      -                door_ki_rele(mountd_dh);
 166      -        mountd_dh = door_ki_lookup(did);
 167      -        mutex_exit(&mountd_lock);
      190 +        nfsauth_globals_t *nag;
      191 +
      192 +        nag = nfsauth_get_zg();
      193 +        mutex_enter(&nag->mountd_lock);
      194 +        if (nag->mountd_dh != NULL)
      195 +                door_ki_rele(nag->mountd_dh);
      196 +        nag->mountd_dh = door_ki_lookup(did);
      197 +        mutex_exit(&nag->mountd_lock);
 168  198  }
 169  199  
 170  200  void
 171  201  nfsauth_init(void)
 172  202  {
 173      -        /*
 174      -         * mountd can be restarted by smf(5). We need to make sure
 175      -         * the updated door handle will safely make it to mountd_dh
 176      -         */
 177      -        mutex_init(&mountd_lock, NULL, MUTEX_DEFAULT, NULL);
      203 +        exi_cache_handle = kmem_cache_create("exi_cache_handle",
      204 +            sizeof (struct auth_cache), 0, NULL, NULL,
      205 +            exi_cache_reclaim, NULL, NULL, 0);
      206 +}
 178  207  
 179      -        mutex_init(&refreshq_lock, NULL, MUTEX_DEFAULT, NULL);
 180      -        list_create(&refreshq_queue, sizeof (refreshq_exi_node_t),
 181      -            offsetof(refreshq_exi_node_t, ren_node));
      208 +void
      209 +nfsauth_fini(void)
      210 +{
      211 +        kmem_cache_destroy(exi_cache_handle);
      212 +}
 182  213  
 183      -        cv_init(&refreshq_cv, NULL, CV_DEFAULT, NULL);
      214 +void
      215 +nfsauth_zone_init(nfs_globals_t *ng)
      216 +{
      217 +        nfsauth_globals_t *nag;
 184  218  
      219 +        nag = kmem_zalloc(sizeof (*nag), KM_SLEEP);
      220 +
 185  221          /*
 186      -         * Allocate nfsauth cache handle
      222 +         * mountd can be restarted by smf(5).  We need to make sure
      223 +         * the updated door handle will safely make it to mountd_dh.
 187  224           */
 188      -        exi_cache_handle = kmem_cache_create("exi_cache_handle",
 189      -            sizeof (struct auth_cache), 0, NULL, NULL,
 190      -            exi_cache_reclaim, NULL, NULL, 0);
      225 +        mutex_init(&nag->mountd_lock, NULL, MUTEX_DEFAULT, NULL);
      226 +        mutex_init(&nag->refreshq_lock, NULL, MUTEX_DEFAULT, NULL);
      227 +        list_create(&nag->refreshq_queue, sizeof (refreshq_exi_node_t),
      228 +            offsetof(refreshq_exi_node_t, ren_node));
      229 +        cv_init(&nag->refreshq_cv, NULL, CV_DEFAULT, NULL);
      230 +        nag->refreshq_thread_state = REFRESHQ_THREAD_NEED_CREATE;
 191  231  
 192      -        refreshq_thread_state = REFRESHQ_THREAD_RUNNING;
 193      -        (void) zthread_create(NULL, 0, nfsauth_refresh_thread,
 194      -            NULL, 0, minclsyspri);
      232 +        ng->nfs_auth = nag;
 195  233  }
 196  234  
 197      -/*
 198      - * Finalization routine for nfsauth. It is important to call this routine
 199      - * before destroying the exported_lock.
 200      - */
 201  235  void
 202      -nfsauth_fini(void)
      236 +nfsauth_zone_shutdown(nfs_globals_t *ng)
 203  237  {
 204  238          refreshq_exi_node_t     *ren;
      239 +        nfsauth_globals_t       *nag = ng->nfs_auth;
 205  240  
 206      -        /*
 207      -         * Prevent the nfsauth_refresh_thread from getting new
 208      -         * work.
 209      -         */
 210      -        mutex_enter(&refreshq_lock);
 211      -        if (refreshq_thread_state != REFRESHQ_THREAD_HALTED) {
 212      -                refreshq_thread_state = REFRESHQ_THREAD_FINI_REQ;
 213      -                cv_broadcast(&refreshq_cv);
      241 +        /* Prevent the nfsauth_refresh_thread from getting new work */
      242 +        mutex_enter(&nag->refreshq_lock);
      243 +        if (nag->refreshq_thread_state == REFRESHQ_THREAD_RUNNING) {
      244 +                nag->refreshq_thread_state = REFRESHQ_THREAD_FINI_REQ;
      245 +                cv_broadcast(&nag->refreshq_cv);
 214  246  
 215      -                /*
 216      -                 * Also, wait for nfsauth_refresh_thread() to exit.
 217      -                 */
 218      -                while (refreshq_thread_state != REFRESHQ_THREAD_HALTED) {
 219      -                        cv_wait(&refreshq_cv, &refreshq_lock);
 220      -                }
      247 +                /* Wait for nfsauth_refresh_thread() to exit */
      248 +                while (nag->refreshq_thread_state != REFRESHQ_THREAD_HALTED)
      249 +                        cv_wait(&nag->refreshq_cv, &nag->refreshq_lock);
 221  250          }
 222      -        mutex_exit(&refreshq_lock);
      251 +        mutex_exit(&nag->refreshq_lock);
 223  252  
 224  253          /*
 225  254           * Walk the exi_list and in turn, walk the auth_lists and free all
 226  255           * lists.  In addition, free INVALID auth_cache entries.
 227  256           */
 228      -        while ((ren = list_remove_head(&refreshq_queue))) {
      257 +        while ((ren = list_remove_head(&nag->refreshq_queue))) {
 229  258                  refreshq_auth_node_t *ran;
 230  259  
 231  260                  while ((ran = list_remove_head(&ren->ren_authlist)) != NULL) {
 232  261                          struct auth_cache *p = ran->ran_auth;
 233  262                          if (p->auth_state == NFS_AUTH_INVALID)
 234  263                                  nfsauth_free_node(p);
 235  264                          strfree(ran->ran_netid);
 236      -                        kmem_free(ran, sizeof (refreshq_auth_node_t));
      265 +                        kmem_free(ran, sizeof (*ran));
 237  266                  }
 238  267  
 239  268                  list_destroy(&ren->ren_authlist);
 240  269                  exi_rele(ren->ren_exi);
 241      -                kmem_free(ren, sizeof (refreshq_exi_node_t));
      270 +                kmem_free(ren, sizeof (*ren));
 242  271          }
 243      -        list_destroy(&refreshq_queue);
      272 +}
 244  273  
 245      -        cv_destroy(&refreshq_cv);
 246      -        mutex_destroy(&refreshq_lock);
      274 +void
      275 +nfsauth_zone_fini(nfs_globals_t *ng)
      276 +{
      277 +        nfsauth_globals_t *nag = ng->nfs_auth;
 247  278  
 248      -        mutex_destroy(&mountd_lock);
      279 +        ng->nfs_auth = NULL;
 249  280  
 250      -        /*
 251      -         * Deallocate nfsauth cache handle
 252      -         */
 253      -        kmem_cache_destroy(exi_cache_handle);
      281 +        list_destroy(&nag->refreshq_queue);
      282 +        cv_destroy(&nag->refreshq_cv);
      283 +        mutex_destroy(&nag->refreshq_lock);
      284 +        mutex_destroy(&nag->mountd_lock);
      285 +        /* Extra cleanup. */
      286 +        if (nag->mountd_dh != NULL)
      287 +                door_ki_rele(nag->mountd_dh);
      288 +        kmem_free(nag, sizeof (*nag));
 254  289  }
 255  290  
 256  291  /*
 257  292   * Convert the address in a netbuf to
 258  293   * a hash index for the auth_cache table.
 259  294   */
 260  295  static int
 261  296  hash(struct netbuf *a)
 262  297  {
 263  298          int i, h = 0;
↓ open down ↓ 71 lines elided ↑ open up ↑
 335  370          if ((tstamp + 60) < now) {
 336  371                  tstamp = now;
 337  372                  cmn_err(CE_WARN, msg);
 338  373          }
 339  374  }
 340  375  
 341  376  /*
 342  377   * Callup to the mountd to get access information in the kernel.
 343  378   */
 344  379  static bool_t
 345      -nfsauth_retrieve(struct exportinfo *exi, char *req_netid, int flavor,
 346      -    struct netbuf *addr, int *access, cred_t *clnt_cred, uid_t *srv_uid,
 347      -    gid_t *srv_gid, uint_t *srv_gids_cnt, gid_t **srv_gids)
      380 +nfsauth_retrieve(nfsauth_globals_t *nag, struct exportinfo *exi,
      381 +    char *req_netid, int flavor, struct netbuf *addr, int *access,
      382 +    cred_t *clnt_cred, uid_t *srv_uid, gid_t *srv_gid, uint_t *srv_gids_cnt,
      383 +    gid_t **srv_gids)
 348  384  {
 349  385          varg_t                    varg = {0};
 350  386          nfsauth_res_t             res = {0};
 351  387          XDR                       xdrs;
 352  388          size_t                    absz;
 353  389          caddr_t                   abuf;
 354  390          int                       last = 0;
 355  391          door_arg_t                da;
 356  392          door_info_t               di;
 357  393          door_handle_t             dh;
↓ open down ↓ 52 lines elided ↑ open up ↑
 410  446           * expected and doesn't pass the data to us.
 411  447           */
 412  448          da.data_ptr = (char *)abuf;
 413  449          da.data_size = absz;
 414  450          da.desc_ptr = NULL;
 415  451          da.desc_num = 0;
 416  452          da.rbuf = NULL;
 417  453          da.rsize = 1;
 418  454  
 419  455  retry:
 420      -        mutex_enter(&mountd_lock);
 421      -        dh = mountd_dh;
      456 +        mutex_enter(&nag->mountd_lock);
      457 +        dh = nag->mountd_dh;
 422  458          if (dh != NULL)
 423  459                  door_ki_hold(dh);
 424      -        mutex_exit(&mountd_lock);
      460 +        mutex_exit(&nag->mountd_lock);
 425  461  
 426  462          if (dh == NULL) {
 427  463                  /*
 428  464                   * The rendezvous point has not been established yet!
 429  465                   * This could mean that either mountd(1m) has not yet
 430  466                   * been started or that _this_ routine nuked the door
 431  467                   * handle after receiving an EINTR for a REVOKED door.
 432  468                   *
 433  469                   * Returning NFSAUTH_DROP will cause the NFS client
 434  470                   * to retransmit the request, so let's try to be more
↓ open down ↓ 49 lines elided ↑ open up ↑
 484  520                          door_ki_rele(dh);
 485  521  
 486  522                          if (di.di_attributes & DOOR_REVOKED) {
 487  523                                  /*
 488  524                                   * The server barfed and revoked
 489  525                                   * the (existing) door on us; we
 490  526                                   * want to wait to give smf(5) a
 491  527                                   * chance to restart mountd(1m)
 492  528                                   * and establish a new door handle.
 493  529                                   */
 494      -                                mutex_enter(&mountd_lock);
 495      -                                if (dh == mountd_dh) {
 496      -                                        door_ki_rele(mountd_dh);
 497      -                                        mountd_dh = NULL;
      530 +                                mutex_enter(&nag->mountd_lock);
      531 +                                if (dh == nag->mountd_dh) {
      532 +                                        door_ki_rele(nag->mountd_dh);
      533 +                                        nag->mountd_dh = NULL;
 498  534                                  }
 499      -                                mutex_exit(&mountd_lock);
      535 +                                mutex_exit(&nag->mountd_lock);
 500  536                                  delay(hz);
 501  537                                  goto retry;
 502  538                          }
 503  539                          /*
 504  540                           * If the door was _not_ revoked on us,
 505  541                           * then more than likely we took an INTR,
 506  542                           * so we need to fail the operation.
 507  543                           */
 508  544                          goto fail;
 509  545                  }
↓ open down ↓ 76 lines elided ↑ open up ↑
 586  622                          /* NOTREACHED */
 587  623          }
 588  624  
 589  625          xdr_free(xdr_nfsauth_res, (char *)&res);
 590  626          kmem_free(abuf, absz);
 591  627  
 592  628          return (TRUE);
 593  629  }
 594  630  
 595  631  static void
 596      -nfsauth_refresh_thread(void)
      632 +nfsauth_refresh_thread(nfsauth_globals_t *nag)
 597  633  {
 598  634          refreshq_exi_node_t     *ren;
 599  635          refreshq_auth_node_t    *ran;
 600  636  
 601  637          struct exportinfo       *exi;
 602  638  
 603  639          int                     access;
 604  640          bool_t                  retrieval;
 605  641  
 606  642          callb_cpr_t             cprinfo;
 607  643  
 608      -        CALLB_CPR_INIT(&cprinfo, &refreshq_lock, callb_generic_cpr,
      644 +        CALLB_CPR_INIT(&cprinfo, &nag->refreshq_lock, callb_generic_cpr,
 609  645              "nfsauth_refresh");
 610  646  
 611  647          for (;;) {
 612      -                mutex_enter(&refreshq_lock);
 613      -                if (refreshq_thread_state != REFRESHQ_THREAD_RUNNING) {
      648 +                mutex_enter(&nag->refreshq_lock);
      649 +                if (nag->refreshq_thread_state != REFRESHQ_THREAD_RUNNING) {
 614  650                          /* Keep the hold on the lock! */
 615  651                          break;
 616  652                  }
 617  653  
 618      -                ren = list_remove_head(&refreshq_queue);
      654 +                ren = list_remove_head(&nag->refreshq_queue);
 619  655                  if (ren == NULL) {
 620  656                          CALLB_CPR_SAFE_BEGIN(&cprinfo);
 621      -                        cv_wait(&refreshq_cv, &refreshq_lock);
 622      -                        CALLB_CPR_SAFE_END(&cprinfo, &refreshq_lock);
 623      -                        mutex_exit(&refreshq_lock);
      657 +                        cv_wait(&nag->refreshq_cv, &nag->refreshq_lock);
      658 +                        CALLB_CPR_SAFE_END(&cprinfo, &nag->refreshq_lock);
      659 +                        mutex_exit(&nag->refreshq_lock);
 624  660                          continue;
 625  661                  }
 626      -                mutex_exit(&refreshq_lock);
      662 +                mutex_exit(&nag->refreshq_lock);
 627  663  
 628  664                  exi = ren->ren_exi;
 629  665                  ASSERT(exi != NULL);
 630  666  
 631  667                  /*
 632  668                   * Since the ren was removed from the refreshq_queue above,
 633  669                   * this is the only thread aware about the ren existence, so we
 634  670                   * have the exclusive ownership of it and we do not need to
 635  671                   * protect it by any lock.
 636  672                   */
↓ open down ↓ 26 lines elided ↑ open up ↑
 663  699                           * close to the refreshq_thread_state check.
 664  700                           *
 665  701                           * The check for the refreshq_thread_state value here
 666  702                           * is purely advisory to allow the faster
 667  703                           * nfsauth_refresh_thread() shutdown.  In a case we
 668  704                           * will miss such advisory, nothing catastrophic
 669  705                           * happens: we will just spin longer here before the
 670  706                           * shutdown.
 671  707                           */
 672  708                          if (p->auth_state == NFS_AUTH_INVALID ||
 673      -                            refreshq_thread_state != REFRESHQ_THREAD_RUNNING) {
      709 +                            nag->refreshq_thread_state !=
      710 +                            REFRESHQ_THREAD_RUNNING) {
 674  711                                  mutex_exit(&p->auth_lock);
 675  712  
 676  713                                  if (p->auth_state == NFS_AUTH_INVALID)
 677  714                                          nfsauth_free_node(p);
 678  715  
 679  716                                  strfree(netid);
 680  717  
 681  718                                  continue;
 682  719                          }
 683  720  
↓ open down ↓ 14 lines elided ↑ open up ↑
 698  735                          /*
 699  736                           * The first caching of the access rights
 700  737                           * is done with the netid pulled out of the
 701  738                           * request from the client. All subsequent
 702  739                           * users of the cache may or may not have
 703  740                           * the same netid. It doesn't matter. So
 704  741                           * when we refresh, we simply use the netid
 705  742                           * of the request which triggered the
 706  743                           * refresh attempt.
 707  744                           */
 708      -                        retrieval = nfsauth_retrieve(exi, netid,
      745 +                        retrieval = nfsauth_retrieve(nag, exi, netid,
 709  746                              p->auth_flavor, &p->auth_clnt->authc_addr, &access,
 710  747                              p->auth_clnt_cred, &uid, &gid, &ngids, &gids);
 711  748  
 712  749                          /*
 713  750                           * This can only be set in one other place
 714  751                           * and the state has to be NFS_AUTH_FRESH.
 715  752                           */
 716  753                          strfree(netid);
 717  754  
 718  755                          mutex_enter(&p->auth_lock);
↓ open down ↓ 26 lines elided ↑ open up ↑
 745  782                                  cv_broadcast(&p->auth_cv);
 746  783                                  mutex_exit(&p->auth_lock);
 747  784                          }
 748  785                  }
 749  786  
 750  787                  list_destroy(&ren->ren_authlist);
 751  788                  exi_rele(ren->ren_exi);
 752  789                  kmem_free(ren, sizeof (refreshq_exi_node_t));
 753  790          }
 754  791  
 755      -        refreshq_thread_state = REFRESHQ_THREAD_HALTED;
 756      -        cv_broadcast(&refreshq_cv);
      792 +        nag->refreshq_thread_state = REFRESHQ_THREAD_HALTED;
      793 +        cv_broadcast(&nag->refreshq_cv);
 757  794          CALLB_CPR_EXIT(&cprinfo);
      795 +        DTRACE_PROBE(nfsauth__nfsauth__refresh__thread__exit);
 758  796          zthread_exit();
 759  797  }
 760  798  
 761  799  int
 762  800  nfsauth_cache_clnt_compar(const void *v1, const void *v2)
 763  801  {
 764  802          int c;
 765  803  
 766  804          const struct auth_cache_clnt *a1 = (const struct auth_cache_clnt *)v1;
 767  805          const struct auth_cache_clnt *a2 = (const struct auth_cache_clnt *)v2;
↓ open down ↓ 51 lines elided ↑ open up ↑
 819  857  }
 820  858  
 821  859  /*
 822  860   * Get the access information from the cache or callup to the mountd
 823  861   * to get and cache the access information in the kernel.
 824  862   */
 825  863  static int
 826  864  nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor,
 827  865      cred_t *cr, uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids)
 828  866  {
      867 +        nfsauth_globals_t       *nag;
 829  868          struct netbuf           *taddrmask;
 830  869          struct netbuf           addr;   /* temporary copy of client's address */
 831  870          const struct netbuf     *claddr;
 832  871          avl_tree_t              *tree;
 833  872          struct auth_cache       ac;     /* used as a template for avl_find() */
 834  873          struct auth_cache_clnt  *c;
 835  874          struct auth_cache_clnt  acc;    /* used as a template for avl_find() */
 836  875          struct auth_cache       *p = NULL;
 837  876          int                     access;
 838  877  
 839  878          uid_t                   tmpuid;
 840  879          gid_t                   tmpgid;
 841  880          uint_t                  tmpngids;
 842  881          gid_t                   *tmpgids;
 843  882  
 844  883          avl_index_t             where;  /* used for avl_find()/avl_insert() */
 845  884  
 846  885          ASSERT(cr != NULL);
 847  886  
      887 +        ASSERT3P(curzone->zone_id, ==, exi->exi_zoneid);
      888 +        nag = nfsauth_get_zg();
      889 +
 848  890          /*
 849  891           * Now check whether this client already
 850  892           * has an entry for this flavor in the cache
 851  893           * for this export.
 852  894           * Get the caller's address, mask off the
 853  895           * parts of the address that do not identify
 854  896           * the host (port number, etc), and then hash
 855  897           * it to find the chain of cache entries.
 856  898           */
 857  899  
 858  900          claddr = svc_getrpccaller(req->rq_xprt);
 859  901          addr = *claddr;
 860      -        addr.buf = kmem_alloc(addr.maxlen, KM_SLEEP);
 861      -        bcopy(claddr->buf, addr.buf, claddr->len);
      902 +        if (claddr->len != 0) {
      903 +                addr.buf = kmem_alloc(addr.maxlen, KM_SLEEP);
      904 +                bcopy(claddr->buf, addr.buf, claddr->len);
      905 +        } else {
      906 +                addr.buf = NULL;
      907 +        }
 862  908  
 863  909          SVC_GETADDRMASK(req->rq_xprt, SVC_TATTR_ADDRMASK, (void **)&taddrmask);
 864  910          ASSERT(taddrmask != NULL);
 865  911          addrmask(&addr, taddrmask);
 866  912  
 867  913          ac.auth_flavor = flavor;
 868  914          ac.auth_clnt_cred = crdup(cr);
 869  915  
 870  916          acc.authc_addr = addr;
 871  917  
↓ open down ↓ 125 lines elided ↑ open up ↑
 997 1043                   */
 998 1044                  auth_state_t state = NFS_AUTH_NEW;
 999 1045  
1000 1046                  p->auth_state = NFS_AUTH_WAITING;
1001 1047                  mutex_exit(&p->auth_lock);
1002 1048                  kmem_free(addr.buf, addr.maxlen);
1003 1049                  addr = p->auth_clnt->authc_addr;
1004 1050  
1005 1051                  atomic_inc_uint(&nfsauth_cache_miss);
1006 1052  
1007      -                res = nfsauth_retrieve(exi, svc_getnetid(req->rq_xprt), flavor,
1008      -                    &addr, &access, cr, &tmpuid, &tmpgid, &tmpngids, &tmpgids);
     1053 +                res = nfsauth_retrieve(nag, exi, svc_getnetid(req->rq_xprt),
     1054 +                    flavor, &addr, &access, cr, &tmpuid, &tmpgid, &tmpngids,
     1055 +                    &tmpgids);
1009 1056  
1010 1057                  p->auth_access = access;
1011 1058                  p->auth_time = p->auth_freshness = gethrestime_sec();
1012 1059  
1013 1060                  if (res == TRUE) {
1014 1061                          if (uid != NULL)
1015 1062                                  *uid = tmpuid;
1016 1063                          if (gid != NULL)
1017 1064                                  *gid = tmpgid;
1018 1065                          if (ngids != NULL && gids != NULL) {
↓ open down ↓ 64 lines elided ↑ open up ↑
1083 1130                          DTRACE_PROBE3(nfsauth__debug__cache__stale,
1084 1131                              struct exportinfo *, exi,
1085 1132                              struct auth_cache *, p,
1086 1133                              uint_t, nacr);
1087 1134  
1088 1135                          ran = kmem_alloc(sizeof (refreshq_auth_node_t),
1089 1136                              KM_SLEEP);
1090 1137                          ran->ran_auth = p;
1091 1138                          ran->ran_netid = strdup(svc_getnetid(req->rq_xprt));
1092 1139  
1093      -                        mutex_enter(&refreshq_lock);
     1140 +                        mutex_enter(&nag->refreshq_lock);
     1141 +
     1142 +                        if (nag->refreshq_thread_state ==
     1143 +                            REFRESHQ_THREAD_NEED_CREATE) {
     1144 +                                /* Launch nfsauth refresh thread */
     1145 +                                nag->refreshq_thread_state =
     1146 +                                    REFRESHQ_THREAD_RUNNING;
     1147 +                                (void) zthread_create(NULL, 0,
     1148 +                                    nfsauth_refresh_thread, nag, 0,
     1149 +                                    minclsyspri);
     1150 +                        }
     1151 +
1094 1152                          /*
1095      -                         * We should not add a work queue
1096      -                         * item if the thread is not
1097      -                         * accepting them.
     1153 +                         * We should not add a work queue item if the thread
     1154 +                         * is not accepting them.
1098 1155                           */
1099      -                        if (refreshq_thread_state == REFRESHQ_THREAD_RUNNING) {
     1156 +                        if (nag->refreshq_thread_state ==
     1157 +                            REFRESHQ_THREAD_RUNNING) {
1100 1158                                  refreshq_exi_node_t *ren;
1101 1159  
1102 1160                                  /*
1103 1161                                   * Is there an existing exi_list?
1104 1162                                   */
1105      -                                for (ren = list_head(&refreshq_queue);
     1163 +                                for (ren = list_head(&nag->refreshq_queue);
1106 1164                                      ren != NULL;
1107      -                                    ren = list_next(&refreshq_queue, ren)) {
     1165 +                                    ren = list_next(&nag->refreshq_queue,
     1166 +                                    ren)) {
1108 1167                                          if (ren->ren_exi == exi) {
1109 1168                                                  list_insert_tail(
1110 1169                                                      &ren->ren_authlist, ran);
1111 1170                                                  break;
1112 1171                                          }
1113 1172                                  }
1114 1173  
1115 1174                                  if (ren == NULL) {
1116 1175                                          ren = kmem_alloc(
1117 1176                                              sizeof (refreshq_exi_node_t),
↓ open down ↓ 2 lines elided ↑ open up ↑
1120 1179                                          exi_hold(exi);
1121 1180                                          ren->ren_exi = exi;
1122 1181  
1123 1182                                          list_create(&ren->ren_authlist,
1124 1183                                              sizeof (refreshq_auth_node_t),
1125 1184                                              offsetof(refreshq_auth_node_t,
1126 1185                                              ran_node));
1127 1186  
1128 1187                                          list_insert_tail(&ren->ren_authlist,
1129 1188                                              ran);
1130      -                                        list_insert_tail(&refreshq_queue, ren);
     1189 +                                        list_insert_tail(&nag->refreshq_queue,
     1190 +                                            ren);
1131 1191                                  }
1132 1192  
1133      -                                cv_broadcast(&refreshq_cv);
     1193 +                                cv_broadcast(&nag->refreshq_cv);
1134 1194                          } else {
1135 1195                                  strfree(ran->ran_netid);
1136 1196                                  kmem_free(ran, sizeof (refreshq_auth_node_t));
1137 1197                          }
1138 1198  
1139      -                        mutex_exit(&refreshq_lock);
     1199 +                        mutex_exit(&nag->refreshq_lock);
1140 1200                  } else {
1141 1201                          mutex_exit(&p->auth_lock);
1142 1202                  }
1143 1203  
1144 1204                  nach = atomic_inc_uint_nv(&nfsauth_cache_hit);
1145 1205                  DTRACE_PROBE2(nfsauth__debug__cache__hit,
1146 1206                      uint_t, nach,
1147 1207                      time_t, refresh);
1148 1208  
1149 1209                  kmem_free(addr.buf, addr.maxlen);
↓ open down ↓ 5 lines elided ↑ open up ↑
1155 1215          crfree(ac.auth_clnt_cred);
1156 1216  
1157 1217          /*
1158 1218           * Retrieve the required data without caching.
1159 1219           */
1160 1220  
1161 1221          ASSERT(p == NULL);
1162 1222  
1163 1223          atomic_inc_uint(&nfsauth_cache_miss);
1164 1224  
1165      -        if (nfsauth_retrieve(exi, svc_getnetid(req->rq_xprt), flavor, &addr,
1166      -            &access, cr, &tmpuid, &tmpgid, &tmpngids, &tmpgids)) {
     1225 +        if (nfsauth_retrieve(nag, exi, svc_getnetid(req->rq_xprt), flavor,
     1226 +            &addr, &access, cr, &tmpuid, &tmpgid, &tmpngids, &tmpgids)) {
1167 1227                  if (uid != NULL)
1168 1228                          *uid = tmpuid;
1169 1229                  if (gid != NULL)
1170 1230                          *gid = tmpgid;
1171 1231                  if (ngids != NULL && gids != NULL) {
1172 1232                          *ngids = tmpngids;
1173 1233                          *gids = tmpgids;
1174 1234                  } else {
1175 1235                          kmem_free(tmpgids, tmpngids * sizeof (gid_t));
1176 1236                  }
↓ open down ↓ 226 lines elided ↑ open up ↑
1403 1463                  avl_tree_t *tree = exi->exi_cache[i];
1404 1464                  void *cookie = NULL;
1405 1465                  struct auth_cache_clnt *node;
1406 1466  
1407 1467                  while ((node = avl_destroy_nodes(tree, &cookie)) != NULL)
1408 1468                          nfsauth_free_clnt_node(node);
1409 1469          }
1410 1470  }
1411 1471  
1412 1472  /*
1413      - * Called by the kernel memory allocator when
1414      - * memory is low. Free unused cache entries.
1415      - * If that's not enough, the VM system will
1416      - * call again for some more.
     1473 + * Called by the kernel memory allocator when memory is low.
     1474 + * Free unused cache entries. If that's not enough, the VM system
     1475 + * will call again for some more.
     1476 + *
     1477 + * This needs to operate on all zones, so we take a reader lock
     1478 + * on the list of zones and walk the list.  This is OK here
     1479 + * becuase exi_cache_trim doesn't block or cause new objects
     1480 + * to be allocated (basically just frees lots of stuff).
     1481 + * Use care if nfssrv_globals_rwl is taken as reader in any
     1482 + * other cases because it will block nfs_server_zone_init
     1483 + * and nfs_server_zone_fini, which enter as writer.
1417 1484   */
1418 1485  /*ARGSUSED*/
1419 1486  void
1420 1487  exi_cache_reclaim(void *cdrarg)
1421 1488  {
     1489 +        nfs_globals_t *ng;
     1490 +
     1491 +        rw_enter(&nfssrv_globals_rwl, RW_READER);
     1492 +
     1493 +        ng = list_head(&nfssrv_globals_list);
     1494 +        while (ng != NULL) {
     1495 +                exi_cache_reclaim_zone(ng);
     1496 +                ng = list_next(&nfssrv_globals_list, ng);
     1497 +        }
     1498 +
     1499 +        rw_exit(&nfssrv_globals_rwl);
     1500 +}
     1501 +
     1502 +static void
     1503 +exi_cache_reclaim_zone(nfs_globals_t *ng)
     1504 +{
1422 1505          int i;
1423 1506          struct exportinfo *exi;
     1507 +        nfs_export_t *ne = ng->nfs_export;
1424 1508  
1425      -        rw_enter(&exported_lock, RW_READER);
     1509 +        rw_enter(&ne->exported_lock, RW_READER);
1426 1510  
1427 1511          for (i = 0; i < EXPTABLESIZE; i++) {
1428      -                for (exi = exptable[i]; exi; exi = exi->fid_hash.next) {
     1512 +                for (exi = ne->exptable[i]; exi; exi = exi->fid_hash.next)
1429 1513                          exi_cache_trim(exi);
1430      -                }
1431 1514          }
1432 1515  
1433      -        rw_exit(&exported_lock);
     1516 +        rw_exit(&ne->exported_lock);
1434 1517  
1435 1518          atomic_inc_uint(&nfsauth_cache_reclaim);
1436 1519  }
1437 1520  
1438      -void
     1521 +static void
1439 1522  exi_cache_trim(struct exportinfo *exi)
1440 1523  {
1441 1524          struct auth_cache_clnt *c;
1442 1525          struct auth_cache_clnt *nextc;
1443 1526          struct auth_cache *p;
1444 1527          struct auth_cache *next;
1445 1528          int i;
1446 1529          time_t stale_time;
1447 1530          avl_tree_t *tree;
1448 1531  
↓ open down ↓ 83 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX