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