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
   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   *
  
    | 
      ↓ 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>
  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>
  
    | 
      ↓ 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   * ------------------------------------
  70   72   *
  71   73   * An auth cache entry is created with both the auth_time
  72   74   * and auth_freshness times set to the current time.
  73   75   *
  74   76   * Upon every client access which results in a hit, the
  75   77   * auth_time will be updated.
  76   78   *
  77   79   * If a client access determines that the auth_freshness
  78   80   * indicates that the entry is STALE, then it will be
  79   81   * refreshed. Note that this will explicitly reset
  80   82   * auth_time.
  81   83   *
  82   84   * When the REFRESH successfully occurs, then the
  83   85   * auth_freshness is updated.
  84   86   *
  85   87   * There are two ways for an entry to leave the cache:
  86   88   *
  87   89   * 1) Purged by an action on the export (remove or changed)
  88   90   * 2) Memory backpressure from the kernel (check against NFSAUTH_CACHE_TRIM)
  89   91   *
  90   92   * For 2) we check the timeout value against auth_time.
  91   93   */
  92   94  
  93   95  /*
  94   96   * Number of seconds until we mark for refresh an auth cache entry.
  95   97   */
  96   98  #define NFSAUTH_CACHE_REFRESH 600
  97   99  
  98  100  /*
  99  101   * Number of idle seconds until we yield to backpressure
 100  102   * to trim a cache entry.
 101  103   */
 102  104  #define NFSAUTH_CACHE_TRIM 3600
 103  105  
 104  106  /*
 105  107   * While we could encapuslate the exi_list inside the
 106  108   * exi structure, we can't do that for the auth_list.
 107  109   * So, to keep things looking clean, we keep them both
 108  110   * in these external lists.
 109  111   */
 110  112  typedef struct refreshq_exi_node {
 111  113          struct exportinfo       *ren_exi;
 112  114          list_t                  ren_authlist;
  
    | 
      ↓ 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;
 264  299  
 265  300          for (i = 0; i < a->len; i++)
 266  301                  h ^= a->buf[i];
 267  302  
 268  303          return (h & (AUTH_TABLESIZE - 1));
 269  304  }
 270  305  
 271  306  /*
 272  307   * Mask out the components of an
 273  308   * address that do not identify
 274  309   * a host. For socket addresses the
 275  310   * masking gets rid of the port number.
 276  311   */
 277  312  static void
 278  313  addrmask(struct netbuf *addr, struct netbuf *mask)
 279  314  {
 280  315          int i;
 281  316  
 282  317          for (i = 0; i < addr->len; i++)
 283  318                  addr->buf[i] &= mask->buf[i];
 284  319  }
 285  320  
 286  321  /*
 287  322   * nfsauth4_access is used for NFS V4 auth checking. Besides doing
 288  323   * the common nfsauth_access(), it will check if the client can
 289  324   * have a limited access to this vnode even if the security flavor
 290  325   * used does not meet the policy.
 291  326   */
 292  327  int
 293  328  nfsauth4_access(struct exportinfo *exi, vnode_t *vp, struct svc_req *req,
 294  329      cred_t *cr, uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids)
 295  330  {
 296  331          int access;
 297  332  
 298  333          access = nfsauth_access(exi, req, cr, uid, gid, ngids, gids);
 299  334  
 300  335          /*
 301  336           * There are cases that the server needs to allow the client
 302  337           * to have a limited view.
 303  338           *
 304  339           * e.g.
 305  340           * /export is shared as "sec=sys,rw=dfs-test-4,sec=krb5,rw"
 306  341           * /export/home is shared as "sec=sys,rw"
 307  342           *
 308  343           * When the client mounts /export with sec=sys, the client
 309  344           * would get a limited view with RO access on /export to see
 310  345           * "home" only because the client is allowed to access
 311  346           * /export/home with auth_sys.
 312  347           */
 313  348          if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) {
 314  349                  /*
 315  350                   * Allow ro permission with LIMITED view if there is a
 316  351                   * sub-dir exported under vp.
 317  352                   */
 318  353                  if (has_visible(exi, vp))
 319  354                          return (NFSAUTH_LIMITED);
 320  355          }
 321  356  
 322  357          return (access);
 323  358  }
 324  359  
 325  360  static void
 326  361  sys_log(const char *msg)
 327  362  {
 328  363          static time_t   tstamp = 0;
 329  364          time_t          now;
 330  365  
 331  366          /*
 332  367           * msg is shown (at most) once per minute
 333  368           */
 334  369          now = gethrestime_sec();
  
    | 
      ↓ 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;
 358  394          uint_t                    ntries = 0;
 359  395  
 360  396          /*
 361  397           * No entry in the cache for this client/flavor
 362  398           * so we need to call the nfsauth service in the
 363  399           * mount daemon.
 364  400           */
 365  401  
 366  402          varg.vers = V_PROTO;
 367  403          varg.arg_u.arg.cmd = NFSAUTH_ACCESS;
 368  404          varg.arg_u.arg.areq.req_client.n_len = addr->len;
 369  405          varg.arg_u.arg.areq.req_client.n_bytes = addr->buf;
 370  406          varg.arg_u.arg.areq.req_netid = req_netid;
 371  407          varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path;
 372  408          varg.arg_u.arg.areq.req_flavor = flavor;
 373  409          varg.arg_u.arg.areq.req_clnt_uid = crgetuid(clnt_cred);
 374  410          varg.arg_u.arg.areq.req_clnt_gid = crgetgid(clnt_cred);
 375  411          varg.arg_u.arg.areq.req_clnt_gids.len = crgetngroups(clnt_cred);
 376  412          varg.arg_u.arg.areq.req_clnt_gids.val = (gid_t *)crgetgroups(clnt_cred);
 377  413  
 378  414          DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg);
 379  415  
 380  416          /*
 381  417           * Setup the XDR stream for encoding the arguments. Notice that
 382  418           * in addition to the args having variable fields (req_netid and
 383  419           * req_path), the argument data structure is itself versioned,
 384  420           * so we need to make sure we can size the arguments buffer
 385  421           * appropriately to encode all the args. If we can't get sizing
 386  422           * info _or_ properly encode the arguments, there's really no
 387  423           * point in continuting, so we fail the request.
 388  424           */
 389  425          if ((absz = xdr_sizeof(xdr_varg, &varg)) == 0) {
 390  426                  *access = NFSAUTH_DENIED;
 391  427                  return (FALSE);
 392  428          }
 393  429  
 394  430          abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP);
 395  431          xdrmem_create(&xdrs, abuf, absz, XDR_ENCODE);
 396  432          if (!xdr_varg(&xdrs, &varg)) {
 397  433                  XDR_DESTROY(&xdrs);
 398  434                  goto fail;
 399  435          }
 400  436          XDR_DESTROY(&xdrs);
 401  437  
 402  438          /*
 403  439           * Prepare the door arguments
 404  440           *
 405  441           * We don't know the size of the message the daemon
 406  442           * will pass back to us.  By setting rbuf to NULL,
 407  443           * we force the door code to allocate a buf of the
 408  444           * appropriate size.  We must set rsize > 0, however,
 409  445           * else the door code acts as if no response was
  
    | 
      ↓ 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
 435  471                   * rescillient and attempt for ntries before we bail.
 436  472                   */
 437  473                  if (++ntries % NFSAUTH_DR_TRYCNT) {
 438  474                          delay(hz);
 439  475                          goto retry;
 440  476                  }
 441  477  
 442  478                  kmem_free(abuf, absz);
 443  479  
 444  480                  sys_log("nfsauth: mountd has not established door");
 445  481                  *access = NFSAUTH_DROP;
 446  482                  return (FALSE);
 447  483          }
 448  484  
 449  485          ntries = 0;
 450  486  
 451  487          /*
 452  488           * Now that we've got what we need, place the call.
 453  489           */
 454  490          switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) {
 455  491          case 0:                         /* Success */
 456  492                  door_ki_rele(dh);
 457  493  
 458  494                  if (da.data_ptr == NULL && da.data_size == 0) {
 459  495                          /*
 460  496                           * The door_return that contained the data
 461  497                           * failed! We're here because of the 2nd
 462  498                           * door_return (w/o data) such that we can
 463  499                           * get control of the thread (and exit
 464  500                           * gracefully).
 465  501                           */
 466  502                          DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil,
 467  503                              door_arg_t *, &da);
 468  504                          goto fail;
 469  505                  }
 470  506  
 471  507                  break;
 472  508  
 473  509          case EAGAIN:
 474  510                  /*
 475  511                   * Server out of resources; back off for a bit
 476  512                   */
 477  513                  door_ki_rele(dh);
 478  514                  delay(hz);
 479  515                  goto retry;
 480  516                  /* NOTREACHED */
 481  517  
 482  518          case EINTR:
 483  519                  if (!door_ki_info(dh, &di)) {
  
    | 
      ↓ 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                  }
 510  546                  /*
 511  547                   * The only failure that can occur from getting
 512  548                   * the door info is EINVAL, so we let the code
 513  549                   * below handle it.
 514  550                   */
 515  551                  /* FALLTHROUGH */
 516  552  
 517  553          case EBADF:
 518  554          case EINVAL:
 519  555          default:
 520  556                  /*
 521  557                   * If we have a stale door handle, give smf a last
 522  558                   * chance to start it by sleeping for a little bit.
 523  559                   * If we're still hosed, we'll fail the call.
 524  560                   *
 525  561                   * Since we're going to reacquire the door handle
 526  562                   * upon the retry, we opt to sleep for a bit and
 527  563                   * _not_ to clear mountd_dh. If mountd restarted
 528  564                   * and was able to set mountd_dh, we should see
 529  565                   * the new instance; if not, we won't get caught
 530  566                   * up in the retry/DELAY loop.
 531  567                   */
 532  568                  door_ki_rele(dh);
 533  569                  if (!last) {
 534  570                          delay(hz);
 535  571                          last++;
 536  572                          goto retry;
 537  573                  }
 538  574                  sys_log("nfsauth: stale mountd door handle");
 539  575                  goto fail;
 540  576          }
 541  577  
 542  578          ASSERT(da.rbuf != NULL);
 543  579  
 544  580          /*
 545  581           * No door errors encountered; setup the XDR stream for decoding
 546  582           * the results. If we fail to decode the results, we've got no
 547  583           * other recourse than to fail the request.
 548  584           */
 549  585          xdrmem_create(&xdrs, da.rbuf, da.rsize, XDR_DECODE);
 550  586          if (!xdr_nfsauth_res(&xdrs, &res)) {
 551  587                  xdr_free(xdr_nfsauth_res, (char *)&res);
 552  588                  XDR_DESTROY(&xdrs);
 553  589                  kmem_free(da.rbuf, da.rsize);
 554  590                  goto fail;
 555  591          }
 556  592          XDR_DESTROY(&xdrs);
 557  593          kmem_free(da.rbuf, da.rsize);
 558  594  
 559  595          DTRACE_PROBE1(nfsserv__func__nfsauth__results, nfsauth_res_t *, &res);
 560  596          switch (res.stat) {
 561  597                  case NFSAUTH_DR_OKAY:
 562  598                          *access = res.ares.auth_perm;
 563  599                          *srv_uid = res.ares.auth_srv_uid;
 564  600                          *srv_gid = res.ares.auth_srv_gid;
 565  601  
 566  602                          if ((*srv_gids_cnt = res.ares.auth_srv_gids.len) != 0) {
 567  603                                  *srv_gids = kmem_alloc(*srv_gids_cnt *
 568  604                                      sizeof (gid_t), KM_SLEEP);
 569  605                                  bcopy(res.ares.auth_srv_gids.val, *srv_gids,
 570  606                                      *srv_gids_cnt * sizeof (gid_t));
 571  607                          } else {
 572  608                                  *srv_gids = NULL;
 573  609                          }
 574  610  
 575  611                          break;
 576  612  
 577  613                  case NFSAUTH_DR_EFAIL:
 578  614                  case NFSAUTH_DR_DECERR:
 579  615                  case NFSAUTH_DR_BADCMD:
 580  616                  default:
 581  617                          xdr_free(xdr_nfsauth_res, (char *)&res);
 582  618  fail:
 583  619                          *access = NFSAUTH_DENIED;
 584  620                          kmem_free(abuf, absz);
 585  621                          return (FALSE);
  
    | 
      ↓ 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                   */
 637  673                  while ((ran = list_remove_head(&ren->ren_authlist))) {
 638  674                          uid_t uid;
 639  675                          gid_t gid;
 640  676                          uint_t ngids;
 641  677                          gid_t *gids;
 642  678                          struct auth_cache *p = ran->ran_auth;
 643  679                          char *netid = ran->ran_netid;
 644  680  
 645  681                          ASSERT(p != NULL);
 646  682                          ASSERT(netid != NULL);
 647  683  
 648  684                          kmem_free(ran, sizeof (refreshq_auth_node_t));
 649  685  
 650  686                          mutex_enter(&p->auth_lock);
 651  687  
 652  688                          /*
 653  689                           * Once the entry goes INVALID, it can not change
 654  690                           * state.
 655  691                           *
 656  692                           * No need to refresh entries also in a case we are
 657  693                           * just shutting down.
 658  694                           *
 659  695                           * In general, there is no need to hold the
 660  696                           * refreshq_lock to test the refreshq_thread_state.  We
 661  697                           * do hold it at other places because there is some
 662  698                           * related thread synchronization (or some other tasks)
  
    | 
      ↓ 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  
 684  721                          /*
 685  722                           * Make sure the state is valid.  Note that once we
 686  723                           * change the state to NFS_AUTH_REFRESHING, no other
 687  724                           * thread will be able to work on this entry.
 688  725                           */
 689  726                          ASSERT(p->auth_state == NFS_AUTH_STALE);
 690  727  
 691  728                          p->auth_state = NFS_AUTH_REFRESHING;
 692  729                          mutex_exit(&p->auth_lock);
 693  730  
 694  731                          DTRACE_PROBE2(nfsauth__debug__cache__refresh,
 695  732                              struct exportinfo *, exi,
 696  733                              struct auth_cache *, p);
 697  734  
  
    | 
      ↓ 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);
 719  756                          if (p->auth_state == NFS_AUTH_INVALID) {
 720  757                                  mutex_exit(&p->auth_lock);
 721  758                                  nfsauth_free_node(p);
 722  759                                  if (retrieval == TRUE)
 723  760                                          kmem_free(gids, ngids * sizeof (gid_t));
 724  761                          } else {
 725  762                                  /*
 726  763                                   * If we got an error, do not reset the
 727  764                                   * time. This will cause the next access
 728  765                                   * check for the client to reschedule this
 729  766                                   * node.
 730  767                                   */
 731  768                                  if (retrieval == TRUE) {
 732  769                                          p->auth_access = access;
 733  770  
 734  771                                          p->auth_srv_uid = uid;
 735  772                                          p->auth_srv_gid = gid;
 736  773                                          kmem_free(p->auth_srv_gids,
 737  774                                              p->auth_srv_ngids * sizeof (gid_t));
 738  775                                          p->auth_srv_ngids = ngids;
 739  776                                          p->auth_srv_gids = gids;
 740  777  
 741  778                                          p->auth_freshness = gethrestime_sec();
 742  779                                  }
 743  780                                  p->auth_state = NFS_AUTH_FRESH;
 744  781  
  
    | 
      ↓ 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;
 768  806  
 769  807          if (a1->authc_addr.len < a2->authc_addr.len)
 770  808                  return (-1);
 771  809          if (a1->authc_addr.len > a2->authc_addr.len)
 772  810                  return (1);
 773  811  
 774  812          c = memcmp(a1->authc_addr.buf, a2->authc_addr.buf, a1->authc_addr.len);
 775  813          if (c < 0)
 776  814                  return (-1);
 777  815          if (c > 0)
 778  816                  return (1);
 779  817  
 780  818          return (0);
 781  819  }
 782  820  
 783  821  static int
 784  822  nfsauth_cache_compar(const void *v1, const void *v2)
 785  823  {
 786  824          int c;
 787  825  
 788  826          const struct auth_cache *a1 = (const struct auth_cache *)v1;
 789  827          const struct auth_cache *a2 = (const struct auth_cache *)v2;
 790  828  
 791  829          if (a1->auth_flavor < a2->auth_flavor)
 792  830                  return (-1);
 793  831          if (a1->auth_flavor > a2->auth_flavor)
 794  832                  return (1);
 795  833  
 796  834          if (crgetuid(a1->auth_clnt_cred) < crgetuid(a2->auth_clnt_cred))
 797  835                  return (-1);
 798  836          if (crgetuid(a1->auth_clnt_cred) > crgetuid(a2->auth_clnt_cred))
 799  837                  return (1);
 800  838  
 801  839          if (crgetgid(a1->auth_clnt_cred) < crgetgid(a2->auth_clnt_cred))
 802  840                  return (-1);
 803  841          if (crgetgid(a1->auth_clnt_cred) > crgetgid(a2->auth_clnt_cred))
 804  842                  return (1);
 805  843  
 806  844          if (crgetngroups(a1->auth_clnt_cred) < crgetngroups(a2->auth_clnt_cred))
 807  845                  return (-1);
 808  846          if (crgetngroups(a1->auth_clnt_cred) > crgetngroups(a2->auth_clnt_cred))
 809  847                  return (1);
 810  848  
 811  849          c = memcmp(crgetgroups(a1->auth_clnt_cred),
 812  850              crgetgroups(a2->auth_clnt_cred), crgetngroups(a1->auth_clnt_cred));
 813  851          if (c < 0)
 814  852                  return (-1);
 815  853          if (c > 0)
 816  854                  return (1);
 817  855  
 818  856          return (0);
  
    | 
      ↓ 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  
 872  918          tree = exi->exi_cache[hash(&addr)];
 873  919  
 874  920          rw_enter(&exi->exi_cache_lock, RW_READER);
 875  921          c = (struct auth_cache_clnt *)avl_find(tree, &acc, NULL);
 876  922  
 877  923          if (c == NULL) {
 878  924                  struct auth_cache_clnt *nc;
 879  925  
 880  926                  rw_exit(&exi->exi_cache_lock);
 881  927  
 882  928                  nc = kmem_alloc(sizeof (*nc), KM_NOSLEEP | KM_NORMALPRI);
 883  929                  if (nc == NULL)
 884  930                          goto retrieve;
 885  931  
 886  932                  /*
 887  933                   * Initialize the new auth_cache_clnt
 888  934                   */
 889  935                  nc->authc_addr = addr;
 890  936                  nc->authc_addr.buf = kmem_alloc(addr.maxlen,
 891  937                      KM_NOSLEEP | KM_NORMALPRI);
 892  938                  if (addr.maxlen != 0 && nc->authc_addr.buf == NULL) {
 893  939                          kmem_free(nc, sizeof (*nc));
 894  940                          goto retrieve;
 895  941                  }
 896  942                  bcopy(addr.buf, nc->authc_addr.buf, addr.len);
 897  943                  rw_init(&nc->authc_lock, NULL, RW_DEFAULT, NULL);
 898  944                  avl_create(&nc->authc_tree, nfsauth_cache_compar,
 899  945                      sizeof (struct auth_cache),
 900  946                      offsetof(struct auth_cache, auth_link));
 901  947  
 902  948                  rw_enter(&exi->exi_cache_lock, RW_WRITER);
 903  949                  c = (struct auth_cache_clnt *)avl_find(tree, &acc, &where);
 904  950                  if (c == NULL) {
 905  951                          avl_insert(tree, nc, where);
 906  952                          rw_downgrade(&exi->exi_cache_lock);
 907  953                          c = nc;
 908  954                  } else {
 909  955                          rw_downgrade(&exi->exi_cache_lock);
 910  956  
 911  957                          avl_destroy(&nc->authc_tree);
 912  958                          rw_destroy(&nc->authc_lock);
 913  959                          kmem_free(nc->authc_addr.buf, nc->authc_addr.maxlen);
 914  960                          kmem_free(nc, sizeof (*nc));
 915  961                  }
 916  962          }
 917  963  
 918  964          ASSERT(c != NULL);
 919  965  
 920  966          rw_enter(&c->authc_lock, RW_READER);
 921  967          p = (struct auth_cache *)avl_find(&c->authc_tree, &ac, NULL);
 922  968  
 923  969          if (p == NULL) {
 924  970                  struct auth_cache *np;
 925  971  
 926  972                  rw_exit(&c->authc_lock);
 927  973  
 928  974                  np = kmem_cache_alloc(exi_cache_handle,
 929  975                      KM_NOSLEEP | KM_NORMALPRI);
 930  976                  if (np == NULL) {
 931  977                          rw_exit(&exi->exi_cache_lock);
 932  978                          goto retrieve;
 933  979                  }
 934  980  
 935  981                  /*
 936  982                   * Initialize the new auth_cache
 937  983                   */
 938  984                  np->auth_clnt = c;
 939  985                  np->auth_flavor = flavor;
 940  986                  np->auth_clnt_cred = ac.auth_clnt_cred;
 941  987                  np->auth_srv_ngids = 0;
 942  988                  np->auth_srv_gids = NULL;
 943  989                  np->auth_time = np->auth_freshness = gethrestime_sec();
 944  990                  np->auth_state = NFS_AUTH_NEW;
 945  991                  mutex_init(&np->auth_lock, NULL, MUTEX_DEFAULT, NULL);
 946  992                  cv_init(&np->auth_cv, NULL, CV_DEFAULT, NULL);
 947  993  
 948  994                  rw_enter(&c->authc_lock, RW_WRITER);
 949  995                  rw_exit(&exi->exi_cache_lock);
 950  996  
 951  997                  p = (struct auth_cache *)avl_find(&c->authc_tree, &ac, &where);
 952  998                  if (p == NULL) {
 953  999                          avl_insert(&c->authc_tree, np, where);
 954 1000                          rw_downgrade(&c->authc_lock);
 955 1001                          p = np;
 956 1002                  } else {
 957 1003                          rw_downgrade(&c->authc_lock);
 958 1004  
 959 1005                          cv_destroy(&np->auth_cv);
 960 1006                          mutex_destroy(&np->auth_lock);
 961 1007                          crfree(ac.auth_clnt_cred);
 962 1008                          kmem_cache_free(exi_cache_handle, np);
 963 1009                  }
 964 1010          } else {
 965 1011                  rw_exit(&exi->exi_cache_lock);
 966 1012                  crfree(ac.auth_clnt_cred);
 967 1013          }
 968 1014  
 969 1015          mutex_enter(&p->auth_lock);
 970 1016          rw_exit(&c->authc_lock);
 971 1017  
 972 1018          /*
 973 1019           * If the entry is in the WAITING state then some other thread is just
 974 1020           * retrieving the required info.  The entry was either NEW, or the list
 975 1021           * of client's supplemental groups is going to be changed (either by
 976 1022           * this thread, or by some other thread).  We need to wait until the
 977 1023           * nfsauth_retrieve() is done.
 978 1024           */
 979 1025          while (p->auth_state == NFS_AUTH_WAITING)
 980 1026                  cv_wait(&p->auth_cv, &p->auth_lock);
 981 1027  
 982 1028          /*
 983 1029           * Here the entry cannot be in WAITING or INVALID state.
 984 1030           */
 985 1031          ASSERT(p->auth_state != NFS_AUTH_WAITING);
 986 1032          ASSERT(p->auth_state != NFS_AUTH_INVALID);
 987 1033  
 988 1034          /*
 989 1035           * If the cache entry is not valid yet, we need to retrieve the
 990 1036           * info ourselves.
 991 1037           */
 992 1038          if (p->auth_state == NFS_AUTH_NEW) {
 993 1039                  bool_t res;
 994 1040                  /*
 995 1041                   * NFS_AUTH_NEW is the default output auth_state value in a
 996 1042                   * case we failed somewhere below.
  
    | 
      ↓ 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) {
1019 1066                                  *ngids = tmpngids;
1020 1067                                  *gids = tmpgids;
1021 1068  
1022 1069                                  /*
1023 1070                                   * We need a copy of gids for the
1024 1071                                   * auth_cache entry
1025 1072                                   */
1026 1073                                  tmpgids = kmem_alloc(tmpngids * sizeof (gid_t),
1027 1074                                      KM_NOSLEEP | KM_NORMALPRI);
1028 1075                                  if (tmpgids != NULL)
1029 1076                                          bcopy(*gids, tmpgids,
1030 1077                                              tmpngids * sizeof (gid_t));
1031 1078                          }
1032 1079  
1033 1080                          if (tmpgids != NULL || tmpngids == 0) {
1034 1081                                  p->auth_srv_uid = tmpuid;
1035 1082                                  p->auth_srv_gid = tmpgid;
1036 1083                                  p->auth_srv_ngids = tmpngids;
1037 1084                                  p->auth_srv_gids = tmpgids;
1038 1085  
1039 1086                                  state = NFS_AUTH_FRESH;
1040 1087                          }
1041 1088                  }
1042 1089  
1043 1090                  /*
1044 1091                   * Set the auth_state and notify waiters.
1045 1092                   */
1046 1093                  mutex_enter(&p->auth_lock);
1047 1094                  p->auth_state = state;
1048 1095                  cv_broadcast(&p->auth_cv);
1049 1096                  mutex_exit(&p->auth_lock);
1050 1097          } else {
1051 1098                  uint_t nach;
1052 1099                  time_t refresh;
1053 1100  
1054 1101                  refresh = gethrestime_sec() - p->auth_freshness;
1055 1102  
1056 1103                  p->auth_time = gethrestime_sec();
1057 1104  
1058 1105                  if (uid != NULL)
1059 1106                          *uid = p->auth_srv_uid;
1060 1107                  if (gid != NULL)
1061 1108                          *gid = p->auth_srv_gid;
1062 1109                  if (ngids != NULL && gids != NULL) {
1063 1110                          if ((*ngids = p->auth_srv_ngids) != 0) {
1064 1111                                  size_t sz = *ngids * sizeof (gid_t);
1065 1112                                  *gids = kmem_alloc(sz, KM_SLEEP);
1066 1113                                  bcopy(p->auth_srv_gids, *gids, sz);
1067 1114                          } else {
1068 1115                                  *gids = NULL;
1069 1116                          }
1070 1117                  }
1071 1118  
1072 1119                  access = p->auth_access;
1073 1120  
1074 1121                  if ((refresh > NFSAUTH_CACHE_REFRESH) &&
1075 1122                      p->auth_state == NFS_AUTH_FRESH) {
1076 1123                          refreshq_auth_node_t *ran;
1077 1124                          uint_t nacr;
1078 1125  
1079 1126                          p->auth_state = NFS_AUTH_STALE;
1080 1127                          mutex_exit(&p->auth_lock);
1081 1128  
1082 1129                          nacr = atomic_inc_uint_nv(&nfsauth_cache_refresh);
  
    | 
      ↓ 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),
1118 1177                                              KM_SLEEP);
1119 1178  
  
    | 
      ↓ 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);
1150 1210          }
1151 1211  
1152 1212          return (access);
1153 1213  
1154 1214  retrieve:
  
    | 
      ↓ 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                  }
1177 1237          }
1178 1238  
1179 1239          kmem_free(addr.buf, addr.maxlen);
1180 1240  
1181 1241          return (access);
1182 1242  }
1183 1243  
1184 1244  /*
1185 1245   * Check if the requesting client has access to the filesystem with
1186 1246   * a given nfs flavor number which is an explicitly shared flavor.
1187 1247   */
1188 1248  int
1189 1249  nfsauth4_secinfo_access(struct exportinfo *exi, struct svc_req *req,
1190 1250      int flavor, int perm, cred_t *cr)
1191 1251  {
1192 1252          int access;
1193 1253  
1194 1254          if (! (perm & M_4SEC_EXPORTED)) {
1195 1255                  return (NFSAUTH_DENIED);
1196 1256          }
1197 1257  
1198 1258          /*
1199 1259           * Optimize if there are no lists
1200 1260           */
1201 1261          if ((perm & (M_ROOT | M_NONE | M_MAP)) == 0) {
1202 1262                  perm &= ~M_4SEC_EXPORTED;
1203 1263                  if (perm == M_RO)
1204 1264                          return (NFSAUTH_RO);
1205 1265                  if (perm == M_RW)
1206 1266                          return (NFSAUTH_RW);
1207 1267          }
1208 1268  
1209 1269          access = nfsauth_cache_get(exi, req, flavor, cr, NULL, NULL, NULL,
1210 1270              NULL);
1211 1271  
1212 1272          return (access);
1213 1273  }
1214 1274  
1215 1275  int
1216 1276  nfsauth_access(struct exportinfo *exi, struct svc_req *req, cred_t *cr,
1217 1277      uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids)
1218 1278  {
1219 1279          int access, mapaccess;
1220 1280          struct secinfo *sp;
1221 1281          int i, flavor, perm;
1222 1282          int authnone_entry = -1;
1223 1283  
1224 1284          /*
1225 1285           * By default root is mapped to anonymous user.
1226 1286           * This might get overriden later in nfsauth_cache_get().
1227 1287           */
1228 1288          if (crgetuid(cr) == 0) {
1229 1289                  if (uid != NULL)
1230 1290                          *uid = exi->exi_export.ex_anon;
1231 1291                  if (gid != NULL)
1232 1292                          *gid = exi->exi_export.ex_anon;
1233 1293          } else {
1234 1294                  if (uid != NULL)
1235 1295                          *uid = crgetuid(cr);
1236 1296                  if (gid != NULL)
1237 1297                          *gid = crgetgid(cr);
1238 1298          }
1239 1299  
1240 1300          if (ngids != NULL)
1241 1301                  *ngids = 0;
1242 1302          if (gids != NULL)
1243 1303                  *gids = NULL;
1244 1304  
1245 1305          /*
1246 1306           *  Get the nfs flavor number from xprt.
1247 1307           */
1248 1308          flavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
1249 1309  
1250 1310          /*
1251 1311           * First check the access restrictions on the filesystem.  If
1252 1312           * there are no lists associated with this flavor then there's no
1253 1313           * need to make an expensive call to the nfsauth service or to
1254 1314           * cache anything.
1255 1315           */
1256 1316  
1257 1317          sp = exi->exi_export.ex_secinfo;
1258 1318          for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
1259 1319                  if (flavor != sp[i].s_secinfo.sc_nfsnum) {
1260 1320                          if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE)
1261 1321                                  authnone_entry = i;
1262 1322                          continue;
1263 1323                  }
1264 1324                  break;
1265 1325          }
1266 1326  
1267 1327          mapaccess = 0;
1268 1328  
1269 1329          if (i >= exi->exi_export.ex_seccnt) {
1270 1330                  /*
1271 1331                   * Flavor not found, but use AUTH_NONE if it exists
1272 1332                   */
1273 1333                  if (authnone_entry == -1)
1274 1334                          return (NFSAUTH_DENIED);
1275 1335                  flavor = AUTH_NONE;
1276 1336                  mapaccess = NFSAUTH_MAPNONE;
1277 1337                  i = authnone_entry;
1278 1338          }
1279 1339  
1280 1340          /*
1281 1341           * If the flavor is in the ex_secinfo list, but not an explicitly
1282 1342           * shared flavor by the user, it is a result of the nfsv4 server
1283 1343           * namespace setup. We will grant an RO permission similar for
1284 1344           * a pseudo node except that this node is a shared one.
1285 1345           *
1286 1346           * e.g. flavor in (flavor) indicates that it is not explictly
1287 1347           *      shared by the user:
1288 1348           *
1289 1349           *              /       (sys, krb5)
1290 1350           *              |
1291 1351           *              export  #share -o sec=sys (krb5)
1292 1352           *              |
1293 1353           *              secure  #share -o sec=krb5
1294 1354           *
1295 1355           *      In this case, when a krb5 request coming in to access
1296 1356           *      /export, RO permission is granted.
1297 1357           */
1298 1358          if (!(sp[i].s_flags & M_4SEC_EXPORTED))
1299 1359                  return (mapaccess | NFSAUTH_RO);
1300 1360  
1301 1361          /*
1302 1362           * Optimize if there are no lists.
1303 1363           * We cannot optimize for AUTH_SYS with NGRPS (16) supplemental groups.
1304 1364           */
1305 1365          perm = sp[i].s_flags;
1306 1366          if ((perm & (M_ROOT | M_NONE | M_MAP)) == 0 && (ngroups_max <= NGRPS ||
1307 1367              flavor != AUTH_SYS || crgetngroups(cr) < NGRPS)) {
1308 1368                  perm &= ~M_4SEC_EXPORTED;
1309 1369                  if (perm == M_RO)
1310 1370                          return (mapaccess | NFSAUTH_RO);
1311 1371                  if (perm == M_RW)
1312 1372                          return (mapaccess | NFSAUTH_RW);
1313 1373          }
1314 1374  
1315 1375          access = nfsauth_cache_get(exi, req, flavor, cr, uid, gid, ngids, gids);
1316 1376  
1317 1377          /*
1318 1378           * For both NFSAUTH_DENIED and NFSAUTH_WRONGSEC we do not care about
1319 1379           * the supplemental groups.
1320 1380           */
1321 1381          if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) {
1322 1382                  if (ngids != NULL && gids != NULL) {
1323 1383                          kmem_free(*gids, *ngids * sizeof (gid_t));
1324 1384                          *ngids = 0;
1325 1385                          *gids = NULL;
1326 1386                  }
1327 1387          }
1328 1388  
1329 1389          /*
1330 1390           * Client's security flavor doesn't match with "ro" or
1331 1391           * "rw" list. Try again using AUTH_NONE if present.
1332 1392           */
1333 1393          if ((access & NFSAUTH_WRONGSEC) && (flavor != AUTH_NONE)) {
1334 1394                  /*
1335 1395                   * Have we already encountered AUTH_NONE ?
1336 1396                   */
1337 1397                  if (authnone_entry != -1) {
1338 1398                          mapaccess = NFSAUTH_MAPNONE;
1339 1399                          access = nfsauth_cache_get(exi, req, AUTH_NONE, cr,
1340 1400                              NULL, NULL, NULL, NULL);
1341 1401                  } else {
1342 1402                          /*
1343 1403                           * Check for AUTH_NONE presence.
1344 1404                           */
1345 1405                          for (; i < exi->exi_export.ex_seccnt; i++) {
1346 1406                                  if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) {
1347 1407                                          mapaccess = NFSAUTH_MAPNONE;
1348 1408                                          access = nfsauth_cache_get(exi, req,
1349 1409                                              AUTH_NONE, cr, NULL, NULL, NULL,
1350 1410                                              NULL);
1351 1411                                          break;
1352 1412                                  }
1353 1413                          }
1354 1414                  }
1355 1415          }
1356 1416  
1357 1417          if (access & NFSAUTH_DENIED)
1358 1418                  access = NFSAUTH_DENIED;
1359 1419  
1360 1420          return (access | mapaccess);
1361 1421  }
1362 1422  
1363 1423  static void
1364 1424  nfsauth_free_clnt_node(struct auth_cache_clnt *p)
1365 1425  {
1366 1426          void *cookie = NULL;
1367 1427          struct auth_cache *node;
1368 1428  
1369 1429          while ((node = avl_destroy_nodes(&p->authc_tree, &cookie)) != NULL)
1370 1430                  nfsauth_free_node(node);
1371 1431          avl_destroy(&p->authc_tree);
1372 1432  
1373 1433          kmem_free(p->authc_addr.buf, p->authc_addr.maxlen);
1374 1434          rw_destroy(&p->authc_lock);
1375 1435  
1376 1436          kmem_free(p, sizeof (*p));
1377 1437  }
1378 1438  
1379 1439  static void
1380 1440  nfsauth_free_node(struct auth_cache *p)
1381 1441  {
1382 1442          crfree(p->auth_clnt_cred);
1383 1443          kmem_free(p->auth_srv_gids, p->auth_srv_ngids * sizeof (gid_t));
1384 1444          mutex_destroy(&p->auth_lock);
1385 1445          cv_destroy(&p->auth_cv);
1386 1446          kmem_cache_free(exi_cache_handle, p);
1387 1447  }
1388 1448  
1389 1449  /*
1390 1450   * Free the nfsauth cache for a given export
1391 1451   */
1392 1452  void
1393 1453  nfsauth_cache_free(struct exportinfo *exi)
1394 1454  {
1395 1455          int i;
1396 1456  
1397 1457          /*
1398 1458           * The only way we got here was with an exi_rele, which means that no
1399 1459           * auth cache entry is being refreshed.
1400 1460           */
1401 1461  
1402 1462          for (i = 0; i < AUTH_TABLESIZE; i++) {
  
    | 
      ↓ 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  
1449 1532          for (i = 0; i < AUTH_TABLESIZE; i++) {
1450 1533                  tree = exi->exi_cache[i];
1451 1534                  stale_time = gethrestime_sec() - NFSAUTH_CACHE_TRIM;
1452 1535                  rw_enter(&exi->exi_cache_lock, RW_READER);
1453 1536  
1454 1537                  /*
1455 1538                   * Free entries that have not been
1456 1539                   * used for NFSAUTH_CACHE_TRIM seconds.
1457 1540                   */
1458 1541                  for (c = avl_first(tree); c != NULL; c = AVL_NEXT(tree, c)) {
1459 1542                          /*
1460 1543                           * We are being called by the kmem subsystem to reclaim
1461 1544                           * memory so don't block if we can't get the lock.
1462 1545                           */
1463 1546                          if (rw_tryenter(&c->authc_lock, RW_WRITER) == 0) {
1464 1547                                  exi_cache_auth_reclaim_failed++;
1465 1548                                  rw_exit(&exi->exi_cache_lock);
1466 1549                                  return;
1467 1550                          }
1468 1551  
1469 1552                          for (p = avl_first(&c->authc_tree); p != NULL;
1470 1553                              p = next) {
1471 1554                                  next = AVL_NEXT(&c->authc_tree, p);
1472 1555  
1473 1556                                  ASSERT(p->auth_state != NFS_AUTH_INVALID);
1474 1557  
1475 1558                                  mutex_enter(&p->auth_lock);
1476 1559  
1477 1560                                  /*
1478 1561                                   * We won't trim recently used and/or WAITING
1479 1562                                   * entries.
1480 1563                                   */
1481 1564                                  if (p->auth_time > stale_time ||
1482 1565                                      p->auth_state == NFS_AUTH_WAITING) {
1483 1566                                          mutex_exit(&p->auth_lock);
1484 1567                                          continue;
1485 1568                                  }
1486 1569  
1487 1570                                  DTRACE_PROBE1(nfsauth__debug__trim__state,
1488 1571                                      auth_state_t, p->auth_state);
1489 1572  
1490 1573                                  /*
1491 1574                                   * STALE and REFRESHING entries needs to be
1492 1575                                   * marked INVALID only because they are
1493 1576                                   * referenced by some other structures or
1494 1577                                   * threads.  They will be freed later.
1495 1578                                   */
1496 1579                                  if (p->auth_state == NFS_AUTH_STALE ||
1497 1580                                      p->auth_state == NFS_AUTH_REFRESHING) {
1498 1581                                          p->auth_state = NFS_AUTH_INVALID;
1499 1582                                          mutex_exit(&p->auth_lock);
1500 1583  
1501 1584                                          avl_remove(&c->authc_tree, p);
1502 1585                                  } else {
1503 1586                                          mutex_exit(&p->auth_lock);
1504 1587  
1505 1588                                          avl_remove(&c->authc_tree, p);
1506 1589                                          nfsauth_free_node(p);
1507 1590                                  }
1508 1591                          }
1509 1592                          rw_exit(&c->authc_lock);
1510 1593                  }
1511 1594  
1512 1595                  if (rw_tryupgrade(&exi->exi_cache_lock) == 0) {
1513 1596                          rw_exit(&exi->exi_cache_lock);
1514 1597                          exi_cache_clnt_reclaim_failed++;
1515 1598                          continue;
1516 1599                  }
1517 1600  
1518 1601                  for (c = avl_first(tree); c != NULL; c = nextc) {
1519 1602                          nextc = AVL_NEXT(tree, c);
1520 1603  
1521 1604                          if (avl_is_empty(&c->authc_tree) == B_FALSE)
1522 1605                                  continue;
1523 1606  
1524 1607                          avl_remove(tree, c);
1525 1608  
1526 1609                          nfsauth_free_clnt_node(c);
1527 1610                  }
1528 1611  
1529 1612                  rw_exit(&exi->exi_cache_lock);
1530 1613          }
1531 1614  }
  
    | 
      ↓ open down ↓ | 
    83 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX