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_export.c
          +++ new/usr/src/uts/common/fs/nfs/nfs_export.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 2015 Nexenta Systems, Inc.  All rights reserved.
  24   23   * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  25   24   */
  26   25  
  27   26  /*
  28      - *      Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
       27 + *      Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
  29   28   *              All rights reserved.
  30   29   */
  31   30  
       31 +/*
       32 + * Copyright 2018 Nexenta Systems, Inc.
       33 + */
  32   34  
  33   35  #include <sys/types.h>
  34   36  #include <sys/param.h>
  35   37  #include <sys/time.h>
  36   38  #include <sys/vfs.h>
  37   39  #include <sys/vnode.h>
  38   40  #include <sys/socket.h>
  39   41  #include <sys/errno.h>
  40   42  #include <sys/uio.h>
  41   43  #include <sys/proc.h>
  42   44  #include <sys/user.h>
  43   45  #include <sys/file.h>
  44   46  #include <sys/tiuser.h>
  45   47  #include <sys/kmem.h>
  46   48  #include <sys/pathname.h>
  47   49  #include <sys/debug.h>
  48   50  #include <sys/vtrace.h>
  49   51  #include <sys/cmn_err.h>
  50   52  #include <sys/acl.h>
  51   53  #include <sys/utsname.h>
  52   54  #include <sys/sdt.h>
  53   55  #include <netinet/in.h>
  54   56  #include <sys/avl.h>
  55   57  
  56   58  #include <rpc/types.h>
  57   59  #include <rpc/auth.h>
  
    | 
      ↓ open down ↓ | 
    16 lines elided | 
    
      ↑ open up ↑ | 
  
  58   60  #include <rpc/svc.h>
  59   61  
  60   62  #include <nfs/nfs.h>
  61   63  #include <nfs/export.h>
  62   64  #include <nfs/nfssys.h>
  63   65  #include <nfs/nfs_clnt.h>
  64   66  #include <nfs/nfs_acl.h>
  65   67  #include <nfs/nfs_log.h>
  66   68  #include <nfs/lm.h>
  67   69  #include <sys/sunddi.h>
  68      -#include <sys/pkp_hash.h>
  69   70  
  70      -treenode_t *ns_root;
       71 +/*
       72 + * exi_id support
       73 + *
       74 + * exi_id_next          The next exi_id available.
       75 + * exi_id_overflow      The exi_id_next already overflowed, so we should
       76 + *                      thoroughly check for duplicates.
       77 + * exi_id_tree          AVL tree indexed by exi_id.
       78 + * nfs_exi_id_lock      Lock to protect the export ID list
       79 + *
       80 + * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
       81 + * nfs_exi_id_lock.
       82 + */
       83 +static int exi_id_next;
       84 +static bool_t exi_id_overflow;
       85 +avl_tree_t exi_id_tree;
       86 +kmutex_t nfs_exi_id_lock;
  71   87  
  72      -struct exportinfo *exptable_path_hash[PKP_HASH_SIZE];
  73      -struct exportinfo *exptable[EXPTABLESIZE];
  74      -
  75      -static int      unexport(exportinfo_t *);
       88 +static int      unexport(nfs_export_t *, exportinfo_t *);
  76   89  static void     exportfree(exportinfo_t *);
  77   90  static int      loadindex(exportdata_t *);
  78   91  
  79   92  extern void     nfsauth_cache_free(exportinfo_t *);
  80   93  extern int      sec_svc_loadrootnames(int, int, caddr_t **, model_t);
  81   94  extern void     sec_svc_freerootnames(int, int, caddr_t *);
  82   95  
  83      -static int build_seclist_nodups(exportdata_t *, secinfo_t *, int);
  84      -static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
  85      -static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
  86      -static void srv_secinfo_treeclimb(exportinfo_t *, secinfo_t *, int, bool_t);
       96 +static int      build_seclist_nodups(exportdata_t *, secinfo_t *, int);
       97 +static void     srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
       98 +static void     srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
       99 +static void     srv_secinfo_treeclimb(nfs_export_t *, exportinfo_t *,
      100 +                    secinfo_t *, int, bool_t);
  87  101  
  88  102  #ifdef VOLATILE_FH_TEST
  89  103  static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
  90  104  static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
  91      -static void free_volrnm_list(exportinfo_t *);
      105 +static void     free_volrnm_list(exportinfo_t *);
  92  106  #endif /* VOLATILE_FH_TEST */
  93  107  
  94      -/*
  95      - * exported_lock        Read/Write lock that protects the exportinfo list.
  96      - *                      This lock must be held when searching or modifiying
  97      - *                      the exportinfo list.
  98      - */
  99      -krwlock_t exported_lock;
 100      -
 101      -/*
 102      - * "public" and default (root) location for public filehandle
 103      - */
 104      -struct exportinfo *exi_public, *exi_root;
 105      -
 106      -fid_t exi_rootfid;      /* for checking the default public file handle */
 107      -
 108  108  fhandle_t nullfh2;      /* for comparing V2 filehandles */
 109  109  
 110  110  /*
 111  111   * macro for static dtrace probes to trace server namespace ref count mods.
 112  112   */
 113  113  #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
 114  114          DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
 115  115                  char *, (tag), int, (int)(flav), int, (int)(aftcnt))
 116  116  
 117  117  
 118  118  #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
 119  119  
      120 +extern nfs_export_t *
      121 +nfs_get_export(void)
      122 +{
      123 +        nfs_globals_t *ng = nfs_srv_getzg();
      124 +        nfs_export_t *ne = ng->nfs_export;
      125 +        ASSERT(ne != NULL);
      126 +        return (ne);
      127 +}
      128 +
 120  129  static uint8_t
 121  130  xor_hash(uint8_t *data, int len)
 122  131  {
 123  132          uint8_t h = 0;
 124  133  
 125  134          while (len--)
 126  135                  h ^= *data++;
 127  136  
 128  137          return (h);
 129  138  }
 130  139  
 131  140  /*
 132  141   * File handle hash function, XOR over all bytes in fsid and fid.
 133  142   */
 134  143  static unsigned
 135  144  nfs_fhhash(fsid_t *fsid, fid_t *fid)
 136  145  {
 137  146          int len;
 138  147          uint8_t h;
 139  148  
 140  149          h = xor_hash((uint8_t *)fsid, sizeof (fsid_t));
 141  150  
 142  151          /*
 143  152           * Sanity check the length before using it
 144  153           * blindly in case the client trashed it.
 145  154           */
 146  155          len = fid->fid_len > NFS_FH4MAXDATA ? 0 : fid->fid_len;
 147  156          h ^= xor_hash((uint8_t *)fid->fid_data, len);
 148  157  
 149  158          return ((unsigned)h);
 150  159  }
 151  160  
 152  161  /*
 153  162   * Free the memory allocated within a secinfo entry.
 154  163   */
 155  164  void
 156  165  srv_secinfo_entry_free(struct secinfo *secp)
 157  166  {
 158  167          if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) {
 159  168                  sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum,
 160  169                      secp->s_rootcnt, secp->s_rootnames);
 161  170                  secp->s_rootcnt = 0;
 162  171          }
 163  172  
 164  173          if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) &&
 165  174              (secp->s_secinfo.sc_gss_mech_type)) {
 166  175                  kmem_free(secp->s_secinfo.sc_gss_mech_type->elements,
 167  176                      secp->s_secinfo.sc_gss_mech_type->length);
 168  177                  kmem_free(secp->s_secinfo.sc_gss_mech_type,
 169  178                      sizeof (rpc_gss_OID_desc));
 170  179                  secp->s_secinfo.sc_gss_mech_type = NULL;
 171  180          }
 172  181  }
 173  182  
 174  183  /*
 175  184   * Free a list of secinfo allocated in the exportdata structure.
 176  185   */
 177  186  void
 178  187  srv_secinfo_list_free(struct secinfo *secinfo, int cnt)
 179  188  {
 180  189          int i;
 181  190  
 182  191          if (cnt == 0)
 183  192                  return;
 184  193  
 185  194          for (i = 0; i < cnt; i++)
 186  195                  srv_secinfo_entry_free(&secinfo[i]);
 187  196  
 188  197          kmem_free(secinfo, cnt * sizeof (struct secinfo));
 189  198  }
 190  199  
 191  200  /*
 192  201   * Allocate and copy a secinfo data from "from" to "to".
 193  202   *
 194  203   * This routine is used by srv_secinfo_add() to add a new flavor to an
 195  204   * ancestor's export node. The rootnames are not copied because the
 196  205   * allowable rootname access only applies to the explicit exported node,
 197  206   * not its ancestor's.
 198  207   *
 199  208   * "to" should have already been allocated and zeroed before calling
 200  209   * this routine.
 201  210   *
 202  211   * This routine is used under the protection of exported_lock (RW_WRITER).
 203  212   */
 204  213  void
 205  214  srv_secinfo_copy(struct secinfo *from, struct secinfo *to)
 206  215  {
 207  216          to->s_secinfo.sc_nfsnum = from->s_secinfo.sc_nfsnum;
 208  217          to->s_secinfo.sc_rpcnum = from->s_secinfo.sc_rpcnum;
 209  218  
 210  219          if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
 211  220                  to->s_secinfo.sc_service = from->s_secinfo.sc_service;
 212  221                  bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name,
 213  222                      strlen(from->s_secinfo.sc_name));
 214  223                  bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech,
 215  224                      strlen(from->s_secinfo.sc_gss_mech));
 216  225  
 217  226                  /* copy mechanism oid */
 218  227                  to->s_secinfo.sc_gss_mech_type =
 219  228                      kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
 220  229                  to->s_secinfo.sc_gss_mech_type->length =
 221  230                      from->s_secinfo.sc_gss_mech_type->length;
 222  231                  to->s_secinfo.sc_gss_mech_type->elements =
 223  232                      kmem_alloc(from->s_secinfo.sc_gss_mech_type->length,
 224  233                      KM_SLEEP);
 225  234                  bcopy(from->s_secinfo.sc_gss_mech_type->elements,
 226  235                      to->s_secinfo.sc_gss_mech_type->elements,
 227  236                      from->s_secinfo.sc_gss_mech_type->length);
 228  237          }
 229  238  
 230  239          to->s_refcnt = from->s_refcnt;
 231  240          to->s_window = from->s_window;
 232  241          /* no need to copy the mode bits - s_flags */
 233  242  }
 234  243  
 235  244  /*
 236  245   * Create a secinfo array without duplicates.  The condensed
 237  246   * flavor list is used to propagate flavor ref counts  to an
 238  247   * export's ancestor pseudonodes.
 239  248   */
 240  249  static int
 241  250  build_seclist_nodups(exportdata_t *exd, secinfo_t *nodups, int exponly)
 242  251  {
 243  252          int ccnt, c;
 244  253          int ncnt, n;
 245  254          struct secinfo *cursec;
 246  255  
 247  256          ncnt = 0;
 248  257          ccnt = exd->ex_seccnt;
 249  258          cursec = exd->ex_secinfo;
 250  259  
 251  260          for (c = 0; c < ccnt; c++) {
 252  261  
 253  262                  if (exponly && ! SEC_REF_EXPORTED(&cursec[c]))
 254  263                          continue;
 255  264  
 256  265                  for (n = 0; n < ncnt; n++) {
 257  266                          if (nodups[n].s_secinfo.sc_nfsnum ==
 258  267                              cursec[c].s_secinfo.sc_nfsnum)
 259  268                                  break;
 260  269                  }
 261  270  
 262  271                  /*
 263  272                   * The structure copy below also copys ptrs embedded
 264  273                   * within struct secinfo.  The ptrs are copied but
 265  274                   * they are never freed from the nodups array.  If
 266  275                   * an ancestor's secinfo array doesn't contain one
 267  276                   * of the nodups flavors, then the entry is properly
 268  277                   * copied into the ancestor's secinfo array.
 269  278                   * (see srv_secinfo_copy)
 270  279                   */
 271  280                  if (n == ncnt) {
 272  281                          nodups[n] = cursec[c];
 273  282                          ncnt++;
 274  283                  }
 275  284          }
 276  285          return (ncnt);
 277  286  }
 278  287  
 279  288  /*
 280  289   * Add the new security flavors from newdata to the current list, pcursec.
 281  290   * Upon return, *pcursec has the newly merged secinfo list.
 282  291   *
 283  292   * There should be at least 1 secinfo entry in newsec.
 284  293   *
 285  294   * This routine is used under the protection of exported_lock (RW_WRITER).
 286  295   */
 287  296  static void
 288  297  srv_secinfo_add(secinfo_t **pcursec, int *pcurcnt, secinfo_t *newsec,
 289  298      int newcnt, int is_pseudo)
 290  299  {
 291  300          int ccnt, c;            /* sec count in current data - curdata */
 292  301          int n;                  /* index for newsec  - newsecinfo */
 293  302          int tcnt;               /* total sec count after merge */
 294  303          int mcnt;               /* total sec count after merge */
 295  304          struct secinfo *msec;   /* merged secinfo list */
 296  305          struct secinfo *cursec;
 297  306  
 298  307          cursec = *pcursec;
 299  308          ccnt = *pcurcnt;
 300  309  
 301  310          ASSERT(newcnt > 0);
 302  311          tcnt = ccnt + newcnt;
 303  312  
 304  313          for (n = 0; n < newcnt; n++) {
 305  314                  for (c = 0; c < ccnt; c++) {
 306  315                          if (newsec[n].s_secinfo.sc_nfsnum ==
 307  316                              cursec[c].s_secinfo.sc_nfsnum) {
 308  317                                  cursec[c].s_refcnt += newsec[n].s_refcnt;
 309  318                                  SECREF_TRACE(cursec, "add_ref",
 310  319                                      cursec[c].s_secinfo.sc_nfsnum,
 311  320                                      cursec[c].s_refcnt);
 312  321                                  tcnt--;
 313  322                                  break;
 314  323                          }
 315  324                  }
 316  325          }
 317  326  
 318  327          if (tcnt == ccnt)
 319  328                  return; /* no change; no new flavors */
 320  329  
 321  330          msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
 322  331  
 323  332          /* move current secinfo list data to the new list */
 324  333          for (c = 0; c < ccnt; c++)
 325  334                  msec[c] = cursec[c];
 326  335  
 327  336          /* Add the flavor that's not in the current data */
 328  337          mcnt = ccnt;
 329  338          for (n = 0; n < newcnt; n++) {
 330  339                  for (c = 0; c < ccnt; c++) {
 331  340                          if (newsec[n].s_secinfo.sc_nfsnum ==
 332  341                              cursec[c].s_secinfo.sc_nfsnum)
 333  342                                  break;
 334  343                  }
 335  344  
 336  345                  /* This is the one. Add it. */
 337  346                  if (c == ccnt) {
 338  347                          srv_secinfo_copy(&newsec[n], &msec[mcnt]);
 339  348  
 340  349                          if (is_pseudo)
 341  350                                  msec[mcnt].s_flags = M_RO;
 342  351  
 343  352                          SECREF_TRACE(msec, "new_ref",
 344  353                              msec[mcnt].s_secinfo.sc_nfsnum,
 345  354                              msec[mcnt].s_refcnt);
 346  355                          mcnt++;
 347  356                  }
 348  357          }
 349  358  
 350  359          ASSERT(mcnt == tcnt);
 351  360  
 352  361          /*
 353  362           * Done. Update curdata. Free the old secinfo list in
 354  363           * curdata and return the new sec array info
 355  364           */
 356  365          if (ccnt > 0)
 357  366                  kmem_free(cursec, ccnt * sizeof (struct secinfo));
 358  367          *pcurcnt = tcnt;
 359  368          *pcursec = msec;
 360  369  }
 361  370  
 362  371  /*
 363  372   * For NFS V4.
 364  373   * Remove the security data of the unexported node from its ancestors.
 365  374   * Assume there is at least one flavor entry in the current sec list
 366  375   * (pcursec).
 367  376   *
 368  377   * This routine is used under the protection of exported_lock (RW_WRITER).
 369  378   *
 370  379   * Every element of remsec is an explicitly exported flavor.  If
 371  380   * srv_secinfo_remove() is called fom an exportfs error path, then
 372  381   * the flavor list was derived from the user's share cmdline,
 373  382   * and all flavors are explicit.  If it was called from the unshare path,
 374  383   * build_seclist_nodups() was called with the exponly flag.
 375  384   */
 376  385  static void
 377  386  srv_secinfo_remove(secinfo_t **pcursec, int *pcurcnt, secinfo_t *remsec,
 378  387      int remcnt)
 379  388  {
 380  389          int ccnt, c;            /* sec count in current data - cursec */
 381  390          int r;                  /* sec count in removal data - remsec */
 382  391          int tcnt, mcnt;         /* total sec count after removing */
 383  392          struct secinfo *msec;   /* final secinfo list after removing */
 384  393          struct secinfo *cursec;
 385  394  
 386  395          cursec = *pcursec;
 387  396          ccnt = *pcurcnt;
 388  397          tcnt = ccnt;
 389  398  
 390  399          for (r = 0; r < remcnt; r++) {
 391  400                  /*
 392  401                   * At unshare/reshare time, only explicitly shared flavor ref
 393  402                   * counts are decremented and propagated to ancestors.
 394  403                   * Implicit flavor refs came from shared descendants, and
 395  404                   * they must be kept.
 396  405                   */
 397  406                  if (! SEC_REF_EXPORTED(&remsec[r]))
 398  407                          continue;
 399  408  
 400  409                  for (c = 0; c < ccnt; c++) {
 401  410                          if (remsec[r].s_secinfo.sc_nfsnum ==
 402  411                              cursec[c].s_secinfo.sc_nfsnum) {
 403  412  
 404  413                                  /*
 405  414                                   * Decrement secinfo reference count by 1.
 406  415                                   * If this entry is invalid after decrementing
 407  416                                   * the count (i.e. count < 1), this entry will
 408  417                                   * be removed.
 409  418                                   */
 410  419                                  cursec[c].s_refcnt--;
 411  420  
 412  421                                  SECREF_TRACE(cursec, "del_ref",
 413  422                                      cursec[c].s_secinfo.sc_nfsnum,
 414  423                                      cursec[c].s_refcnt);
 415  424  
 416  425                                  ASSERT(cursec[c].s_refcnt >= 0);
 417  426  
 418  427                                  if (SEC_REF_INVALID(&cursec[c]))
 419  428                                          tcnt--;
 420  429                                  break;
 421  430                          }
 422  431                  }
 423  432          }
 424  433  
 425  434          ASSERT(tcnt >= 0);
 426  435          if (tcnt == ccnt)
 427  436                  return; /* no change; no flavors to remove */
 428  437  
 429  438          if (tcnt == 0) {
 430  439                  srv_secinfo_list_free(cursec, ccnt);
 431  440                  *pcurcnt = 0;
 432  441                  *pcursec = NULL;
 433  442                  return;
 434  443          }
 435  444  
 436  445          msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
 437  446  
 438  447          /* walk thru the given secinfo list to remove the flavors */
 439  448          mcnt = 0;
 440  449          for (c = 0; c < ccnt; c++) {
 441  450                  if (SEC_REF_INVALID(&cursec[c])) {
 442  451                          srv_secinfo_entry_free(&cursec[c]);
 443  452                  } else {
 444  453                          msec[mcnt] = cursec[c];
 445  454                          mcnt++;
 446  455                  }
 447  456          }
 448  457  
 449  458          ASSERT(mcnt == tcnt);
 450  459          /*
 451  460           * Done. Update curdata.
 452  461           * Free the existing secinfo list in curdata. All pointers
 453  462           * within the list have either been moved to msec or freed
 454  463           * if it's invalid.
 455  464           */
 456  465          kmem_free(*pcursec, ccnt * sizeof (struct secinfo));
 457  466          *pcursec = msec;
 458  467          *pcurcnt = tcnt;
 459  468  }
 460  469  
 461  470  
 462  471  /*
 463  472   * For the reshare case, sec flavor accounting happens in 3 steps:
 464  473   * 1) propagate addition of new flavor refs up the ancestor tree
 465  474   * 2) transfer flavor refs of descendants to new/reshared exportdata
 466  475   * 3) propagate removal of old flavor refs up the ancestor tree
 467  476   *
 468  477   * srv_secinfo_exp2exp() implements step 2 of a reshare.  At this point,
 469  478   * the new flavor list has already been propagated up through the
 470  479   * ancestor tree via srv_secinfo_treeclimb().
 471  480   *
 472  481   * If there is more than 1 export reference to an old flavor (i.e. some
 473  482   * of its children shared with this flavor), this flavor information
 474  483   * needs to be transferred to the new exportdata struct.  A flavor in
 475  484   * the old exportdata has descendant refs when its s_refcnt > 1 or it
 476  485   * is implicitly shared (M_SEC4_EXPORTED not set in s_flags).
 477  486   *
 478  487   * SEC_REF_EXPORTED() is only true when  M_SEC4_EXPORTED is set
 479  488   * SEC_REF_SELF() is only true when both M_SEC4_EXPORTED is set and s_refcnt==1
 480  489   *
 481  490   * Transferring descendant flavor refcnts happens in 2 passes:
 482  491   * a) flavors used before (oldsecinfo) and after (curdata->ex_secinfo) reshare
 483  492   * b) flavors used before but not after reshare
 484  493   *
 485  494   * This routine is used under the protection of exported_lock (RW_WRITER).
 486  495   */
 487  496  void
 488  497  srv_secinfo_exp2exp(exportdata_t *curdata, secinfo_t *oldsecinfo, int ocnt)
 489  498  {
 490  499          int ccnt, c;            /* sec count in current data - curdata */
 491  500          int o;                  /* sec count in old data - oldsecinfo */
 492  501          int tcnt, mcnt;         /* total sec count after the transfer */
 493  502          struct secinfo *msec;   /* merged secinfo list */
 494  503  
 495  504          ccnt = curdata->ex_seccnt;
 496  505  
 497  506          ASSERT(ocnt > 0);
 498  507          ASSERT(!(curdata->ex_flags & EX_PSEUDO));
 499  508  
 500  509          /*
 501  510           * If the oldsecinfo has flavors with more than 1 reference count
 502  511           * and the flavor is specified in the reshare, transfer the flavor
 503  512           * refs to the new seclist (curdata.ex_secinfo).
 504  513           */
 505  514          tcnt = ccnt + ocnt;
 506  515  
 507  516          for (o = 0; o < ocnt; o++) {
 508  517  
 509  518                  if (SEC_REF_SELF(&oldsecinfo[o])) {
 510  519                          tcnt--;
 511  520                          continue;
 512  521                  }
 513  522  
 514  523                  for (c = 0; c < ccnt; c++) {
 515  524                          if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
 516  525                              curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
 517  526  
 518  527                                  /*
 519  528                                   * add old reference to the current
 520  529                                   * secinfo count
 521  530                                   */
 522  531                                  curdata->ex_secinfo[c].s_refcnt +=
 523  532                                      oldsecinfo[o].s_refcnt;
 524  533  
 525  534                                  /*
 526  535                                   * Delete the old export flavor
 527  536                                   * reference.  The initial reference
 528  537                                   * was created during srv_secinfo_add,
 529  538                                   * and the count is decremented below
 530  539                                   * to account for the initial reference.
 531  540                                   */
 532  541                                  if (SEC_REF_EXPORTED(&oldsecinfo[o]))
 533  542                                          curdata->ex_secinfo[c].s_refcnt--;
 534  543  
 535  544                                  SECREF_TRACE(curdata->ex_path,
 536  545                                      "reshare_xfer_common_child_refs",
 537  546                                      curdata->ex_secinfo[c].s_secinfo.sc_nfsnum,
 538  547                                      curdata->ex_secinfo[c].s_refcnt);
 539  548  
 540  549                                  ASSERT(curdata->ex_secinfo[c].s_refcnt >= 0);
 541  550  
 542  551                                  tcnt--;
 543  552                                  break;
 544  553                          }
 545  554                  }
 546  555          }
 547  556  
 548  557          if (tcnt == ccnt)
 549  558                  return; /* no more transfer to do */
 550  559  
 551  560          /*
 552  561           * oldsecinfo has flavors referenced by its children that are not
 553  562           * in the current (new) export flavor list.  Add these flavors.
 554  563           */
 555  564          msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
 556  565  
 557  566          /* move current secinfo list data to the new list */
 558  567          for (c = 0; c < ccnt; c++)
 559  568                  msec[c] = curdata->ex_secinfo[c];
 560  569  
 561  570          /*
 562  571           * Add the flavor that's not in the new export, but still
 563  572           * referenced by its children.
 564  573           */
 565  574          mcnt = ccnt;
 566  575          for (o = 0; o < ocnt; o++) {
 567  576                  if (! SEC_REF_SELF(&oldsecinfo[o])) {
 568  577                          for (c = 0; c < ccnt; c++) {
 569  578                                  if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
 570  579                                      curdata->ex_secinfo[c].s_secinfo.sc_nfsnum)
 571  580                                          break;
 572  581                          }
 573  582  
 574  583                          /*
 575  584                           * This is the one. Add it. Decrement the ref count
 576  585                           * by 1 if the flavor is an explicitly shared flavor
 577  586                           * for the oldsecinfo export node.
 578  587                           */
 579  588                          if (c == ccnt) {
 580  589                                  srv_secinfo_copy(&oldsecinfo[o], &msec[mcnt]);
 581  590                                  if (SEC_REF_EXPORTED(&oldsecinfo[o]))
 582  591                                          msec[mcnt].s_refcnt--;
 583  592  
 584  593                                  SECREF_TRACE(curdata,
 585  594                                      "reshare_xfer_implicit_child_refs",
 586  595                                      msec[mcnt].s_secinfo.sc_nfsnum,
 587  596                                      msec[mcnt].s_refcnt);
 588  597  
 589  598                                  ASSERT(msec[mcnt].s_refcnt >= 0);
 590  599                                  mcnt++;
 591  600                          }
 592  601                  }
 593  602          }
 594  603  
 595  604          ASSERT(mcnt == tcnt);
 596  605          /*
 597  606           * Done. Update curdata, free the existing secinfo list in
 598  607           * curdata and set the new value.
 599  608           */
 600  609          if (ccnt > 0)
 601  610                  kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
 602  611          curdata->ex_seccnt = tcnt;
 603  612          curdata->ex_secinfo = msec;
 604  613  }
 605  614  
 606  615  /*
 607  616   * When unsharing an old export node and the old node becomes a pseudo node,
 608  617   * if there is more than 1 export reference to an old flavor (i.e. some of
 609  618   * its children shared with this flavor), this flavor information needs to
 610  619   * be transferred to the new shared node.
 611  620   *
 612  621   * This routine is used under the protection of exported_lock (RW_WRITER).
 613  622   */
 614  623  void
 615  624  srv_secinfo_exp2pseu(exportdata_t *curdata, exportdata_t *olddata)
 616  625  {
 617  626          int ocnt, o;            /* sec count in transfer data - trandata */
 618  627          int tcnt, mcnt;         /* total sec count after transfer */
 619  628          struct secinfo *msec;   /* merged secinfo list */
 620  629  
 621  630          ASSERT(curdata->ex_flags & EX_PSEUDO);
 622  631          ASSERT(curdata->ex_seccnt == 0);
 623  632  
 624  633          ocnt = olddata->ex_seccnt;
 625  634  
 626  635          /*
 627  636           * If the olddata has flavors with more than 1 reference count,
 628  637           * transfer the information to the curdata.
 629  638           */
 630  639          tcnt = ocnt;
 631  640  
 632  641          for (o = 0; o < ocnt; o++) {
 633  642                  if (SEC_REF_SELF(&olddata->ex_secinfo[o]))
 634  643                          tcnt--;
 635  644          }
 636  645  
 637  646          if (tcnt == 0)
 638  647                  return; /* no transfer to do */
 639  648  
 640  649          msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
 641  650  
 642  651          mcnt = 0;
 643  652          for (o = 0; o < ocnt; o++) {
 644  653                  if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) {
 645  654  
 646  655                          /*
 647  656                           * Decrement the reference count by 1 if the flavor is
 648  657                           * an explicitly shared flavor for the olddata export
 649  658                           * node.
 650  659                           */
 651  660                          srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]);
 652  661                          msec[mcnt].s_flags = M_RO;
 653  662                          if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
 654  663                                  msec[mcnt].s_refcnt--;
 655  664  
 656  665                          SECREF_TRACE(curdata, "unshare_morph_pseudo",
 657  666                              msec[mcnt].s_secinfo.sc_nfsnum,
 658  667                              msec[mcnt].s_refcnt);
 659  668  
 660  669                          ASSERT(msec[mcnt].s_refcnt >= 0);
 661  670                          mcnt++;
 662  671                  }
 663  672          }
 664  673  
 665  674          ASSERT(mcnt == tcnt);
 666  675          /*
 667  676           * Done. Update curdata.
 668  677           * Free up the existing secinfo list in curdata and
 669  678           * set the new value.
 670  679           */
 671  680          curdata->ex_seccnt = tcnt;
 672  681          curdata->ex_secinfo = msec;
 673  682  }
 674  683  
 675  684  /*
 676  685   * Find for given treenode the exportinfo which has its
 677  686   * exp_visible linked on its exi_visible list.
 678  687   *
 679  688   * Note: We could add new pointer either to treenode or
 680  689   * to exp_visible, which will point there directly.
 681  690   * This would buy some speed for some memory.
 682  691   */
 683  692  exportinfo_t *
 684  693  vis2exi(treenode_t *tnode)
 685  694  {
  
    | 
      ↓ open down ↓ | 
    556 lines elided | 
    
      ↑ open up ↑ | 
  
 686  695          exportinfo_t *exi_ret = NULL;
 687  696  
 688  697          for (;;) {
 689  698                  tnode = tnode->tree_parent;
 690  699                  if (TREE_ROOT(tnode)) {
 691  700                          exi_ret = tnode->tree_exi;
 692  701                          break;
 693  702                  }
 694  703          }
 695  704  
 696      -        ASSERT(exi_ret); /* Every visible should have its home exportinfo */
      705 +        /* Every visible should have its home exportinfo */
      706 +        ASSERT(exi_ret != NULL);
 697  707          return (exi_ret);
 698  708  }
 699  709  
 700  710  /*
 701  711   * For NFS V4.
 702  712   * Add or remove the newly exported or unexported security flavors of the
 703  713   * given exportinfo from its ancestors upto the system root.
 704  714   */
 705      -void
 706      -srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt,
 707      -    bool_t isadd)
      715 +static void
      716 +srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
      717 +    int seccnt, bool_t isadd)
 708  718  {
 709      -        treenode_t *tnode = exip->exi_tree;
      719 +        treenode_t *tnode;
 710  720  
 711      -        ASSERT(RW_WRITE_HELD(&exported_lock));
 712      -        ASSERT(tnode != NULL);
      721 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 713  722  
      723 +        /*
      724 +         * exi_tree can be null for the zone root
      725 +         * which means we're already at the "top"
      726 +         * and there's nothing more to "climb".
      727 +         */
      728 +        tnode = exip->exi_tree;
      729 +        if (tnode == NULL) {
      730 +                /* Should only happen for... */
      731 +                ASSERT(exip == ne->exi_root);
      732 +                return;
      733 +        }
      734 +
 714  735          if (seccnt == 0)
 715  736                  return;
 716  737  
 717  738          /*
 718  739           * If flavors are being added and the new export root isn't
 719  740           * also VROOT, its implicitly allowed flavors are inherited from
 720  741           * its pseudonode.
 721  742           * Note - for VROOT exports the implicitly allowed flavors were
 722  743           * transferred from the PSEUDO export in exportfs()
 723  744           */
 724  745          if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
      746 +            !VN_CMP(exip->exi_vp, EXI_TO_ZONEROOTVP(exip)) &&
 725  747              tnode->tree_vis->vis_seccnt > 0) {
 726  748                  srv_secinfo_add(&exip->exi_export.ex_secinfo,
 727  749                      &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 728  750                      tnode->tree_vis->vis_seccnt, FALSE);
 729  751          }
 730  752  
 731  753          /*
 732  754           * Move to parent node and propagate sec flavor
 733  755           * to exportinfo and to visible structures.
 734  756           */
 735  757          tnode = tnode->tree_parent;
 736  758  
 737  759          while (tnode != NULL) {
 738  760  
 739  761                  /* If there is exportinfo, update it */
 740  762                  if (tnode->tree_exi != NULL) {
 741  763                          secinfo_t **pxsec =
 742  764                              &tnode->tree_exi->exi_export.ex_secinfo;
 743  765                          int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
 744  766                          int is_pseudo = PSEUDO(tnode->tree_exi);
 745  767                          if (isadd)
 746  768                                  srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
 747  769                                      is_pseudo);
 748  770                          else
 749  771                                  srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
 750  772                  }
 751  773  
 752  774                  /* Update every visible - only root node has no visible */
 753  775                  if (tnode->tree_vis != NULL) {
 754  776                          secinfo_t **pxsec = &tnode->tree_vis->vis_secinfo;
 755  777                          int *pxcnt = &tnode->tree_vis->vis_seccnt;
 756  778                          if (isadd)
 757  779                                  srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
 758  780                                      FALSE);
 759  781                          else
 760  782                                  srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
 761  783                  }
 762  784                  tnode = tnode->tree_parent;
 763  785          }
 764  786  }
 765  787  
 766  788  /* hash_name is a text substitution for either fid_hash or path_hash */
 767  789  #define exp_hash_unlink(exi, hash_name) \
 768  790          if (*(exi)->hash_name.bckt == (exi)) \
 769  791                  *(exi)->hash_name.bckt = (exi)->hash_name.next; \
 770  792          if ((exi)->hash_name.prev) \
 771  793                  (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
 772  794          if ((exi)->hash_name.next) \
 773  795                  (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
 774  796          (exi)->hash_name.bckt = NULL;
  
    | 
      ↓ open down ↓ | 
    40 lines elided | 
    
      ↑ open up ↑ | 
  
 775  797  
 776  798  #define exp_hash_link(exi, hash_name, bucket) \
 777  799          (exi)->hash_name.bckt = (bucket); \
 778  800          (exi)->hash_name.prev = NULL; \
 779  801          (exi)->hash_name.next = *(bucket); \
 780  802          if ((exi)->hash_name.next) \
 781  803                  (exi)->hash_name.next->hash_name.prev = (exi); \
 782  804          *(bucket) = (exi);
 783  805  
 784  806  void
 785      -export_link(exportinfo_t *exi)
      807 +export_link(nfs_export_t *ne, exportinfo_t *exi)
 786  808  {
 787  809          exportinfo_t **bckt;
 788  810  
 789      -        bckt = &exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
      811 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
      812 +
      813 +        bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 790  814          exp_hash_link(exi, fid_hash, bckt);
 791  815  
 792      -        bckt = &exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
      816 +        bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 793  817              strlen(exi->exi_export.ex_path))];
 794  818          exp_hash_link(exi, path_hash, bckt);
      819 +        exi->exi_ne = ne;
 795  820  }
 796  821  
 797  822  /*
 798      - * Initialization routine for export routines. Should only be called once.
      823 + * Helper functions for exi_id handling
 799  824   */
      825 +static int
      826 +exi_id_compar(const void *v1, const void *v2)
      827 +{
      828 +        const struct exportinfo *e1 = v1;
      829 +        const struct exportinfo *e2 = v2;
      830 +
      831 +        if (e1->exi_id < e2->exi_id)
      832 +                return (-1);
      833 +        if (e1->exi_id > e2->exi_id)
      834 +                return (1);
      835 +
      836 +        return (0);
      837 +}
      838 +
 800  839  int
 801      -nfs_exportinit(void)
      840 +exi_id_get_next()
 802  841  {
 803      -        int error;
      842 +        struct exportinfo e;
      843 +        int ret = exi_id_next;
      844 +
      845 +        ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
      846 +
      847 +        do {
      848 +                exi_id_next++;
      849 +                if (exi_id_next == 0)
      850 +                        exi_id_overflow = TRUE;
      851 +
      852 +                if (!exi_id_overflow)
      853 +                        break;
      854 +
      855 +                if (exi_id_next == ret)
      856 +                        cmn_err(CE_PANIC, "exi_id exhausted");
      857 +
      858 +                e.exi_id = exi_id_next;
      859 +        } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
      860 +
      861 +        return (ret);
      862 +}
      863 +
      864 +/*
      865 + * Get the root file handle for this zone.
      866 + * Called when nfs_svc() starts
      867 + */
      868 +int
      869 +nfs_export_get_rootfh(nfs_globals_t *g)
      870 +{
      871 +        nfs_export_t *ne = g->nfs_export;
      872 +        int err;
      873 +
      874 +        ne->exi_rootfid.fid_len = MAXFIDSZ;
      875 +        err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid);
      876 +        if (err != 0) {
      877 +                ne->exi_rootfid.fid_len = 0;
      878 +                return (err);
      879 +        }
      880 +
      881 +        /* Setup the fhandle template exi_fh */
      882 +        ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
      883 +        ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
      884 +        bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
      885 +            ne->exi_rootfid.fid_len);
      886 +        ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
      887 +
      888 +        return (0);
      889 +}
      890 +
      891 +void
      892 +nfs_export_zone_init(nfs_globals_t *ng)
      893 +{
 804  894          int i;
      895 +        nfs_export_t *ne;
      896 +        zone_t *zone;
 805  897  
 806      -        rw_init(&exported_lock, NULL, RW_DEFAULT, NULL);
      898 +        ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 807  899  
      900 +        rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
      901 +
      902 +        ne->ne_globals = ng; /* "up" pointer */
      903 +
 808  904          /*
 809  905           * Allocate the place holder for the public file handle, which
 810  906           * is all zeroes. It is initially set to the root filesystem.
 811  907           */
 812      -        exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP);
 813      -        exi_public = exi_root;
      908 +        ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
      909 +        ne->exi_public = ne->exi_root;
 814  910  
 815      -        exi_root->exi_export.ex_flags = EX_PUBLIC;
 816      -        exi_root->exi_export.ex_pathlen = 1;    /* length of "/" */
 817      -        exi_root->exi_export.ex_path =
 818      -            kmem_alloc(exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 819      -        exi_root->exi_export.ex_path[0] = '/';
 820      -        exi_root->exi_export.ex_path[1] = '\0';
      911 +        ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
      912 +        ne->exi_root->exi_export.ex_pathlen = 1;        /* length of "/" */
      913 +        ne->exi_root->exi_export.ex_path =
      914 +            kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
      915 +        ne->exi_root->exi_export.ex_path[0] = '/';
      916 +        ne->exi_root->exi_export.ex_path[1] = '\0';
 821  917  
 822      -        exi_root->exi_count = 1;
 823      -        mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
      918 +        ne->exi_root->exi_count = 1;
      919 +        mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 824  920  
 825      -        exi_root->exi_vp = rootdir;
 826      -        exi_rootfid.fid_len = MAXFIDSZ;
 827      -        error = vop_fid_pseudo(exi_root->exi_vp, &exi_rootfid);
 828      -        if (error) {
 829      -                mutex_destroy(&exi_root->exi_lock);
 830      -                kmem_free(exi_root, sizeof (*exi_root));
 831      -                return (error);
 832      -        }
      921 +        /*
      922 +         * Because we cannot:
      923 +         *      ASSERT(curzone->zone_id == ng->nfs_zoneid);
      924 +         * We grab the zone pointer explicitly (like netstacks do) and
      925 +         * set the rootvp here.
      926 +         *
      927 +         * Subsequent exportinfo_t's that get export_link()ed to "ne" also
      928 +         * will backpoint to "ne" such that exi->exi_ne->exi_root->exi_vp
      929 +         * will get the zone's rootvp for a given exportinfo_t.
      930 +         */
      931 +        zone = zone_find_by_id_nolock(ng->nfs_zoneid);
      932 +        ne->exi_root->exi_vp = zone->zone_rootvp;
      933 +        ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 833  934  
 834  935          /*
 835      -         * Initialize auth cache and auth cache lock
      936 +         * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
      937 +         * because we can't correctly return errors here.
 836  938           */
      939 +
      940 +        /* Initialize auth cache and auth cache lock */
 837  941          for (i = 0; i < AUTH_TABLESIZE; i++) {
 838      -                exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
      942 +                ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 839  943                      KM_SLEEP);
 840      -                avl_create(exi_root->exi_cache[i], nfsauth_cache_clnt_compar,
 841      -                    sizeof (struct auth_cache_clnt),
      944 +                avl_create(ne->exi_root->exi_cache[i],
      945 +                    nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 842  946                      offsetof(struct auth_cache_clnt, authc_link));
 843  947          }
 844      -        rw_init(&exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
      948 +        rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 845  949  
 846      -        /* setup the fhandle template */
 847      -        exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 848      -        exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len;
 849      -        bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata,
 850      -            exi_rootfid.fid_len);
 851      -        exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data);
      950 +        /* setup exi_fh later, in nfs_export_get_rootfid */
 852  951  
 853      -        /*
 854      -         * Publish the exportinfo in the hash table
 855      -         */
 856      -        export_link(exi_root);
      952 +        rw_enter(&ne->exported_lock, RW_WRITER);
 857  953  
 858      -        nfslog_init();
 859      -        ns_root = NULL;
      954 +        /* Publish the exportinfo in the hash table */
      955 +        export_link(ne, ne->exi_root);
 860  956  
 861      -        return (0);
      957 +        /* Initialize exi_id and exi_kstats */
      958 +        mutex_enter(&nfs_exi_id_lock);
      959 +        ne->exi_root->exi_id = exi_id_get_next();
      960 +        avl_add(&exi_id_tree, ne->exi_root);
      961 +        mutex_exit(&nfs_exi_id_lock);
      962 +
      963 +        rw_exit(&ne->exported_lock);
      964 +        ne->ns_root = NULL;
      965 +
      966 +        ng->nfs_export = ne;
 862  967  }
 863  968  
 864  969  /*
 865      - * Finalization routine for export routines. Called to cleanup previously
 866      - * initialization work when the NFS server module could not be loaded correctly.
      970 + * During zone shutdown, remove exports
 867  971   */
 868  972  void
 869      -nfs_exportfini(void)
      973 +nfs_export_zone_shutdown(nfs_globals_t *ng)
 870  974  {
      975 +        nfs_export_t *ne = ng->nfs_export;
      976 +        struct exportinfo *exi, *nexi;
      977 +        int i, errors;
      978 +
      979 +        rw_enter(&ne->exported_lock, RW_READER);
      980 +
      981 +        errors = 0;
      982 +        for (i = 0; i < EXPTABLESIZE; i++) {
      983 +
      984 +                exi = ne->exptable[i];
      985 +                if (exi != NULL)
      986 +                        exi_hold(exi);
      987 +
      988 +                while (exi != NULL) {
      989 +
      990 +                        /*
      991 +                         * Get and hold next export before
      992 +                         * dropping the rwlock and unexport
      993 +                         */
      994 +                        nexi = exi->fid_hash.next;
      995 +                        if (nexi != NULL)
      996 +                                exi_hold(nexi);
      997 +
      998 +                        rw_exit(&ne->exported_lock);
      999 +
     1000 +                        /*
     1001 +                         * Skip ne->exi_root which gets special
     1002 +                         * create/destroy handling.
     1003 +                         */
     1004 +                        if (exi != ne->exi_root &&
     1005 +                            unexport(ne, exi) != 0)
     1006 +                                errors++;
     1007 +                        exi_rele(exi);
     1008 +
     1009 +                        rw_enter(&ne->exported_lock, RW_READER);
     1010 +                        exi = nexi;
     1011 +                }
     1012 +        }
     1013 +        if (errors > 0) {
     1014 +                cmn_err(CE_NOTE, "NFS: failed un-exports in zone %d",
     1015 +                    (int)ng->nfs_zoneid);
     1016 +        }
     1017 +
     1018 +        rw_exit(&ne->exported_lock);
     1019 +}
     1020 +
     1021 +void
     1022 +nfs_export_zone_fini(nfs_globals_t *ng)
     1023 +{
 871 1024          int i;
     1025 +        nfs_export_t *ne = ng->nfs_export;
     1026 +        struct exportinfo *exi;
 872 1027  
     1028 +        ng->nfs_export = NULL;
     1029 +
     1030 +        rw_enter(&ne->exported_lock, RW_WRITER);
     1031 +
     1032 +        mutex_enter(&nfs_exi_id_lock);
     1033 +        avl_remove(&exi_id_tree, ne->exi_root);
     1034 +        mutex_exit(&nfs_exi_id_lock);
     1035 +
     1036 +        export_unlink(ne, ne->exi_root);
     1037 +
     1038 +        rw_exit(&ne->exported_lock);
     1039 +
     1040 +        /* Deallocate the place holder for the public file handle */
     1041 +        srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
     1042 +            ne->exi_root->exi_export.ex_seccnt);
     1043 +        mutex_destroy(&ne->exi_root->exi_lock);
     1044 +
     1045 +        rw_destroy(&ne->exi_root->exi_cache_lock);
     1046 +        for (i = 0; i < AUTH_TABLESIZE; i++) {
     1047 +                avl_destroy(ne->exi_root->exi_cache[i]);
     1048 +                kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
     1049 +        }
     1050 +
     1051 +        kmem_free(ne->exi_root->exi_export.ex_path,
     1052 +            ne->exi_root->exi_export.ex_pathlen + 1);
     1053 +        kmem_free(ne->exi_root, sizeof (*ne->exi_root));
     1054 +
 873 1055          /*
 874      -         * Deallocate the place holder for the public file handle.
     1056 +         * The shutdown hook should have left the exi_id_tree
     1057 +         * with nothing belonging to this zone.
 875 1058           */
 876      -        srv_secinfo_list_free(exi_root->exi_export.ex_secinfo,
 877      -            exi_root->exi_export.ex_seccnt);
 878      -        mutex_destroy(&exi_root->exi_lock);
 879      -        rw_destroy(&exi_root->exi_cache_lock);
 880      -        for (i = 0; i < AUTH_TABLESIZE; i++) {
 881      -                avl_destroy(exi_root->exi_cache[i]);
 882      -                kmem_free(exi_root->exi_cache[i], sizeof (avl_tree_t));
     1059 +        mutex_enter(&nfs_exi_id_lock);
     1060 +        i = 0;
     1061 +        exi = avl_first(&exi_id_tree);
     1062 +        while (exi != NULL) {
     1063 +                if (exi->exi_zoneid == ng->nfs_zoneid)
     1064 +                        i++;
     1065 +                exi = AVL_NEXT(&exi_id_tree, exi);
 883 1066          }
 884      -        kmem_free(exi_root, sizeof (*exi_root));
     1067 +        mutex_exit(&nfs_exi_id_lock);
     1068 +        if (i > 0) {
     1069 +                cmn_err(CE_NOTE,
     1070 +                    "NFS: zone %d has %d export IDs left after shutdown",
     1071 +                    (int)ng->nfs_zoneid, i);
     1072 +        }
     1073 +        rw_destroy(&ne->exported_lock);
     1074 +        kmem_free(ne, sizeof (*ne));
     1075 +}
 885 1076  
 886      -        rw_destroy(&exported_lock);
     1077 +/*
     1078 + * Initialization routine for export routines.
     1079 + * Should only be called once.
     1080 + */
     1081 +void
     1082 +nfs_exportinit(void)
     1083 +{
     1084 +        mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
     1085 +
     1086 +        /* exi_id handling initialization */
     1087 +        exi_id_next = 0;
     1088 +        exi_id_overflow = FALSE;
     1089 +        avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
     1090 +            offsetof(struct exportinfo, exi_id_link));
     1091 +
     1092 +        nfslog_init();
 887 1093  }
 888 1094  
 889 1095  /*
     1096 + * Finalization routine for export routines.
     1097 + */
     1098 +void
     1099 +nfs_exportfini(void)
     1100 +{
     1101 +        avl_destroy(&exi_id_tree);
     1102 +        mutex_destroy(&nfs_exi_id_lock);
     1103 +}
     1104 +
     1105 +/*
 890 1106   *  Check if 2 gss mechanism identifiers are the same.
 891 1107   *
 892 1108   *  return FALSE if not the same.
 893 1109   *  return TRUE if the same.
 894 1110   */
 895 1111  static bool_t
 896 1112  nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
 897 1113  {
 898 1114          if ((mech1->length == 0) && (mech2->length == 0))
 899 1115                  return (TRUE);
 900 1116  
 901 1117          if (mech1->length != mech2->length)
 902 1118                  return (FALSE);
 903 1119  
 904 1120          return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
 905 1121  }
 906 1122  
 907 1123  /*
 908 1124   *  This routine is used by rpc to map rpc security number
 909 1125   *  to nfs specific security flavor number.
 910 1126   *
 911 1127   *  The gss callback prototype is
 912 1128   *  callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
 913 1129   *                              rpc_gss_lock_t *, void **),
 914 1130   *  since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
  
    | 
      ↓ open down ↓ | 
    15 lines elided | 
    
      ↑ open up ↑ | 
  
 915 1131   *  we cast them to void.
 916 1132   */
 917 1133  /*ARGSUSED*/
 918 1134  bool_t
 919 1135  rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
 920 1136      rpc_gss_lock_t *lock, void **cookie)
 921 1137  {
 922 1138          int i, j;
 923 1139          rpc_gss_rawcred_t *raw_cred;
 924 1140          struct exportinfo *exi;
     1141 +        nfs_export_t *ne = nfs_get_export();
 925 1142  
 926 1143          /*
 927 1144           * We don't deal with delegated credentials.
 928 1145           */
 929 1146          if (deleg != GSS_C_NO_CREDENTIAL)
 930 1147                  return (FALSE);
 931 1148  
 932 1149          raw_cred = lock->raw_cred;
 933 1150          *cookie = NULL;
 934 1151  
 935      -        rw_enter(&exported_lock, RW_READER);
     1152 +        rw_enter(&ne->exported_lock, RW_READER);
     1153 +
 936 1154          for (i = 0; i < EXPTABLESIZE; i++) {
 937      -                exi = exptable[i];
     1155 +                exi = ne->exptable[i];
 938 1156                  while (exi) {
 939 1157                          if (exi->exi_export.ex_seccnt > 0) {
 940 1158                                  struct secinfo *secp;
 941 1159                                  seconfig_t *se;
 942 1160                                  int seccnt;
 943 1161  
 944 1162                                  secp = exi->exi_export.ex_secinfo;
 945 1163                                  seccnt = exi->exi_export.ex_seccnt;
 946 1164                                  for (j = 0; j < seccnt; j++) {
 947 1165                                          /*
 948 1166                                           *  If there is a map of the triplet
 949 1167                                           *  (mechanism, service, qop) between
 950 1168                                           *  raw_cred and the exported flavor,
 951 1169                                           *  get the psudo flavor number.
 952 1170                                           *  Also qop should not be NULL, it
 953 1171                                           *  should be "default" or something
 954 1172                                           *  else.
 955 1173                                           */
 956 1174                                          se = &secp[j].s_secinfo;
 957 1175                                          if ((se->sc_rpcnum == RPCSEC_GSS) &&
 958 1176  
 959 1177                                              (nfs_mech_equal(
 960 1178                                              se->sc_gss_mech_type,
 961 1179                                              raw_cred->mechanism)) &&
 962 1180  
 963 1181                                              (se->sc_service ==
 964 1182                                              raw_cred->service) &&
 965 1183                                              (raw_cred->qop == se->sc_qop)) {
 966 1184  
  
    | 
      ↓ open down ↓ | 
    19 lines elided | 
    
      ↑ open up ↑ | 
  
 967 1185                                                  *cookie = (void *)(uintptr_t)
 968 1186                                                      se->sc_nfsnum;
 969 1187                                                  goto done;
 970 1188                                          }
 971 1189                                  }
 972 1190                          }
 973 1191                          exi = exi->fid_hash.next;
 974 1192                  }
 975 1193          }
 976 1194  done:
 977      -        rw_exit(&exported_lock);
     1195 +        rw_exit(&ne->exported_lock);
 978 1196  
 979 1197          /*
 980 1198           * If no nfs pseudo number mapping can be found in the export
 981 1199           * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
 982 1200           * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
 983 1201           *
 984 1202           * For example:
 985 1203           *      server first shares with krb5i;
 986 1204           *      client mounts with krb5i;
 987 1205           *      server re-shares with krb5p;
 988 1206           *      client tries with krb5i, but no mapping can be found;
 989 1207           *      rpcsec_gss module calls this routine to do the mapping,
 990 1208           *              if this routine fails, request is rejected from
 991 1209           *              the rpc layer.
 992 1210           *      What we need is to let the nfs layer rejects the request.
 993 1211           *      For V4, we can reject with NFS4ERR_WRONGSEC and the client
 994 1212           *      may recover from it by getting the new flavor via SECINFO.
 995 1213           *
 996 1214           * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
 997 1215           * is owned by IANA (see RFC 2623).
 998 1216           *
 999 1217           * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
1000 1218           * the implementation issue. This number should not overlap with
1001 1219           * any new IANA defined pseudo flavor numbers.
1002 1220           */
1003 1221          if (*cookie == NULL)
1004 1222                  *cookie = (void *)NFS_FLAVOR_NOMAP;
1005 1223  
1006 1224          lock->locked = TRUE;
1007 1225  
1008 1226          return (TRUE);
1009 1227  }
1010 1228  
1011 1229  
1012 1230  /*
1013 1231   * Exportfs system call; credentials should be checked before
1014 1232   * calling this function.
1015 1233   */
1016 1234  int
1017 1235  exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
1018 1236  {
1019 1237          vnode_t *vp;
1020 1238          vnode_t *dvp;
1021 1239          struct exportdata *kex;
1022 1240          struct exportinfo *exi = NULL;
1023 1241          struct exportinfo *ex, *ex1, *ex2;
1024 1242          fid_t fid;
1025 1243          fsid_t fsid;
1026 1244          int error;
1027 1245          size_t allocsize;
1028 1246          struct secinfo *sp;
1029 1247          struct secinfo *exs;
1030 1248          rpc_gss_callback_t cb;
1031 1249          char *pathbuf;
1032 1250          char *log_buffer;
1033 1251          char *tagbuf;
  
    | 
      ↓ open down ↓ | 
    46 lines elided | 
    
      ↑ open up ↑ | 
  
1034 1252          int callback;
1035 1253          int allocd_seccnt;
1036 1254          STRUCT_HANDLE(exportfs_args, uap);
1037 1255          STRUCT_DECL(exportdata, uexi);
1038 1256          struct secinfo newsec[MAX_FLAVORS];
1039 1257          int newcnt;
1040 1258          struct secinfo oldsec[MAX_FLAVORS];
1041 1259          int oldcnt;
1042 1260          int i;
1043 1261          struct pathname lookpn;
     1262 +        nfs_export_t *ne = nfs_get_export();
1044 1263  
1045 1264          STRUCT_SET_HANDLE(uap, model, args);
1046 1265  
1047 1266          /* Read in pathname from userspace */
1048 1267          if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn))
1049 1268                  return (error);
1050 1269  
1051 1270          /* Walk the export list looking for that pathname */
1052      -        rw_enter(&exported_lock, RW_READER);
     1271 +        rw_enter(&ne->exported_lock, RW_READER);
1053 1272          DTRACE_PROBE(nfss__i__exported_lock1_start);
1054      -        for (ex1 = exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
     1273 +        for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1055 1274              strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1056      -                if (ex1 != exi_root && 0 ==
     1275 +                if (ex1 != ne->exi_root && 0 ==
1057 1276                      strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1058 1277                          exi_hold(ex1);
1059 1278                          break;
1060 1279                  }
1061 1280          }
1062 1281          DTRACE_PROBE(nfss__i__exported_lock1_stop);
1063      -        rw_exit(&exported_lock);
     1282 +        rw_exit(&ne->exported_lock);
1064 1283  
1065 1284          /* Is this an unshare? */
1066 1285          if (STRUCT_FGETP(uap, uex) == NULL) {
1067 1286                  pn_free(&lookpn);
1068 1287                  if (ex1 == NULL)
1069 1288                          return (EINVAL);
1070      -                error = unexport(ex1);
     1289 +                error = unexport(ne, ex1);
1071 1290                  exi_rele(ex1);
1072 1291                  return (error);
1073 1292          }
1074 1293  
1075 1294          /* It is a share or a re-share */
1076 1295          error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1077 1296              FOLLOW, &dvp, &vp);
1078 1297          if (error == EINVAL) {
1079 1298                  /*
1080 1299                   * if fname resolves to / we get EINVAL error
1081 1300                   * since we wanted the parent vnode. Try again
1082 1301                   * with NULL dvp.
1083 1302                   */
1084 1303                  error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1085 1304                      FOLLOW, NULL, &vp);
1086 1305                  dvp = NULL;
1087 1306          }
1088 1307          if (!error && vp == NULL) {
1089 1308                  /* Last component of fname not found */
1090 1309                  if (dvp != NULL)
1091 1310                          VN_RELE(dvp);
1092 1311                  error = ENOENT;
1093 1312          }
1094 1313          if (error) {
1095 1314                  pn_free(&lookpn);
1096 1315                  if (ex1)
1097 1316                          exi_rele(ex1);
1098 1317                  return (error);
1099 1318          }
1100 1319  
1101 1320          /*
1102 1321           * 'vp' may be an AUTOFS node, so we perform a
1103 1322           * VOP_ACCESS() to trigger the mount of the
1104 1323           * intended filesystem, so we can share the intended
1105 1324           * filesystem instead of the AUTOFS filesystem.
1106 1325           */
1107 1326          (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
1108 1327  
1109 1328          /*
1110 1329           * We're interested in the top most filesystem.
1111 1330           * This is specially important when uap->dname is a trigger
1112 1331           * AUTOFS node, since we're really interested in sharing the
1113 1332           * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1114 1333           * call not the AUTOFS node itself.
1115 1334           */
1116 1335          if (vn_mountedvfs(vp) != NULL) {
1117 1336                  if (error = traverse(&vp)) {
1118 1337                          VN_RELE(vp);
1119 1338                          if (dvp != NULL)
1120 1339                                  VN_RELE(dvp);
1121 1340                          pn_free(&lookpn);
1122 1341                          if (ex1)
1123 1342                                  exi_rele(ex1);
1124 1343                          return (error);
1125 1344                  }
1126 1345          }
1127 1346  
1128 1347          /* Do not allow sharing another vnode for already shared path */
1129 1348          if (ex1 && !PSEUDO(ex1) && !VN_CMP(ex1->exi_vp, vp)) {
1130 1349                  VN_RELE(vp);
1131 1350                  if (dvp != NULL)
1132 1351                          VN_RELE(dvp);
1133 1352                  pn_free(&lookpn);
1134 1353                  exi_rele(ex1);
1135 1354                  return (EEXIST);
1136 1355          }
1137 1356          if (ex1)
1138 1357                  exi_rele(ex1);
1139 1358  
1140 1359          /*
1141 1360           * Get the vfs id
1142 1361           */
1143 1362          bzero(&fid, sizeof (fid));
1144 1363          fid.fid_len = MAXFIDSZ;
1145 1364          error = VOP_FID(vp, &fid, NULL);
1146 1365          fsid = vp->v_vfsp->vfs_fsid;
1147 1366  
1148 1367          if (error) {
1149 1368                  VN_RELE(vp);
1150 1369                  if (dvp != NULL)
1151 1370                          VN_RELE(dvp);
1152 1371                  /*
1153 1372                   * If VOP_FID returns ENOSPC then the fid supplied
1154 1373                   * is too small.  For now we simply return EREMOTE.
1155 1374                   */
  
    | 
      ↓ open down ↓ | 
    75 lines elided | 
    
      ↑ open up ↑ | 
  
1156 1375                  if (error == ENOSPC)
1157 1376                          error = EREMOTE;
1158 1377                  pn_free(&lookpn);
1159 1378                  return (error);
1160 1379          }
1161 1380  
1162 1381          /*
1163 1382           * Do not allow re-sharing a shared vnode under a different path
1164 1383           * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1165 1384           */
1166      -        rw_enter(&exported_lock, RW_READER);
     1385 +        rw_enter(&ne->exported_lock, RW_READER);
1167 1386          DTRACE_PROBE(nfss__i__exported_lock2_start);
1168      -        for (ex2 = exptable[exptablehash(&fsid, &fid)]; ex2;
     1387 +        for (ex2 = ne->exptable[exptablehash(&fsid, &fid)]; ex2;
1169 1388              ex2 = ex2->fid_hash.next) {
1170      -                if (ex2 != exi_root && !PSEUDO(ex2) &&
     1389 +                if (ex2 != ne->exi_root && !PSEUDO(ex2) &&
1171 1390                      VN_CMP(ex2->exi_vp, vp) &&
1172 1391                      strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1173 1392                          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1174      -                        rw_exit(&exported_lock);
     1393 +                        rw_exit(&ne->exported_lock);
1175 1394                          VN_RELE(vp);
1176 1395                          if (dvp != NULL)
1177 1396                                  VN_RELE(dvp);
1178 1397                          pn_free(&lookpn);
1179 1398                          return (EEXIST);
1180 1399                  }
1181 1400          }
1182 1401          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1183      -        rw_exit(&exported_lock);
     1402 +        rw_exit(&ne->exported_lock);
1184 1403          pn_free(&lookpn);
1185 1404  
1186 1405          exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1187 1406          exi->exi_fsid = fsid;
1188 1407          exi->exi_fid = fid;
1189 1408          exi->exi_vp = vp;
1190 1409          exi->exi_count = 1;
     1410 +        exi->exi_zoneid = crgetzoneid(cr);
     1411 +        ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
1191 1412          exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1192 1413              VSW_VOLATILEDEV) ? 1 : 0;
1193 1414          mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1194 1415          exi->exi_dvp = dvp;
1195 1416  
1196 1417          /*
1197 1418           * Initialize auth cache and auth cache lock
1198 1419           */
1199 1420          for (i = 0; i < AUTH_TABLESIZE; i++) {
1200 1421                  exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1201 1422                  avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
1202 1423                      sizeof (struct auth_cache_clnt),
1203 1424                      offsetof(struct auth_cache_clnt, authc_link));
1204 1425          }
1205 1426          rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1206 1427  
1207 1428          /*
1208 1429           * Build up the template fhandle
1209 1430           */
1210 1431          exi->exi_fh.fh_fsid = fsid;
1211 1432          if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) {
1212 1433                  error = EREMOTE;
1213 1434                  goto out1;
1214 1435          }
1215 1436          exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
1216 1437          bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
1217 1438              exi->exi_fid.fid_len);
1218 1439  
1219 1440          exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
1220 1441  
1221 1442          kex = &exi->exi_export;
1222 1443  
1223 1444          /*
1224 1445           * Load in everything, and do sanity checking
1225 1446           */
1226 1447          STRUCT_INIT(uexi, model);
1227 1448          if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi),
1228 1449              STRUCT_SIZE(uexi))) {
1229 1450                  error = EFAULT;
1230 1451                  goto out1;
1231 1452          }
1232 1453  
1233 1454          kex->ex_version = STRUCT_FGET(uexi, ex_version);
1234 1455          if (kex->ex_version != EX_CURRENT_VERSION) {
1235 1456                  error = EINVAL;
1236 1457                  cmn_err(CE_WARN,
1237 1458                      "NFS: exportfs requires export struct version 2 - got %d\n",
1238 1459                      kex->ex_version);
1239 1460                  goto out1;
1240 1461          }
1241 1462  
1242 1463          /*
1243 1464           * Must have at least one security entry
1244 1465           */
1245 1466          kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt);
1246 1467          if (kex->ex_seccnt < 1) {
1247 1468                  error = EINVAL;
1248 1469                  goto out1;
1249 1470          }
1250 1471  
1251 1472          kex->ex_path = STRUCT_FGETP(uexi, ex_path);
1252 1473          kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen);
1253 1474          kex->ex_flags = STRUCT_FGET(uexi, ex_flags);
1254 1475          kex->ex_anon = STRUCT_FGET(uexi, ex_anon);
1255 1476          kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo);
1256 1477          kex->ex_index = STRUCT_FGETP(uexi, ex_index);
1257 1478          kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer);
1258 1479          kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen);
1259 1480          kex->ex_tag = STRUCT_FGETP(uexi, ex_tag);
1260 1481          kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen);
1261 1482  
1262 1483          /*
1263 1484           * Copy the exported pathname into
1264 1485           * an appropriately sized buffer.
1265 1486           */
1266 1487          pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1267 1488          if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) {
1268 1489                  kmem_free(pathbuf, MAXPATHLEN);
1269 1490                  error = EFAULT;
1270 1491                  goto out1;
1271 1492          }
1272 1493          kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
1273 1494          bcopy(pathbuf, kex->ex_path, kex->ex_pathlen);
1274 1495          kex->ex_path[kex->ex_pathlen] = '\0';
1275 1496          kmem_free(pathbuf, MAXPATHLEN);
1276 1497  
1277 1498          /*
1278 1499           * Get the path to the logging buffer and the tag
1279 1500           */
1280 1501          if (kex->ex_flags & EX_LOG) {
1281 1502                  log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1282 1503                  if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN,
1283 1504                      &kex->ex_log_bufferlen)) {
1284 1505                          kmem_free(log_buffer, MAXPATHLEN);
1285 1506                          error = EFAULT;
1286 1507                          goto out2;
1287 1508                  }
1288 1509                  kex->ex_log_buffer =
1289 1510                      kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP);
1290 1511                  bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen);
1291 1512                  kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0';
1292 1513                  kmem_free(log_buffer, MAXPATHLEN);
1293 1514  
1294 1515                  tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1295 1516                  if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN,
1296 1517                      &kex->ex_taglen)) {
1297 1518                          kmem_free(tagbuf, MAXPATHLEN);
1298 1519                          error = EFAULT;
1299 1520                          goto out3;
1300 1521                  }
1301 1522                  kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP);
1302 1523                  bcopy(tagbuf, kex->ex_tag, kex->ex_taglen);
1303 1524                  kex->ex_tag[kex->ex_taglen] = '\0';
1304 1525                  kmem_free(tagbuf, MAXPATHLEN);
1305 1526          }
1306 1527  
1307 1528          /*
1308 1529           * Load the security information for each flavor
1309 1530           */
1310 1531          allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model);
1311 1532          sp = kmem_zalloc(allocsize, KM_SLEEP);
1312 1533          if (copyin(kex->ex_secinfo, sp, allocsize)) {
1313 1534                  kmem_free(sp, allocsize);
1314 1535                  error = EFAULT;
1315 1536                  goto out4;
1316 1537          }
1317 1538  
1318 1539          /*
1319 1540           * All of these nested structures need to be converted to
1320 1541           * the kernel native format.
1321 1542           */
1322 1543          if (model != DATAMODEL_NATIVE) {
1323 1544                  size_t allocsize2;
1324 1545                  struct secinfo *sp2;
1325 1546  
1326 1547                  allocsize2 = kex->ex_seccnt * sizeof (struct secinfo);
1327 1548                  sp2 = kmem_zalloc(allocsize2, KM_SLEEP);
1328 1549  
1329 1550                  for (i = 0; i < kex->ex_seccnt; i++) {
1330 1551                          STRUCT_HANDLE(secinfo, usi);
1331 1552  
1332 1553                          STRUCT_SET_HANDLE(usi, model,
1333 1554                              (struct secinfo *)((caddr_t)sp +
1334 1555                              (i * SIZEOF_STRUCT(secinfo, model))));
1335 1556                          bcopy(STRUCT_FGET(usi, s_secinfo.sc_name),
1336 1557                              sp2[i].s_secinfo.sc_name, MAX_NAME_LEN);
1337 1558                          sp2[i].s_secinfo.sc_nfsnum =
1338 1559                              STRUCT_FGET(usi, s_secinfo.sc_nfsnum);
1339 1560                          sp2[i].s_secinfo.sc_rpcnum =
1340 1561                              STRUCT_FGET(usi, s_secinfo.sc_rpcnum);
1341 1562                          bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech),
1342 1563                              sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN);
1343 1564                          sp2[i].s_secinfo.sc_gss_mech_type =
1344 1565                              STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type);
1345 1566                          sp2[i].s_secinfo.sc_qop =
1346 1567                              STRUCT_FGET(usi, s_secinfo.sc_qop);
1347 1568                          sp2[i].s_secinfo.sc_service =
1348 1569                              STRUCT_FGET(usi, s_secinfo.sc_service);
1349 1570  
1350 1571                          sp2[i].s_flags = STRUCT_FGET(usi, s_flags);
1351 1572                          sp2[i].s_window = STRUCT_FGET(usi, s_window);
1352 1573                          sp2[i].s_rootid = STRUCT_FGET(usi, s_rootid);
1353 1574                          sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt);
1354 1575                          sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames);
1355 1576                  }
1356 1577                  kmem_free(sp, allocsize);
1357 1578                  sp = sp2;
1358 1579                  allocsize = allocsize2;
1359 1580          }
1360 1581  
1361 1582          kex->ex_secinfo = sp;
1362 1583  
1363 1584          /*
1364 1585           * And now copy rootnames for each individual secinfo.
1365 1586           */
1366 1587          callback = 0;
1367 1588          allocd_seccnt = 0;
1368 1589          while (allocd_seccnt < kex->ex_seccnt) {
1369 1590  
1370 1591                  exs = &sp[allocd_seccnt];
1371 1592                  if (exs->s_rootcnt > 0) {
1372 1593                          if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum,
1373 1594                              exs->s_rootcnt, &exs->s_rootnames, model)) {
1374 1595                                  error = EFAULT;
1375 1596                                  goto out5;
1376 1597                          }
1377 1598                  }
1378 1599  
1379 1600                  if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
1380 1601                          rpc_gss_OID mech_tmp;
1381 1602                          STRUCT_DECL(rpc_gss_OID_s, umech_tmp);
1382 1603                          caddr_t elements_tmp;
1383 1604  
1384 1605                          /* Copyin mechanism type */
1385 1606                          STRUCT_INIT(umech_tmp, model);
1386 1607                          mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP);
1387 1608                          if (copyin(exs->s_secinfo.sc_gss_mech_type,
1388 1609                              STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) {
1389 1610                                  kmem_free(mech_tmp, sizeof (*mech_tmp));
1390 1611                                  error = EFAULT;
1391 1612                                  goto out5;
1392 1613                          }
1393 1614                          mech_tmp->length = STRUCT_FGET(umech_tmp, length);
1394 1615                          mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements);
1395 1616  
1396 1617                          elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP);
1397 1618                          if (copyin(mech_tmp->elements, elements_tmp,
1398 1619                              mech_tmp->length)) {
1399 1620                                  kmem_free(elements_tmp, mech_tmp->length);
1400 1621                                  kmem_free(mech_tmp, sizeof (*mech_tmp));
1401 1622                                  error = EFAULT;
1402 1623                                  goto out5;
1403 1624                          }
1404 1625                          mech_tmp->elements = elements_tmp;
1405 1626                          exs->s_secinfo.sc_gss_mech_type = mech_tmp;
1406 1627                          allocd_seccnt++;
1407 1628  
1408 1629                          callback = 1;
1409 1630                  } else
1410 1631                          allocd_seccnt++;
1411 1632          }
1412 1633  
1413 1634          /*
1414 1635           * Init the secinfo reference count and mark these flavors
1415 1636           * explicitly exported flavors.
1416 1637           */
1417 1638          for (i = 0; i < kex->ex_seccnt; i++) {
1418 1639                  kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED;
1419 1640                  kex->ex_secinfo[i].s_refcnt = 1;
1420 1641          }
1421 1642  
1422 1643          /*
1423 1644           *  Set up rpcsec_gss callback routine entry if any.
1424 1645           */
1425 1646          if (callback) {
1426 1647                  cb.callback = rfs_gsscallback;
1427 1648                  cb.program = NFS_ACL_PROGRAM;
1428 1649                  for (cb.version = NFS_ACL_VERSMIN;
1429 1650                      cb.version <= NFS_ACL_VERSMAX; cb.version++) {
1430 1651                          (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1431 1652                              (void *)&cb);
1432 1653                  }
1433 1654  
1434 1655                  cb.program = NFS_PROGRAM;
1435 1656                  for (cb.version = NFS_VERSMIN;
1436 1657                      cb.version <= NFS_VERSMAX; cb.version++) {
1437 1658                          (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1438 1659                              (void *)&cb);
1439 1660                  }
1440 1661          }
1441 1662  
1442 1663          /*
1443 1664           * Check the index flag. Do this here to avoid holding the
1444 1665           * lock while dealing with the index option (as we do with
1445 1666           * the public option).
1446 1667           */
1447 1668          if (kex->ex_flags & EX_INDEX) {
1448 1669                  if (!kex->ex_index) {   /* sanity check */
1449 1670                          error = EINVAL;
1450 1671                          goto out5;
1451 1672                  }
1452 1673                  if (error = loadindex(kex))
1453 1674                          goto out5;
  
    | 
      ↓ open down ↓ | 
    253 lines elided | 
    
      ↑ open up ↑ | 
  
1454 1675          }
1455 1676  
1456 1677          if (kex->ex_flags & EX_LOG) {
1457 1678                  if (error = nfslog_setup(exi))
1458 1679                          goto out6;
1459 1680          }
1460 1681  
1461 1682          /*
1462 1683           * Insert the new entry at the front of the export list
1463 1684           */
1464      -        rw_enter(&exported_lock, RW_WRITER);
     1685 +        rw_enter(&ne->exported_lock, RW_WRITER);
1465 1686          DTRACE_PROBE(nfss__i__exported_lock3_start);
1466 1687  
1467      -        export_link(exi);
     1688 +        export_link(ne, exi);
1468 1689  
1469 1690          /*
1470 1691           * Check the rest of the list for an old entry for the fs.
1471 1692           * If one is found then unlink it, wait until this is the
1472 1693           * only reference and then free it.
1473 1694           */
1474 1695          for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) {
1475      -                if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) {
1476      -                        export_unlink(ex);
     1696 +                if (ex != ne->exi_root && VN_CMP(ex->exi_vp, vp)) {
     1697 +                        mutex_enter(&nfs_exi_id_lock);
     1698 +                        avl_remove(&exi_id_tree, ex);
     1699 +                        mutex_exit(&nfs_exi_id_lock);
     1700 +                        export_unlink(ne, ex);
1477 1701                          break;
1478 1702                  }
1479 1703          }
1480 1704  
1481 1705          /*
1482 1706           * If the public filehandle is pointing at the
1483 1707           * old entry, then point it back at the root.
1484 1708           */
1485      -        if (ex != NULL && ex == exi_public)
1486      -                exi_public = exi_root;
     1709 +        if (ex != NULL && ex == ne->exi_public)
     1710 +                ne->exi_public = ne->exi_root;
1487 1711  
1488 1712          /*
1489 1713           * If the public flag is on, make the global exi_public
1490 1714           * point to this entry and turn off the public bit so that
1491 1715           * we can distinguish it from the place holder export.
1492 1716           */
1493 1717          if (kex->ex_flags & EX_PUBLIC) {
1494      -                exi_public = exi;
     1718 +                ne->exi_public = exi;
1495 1719                  kex->ex_flags &= ~EX_PUBLIC;
1496 1720          }
1497 1721  
1498 1722  #ifdef VOLATILE_FH_TEST
1499 1723          /*
1500 1724           * Set up the volatile_id value if volatile on share.
1501 1725           * The list of volatile renamed filehandles is always destroyed,
1502 1726           * if the fs was reshared.
1503 1727           */
1504 1728          if (kex->ex_flags & EX_VOLFH)
1505 1729                  exi->exi_volatile_id = gethrestime_sec();
1506 1730  
1507 1731          mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
1508 1732  #endif /* VOLATILE_FH_TEST */
1509 1733  
1510 1734          /*
1511 1735           * If this is a new export, then climb up
1512 1736           * the tree and check if any pseudo exports
1513 1737           * need to be created to provide a path for
1514 1738           * NFS v4 clients.
1515 1739           */
  
    | 
      ↓ open down ↓ | 
    11 lines elided | 
    
      ↑ open up ↑ | 
  
1516 1740          if (ex == NULL) {
1517 1741                  error = treeclimb_export(exi);
1518 1742                  if (error)
1519 1743                          goto out7;
1520 1744          } else {
1521 1745                  /* If it's a re-export update namespace tree */
1522 1746                  exi->exi_tree = ex->exi_tree;
1523 1747                  exi->exi_tree->tree_exi = exi;
1524 1748  
1525 1749                  /* Update the change timestamp */
1526      -                tree_update_change(exi->exi_tree, NULL);
     1750 +                tree_update_change(ne, exi->exi_tree, NULL);
1527 1751          }
1528 1752  
1529 1753          /*
1530 1754           * build a unique flavor list from the flavors specified
1531 1755           * in the share cmd.  unique means that each flavor only
1532 1756           * appears once in the secinfo list -- no duplicates allowed.
1533 1757           */
1534 1758          newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
1535 1759  
1536      -        srv_secinfo_treeclimb(exi, newsec, newcnt, TRUE);
     1760 +        srv_secinfo_treeclimb(ne, exi, newsec, newcnt, TRUE);
1537 1761  
1538 1762          /*
1539 1763           * If re-sharing an old export entry, update the secinfo data
1540 1764           * depending on if the old entry is a pseudo node or not.
1541 1765           */
1542 1766          if (ex != NULL) {
1543 1767                  oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
1544 1768                  if (PSEUDO(ex)) {
1545 1769                          /*
1546 1770                           * The dir being shared is a pseudo export root (which
1547 1771                           * will be transformed into a real export root).  The
1548 1772                           * flavor(s) of the new share were propagated to the
1549 1773                           * ancestors by srv_secinfo_treeclimb() above.  Now
1550 1774                           * transfer the implicit flavor refs from the old
  
    | 
      ↓ open down ↓ | 
    4 lines elided | 
    
      ↑ open up ↑ | 
  
1551 1775                           * pseudo exprot root to the new (real) export root.
1552 1776                           */
1553 1777                          srv_secinfo_add(&exi->exi_export.ex_secinfo,
1554 1778                              &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
1555 1779                  } else {
1556 1780                          /*
1557 1781                           * First transfer implicit flavor refs to new export.
1558 1782                           * Remove old flavor refs last.
1559 1783                           */
1560 1784                          srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
1561      -                        srv_secinfo_treeclimb(ex, oldsec, oldcnt, FALSE);
     1785 +                        srv_secinfo_treeclimb(ne, ex, oldsec, oldcnt, FALSE);
1562 1786                  }
1563 1787          }
1564 1788  
1565 1789          /*
1566 1790           * If it's a re-export and the old entry has a pseudonode list,
1567 1791           * transfer it to the new export.
1568 1792           */
1569 1793          if (ex != NULL && (ex->exi_visible != NULL)) {
1570 1794                  exi->exi_visible = ex->exi_visible;
1571 1795                  ex->exi_visible = NULL;
1572 1796          }
1573 1797  
     1798 +        /*
     1799 +         * Initialize exi_id and exi_kstats
     1800 +         */
     1801 +        if (ex != NULL) {
     1802 +                exi->exi_id = ex->exi_id;
     1803 +        } else {
     1804 +                mutex_enter(&nfs_exi_id_lock);
     1805 +                exi->exi_id = exi_id_get_next();
     1806 +                mutex_exit(&nfs_exi_id_lock);
     1807 +        }
     1808 +        mutex_enter(&nfs_exi_id_lock);
     1809 +        avl_add(&exi_id_tree, exi);
     1810 +        mutex_exit(&nfs_exi_id_lock);
     1811 +
1574 1812          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1575      -        rw_exit(&exported_lock);
     1813 +        rw_exit(&ne->exported_lock);
1576 1814  
1577      -        if (exi_public == exi || kex->ex_flags & EX_LOG) {
     1815 +        if (ne->exi_public == exi || kex->ex_flags & EX_LOG) {
1578 1816                  /*
1579 1817                   * Log share operation to this buffer only.
1580 1818                   */
1581 1819                  nfslog_share_record(exi, cr);
1582 1820          }
1583 1821  
1584 1822          if (ex != NULL)
1585 1823                  exi_rele(ex);
1586 1824  
1587 1825          return (0);
1588 1826  
1589 1827  out7:
1590 1828          /* Unlink the new export in exptable. */
1591      -        export_unlink(exi);
     1829 +        export_unlink(ne, exi);
1592 1830          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1593      -        rw_exit(&exported_lock);
     1831 +        rw_exit(&ne->exported_lock);
1594 1832  out6:
1595 1833          if (kex->ex_flags & EX_INDEX)
1596 1834                  kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1597 1835  out5:
1598 1836          /* free partially completed allocation */
1599 1837          while (--allocd_seccnt >= 0) {
1600 1838                  exs = &kex->ex_secinfo[allocd_seccnt];
1601 1839                  srv_secinfo_entry_free(exs);
1602 1840          }
1603 1841  
1604 1842          if (kex->ex_secinfo) {
1605 1843                  kmem_free(kex->ex_secinfo,
1606 1844                      kex->ex_seccnt * sizeof (struct secinfo));
1607 1845          }
1608 1846  
1609 1847  out4:
1610 1848          if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
1611 1849                  kmem_free(kex->ex_tag, kex->ex_taglen + 1);
1612 1850  out3:
1613 1851          if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
1614 1852                  kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1);
1615 1853  out2:
1616 1854          kmem_free(kex->ex_path, kex->ex_pathlen + 1);
1617 1855  out1:
1618 1856          VN_RELE(vp);
1619 1857          if (dvp != NULL)
1620 1858                  VN_RELE(dvp);
1621 1859          mutex_destroy(&exi->exi_lock);
1622 1860          rw_destroy(&exi->exi_cache_lock);
1623 1861          for (i = 0; i < AUTH_TABLESIZE; i++) {
1624 1862                  avl_destroy(exi->exi_cache[i]);
1625 1863                  kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
1626 1864          }
  
    | 
      ↓ open down ↓ | 
    23 lines elided | 
    
      ↑ open up ↑ | 
  
1627 1865  
1628 1866          kmem_free(exi, sizeof (*exi));
1629 1867  
1630 1868          return (error);
1631 1869  }
1632 1870  
1633 1871  /*
1634 1872   * Remove the exportinfo from the export list
1635 1873   */
1636 1874  void
1637      -export_unlink(struct exportinfo *exi)
     1875 +export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1638 1876  {
1639      -        ASSERT(RW_WRITE_HELD(&exported_lock));
     1877 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1640 1878  
1641 1879          exp_hash_unlink(exi, fid_hash);
1642 1880          exp_hash_unlink(exi, path_hash);
     1881 +        ASSERT3P(exi->exi_ne, ==, ne);
     1882 +        exi->exi_ne = NULL;
1643 1883  }
1644 1884  
1645 1885  /*
1646 1886   * Unexport an exported filesystem
1647 1887   */
1648 1888  static int
1649      -unexport(struct exportinfo *exi)
     1889 +unexport(nfs_export_t *ne, struct exportinfo *exi)
1650 1890  {
1651 1891          struct secinfo cursec[MAX_FLAVORS];
1652 1892          int curcnt;
1653 1893  
1654      -        rw_enter(&exported_lock, RW_WRITER);
     1894 +        rw_enter(&ne->exported_lock, RW_WRITER);
1655 1895  
1656 1896          /* Check if exi is still linked in the export table */
1657 1897          if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1658      -                rw_exit(&exported_lock);
     1898 +                rw_exit(&ne->exported_lock);
1659 1899                  return (EINVAL);
1660 1900          }
1661 1901  
1662      -        export_unlink(exi);
     1902 +        mutex_enter(&nfs_exi_id_lock);
     1903 +        avl_remove(&exi_id_tree, exi);
     1904 +        mutex_exit(&nfs_exi_id_lock);
     1905 +        export_unlink(ne, exi);
1663 1906  
1664 1907          /*
1665 1908           * Remove security flavors before treeclimb_unexport() is called
1666 1909           * because srv_secinfo_treeclimb needs the namespace tree
1667 1910           */
1668 1911          curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
     1912 +        srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1669 1913  
1670      -        srv_secinfo_treeclimb(exi, cursec, curcnt, FALSE);
1671      -
1672 1914          /*
1673 1915           * If there's a visible list, then need to leave
1674 1916           * a pseudo export here to retain the visible list
1675 1917           * for paths to exports below.
1676 1918           */
1677 1919          if (exi->exi_visible != NULL) {
1678 1920                  struct exportinfo *newexi;
1679 1921  
1680      -                newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid,
     1922 +                newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1681 1923                      exi->exi_visible, &exi->exi_export);
1682 1924                  exi->exi_visible = NULL;
1683 1925  
1684 1926                  /* interconnect the existing treenode with the new exportinfo */
1685 1927                  newexi->exi_tree = exi->exi_tree;
1686 1928                  newexi->exi_tree->tree_exi = newexi;
1687 1929  
1688 1930                  /* Update the change timestamp */
1689      -                tree_update_change(exi->exi_tree, NULL);
     1931 +                tree_update_change(ne, exi->exi_tree, NULL);
1690 1932          } else {
1691      -                treeclimb_unexport(exi);
     1933 +                treeclimb_unexport(ne, exi);
1692 1934          }
1693 1935  
1694      -        rw_exit(&exported_lock);
     1936 +        rw_exit(&ne->exported_lock);
1695 1937  
1696 1938          /*
1697 1939           * Need to call into the NFSv4 server and release all data
1698 1940           * held on this particular export.  This is important since
1699 1941           * the v4 server may be holding file locks or vnodes under
1700 1942           * this export.
1701 1943           */
1702      -        rfs4_clean_state_exi(exi);
     1944 +        rfs4_clean_state_exi(ne, exi);
1703 1945  
1704 1946          /*
1705 1947           * Notify the lock manager that the filesystem is being
1706 1948           * unexported.
1707 1949           */
1708 1950          lm_unexport(exi);
1709 1951  
1710 1952          /*
1711 1953           * If this was a public export, restore
1712 1954           * the public filehandle to the root.
1713 1955           */
1714      -        if (exi == exi_public) {
1715      -                exi_public = exi_root;
1716 1956  
1717      -                nfslog_share_record(exi_public, CRED());
     1957 +        /*
     1958 +         * XXX KEBE ASKS --> Should CRED() instead be
     1959 +         * exi->exi_zone->zone_kcred?
     1960 +         */
     1961 +        if (exi == ne->exi_public) {
     1962 +                ne->exi_public = ne->exi_root;
     1963 +
     1964 +                nfslog_share_record(ne->exi_public, CRED());
1718 1965          }
1719 1966  
1720      -        if (exi->exi_export.ex_flags & EX_LOG) {
     1967 +        if (exi->exi_export.ex_flags & EX_LOG)
1721 1968                  nfslog_unshare_record(exi, CRED());
1722      -        }
1723 1969  
1724 1970          exi_rele(exi);
1725 1971          return (0);
1726 1972  }
1727 1973  
1728 1974  /*
1729 1975   * Get file handle system call.
1730 1976   * Takes file name and returns a file handle for it.
1731 1977   * Credentials must be verified before calling.
1732 1978   */
1733 1979  int
1734 1980  nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1735 1981  {
1736 1982          nfs_fh3 fh;
1737 1983          char buf[NFS3_MAXFHSIZE];
1738 1984          char *logptr, logbuf[NFS3_MAXFHSIZE];
1739 1985          int l = NFS3_MAXFHSIZE;
1740 1986          vnode_t *vp;
1741 1987          vnode_t *dvp;
1742 1988          struct exportinfo *exi;
1743 1989          int error;
1744 1990          int vers;
1745 1991          STRUCT_HANDLE(nfs_getfh_args, uap);
1746 1992  
1747 1993  #ifdef lint
1748 1994          model = model;          /* STRUCT macros don't always use it */
1749 1995  #endif
1750 1996  
1751 1997          STRUCT_SET_HANDLE(uap, model, args);
1752 1998  
1753 1999          error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1754 2000              FOLLOW, &dvp, &vp);
1755 2001          if (error == EINVAL) {
1756 2002                  /*
1757 2003                   * if fname resolves to / we get EINVAL error
1758 2004                   * since we wanted the parent vnode. Try again
1759 2005                   * with NULL dvp.
1760 2006                   */
1761 2007                  error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1762 2008                      FOLLOW, NULL, &vp);
1763 2009                  dvp = NULL;
1764 2010          }
1765 2011          if (!error && vp == NULL) {
1766 2012                  /*
1767 2013                   * Last component of fname not found
1768 2014                   */
1769 2015                  if (dvp != NULL) {
1770 2016                          VN_RELE(dvp);
1771 2017                  }
1772 2018                  error = ENOENT;
1773 2019          }
1774 2020          if (error)
1775 2021                  return (error);
1776 2022  
1777 2023          /*
1778 2024           * 'vp' may be an AUTOFS node, so we perform a
1779 2025           * VOP_ACCESS() to trigger the mount of the
1780 2026           * intended filesystem, so we can share the intended
1781 2027           * filesystem instead of the AUTOFS filesystem.
1782 2028           */
1783 2029          (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
1784 2030  
1785 2031          /*
1786 2032           * We're interested in the top most filesystem.
1787 2033           * This is specially important when uap->dname is a trigger
1788 2034           * AUTOFS node, since we're really interested in sharing the
1789 2035           * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1790 2036           * call not the AUTOFS node itself.
1791 2037           */
1792 2038          if (vn_mountedvfs(vp) != NULL) {
1793 2039                  if (error = traverse(&vp)) {
1794 2040                          VN_RELE(vp);
1795 2041                          if (dvp != NULL)
1796 2042                                  VN_RELE(dvp);
1797 2043                          return (error);
1798 2044                  }
1799 2045          }
1800 2046  
1801 2047          vers = STRUCT_FGET(uap, vers);
1802 2048          exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE);
1803 2049          if (!error) {
1804 2050                  if (vers == NFS_VERSION) {
1805 2051                          error = makefh((fhandle_t *)buf, vp, exi);
1806 2052                          l = NFS_FHSIZE;
1807 2053                          logptr = buf;
1808 2054                  } else if (vers == NFS_V3) {
1809 2055                          int i, sz, pad;
1810 2056  
1811 2057                          error = makefh3(&fh, vp, exi);
1812 2058                          l = RNDUP(fh.fh3_length);
1813 2059                          if (!error && (l > sizeof (fhandle3_t)))
1814 2060                                  error = EREMOTE;
1815 2061                          logptr = logbuf;
1816 2062                          if (!error) {
1817 2063                                  i = 0;
1818 2064                                  sz = sizeof (fsid_t);
1819 2065                                  bcopy(&fh.fh3_fsid, &buf[i], sz);
1820 2066                                  i += sz;
1821 2067  
1822 2068                                  /*
1823 2069                                   * For backwards compatibility, the
1824 2070                                   * fid length may be less than
1825 2071                                   * NFS_FHMAXDATA, but it was always
1826 2072                                   * encoded as NFS_FHMAXDATA bytes.
1827 2073                                   */
1828 2074  
1829 2075                                  sz = sizeof (ushort_t);
1830 2076                                  bcopy(&fh.fh3_len, &buf[i], sz);
1831 2077                                  i += sz;
1832 2078                                  bcopy(fh.fh3_data, &buf[i], fh.fh3_len);
1833 2079                                  i += fh.fh3_len;
1834 2080                                  pad = (NFS_FHMAXDATA - fh.fh3_len);
1835 2081                                  if (pad > 0) {
1836 2082                                          bzero(&buf[i], pad);
1837 2083                                          i += pad;
1838 2084                                          l += pad;
1839 2085                                  }
1840 2086  
1841 2087                                  sz = sizeof (ushort_t);
1842 2088                                  bcopy(&fh.fh3_xlen, &buf[i], sz);
1843 2089                                  i += sz;
1844 2090                                  bcopy(fh.fh3_xdata, &buf[i], fh.fh3_xlen);
1845 2091                                  i += fh.fh3_xlen;
1846 2092                                  pad = (NFS_FHMAXDATA - fh.fh3_xlen);
1847 2093                                  if (pad > 0) {
1848 2094                                          bzero(&buf[i], pad);
1849 2095                                          i += pad;
1850 2096                                          l += pad;
1851 2097                                  }
1852 2098                          }
1853 2099                          /*
1854 2100                           * If we need to do NFS logging, the filehandle
1855 2101                           * must be downsized to 32 bytes.
1856 2102                           */
1857 2103                          if (!error && exi->exi_export.ex_flags & EX_LOG) {
1858 2104                                  i = 0;
1859 2105                                  sz = sizeof (fsid_t);
1860 2106                                  bcopy(&fh.fh3_fsid, &logbuf[i], sz);
1861 2107                                  i += sz;
1862 2108                                  sz = sizeof (ushort_t);
1863 2109                                  bcopy(&fh.fh3_len, &logbuf[i], sz);
1864 2110                                  i += sz;
1865 2111                                  sz = NFS_FHMAXDATA;
1866 2112                                  bcopy(fh.fh3_data, &logbuf[i], sz);
1867 2113                                  i += sz;
1868 2114                                  sz = sizeof (ushort_t);
1869 2115                                  bcopy(&fh.fh3_xlen, &logbuf[i], sz);
1870 2116                                  i += sz;
1871 2117                                  sz = NFS_FHMAXDATA;
1872 2118                                  bcopy(fh.fh3_xdata, &logbuf[i], sz);
1873 2119                                  i += sz;
1874 2120                          }
1875 2121                  }
1876 2122                  if (!error && exi->exi_export.ex_flags & EX_LOG) {
1877 2123                          nfslog_getfh(exi, (fhandle_t *)logptr,
1878 2124                              STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr);
1879 2125                  }
1880 2126                  exi_rele(exi);
1881 2127                  if (!error) {
1882 2128                          if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int)))
1883 2129                                  error = EFAULT;
1884 2130                          if (copyout(buf, STRUCT_FGETP(uap, fhp), l))
1885 2131                                  error = EFAULT;
1886 2132                  }
1887 2133          }
1888 2134          VN_RELE(vp);
1889 2135          if (dvp != NULL) {
1890 2136                  VN_RELE(dvp);
1891 2137          }
1892 2138          return (error);
1893 2139  }
1894 2140  
1895 2141  /*
1896 2142   * Strategy: if vp is in the export list, then
1897 2143   * return the associated file handle. Otherwise, ".."
1898 2144   * once up the vp and try again, until the root of the
1899 2145   * filesystem is reached.
1900 2146   */
1901 2147  struct   exportinfo *
1902 2148  nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
1903 2149      int *err, bool_t v4srv)
1904 2150  {
1905 2151          fid_t fid;
1906 2152          int error;
1907 2153          struct exportinfo *exi;
1908 2154  
1909 2155          ASSERT(vp);
1910 2156          VN_HOLD(vp);
1911 2157          if (dvp != NULL) {
1912 2158                  VN_HOLD(dvp);
1913 2159          }
1914 2160          if (walk != NULL)
1915 2161                  *walk = 0;
1916 2162  
1917 2163          for (;;) {
1918 2164                  bzero(&fid, sizeof (fid));
1919 2165                  fid.fid_len = MAXFIDSZ;
1920 2166                  error = vop_fid_pseudo(vp, &fid);
1921 2167                  if (error) {
1922 2168                          /*
1923 2169                           * If vop_fid_pseudo returns ENOSPC then the fid
1924 2170                           * supplied is too small. For now we simply
1925 2171                           * return EREMOTE.
1926 2172                           */
1927 2173                          if (error == ENOSPC)
1928 2174                                  error = EREMOTE;
1929 2175                          break;
1930 2176                  }
1931 2177  
1932 2178                  if (v4srv)
1933 2179                          exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
1934 2180                  else
1935 2181                          exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
1936 2182  
1937 2183                  if (exi != NULL) {
1938 2184                          /*
  
    | 
      ↓ open down ↓ | 
    206 lines elided | 
    
      ↑ open up ↑ | 
  
1939 2185                           * Found the export info
1940 2186                           */
1941 2187                          break;
1942 2188                  }
1943 2189  
1944 2190                  /*
1945 2191                   * We have just failed finding a matching export.
1946 2192                   * If we're at the root of this filesystem, then
1947 2193                   * it's time to stop (with failure).
1948 2194                   */
1949      -                if (vp->v_flag & VROOT) {
     2195 +                ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
     2196 +                if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
1950 2197                          error = EINVAL;
1951 2198                          break;
1952 2199                  }
1953 2200  
1954 2201                  if (walk != NULL)
1955 2202                          (*walk)++;
1956 2203  
1957 2204                  /*
1958 2205                   * Now, do a ".." up vp. If dvp is supplied, use it,
1959 2206                   * otherwise, look it up.
1960 2207                   */
1961 2208                  if (dvp == NULL) {
1962 2209                          error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
1963 2210                              NULL, NULL, NULL);
1964 2211                          if (error)
1965 2212                                  break;
1966 2213                  }
1967 2214                  VN_RELE(vp);
1968 2215                  vp = dvp;
1969 2216                  dvp = NULL;
1970 2217          }
1971 2218          VN_RELE(vp);
1972 2219          if (dvp != NULL) {
1973 2220                  VN_RELE(dvp);
1974 2221          }
1975 2222          if (error != 0) {
1976 2223                  if (err != NULL)
1977 2224                          *err = error;
1978 2225                  return (NULL);
1979 2226          }
1980 2227          return (exi);
1981 2228  }
1982 2229  
1983 2230  int
1984 2231  chk_clnt_sec(exportinfo_t *exi, struct svc_req *req)
1985 2232  {
1986 2233          int i, nfsflavor;
1987 2234          struct secinfo *sp;
1988 2235  
1989 2236          /*
1990 2237           *  Get the nfs flavor number from xprt.
1991 2238           */
1992 2239          nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
1993 2240  
1994 2241          sp = exi->exi_export.ex_secinfo;
1995 2242          for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
1996 2243                  if ((nfsflavor == sp[i].s_secinfo.sc_nfsnum) &&
1997 2244                      SEC_REF_EXPORTED(sp + i))
1998 2245                          return (TRUE);
1999 2246          }
2000 2247          return (FALSE);
2001 2248  }
2002 2249  
2003 2250  /*
2004 2251   * Make an fhandle from a vnode
2005 2252   */
2006 2253  int
2007 2254  makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi)
2008 2255  {
2009 2256          int error;
2010 2257  
2011 2258          *fh = exi->exi_fh;      /* struct copy */
2012 2259  
2013 2260          error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL);
2014 2261          if (error) {
2015 2262                  /*
2016 2263                   * Should be something other than EREMOTE
2017 2264                   */
2018 2265                  return (EREMOTE);
2019 2266          }
2020 2267          return (0);
2021 2268  }
2022 2269  
2023 2270  /*
2024 2271   * This routine makes an overloaded V2 fhandle which contains
2025 2272   * sec modes.
2026 2273   *
2027 2274   * Note that the first four octets contain the length octet,
2028 2275   * the status octet, and two padded octets to make them XDR
2029 2276   * four-octet aligned.
2030 2277   *
2031 2278   *   1   2   3   4                                          32
2032 2279   * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
2033 2280   * | l | s |   |   |     sec_1     |...|     sec_n     |...|   |
2034 2281   * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
2035 2282   *
2036 2283   * where
2037 2284   *
2038 2285   *   the status octet s indicates whether there are more security
2039 2286   *   flavors (1 means yes, 0 means no) that require the client to
2040 2287   *   perform another 0x81 LOOKUP to get them,
2041 2288   *
2042 2289   *   the length octet l is the length describing the number of
2043 2290   *   valid octets that follow.  (l = 4 * n, where n is the number
2044 2291   *   of security flavors sent in the current overloaded filehandle.)
2045 2292   *
2046 2293   *   sec_index should always be in the inclusive range: [1 - ex_seccnt],
2047 2294   *   and it tells server where to start within the secinfo array.
2048 2295   *   Usually it will always be 1; however, if more flavors are used
2049 2296   *   for the public export than can be encoded in the overloaded FH
2050 2297   *   (7 for NFS2), subsequent SNEGO MCLs will have a larger index
2051 2298   *   so the server will pick up where it left off from the previous
2052 2299   *   MCL reply.
2053 2300   *
2054 2301   *   With NFS4 support, implicitly allowed flavors are also in
2055 2302   *   the secinfo array; however, they should not be returned in
2056 2303   *   SNEGO MCL replies.
2057 2304   */
2058 2305  int
2059 2306  makefh_ol(fhandle_t *fh, exportinfo_t *exi, uint_t sec_index)
2060 2307  {
2061 2308          secinfo_t sec[MAX_FLAVORS];
2062 2309          int totalcnt, i, *ipt, cnt, seccnt, secidx, fh_max_cnt;
2063 2310          char *c;
2064 2311  
2065 2312          if (fh == NULL || exi == NULL || sec_index < 1)
2066 2313                  return (EREMOTE);
2067 2314  
2068 2315          /*
2069 2316           * WebNFS clients need to know the unique set of explicitly
2070 2317           * shared flavors in used for the public export. When
2071 2318           * "TRUE" is passed to build_seclist_nodups(), only explicitly
2072 2319           * shared flavors are included in the list.
2073 2320           */
2074 2321          seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2075 2322          if (sec_index > seccnt)
2076 2323                  return (EREMOTE);
2077 2324  
2078 2325          fh_max_cnt = (NFS_FHSIZE / sizeof (int)) - 1;
2079 2326          totalcnt = seccnt - sec_index + 1;
2080 2327          cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2081 2328  
2082 2329          c = (char *)fh;
2083 2330          /*
2084 2331           * Encode the length octet representing the number of
2085 2332           * security flavors (in bytes) in this overloaded fh.
2086 2333           */
2087 2334          *c = cnt * sizeof (int);
2088 2335  
2089 2336          /*
2090 2337           * Encode the status octet that indicates whether there
2091 2338           * are more security flavors the client needs to get.
2092 2339           */
2093 2340          *(c + 1) = totalcnt > fh_max_cnt;
2094 2341  
2095 2342          /*
2096 2343           * put security flavors in the overloaded fh
2097 2344           */
2098 2345          ipt = (int *)(c + sizeof (int32_t));
2099 2346          secidx = sec_index - 1;
2100 2347          for (i = 0; i < cnt; i++) {
2101 2348                  ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2102 2349          }
2103 2350          return (0);
2104 2351  }
2105 2352  
2106 2353  /*
2107 2354   * Make an nfs_fh3 from a vnode
2108 2355   */
2109 2356  int
2110 2357  makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
2111 2358  {
2112 2359          int error;
2113 2360          fid_t fid;
2114 2361  
2115 2362          bzero(&fid, sizeof (fid));
2116 2363          fid.fid_len = sizeof (fh->fh3_data);
2117 2364          error = VOP_FID(vp, &fid, NULL);
2118 2365          if (error)
2119 2366                  return (EREMOTE);
2120 2367  
2121 2368          bzero(fh, sizeof (nfs_fh3));
2122 2369          fh->fh3_fsid = exi->exi_fsid;
2123 2370          fh->fh3_len = fid.fid_len;
2124 2371          bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len);
2125 2372  
2126 2373          fh->fh3_xlen = exi->exi_fid.fid_len;
2127 2374          ASSERT(fh->fh3_xlen <= sizeof (fh->fh3_xdata));
2128 2375          bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen);
2129 2376  
2130 2377          fh->fh3_length = sizeof (fh->fh3_fsid)
2131 2378              + sizeof (fh->fh3_len) + fh->fh3_len
2132 2379              + sizeof (fh->fh3_xlen) + fh->fh3_xlen;
2133 2380          fh->fh3_flags = 0;
2134 2381  
2135 2382          return (0);
2136 2383  }
2137 2384  
2138 2385  /*
2139 2386   * This routine makes an overloaded V3 fhandle which contains
2140 2387   * sec modes.
2141 2388   *
2142 2389   *  1        4
2143 2390   * +--+--+--+--+
2144 2391   * |    len    |
2145 2392   * +--+--+--+--+
2146 2393   *                                               up to 64
2147 2394   * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
2148 2395   * |s |  |  |  |   sec_1   |   sec_2   | ... |   sec_n   |
2149 2396   * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
2150 2397   *
2151 2398   * len = 4 * (n+1), where n is the number of security flavors
2152 2399   * sent in the current overloaded filehandle.
2153 2400   *
2154 2401   * the status octet s indicates whether there are more security
2155 2402   * mechanisms (1 means yes, 0 means no) that require the client
2156 2403   * to perform another 0x81 LOOKUP to get them.
2157 2404   *
2158 2405   * Three octets are padded after the status octet.
2159 2406   */
2160 2407  int
2161 2408  makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index)
2162 2409  {
2163 2410          secinfo_t sec[MAX_FLAVORS];
2164 2411          int totalcnt, cnt, *ipt, i, seccnt, fh_max_cnt, secidx;
2165 2412          char *c;
2166 2413  
2167 2414          if (fh == NULL || exi == NULL || sec_index < 1)
2168 2415                  return (EREMOTE);
2169 2416  
2170 2417          /*
2171 2418           * WebNFS clients need to know the unique set of explicitly
2172 2419           * shared flavors in used for the public export. When
2173 2420           * "TRUE" is passed to build_seclist_nodups(), only explicitly
2174 2421           * shared flavors are included in the list.
2175 2422           */
2176 2423          seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2177 2424  
2178 2425          if (sec_index > seccnt)
2179 2426                  return (EREMOTE);
2180 2427  
2181 2428          fh_max_cnt = (NFS3_FHSIZE / sizeof (int)) - 1;
2182 2429          totalcnt = seccnt - sec_index + 1;
2183 2430          cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2184 2431  
2185 2432          /*
2186 2433           * Place the length in fh3_length representing the number
2187 2434           * of security flavors (in bytes) in this overloaded fh.
2188 2435           */
2189 2436          fh->fh3_flags = FH_WEBNFS;
2190 2437          fh->fh3_length = (cnt+1) * sizeof (int32_t);
2191 2438  
2192 2439          c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i;
2193 2440          /*
2194 2441           * Encode the status octet that indicates whether there
2195 2442           * are more security flavors the client needs to get.
2196 2443           */
2197 2444          *c = totalcnt > fh_max_cnt;
2198 2445  
2199 2446          /*
2200 2447           * put security flavors in the overloaded fh
2201 2448           */
2202 2449          secidx = sec_index - 1;
2203 2450          ipt = (int *)(c + sizeof (int32_t));
2204 2451          for (i = 0; i < cnt; i++) {
2205 2452                  ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2206 2453          }
2207 2454          return (0);
2208 2455  }
2209 2456  
2210 2457  /*
2211 2458   * Make an nfs_fh4 from a vnode
2212 2459   */
2213 2460  int
2214 2461  makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi)
2215 2462  {
2216 2463          int error;
2217 2464          nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2218 2465          fid_t fid;
2219 2466  
2220 2467          bzero(&fid, sizeof (fid));
2221 2468          fid.fid_len = MAXFIDSZ;
2222 2469          /*
2223 2470           * vop_fid_pseudo() is used to set up NFSv4 namespace, so
2224 2471           * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
2225 2472           */
2226 2473          error = vop_fid_pseudo(vp, &fid);
2227 2474          if (error)
2228 2475                  return (error);
2229 2476  
2230 2477          fh->nfs_fh4_len = NFS_FH4_LEN;
2231 2478  
2232 2479          fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid;
2233 2480          fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen;
2234 2481  
2235 2482          bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data));
2236 2483          bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata));
2237 2484          ASSERT(exi->exi_fh.fh_xlen <= sizeof (fh_fmtp->fh4_i.fhx_xdata));
2238 2485          bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata,
2239 2486              exi->exi_fh.fh_xlen);
2240 2487  
2241 2488          fh_fmtp->fh4_len = fid.fid_len;
2242 2489          ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data));
2243 2490          bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len);
2244 2491          fh_fmtp->fh4_flag = 0;
2245 2492  
2246 2493  #ifdef VOLATILE_FH_TEST
2247 2494          /*
2248 2495           * XXX (temporary?)
2249 2496           * Use the rnode volatile_id value to add volatility to the fh.
2250 2497           *
2251 2498           * For testing purposes there are currently two scenarios, based
2252 2499           * on whether the filesystem was shared with "volatile_fh"
2253 2500           * or "expire_on_rename". In the first case, use the value of
2254 2501           * export struct share_time as the volatile_id. In the second
2255 2502           * case use the vnode volatile_id value (which is set to the
2256 2503           * time in which the file was renamed).
2257 2504           *
2258 2505           * Note that the above are temporary constructs for testing only
2259 2506           * XXX
2260 2507           */
2261 2508          if (exi->exi_export.ex_flags & EX_VOLRNM) {
2262 2509                  fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh);
2263 2510          } else if (exi->exi_export.ex_flags & EX_VOLFH) {
2264 2511                  fh_fmtp->fh4_volatile_id = exi->exi_volatile_id;
2265 2512          } else {
2266 2513                  fh_fmtp->fh4_volatile_id = 0;
2267 2514          }
2268 2515  #endif /* VOLATILE_FH_TEST */
2269 2516  
2270 2517          return (0);
2271 2518  }
2272 2519  
2273 2520  /*
2274 2521   * Convert an fhandle into a vnode.
2275 2522   * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2276 2523   * WARNING: users of this routine must do a VN_RELE on the vnode when they
2277 2524   * are done with it.
2278 2525   */
2279 2526  vnode_t *
2280 2527  nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi)
2281 2528  {
2282 2529          vfs_t *vfsp;
2283 2530          vnode_t *vp;
2284 2531          int error;
2285 2532          fid_t *fidp;
2286 2533  
2287 2534          TRACE_0(TR_FAC_NFS, TR_FHTOVP_START,
2288 2535              "fhtovp_start");
2289 2536  
2290 2537          if (exi == NULL) {
2291 2538                  TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2292 2539                      "fhtovp_end:(%S)", "exi NULL");
2293 2540                  return (NULL);  /* not exported */
2294 2541          }
2295 2542  
2296 2543          ASSERT(exi->exi_vp != NULL);
2297 2544  
2298 2545          if (PUBLIC_FH2(fh)) {
2299 2546                  if (exi->exi_export.ex_flags & EX_PUBLIC) {
2300 2547                          TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2301 2548                              "fhtovp_end:(%S)", "root not exported");
2302 2549                          return (NULL);
2303 2550                  }
2304 2551                  vp = exi->exi_vp;
2305 2552                  VN_HOLD(vp);
2306 2553                  return (vp);
2307 2554          }
2308 2555  
2309 2556          vfsp = exi->exi_vp->v_vfsp;
2310 2557          ASSERT(vfsp != NULL);
2311 2558          fidp = (fid_t *)&fh->fh_len;
2312 2559  
2313 2560          error = VFS_VGET(vfsp, &vp, fidp);
2314 2561          if (error || vp == NULL) {
2315 2562                  TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2316 2563                      "fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2317 2564                  return (NULL);
2318 2565          }
2319 2566          TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2320 2567              "fhtovp_end:(%S)", "end");
2321 2568          return (vp);
2322 2569  }
2323 2570  
2324 2571  /*
2325 2572   * Convert an nfs_fh3 into a vnode.
2326 2573   * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2327 2574   * WARNING: users of this routine must do a VN_RELE on the vnode when they
2328 2575   * are done with it.
2329 2576   */
2330 2577  vnode_t *
2331 2578  nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi)
2332 2579  {
2333 2580          vfs_t *vfsp;
2334 2581          vnode_t *vp;
2335 2582          int error;
2336 2583          fid_t *fidp;
2337 2584  
2338 2585          if (exi == NULL)
2339 2586                  return (NULL);  /* not exported */
2340 2587  
2341 2588          ASSERT(exi->exi_vp != NULL);
2342 2589  
2343 2590          if (PUBLIC_FH3(fh)) {
2344 2591                  if (exi->exi_export.ex_flags & EX_PUBLIC)
2345 2592                          return (NULL);
2346 2593                  vp = exi->exi_vp;
2347 2594                  VN_HOLD(vp);
2348 2595                  return (vp);
2349 2596          }
2350 2597  
2351 2598          if (fh->fh3_length < NFS3_OLDFHSIZE ||
2352 2599              fh->fh3_length > NFS3_MAXFHSIZE)
2353 2600                  return (NULL);
2354 2601  
2355 2602          vfsp = exi->exi_vp->v_vfsp;
2356 2603          ASSERT(vfsp != NULL);
2357 2604          fidp = FH3TOFIDP(fh);
2358 2605  
2359 2606          error = VFS_VGET(vfsp, &vp, fidp);
2360 2607          if (error || vp == NULL)
2361 2608                  return (NULL);
2362 2609  
2363 2610          return (vp);
2364 2611  }
2365 2612  
2366 2613  /*
2367 2614   * Convert an nfs_fh4 into a vnode.
2368 2615   * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2369 2616   * WARNING: users of this routine must do a VN_RELE on the vnode when they
2370 2617   * are done with it.
2371 2618   */
2372 2619  vnode_t *
2373 2620  nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp)
2374 2621  {
2375 2622          vfs_t *vfsp;
2376 2623          vnode_t *vp = NULL;
2377 2624          int error;
2378 2625          fid_t *fidp;
2379 2626          nfs_fh4_fmt_t *fh_fmtp;
2380 2627  #ifdef VOLATILE_FH_TEST
2381 2628          uint32_t volatile_id = 0;
2382 2629  #endif /* VOLATILE_FH_TEST */
2383 2630  
2384 2631          if (exi == NULL) {
2385 2632                  *statp = NFS4ERR_STALE;
2386 2633                  return (NULL);  /* not exported */
2387 2634          }
2388 2635          ASSERT(exi->exi_vp != NULL);
2389 2636  
2390 2637          /* caller should have checked this */
2391 2638          ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN);
2392 2639  
2393 2640          fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2394 2641          vfsp = exi->exi_vp->v_vfsp;
2395 2642          ASSERT(vfsp != NULL);
2396 2643          fidp = (fid_t *)&fh_fmtp->fh4_len;
2397 2644  
2398 2645  #ifdef VOLATILE_FH_TEST
2399 2646          /* XXX check if volatile - should be changed later */
2400 2647          if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) {
2401 2648                  /*
2402 2649                   * Filesystem is shared with volatile filehandles
2403 2650                   */
2404 2651                  if (exi->exi_export.ex_flags & EX_VOLRNM)
2405 2652                          volatile_id = find_volrnm_fh_id(exi, fh);
2406 2653                  else
2407 2654                          volatile_id = exi->exi_volatile_id;
2408 2655  
2409 2656                  if (fh_fmtp->fh4_volatile_id != volatile_id) {
2410 2657                          *statp = NFS4ERR_FHEXPIRED;
2411 2658                          return (NULL);
2412 2659                  }
2413 2660          }
2414 2661          /*
2415 2662           * XXX even if test_volatile_fh false, the fh may contain a
2416 2663           * volatile id if obtained when the test was set.
2417 2664           */
2418 2665          fh_fmtp->fh4_volatile_id = (uchar_t)0;
2419 2666  #endif /* VOLATILE_FH_TEST */
2420 2667  
2421 2668          error = VFS_VGET(vfsp, &vp, fidp);
2422 2669          /*
2423 2670           * If we can not get vp from VFS_VGET, perhaps this is
2424 2671           * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2425 2672           * Check it out.
2426 2673           */
2427 2674          if (error && PSEUDO(exi))
2428 2675                  error = nfs4_vget_pseudo(exi, &vp, fidp);
2429 2676  
2430 2677          if (error || vp == NULL) {
2431 2678                  *statp = NFS4ERR_STALE;
2432 2679                  return (NULL);
2433 2680          }
2434 2681          /* XXX - disgusting hack */
2435 2682          if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
2436 2683                  vp->v_type = VDIR;
2437 2684          *statp = NFS4_OK;
2438 2685          return (vp);
  
    | 
      ↓ open down ↓ | 
    479 lines elided | 
    
      ↑ open up ↑ | 
  
2439 2686  }
2440 2687  
2441 2688  /*
2442 2689   * Find the export structure associated with the given filesystem.
2443 2690   * If found, then increment the ref count (exi_count).
2444 2691   */
2445 2692  struct exportinfo *
2446 2693  checkexport(fsid_t *fsid, fid_t *fid)
2447 2694  {
2448 2695          struct exportinfo *exi;
     2696 +        nfs_export_t *ne = nfs_get_export();
2449 2697  
2450      -        rw_enter(&exported_lock, RW_READER);
2451      -        for (exi = exptable[exptablehash(fsid, fid)];
     2698 +        rw_enter(&ne->exported_lock, RW_READER);
     2699 +        for (exi = ne->exptable[exptablehash(fsid, fid)];
2452 2700              exi != NULL;
2453 2701              exi = exi->fid_hash.next) {
2454 2702                  if (exportmatch(exi, fsid, fid)) {
2455 2703                          /*
2456 2704                           * If this is the place holder for the
2457 2705                           * public file handle, then return the
2458 2706                           * real export entry for the public file
2459 2707                           * handle.
2460 2708                           */
2461 2709                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2462      -                                exi = exi_public;
     2710 +                                exi = ne->exi_public;
2463 2711                          }
2464 2712  
2465 2713                          exi_hold(exi);
2466      -                        rw_exit(&exported_lock);
     2714 +                        rw_exit(&ne->exported_lock);
2467 2715                          return (exi);
2468 2716                  }
2469 2717          }
2470      -        rw_exit(&exported_lock);
     2718 +        rw_exit(&ne->exported_lock);
2471 2719          return (NULL);
2472 2720  }
2473 2721  
2474 2722  
2475 2723  /*
2476 2724   * "old school" version of checkexport() for NFS4.  NFS4
2477 2725   * rfs4_compound holds exported_lock for duration of compound
2478 2726   * processing.  This version doesn't manipulate exi_count
2479 2727   * since NFS4 breaks fundamental assumptions in the exi_count
2480 2728   * design.
2481 2729   */
2482 2730  struct exportinfo *
2483 2731  checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2484 2732  {
2485 2733          struct exportinfo *exi;
     2734 +        nfs_export_t *ne = nfs_get_export();
2486 2735  
2487      -        ASSERT(RW_LOCK_HELD(&exported_lock));
     2736 +        ASSERT(RW_LOCK_HELD(&ne->exported_lock));
2488 2737  
2489      -        for (exi = exptable[exptablehash(fsid, fid)];
     2738 +        for (exi = ne->exptable[exptablehash(fsid, fid)];
2490 2739              exi != NULL;
2491 2740              exi = exi->fid_hash.next) {
2492 2741                  if (exportmatch(exi, fsid, fid)) {
2493 2742                          /*
2494 2743                           * If this is the place holder for the
2495 2744                           * public file handle, then return the
2496 2745                           * real export entry for the public file
2497 2746                           * handle.
2498 2747                           */
2499 2748                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2500      -                                exi = exi_public;
     2749 +                                exi = ne->exi_public;
2501 2750                          }
2502 2751  
2503 2752                          /*
2504 2753                           * If vp is given, check if vp is the
2505 2754                           * same vnode as the exported node.
2506 2755                           *
2507 2756                           * Since VOP_FID of a lofs node returns the
2508 2757                           * fid of its real node (ufs), the exported
2509 2758                           * node for lofs and (pseudo) ufs may have
2510 2759                           * the same fsid and fid.
2511 2760                           */
2512 2761                          if (vp == NULL || vp == exi->exi_vp)
2513 2762                                  return (exi);
2514 2763                  }
2515 2764          }
2516 2765  
2517 2766          return (NULL);
2518 2767  }
2519 2768  
2520 2769  /*
2521 2770   * Free an entire export list node
2522 2771   */
2523 2772  void
2524 2773  exportfree(struct exportinfo *exi)
2525 2774  {
2526 2775          struct exportdata *ex;
2527 2776          struct charset_cache *cache;
2528 2777          int i;
2529 2778  
2530 2779          ex = &exi->exi_export;
2531 2780  
2532 2781          ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC));
2533 2782          VN_RELE(exi->exi_vp);
2534 2783          if (exi->exi_dvp != NULL)
2535 2784                  VN_RELE(exi->exi_dvp);
2536 2785  
2537 2786          if (ex->ex_flags & EX_INDEX)
2538 2787                  kmem_free(ex->ex_index, strlen(ex->ex_index) + 1);
2539 2788  
2540 2789          kmem_free(ex->ex_path, ex->ex_pathlen + 1);
2541 2790          nfsauth_cache_free(exi);
2542 2791  
2543 2792          /*
2544 2793           * if there is a character set mapping cached, clean it up.
2545 2794           */
2546 2795          for (cache = exi->exi_charset; cache != NULL;
2547 2796              cache = exi->exi_charset) {
2548 2797                  if (cache->inbound != (kiconv_t)-1)
2549 2798                          (void) kiconv_close(cache->inbound);
2550 2799                  if (cache->outbound != (kiconv_t)-1)
2551 2800                          (void) kiconv_close(cache->outbound);
2552 2801                  exi->exi_charset = cache->next;
2553 2802                  kmem_free(cache, sizeof (struct charset_cache));
2554 2803          }
2555 2804  
2556 2805          if (exi->exi_logbuffer != NULL)
2557 2806                  nfslog_disable(exi);
2558 2807  
2559 2808          if (ex->ex_flags & EX_LOG) {
2560 2809                  kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1);
2561 2810                  kmem_free(ex->ex_tag, ex->ex_taglen + 1);
2562 2811          }
2563 2812  
2564 2813          if (exi->exi_visible)
2565 2814                  free_visible(exi->exi_visible);
2566 2815  
2567 2816          srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt);
2568 2817  
2569 2818  #ifdef VOLATILE_FH_TEST
2570 2819          free_volrnm_list(exi);
2571 2820          mutex_destroy(&exi->exi_vol_rename_lock);
2572 2821  #endif /* VOLATILE_FH_TEST */
2573 2822  
2574 2823          mutex_destroy(&exi->exi_lock);
2575 2824          rw_destroy(&exi->exi_cache_lock);
2576 2825          /*
2577 2826           * All nodes in the exi_cache AVL trees were removed and freed in the
2578 2827           * nfsauth_cache_free() call above.  We will just destroy and free the
2579 2828           * empty AVL trees here.
2580 2829           */
2581 2830          for (i = 0; i < AUTH_TABLESIZE; i++) {
2582 2831                  avl_destroy(exi->exi_cache[i]);
2583 2832                  kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
2584 2833          }
2585 2834  
2586 2835          kmem_free(exi, sizeof (*exi));
2587 2836  }
2588 2837  
2589 2838  /*
2590 2839   * load the index file from user space into kernel space.
2591 2840   */
2592 2841  static int
2593 2842  loadindex(struct exportdata *kex)
2594 2843  {
2595 2844          int error;
2596 2845          char index[MAXNAMELEN+1];
2597 2846          size_t len;
2598 2847  
2599 2848          /*
2600 2849           * copyinstr copies the complete string including the NULL and
2601 2850           * returns the len with the NULL byte included in the calculation
2602 2851           * as long as the max length is not exceeded.
2603 2852           */
2604 2853          if (error = copyinstr(kex->ex_index, index, sizeof (index), &len))
2605 2854                  return (error);
2606 2855  
2607 2856          kex->ex_index = kmem_alloc(len, KM_SLEEP);
2608 2857          bcopy(index, kex->ex_index, len);
2609 2858  
2610 2859          return (0);
2611 2860  }
2612 2861  
2613 2862  void
2614 2863  exi_hold(struct exportinfo *exi)
2615 2864  {
2616 2865          mutex_enter(&exi->exi_lock);
2617 2866          exi->exi_count++;
2618 2867          mutex_exit(&exi->exi_lock);
2619 2868  }
2620 2869  
2621 2870  /*
2622 2871   * When a thread completes using exi, it should call exi_rele().
2623 2872   * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2624 2873   * if this is the last user of exi and exi is not on exportinfo list anymore
2625 2874   */
2626 2875  void
2627 2876  exi_rele(struct exportinfo *exi)
2628 2877  {
2629 2878          mutex_enter(&exi->exi_lock);
2630 2879          exi->exi_count--;
2631 2880          if (exi->exi_count == 0) {
2632 2881                  mutex_exit(&exi->exi_lock);
2633 2882                  exportfree(exi);
2634 2883          } else
2635 2884                  mutex_exit(&exi->exi_lock);
2636 2885  }
2637 2886  
2638 2887  #ifdef VOLATILE_FH_TEST
2639 2888  /*
2640 2889   * Test for volatile fh's - add file handle to list and set its volatile id
2641 2890   * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2642 2891   * the vol_rename queue is purged.
2643 2892   *
2644 2893   * XXX This code is for unit testing purposes only... To correctly use it, it
2645 2894   * needs to tie a rename list to the export struct and (more
2646 2895   * important), protect access to the exi rename list using a write lock.
2647 2896   */
2648 2897  
2649 2898  /*
2650 2899   * get the fh vol record if it's in the volatile on rename list. Don't check
2651 2900   * volatile_id in the file handle - compare only the file handles.
2652 2901   */
2653 2902  static struct ex_vol_rename *
2654 2903  find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p)
2655 2904  {
2656 2905          struct ex_vol_rename *p = NULL;
2657 2906          fhandle4_t *fhp;
2658 2907  
2659 2908          /* XXX shouldn't we assert &exported_lock held? */
2660 2909          ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock));
2661 2910  
2662 2911          if (fh4p->nfs_fh4_len != NFS_FH4_LEN) {
2663 2912                  return (NULL);
2664 2913          }
2665 2914          fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i;
2666 2915          for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) {
2667 2916                  if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i,
2668 2917                      sizeof (fhandle4_t)) == 0)
2669 2918                          break;
2670 2919          }
2671 2920          return (p);
2672 2921  }
2673 2922  
2674 2923  /*
2675 2924   * get the volatile id for the fh (if there is - else return 0). Ignore the
2676 2925   * volatile_id in the file handle - compare only the file handles.
2677 2926   */
2678 2927  static uint32_t
2679 2928  find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p)
2680 2929  {
2681 2930          struct ex_vol_rename *p;
2682 2931          uint32_t volatile_id;
2683 2932  
2684 2933          mutex_enter(&exi->exi_vol_rename_lock);
2685 2934          p = find_volrnm_fh(exi, fh4p);
2686 2935          volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id :
2687 2936              exi->exi_volatile_id);
2688 2937          mutex_exit(&exi->exi_vol_rename_lock);
2689 2938          return (volatile_id);
2690 2939  }
2691 2940  
2692 2941  /*
2693 2942   * Free the volatile on rename list - will be called if a filesystem is
2694 2943   * unshared or reshared without EX_VOLRNM
2695 2944   */
2696 2945  static void
2697 2946  free_volrnm_list(struct exportinfo *exi)
2698 2947  {
2699 2948          struct ex_vol_rename *p, *pnext;
2700 2949  
2701 2950          /* no need to hold mutex lock - this one is called from exportfree */
2702 2951          for (p = exi->exi_vol_rename; p != NULL; p = pnext) {
2703 2952                  pnext = p->vrn_next;
2704 2953                  kmem_free(p, sizeof (*p));
2705 2954          }
2706 2955          exi->exi_vol_rename = NULL;
2707 2956  }
2708 2957  
2709 2958  /*
2710 2959   * Add a file handle to the volatile on rename list.
2711 2960   */
2712 2961  void
2713 2962  add_volrnm_fh(struct exportinfo *exi, vnode_t *vp)
2714 2963  {
2715 2964          struct ex_vol_rename *p;
2716 2965          char fhbuf[NFS4_FHSIZE];
2717 2966          nfs_fh4 fh4;
2718 2967          int error;
2719 2968  
2720 2969          fh4.nfs_fh4_val = fhbuf;
2721 2970          error = makefh4(&fh4, vp, exi);
2722 2971          if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) {
2723 2972                  return;
2724 2973          }
2725 2974  
2726 2975          mutex_enter(&exi->exi_vol_rename_lock);
2727 2976  
2728 2977          p = find_volrnm_fh(exi, &fh4);
2729 2978  
2730 2979          if (p == NULL) {
2731 2980                  p = kmem_alloc(sizeof (*p), KM_SLEEP);
2732 2981                  bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt));
2733 2982                  p->vrn_next = exi->exi_vol_rename;
2734 2983                  exi->exi_vol_rename = p;
2735 2984          }
2736 2985  
2737 2986          p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec();
2738 2987          mutex_exit(&exi->exi_vol_rename_lock);
2739 2988  }
2740 2989  
2741 2990  #endif /* VOLATILE_FH_TEST */
  
    | 
      ↓ open down ↓ | 
    231 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX