Print this page
    
Untrip aggressive assert AND use EXI_TO_ZONEROOTVP
Revert exi_zone to exi_zoneid, and install exi_ne backpointer
    
      
        | 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
  
    | 
      ↓ open down ↓ | 
    685 lines elided | 
    
      ↑ open up ↑ | 
  
 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  {
 695  695          exportinfo_t *exi_ret = NULL;
 696      -#ifdef DEBUG
 697      -        zone_t *zone = NULL;
 698      -#endif
 699  696  
 700  697          for (;;) {
 701  698                  tnode = tnode->tree_parent;
 702      -#ifdef DEBUG
 703      -                if (zone == NULL && tnode->tree_exi != NULL)
 704      -                        zone = tnode->tree_exi->exi_zone;
 705      -#endif
 706  699                  if (TREE_ROOT(tnode)) {
 707      -                        ASSERT3P(zone, ==, tnode->tree_exi->exi_zone);
 708  700                          exi_ret = tnode->tree_exi;
 709  701                          break;
 710  702                  }
 711  703          }
 712  704  
 713      -        ASSERT(exi_ret); /* Every visible should have its home exportinfo */
      705 +        /* Every visible should have its home exportinfo */
      706 +        ASSERT(exi_ret != NULL);
 714  707          return (exi_ret);
 715  708  }
 716  709  
 717  710  /*
 718  711   * For NFS V4.
 719  712   * Add or remove the newly exported or unexported security flavors of the
 720  713   * given exportinfo from its ancestors upto the system root.
 721  714   */
 722  715  static void
 723  716  srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
 724  717      int seccnt, bool_t isadd)
 725  718  {
 726  719          treenode_t *tnode;
 727  720  
 728  721          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 729      -        ASSERT3U(exip->exi_zoneid, ==, curzone->zone_id);
 730  722  
 731  723          /*
 732  724           * exi_tree can be null for the zone root
 733  725           * which means we're already at the "top"
 734  726           * and there's nothing more to "climb".
 735  727           */
 736  728          tnode = exip->exi_tree;
 737  729          if (tnode == NULL) {
 738  730                  /* Should only happen for... */
 739  731                  ASSERT(exip == ne->exi_root);
 740  732                  return;
 741  733          }
 742  734  
 743  735          if (seccnt == 0)
  
    | 
      ↓ open down ↓ | 
    4 lines elided | 
    
      ↑ open up ↑ | 
  
 744  736                  return;
 745  737  
 746  738          /*
 747  739           * If flavors are being added and the new export root isn't
 748  740           * also VROOT, its implicitly allowed flavors are inherited from
 749  741           * its pseudonode.
 750  742           * Note - for VROOT exports the implicitly allowed flavors were
 751  743           * transferred from the PSEUDO export in exportfs()
 752  744           */
 753  745          if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
 754      -            !VN_IS_CURZONEROOT(exip->exi_vp) &&
      746 +            !VN_CMP(exip->exi_vp, EXI_TO_ZONEROOTVP(exip)) &&
 755  747              tnode->tree_vis->vis_seccnt > 0) {
 756  748                  srv_secinfo_add(&exip->exi_export.ex_secinfo,
 757  749                      &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 758  750                      tnode->tree_vis->vis_seccnt, FALSE);
 759  751          }
 760  752  
 761  753          /*
 762  754           * Move to parent node and propagate sec flavor
 763  755           * to exportinfo and to visible structures.
 764  756           */
 765  757          tnode = tnode->tree_parent;
 766  758  
 767  759          while (tnode != NULL) {
 768  760  
 769  761                  /* If there is exportinfo, update it */
 770  762                  if (tnode->tree_exi != NULL) {
 771  763                          secinfo_t **pxsec =
 772  764                              &tnode->tree_exi->exi_export.ex_secinfo;
 773  765                          int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
 774  766                          int is_pseudo = PSEUDO(tnode->tree_exi);
 775  767                          if (isadd)
 776  768                                  srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
 777  769                                      is_pseudo);
 778  770                          else
 779  771                                  srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
 780  772                  }
 781  773  
 782  774                  /* Update every visible - only root node has no visible */
 783  775                  if (tnode->tree_vis != NULL) {
 784  776                          secinfo_t **pxsec = &tnode->tree_vis->vis_secinfo;
 785  777                          int *pxcnt = &tnode->tree_vis->vis_seccnt;
 786  778                          if (isadd)
 787  779                                  srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
 788  780                                      FALSE);
 789  781                          else
 790  782                                  srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
 791  783                  }
 792  784                  tnode = tnode->tree_parent;
 793  785          }
 794  786  }
 795  787  
 796  788  /* hash_name is a text substitution for either fid_hash or path_hash */
 797  789  #define exp_hash_unlink(exi, hash_name) \
 798  790          if (*(exi)->hash_name.bckt == (exi)) \
 799  791                  *(exi)->hash_name.bckt = (exi)->hash_name.next; \
 800  792          if ((exi)->hash_name.prev) \
 801  793                  (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
 802  794          if ((exi)->hash_name.next) \
 803  795                  (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
 804  796          (exi)->hash_name.bckt = NULL;
 805  797  
 806  798  #define exp_hash_link(exi, hash_name, bucket) \
 807  799          (exi)->hash_name.bckt = (bucket); \
 808  800          (exi)->hash_name.prev = NULL; \
 809  801          (exi)->hash_name.next = *(bucket); \
 810  802          if ((exi)->hash_name.next) \
 811  803                  (exi)->hash_name.next->hash_name.prev = (exi); \
 812  804          *(bucket) = (exi);
 813  805  
 814  806  void
 815  807  export_link(nfs_export_t *ne, exportinfo_t *exi)
 816  808  {
  
    | 
      ↓ open down ↓ | 
    52 lines elided | 
    
      ↑ open up ↑ | 
  
 817  809          exportinfo_t **bckt;
 818  810  
 819  811          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 820  812  
 821  813          bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 822  814          exp_hash_link(exi, fid_hash, bckt);
 823  815  
 824  816          bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 825  817              strlen(exi->exi_export.ex_path))];
 826  818          exp_hash_link(exi, path_hash, bckt);
      819 +        exi->exi_ne = ne;
 827  820  }
 828  821  
 829  822  /*
 830  823   * Helper functions for exi_id handling
 831  824   */
 832  825  static int
 833  826  exi_id_compar(const void *v1, const void *v2)
 834  827  {
 835  828          const struct exportinfo *e1 = v1;
 836  829          const struct exportinfo *e2 = v2;
 837  830  
 838  831          if (e1->exi_id < e2->exi_id)
 839  832                  return (-1);
 840  833          if (e1->exi_id > e2->exi_id)
 841  834                  return (1);
 842  835  
 843  836          return (0);
 844  837  }
 845  838  
 846  839  int
 847  840  exi_id_get_next()
 848  841  {
 849  842          struct exportinfo e;
 850  843          int ret = exi_id_next;
 851  844  
 852  845          ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
 853  846  
 854  847          do {
 855  848                  exi_id_next++;
 856  849                  if (exi_id_next == 0)
 857  850                          exi_id_overflow = TRUE;
 858  851  
 859  852                  if (!exi_id_overflow)
 860  853                          break;
 861  854  
 862  855                  if (exi_id_next == ret)
 863  856                          cmn_err(CE_PANIC, "exi_id exhausted");
 864  857  
 865  858                  e.exi_id = exi_id_next;
 866  859          } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
 867  860  
 868  861          return (ret);
 869  862  }
 870  863  
 871  864  /*
 872  865   * Get the root file handle for this zone.
 873  866   * Called when nfs_svc() starts
 874  867   */
 875  868  int
 876  869  nfs_export_get_rootfh(nfs_globals_t *g)
 877  870  {
 878  871          nfs_export_t *ne = g->nfs_export;
 879  872          int err;
 880  873  
 881  874          ne->exi_rootfid.fid_len = MAXFIDSZ;
 882  875          err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid);
 883  876          if (err != 0) {
 884  877                  ne->exi_rootfid.fid_len = 0;
 885  878                  return (err);
 886  879          }
 887  880  
 888  881          /* Setup the fhandle template exi_fh */
 889  882          ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 890  883          ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
 891  884          bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
 892  885              ne->exi_rootfid.fid_len);
 893  886          ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
 894  887  
 895  888          return (0);
 896  889  }
 897  890  
 898  891  void
 899  892  nfs_export_zone_init(nfs_globals_t *ng)
 900  893  {
 901  894          int i;
 902  895          nfs_export_t *ne;
 903  896          zone_t *zone;
 904  897  
 905  898          ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 906  899  
 907  900          rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
 908  901  
 909  902          ne->ne_globals = ng; /* "up" pointer */
 910  903  
 911  904          /*
 912  905           * Allocate the place holder for the public file handle, which
 913  906           * is all zeroes. It is initially set to the root filesystem.
 914  907           */
 915  908          ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
 916  909          ne->exi_public = ne->exi_root;
 917  910  
 918  911          ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
 919  912          ne->exi_root->exi_export.ex_pathlen = 1;        /* length of "/" */
 920  913          ne->exi_root->exi_export.ex_path =
 921  914              kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 922  915          ne->exi_root->exi_export.ex_path[0] = '/';
  
    | 
      ↓ open down ↓ | 
    86 lines elided | 
    
      ↑ open up ↑ | 
  
 923  916          ne->exi_root->exi_export.ex_path[1] = '\0';
 924  917  
 925  918          ne->exi_root->exi_count = 1;
 926  919          mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 927  920  
 928  921          /*
 929  922           * Because we cannot:
 930  923           *      ASSERT(curzone->zone_id == ng->nfs_zoneid);
 931  924           * We grab the zone pointer explicitly (like netstacks do) and
 932  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.
 933  930           */
 934  931          zone = zone_find_by_id_nolock(ng->nfs_zoneid);
 935  932          ne->exi_root->exi_vp = zone->zone_rootvp;
 936      -        ne->exi_root->exi_zone = zone;  /* XXX KEBE SAYS lose me, and... */
 937      -        /* ne->exi_root->exi_zoneid = ng->nfs_zoneid; */ /* use me instead! */
      933 +        ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 938  934  
 939  935          /*
 940  936           * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
 941  937           * because we can't correctly return errors here.
 942  938           */
 943  939  
 944  940          /* Initialize auth cache and auth cache lock */
 945  941          for (i = 0; i < AUTH_TABLESIZE; i++) {
 946  942                  ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 947  943                      KM_SLEEP);
 948  944                  avl_create(ne->exi_root->exi_cache[i],
 949  945                      nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 950  946                      offsetof(struct auth_cache_clnt, authc_link));
 951  947          }
 952  948          rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 953  949  
 954  950          /* setup exi_fh later, in nfs_export_get_rootfid */
 955  951  
 956  952          rw_enter(&ne->exported_lock, RW_WRITER);
 957  953  
 958  954          /* Publish the exportinfo in the hash table */
 959  955          export_link(ne, ne->exi_root);
 960  956  
 961  957          /* Initialize exi_id and exi_kstats */
 962  958          mutex_enter(&nfs_exi_id_lock);
 963  959          ne->exi_root->exi_id = exi_id_get_next();
 964  960          avl_add(&exi_id_tree, ne->exi_root);
 965  961          mutex_exit(&nfs_exi_id_lock);
 966  962  
 967  963          rw_exit(&ne->exported_lock);
 968  964          ne->ns_root = NULL;
 969  965  
 970  966          ng->nfs_export = ne;
 971  967  }
 972  968  
 973  969  /*
 974  970   * During zone shutdown, remove exports
 975  971   */
 976  972  void
 977  973  nfs_export_zone_shutdown(nfs_globals_t *ng)
 978  974  {
 979  975          nfs_export_t *ne = ng->nfs_export;
 980  976          struct exportinfo *exi, *nexi;
 981  977          int i, errors;
 982  978  
 983  979          rw_enter(&ne->exported_lock, RW_READER);
 984  980  
 985  981          errors = 0;
 986  982          for (i = 0; i < EXPTABLESIZE; i++) {
 987  983  
 988  984                  exi = ne->exptable[i];
 989  985                  if (exi != NULL)
 990  986                          exi_hold(exi);
 991  987  
 992  988                  while (exi != NULL) {
 993  989  
 994  990                          /*
 995  991                           * Get and hold next export before
 996  992                           * dropping the rwlock and unexport
 997  993                           */
 998  994                          nexi = exi->fid_hash.next;
 999  995                          if (nexi != NULL)
1000  996                                  exi_hold(nexi);
1001  997  
1002  998                          rw_exit(&ne->exported_lock);
1003  999  
1004 1000                          /*
1005 1001                           * Skip ne->exi_root which gets special
1006 1002                           * create/destroy handling.
1007 1003                           */
1008 1004                          if (exi != ne->exi_root &&
1009 1005                              unexport(ne, exi) != 0)
1010 1006                                  errors++;
1011 1007                          exi_rele(exi);
1012 1008  
1013 1009                          rw_enter(&ne->exported_lock, RW_READER);
1014 1010                          exi = nexi;
1015 1011                  }
1016 1012          }
1017 1013          if (errors > 0) {
1018 1014                  cmn_err(CE_NOTE,
1019 1015                      "NFS: failed un-exports in zone %d",
1020 1016                      (int) ng->nfs_zoneid);
1021 1017          }
1022 1018  
1023 1019          rw_exit(&ne->exported_lock);
1024 1020  }
1025 1021  
1026 1022  void
1027 1023  nfs_export_zone_fini(nfs_globals_t *ng)
1028 1024  {
1029 1025          int i;
1030 1026          nfs_export_t *ne = ng->nfs_export;
1031 1027          struct exportinfo *exi;
1032 1028  
1033 1029          ng->nfs_export = NULL;
1034 1030  
1035 1031          rw_enter(&ne->exported_lock, RW_WRITER);
1036 1032  
1037 1033          mutex_enter(&nfs_exi_id_lock);
1038 1034          avl_remove(&exi_id_tree, ne->exi_root);
1039 1035          mutex_exit(&nfs_exi_id_lock);
1040 1036  
1041 1037          export_unlink(ne, ne->exi_root);
1042 1038  
1043 1039          rw_exit(&ne->exported_lock);
1044 1040  
1045 1041          /* Deallocate the place holder for the public file handle */
1046 1042          srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
1047 1043              ne->exi_root->exi_export.ex_seccnt);
1048 1044          mutex_destroy(&ne->exi_root->exi_lock);
1049 1045  
1050 1046          rw_destroy(&ne->exi_root->exi_cache_lock);
1051 1047          for (i = 0; i < AUTH_TABLESIZE; i++) {
1052 1048                  avl_destroy(ne->exi_root->exi_cache[i]);
1053 1049                  kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
1054 1050          }
1055 1051  
1056 1052          kmem_free(ne->exi_root->exi_export.ex_path,
1057 1053              ne->exi_root->exi_export.ex_pathlen + 1);
1058 1054          kmem_free(ne->exi_root, sizeof (*ne->exi_root));
1059 1055  
1060 1056          /*
1061 1057           * The shutdown hook should have left the exi_id_tree
1062 1058           * with nothing belonging to this zone.
1063 1059           */
1064 1060          mutex_enter(&nfs_exi_id_lock);
1065 1061          i = 0;
1066 1062          exi = avl_first(&exi_id_tree);
1067 1063          while (exi != NULL) {
1068 1064                  if (exi->exi_zoneid == ng->nfs_zoneid)
1069 1065                          i++;
1070 1066                  exi = AVL_NEXT(&exi_id_tree, exi);
1071 1067          }
1072 1068          mutex_exit(&nfs_exi_id_lock);
1073 1069          if (i > 0) {
1074 1070                  cmn_err(CE_NOTE,
1075 1071                      "NFS: zone %d has %d export IDs left after shutdown",
1076 1072                      (int) ng->nfs_zoneid, i);
1077 1073          }
1078 1074          rw_destroy(&ne->exported_lock);
1079 1075          kmem_free(ne, sizeof (*ne));
1080 1076  }
1081 1077  
1082 1078  /*
1083 1079   * Initialization routine for export routines.
1084 1080   * Should only be called once.
1085 1081   */
1086 1082  void
1087 1083  nfs_exportinit(void)
1088 1084  {
1089 1085          mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
1090 1086  
1091 1087          /* exi_id handling initialization */
1092 1088          exi_id_next = 0;
1093 1089          exi_id_overflow = FALSE;
1094 1090          avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
1095 1091              offsetof(struct exportinfo, exi_id_link));
1096 1092  
1097 1093          nfslog_init();
1098 1094  }
1099 1095  
1100 1096  /*
1101 1097   * Finalization routine for export routines.
1102 1098   */
1103 1099  void
1104 1100  nfs_exportfini(void)
1105 1101  {
1106 1102          avl_destroy(&exi_id_tree);
1107 1103          mutex_destroy(&nfs_exi_id_lock);
1108 1104  }
1109 1105  
1110 1106  /*
1111 1107   *  Check if 2 gss mechanism identifiers are the same.
1112 1108   *
1113 1109   *  return FALSE if not the same.
1114 1110   *  return TRUE if the same.
1115 1111   */
1116 1112  static bool_t
1117 1113  nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
1118 1114  {
1119 1115          if ((mech1->length == 0) && (mech2->length == 0))
1120 1116                  return (TRUE);
1121 1117  
1122 1118          if (mech1->length != mech2->length)
1123 1119                  return (FALSE);
1124 1120  
1125 1121          return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
1126 1122  }
1127 1123  
1128 1124  /*
1129 1125   *  This routine is used by rpc to map rpc security number
1130 1126   *  to nfs specific security flavor number.
1131 1127   *
1132 1128   *  The gss callback prototype is
1133 1129   *  callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
1134 1130   *                              rpc_gss_lock_t *, void **),
1135 1131   *  since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
1136 1132   *  we cast them to void.
1137 1133   */
1138 1134  /*ARGSUSED*/
1139 1135  bool_t
1140 1136  rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
1141 1137      rpc_gss_lock_t *lock, void **cookie)
1142 1138  {
1143 1139          int i, j;
1144 1140          rpc_gss_rawcred_t *raw_cred;
1145 1141          struct exportinfo *exi;
1146 1142          nfs_export_t *ne = nfs_get_export();
1147 1143  
1148 1144          /*
1149 1145           * We don't deal with delegated credentials.
1150 1146           */
1151 1147          if (deleg != GSS_C_NO_CREDENTIAL)
1152 1148                  return (FALSE);
1153 1149  
1154 1150          raw_cred = lock->raw_cred;
1155 1151          *cookie = NULL;
1156 1152  
1157 1153          rw_enter(&ne->exported_lock, RW_READER);
1158 1154  
1159 1155          for (i = 0; i < EXPTABLESIZE; i++) {
1160 1156                  exi = ne->exptable[i];
1161 1157                  while (exi) {
1162 1158                          if (exi->exi_export.ex_seccnt > 0) {
1163 1159                                  struct secinfo *secp;
1164 1160                                  seconfig_t *se;
1165 1161                                  int seccnt;
1166 1162  
1167 1163                                  secp = exi->exi_export.ex_secinfo;
1168 1164                                  seccnt = exi->exi_export.ex_seccnt;
1169 1165                                  for (j = 0; j < seccnt; j++) {
1170 1166                                          /*
1171 1167                                           *  If there is a map of the triplet
1172 1168                                           *  (mechanism, service, qop) between
1173 1169                                           *  raw_cred and the exported flavor,
1174 1170                                           *  get the psudo flavor number.
1175 1171                                           *  Also qop should not be NULL, it
1176 1172                                           *  should be "default" or something
1177 1173                                           *  else.
1178 1174                                           */
1179 1175                                          se = &secp[j].s_secinfo;
1180 1176                                          if ((se->sc_rpcnum == RPCSEC_GSS) &&
1181 1177  
1182 1178                                              (nfs_mech_equal(
1183 1179                                              se->sc_gss_mech_type,
1184 1180                                              raw_cred->mechanism)) &&
1185 1181  
1186 1182                                              (se->sc_service ==
1187 1183                                              raw_cred->service) &&
1188 1184                                              (raw_cred->qop == se->sc_qop)) {
1189 1185  
1190 1186                                                  *cookie = (void *)(uintptr_t)
1191 1187                                                      se->sc_nfsnum;
1192 1188                                                  goto done;
1193 1189                                          }
1194 1190                                  }
1195 1191                          }
1196 1192                          exi = exi->fid_hash.next;
1197 1193                  }
1198 1194          }
1199 1195  done:
1200 1196          rw_exit(&ne->exported_lock);
1201 1197  
1202 1198          /*
1203 1199           * If no nfs pseudo number mapping can be found in the export
1204 1200           * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
1205 1201           * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
1206 1202           *
1207 1203           * For example:
1208 1204           *      server first shares with krb5i;
1209 1205           *      client mounts with krb5i;
1210 1206           *      server re-shares with krb5p;
1211 1207           *      client tries with krb5i, but no mapping can be found;
1212 1208           *      rpcsec_gss module calls this routine to do the mapping,
1213 1209           *              if this routine fails, request is rejected from
1214 1210           *              the rpc layer.
1215 1211           *      What we need is to let the nfs layer rejects the request.
1216 1212           *      For V4, we can reject with NFS4ERR_WRONGSEC and the client
1217 1213           *      may recover from it by getting the new flavor via SECINFO.
1218 1214           *
1219 1215           * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
1220 1216           * is owned by IANA (see RFC 2623).
1221 1217           *
1222 1218           * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
1223 1219           * the implementation issue. This number should not overlap with
1224 1220           * any new IANA defined pseudo flavor numbers.
1225 1221           */
1226 1222          if (*cookie == NULL)
1227 1223                  *cookie = (void *)NFS_FLAVOR_NOMAP;
1228 1224  
1229 1225          lock->locked = TRUE;
1230 1226  
1231 1227          return (TRUE);
1232 1228  }
1233 1229  
1234 1230  
1235 1231  /*
1236 1232   * Exportfs system call; credentials should be checked before
1237 1233   * calling this function.
1238 1234   */
1239 1235  int
1240 1236  exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
1241 1237  {
1242 1238          vnode_t *vp;
1243 1239          vnode_t *dvp;
1244 1240          struct exportdata *kex;
1245 1241          struct exportinfo *exi = NULL;
1246 1242          struct exportinfo *ex, *ex1, *ex2;
1247 1243          fid_t fid;
1248 1244          fsid_t fsid;
1249 1245          int error;
1250 1246          size_t allocsize;
1251 1247          struct secinfo *sp;
1252 1248          struct secinfo *exs;
1253 1249          rpc_gss_callback_t cb;
1254 1250          char *pathbuf;
1255 1251          char *log_buffer;
1256 1252          char *tagbuf;
1257 1253          int callback;
1258 1254          int allocd_seccnt;
1259 1255          STRUCT_HANDLE(exportfs_args, uap);
1260 1256          STRUCT_DECL(exportdata, uexi);
1261 1257          struct secinfo newsec[MAX_FLAVORS];
1262 1258          int newcnt;
1263 1259          struct secinfo oldsec[MAX_FLAVORS];
1264 1260          int oldcnt;
1265 1261          int i;
1266 1262          struct pathname lookpn;
1267 1263          nfs_export_t *ne = nfs_get_export();
1268 1264  
1269 1265          STRUCT_SET_HANDLE(uap, model, args);
1270 1266  
1271 1267          /* Read in pathname from userspace */
1272 1268          if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn))
1273 1269                  return (error);
1274 1270  
1275 1271          /* Walk the export list looking for that pathname */
1276 1272          rw_enter(&ne->exported_lock, RW_READER);
1277 1273          DTRACE_PROBE(nfss__i__exported_lock1_start);
1278 1274          for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1279 1275              strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1280 1276                  if (ex1 != ne->exi_root && 0 ==
1281 1277                      strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1282 1278                          exi_hold(ex1);
1283 1279                          break;
1284 1280                  }
1285 1281          }
1286 1282          DTRACE_PROBE(nfss__i__exported_lock1_stop);
1287 1283          rw_exit(&ne->exported_lock);
1288 1284  
1289 1285          /* Is this an unshare? */
1290 1286          if (STRUCT_FGETP(uap, uex) == NULL) {
1291 1287                  pn_free(&lookpn);
1292 1288                  if (ex1 == NULL)
1293 1289                          return (EINVAL);
1294 1290                  error = unexport(ne, ex1);
1295 1291                  exi_rele(ex1);
1296 1292                  return (error);
1297 1293          }
1298 1294  
1299 1295          /* It is a share or a re-share */
1300 1296          error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1301 1297              FOLLOW, &dvp, &vp);
1302 1298          if (error == EINVAL) {
1303 1299                  /*
1304 1300                   * if fname resolves to / we get EINVAL error
1305 1301                   * since we wanted the parent vnode. Try again
1306 1302                   * with NULL dvp.
1307 1303                   */
1308 1304                  error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1309 1305                      FOLLOW, NULL, &vp);
1310 1306                  dvp = NULL;
1311 1307          }
1312 1308          if (!error && vp == NULL) {
1313 1309                  /* Last component of fname not found */
1314 1310                  if (dvp != NULL)
1315 1311                          VN_RELE(dvp);
1316 1312                  error = ENOENT;
1317 1313          }
1318 1314          if (error) {
1319 1315                  pn_free(&lookpn);
1320 1316                  if (ex1)
1321 1317                          exi_rele(ex1);
1322 1318                  return (error);
1323 1319          }
1324 1320  
1325 1321          /*
1326 1322           * 'vp' may be an AUTOFS node, so we perform a
1327 1323           * VOP_ACCESS() to trigger the mount of the
1328 1324           * intended filesystem, so we can share the intended
1329 1325           * filesystem instead of the AUTOFS filesystem.
1330 1326           */
1331 1327          (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
1332 1328  
1333 1329          /*
1334 1330           * We're interested in the top most filesystem.
1335 1331           * This is specially important when uap->dname is a trigger
1336 1332           * AUTOFS node, since we're really interested in sharing the
1337 1333           * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1338 1334           * call not the AUTOFS node itself.
1339 1335           */
1340 1336          if (vn_mountedvfs(vp) != NULL) {
1341 1337                  if (error = traverse(&vp)) {
1342 1338                          VN_RELE(vp);
1343 1339                          if (dvp != NULL)
1344 1340                                  VN_RELE(dvp);
1345 1341                          pn_free(&lookpn);
1346 1342                          if (ex1)
1347 1343                                  exi_rele(ex1);
1348 1344                          return (error);
1349 1345                  }
1350 1346          }
1351 1347  
1352 1348          /* Do not allow sharing another vnode for already shared path */
1353 1349          if (ex1 && !PSEUDO(ex1) && !VN_CMP(ex1->exi_vp, vp)) {
1354 1350                  VN_RELE(vp);
1355 1351                  if (dvp != NULL)
1356 1352                          VN_RELE(dvp);
1357 1353                  pn_free(&lookpn);
1358 1354                  exi_rele(ex1);
1359 1355                  return (EEXIST);
1360 1356          }
1361 1357          if (ex1)
1362 1358                  exi_rele(ex1);
1363 1359  
1364 1360          /*
1365 1361           * Get the vfs id
1366 1362           */
1367 1363          bzero(&fid, sizeof (fid));
1368 1364          fid.fid_len = MAXFIDSZ;
1369 1365          error = VOP_FID(vp, &fid, NULL);
1370 1366          fsid = vp->v_vfsp->vfs_fsid;
1371 1367  
1372 1368          if (error) {
1373 1369                  VN_RELE(vp);
1374 1370                  if (dvp != NULL)
1375 1371                          VN_RELE(dvp);
1376 1372                  /*
1377 1373                   * If VOP_FID returns ENOSPC then the fid supplied
1378 1374                   * is too small.  For now we simply return EREMOTE.
1379 1375                   */
1380 1376                  if (error == ENOSPC)
1381 1377                          error = EREMOTE;
1382 1378                  pn_free(&lookpn);
1383 1379                  return (error);
1384 1380          }
1385 1381  
1386 1382          /*
1387 1383           * Do not allow re-sharing a shared vnode under a different path
1388 1384           * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1389 1385           */
1390 1386          rw_enter(&ne->exported_lock, RW_READER);
1391 1387          DTRACE_PROBE(nfss__i__exported_lock2_start);
1392 1388          for (ex2 = ne->exptable[exptablehash(&fsid, &fid)]; ex2;
1393 1389              ex2 = ex2->fid_hash.next) {
1394 1390                  if (ex2 != ne->exi_root && !PSEUDO(ex2) &&
1395 1391                      VN_CMP(ex2->exi_vp, vp) &&
1396 1392                      strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1397 1393                          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1398 1394                          rw_exit(&ne->exported_lock);
1399 1395                          VN_RELE(vp);
1400 1396                          if (dvp != NULL)
1401 1397                                  VN_RELE(dvp);
1402 1398                          pn_free(&lookpn);
1403 1399                          return (EEXIST);
1404 1400                  }
  
    | 
      ↓ open down ↓ | 
    457 lines elided | 
    
      ↑ open up ↑ | 
  
1405 1401          }
1406 1402          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1407 1403          rw_exit(&ne->exported_lock);
1408 1404          pn_free(&lookpn);
1409 1405  
1410 1406          exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1411 1407          exi->exi_fsid = fsid;
1412 1408          exi->exi_fid = fid;
1413 1409          exi->exi_vp = vp;
1414 1410          exi->exi_count = 1;
1415      -        exi->exi_zone = crgetzone(cr);
1416      -        ASSERT(exi->exi_zone != NULL);          /* XXX KEBE ASKS... */
1417      -        ASSERT3P(exi->exi_zone, ==, curzone);   /* ... are these legit? */
     1411 +        exi->exi_zoneid = crgetzoneid(cr);
     1412 +        ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
1418 1413          exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1419 1414              VSW_VOLATILEDEV) ? 1 : 0;
1420 1415          mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1421 1416          exi->exi_dvp = dvp;
1422 1417  
1423 1418          /*
1424 1419           * Initialize auth cache and auth cache lock
1425 1420           */
1426 1421          for (i = 0; i < AUTH_TABLESIZE; i++) {
1427 1422                  exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1428 1423                  avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
1429 1424                      sizeof (struct auth_cache_clnt),
1430 1425                      offsetof(struct auth_cache_clnt, authc_link));
1431 1426          }
1432 1427          rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1433 1428  
1434 1429          /*
1435 1430           * Build up the template fhandle
1436 1431           */
1437 1432          exi->exi_fh.fh_fsid = fsid;
1438 1433          if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) {
1439 1434                  error = EREMOTE;
1440 1435                  goto out1;
1441 1436          }
1442 1437          exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
1443 1438          bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
1444 1439              exi->exi_fid.fid_len);
1445 1440  
1446 1441          exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
1447 1442  
1448 1443          kex = &exi->exi_export;
1449 1444  
1450 1445          /*
1451 1446           * Load in everything, and do sanity checking
1452 1447           */
1453 1448          STRUCT_INIT(uexi, model);
1454 1449          if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi),
1455 1450              STRUCT_SIZE(uexi))) {
1456 1451                  error = EFAULT;
1457 1452                  goto out1;
1458 1453          }
1459 1454  
1460 1455          kex->ex_version = STRUCT_FGET(uexi, ex_version);
1461 1456          if (kex->ex_version != EX_CURRENT_VERSION) {
1462 1457                  error = EINVAL;
1463 1458                  cmn_err(CE_WARN,
1464 1459                      "NFS: exportfs requires export struct version 2 - got %d\n",
1465 1460                      kex->ex_version);
1466 1461                  goto out1;
1467 1462          }
1468 1463  
1469 1464          /*
1470 1465           * Must have at least one security entry
1471 1466           */
1472 1467          kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt);
1473 1468          if (kex->ex_seccnt < 1) {
1474 1469                  error = EINVAL;
1475 1470                  goto out1;
1476 1471          }
1477 1472  
1478 1473          kex->ex_path = STRUCT_FGETP(uexi, ex_path);
1479 1474          kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen);
1480 1475          kex->ex_flags = STRUCT_FGET(uexi, ex_flags);
1481 1476          kex->ex_anon = STRUCT_FGET(uexi, ex_anon);
1482 1477          kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo);
1483 1478          kex->ex_index = STRUCT_FGETP(uexi, ex_index);
1484 1479          kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer);
1485 1480          kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen);
1486 1481          kex->ex_tag = STRUCT_FGETP(uexi, ex_tag);
1487 1482          kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen);
1488 1483  
1489 1484          /*
1490 1485           * Copy the exported pathname into
1491 1486           * an appropriately sized buffer.
1492 1487           */
1493 1488          pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1494 1489          if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) {
1495 1490                  kmem_free(pathbuf, MAXPATHLEN);
1496 1491                  error = EFAULT;
1497 1492                  goto out1;
1498 1493          }
1499 1494          kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
1500 1495          bcopy(pathbuf, kex->ex_path, kex->ex_pathlen);
1501 1496          kex->ex_path[kex->ex_pathlen] = '\0';
1502 1497          kmem_free(pathbuf, MAXPATHLEN);
1503 1498  
1504 1499          /*
1505 1500           * Get the path to the logging buffer and the tag
1506 1501           */
1507 1502          if (kex->ex_flags & EX_LOG) {
1508 1503                  log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1509 1504                  if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN,
1510 1505                      &kex->ex_log_bufferlen)) {
1511 1506                          kmem_free(log_buffer, MAXPATHLEN);
1512 1507                          error = EFAULT;
1513 1508                          goto out2;
1514 1509                  }
1515 1510                  kex->ex_log_buffer =
1516 1511                      kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP);
1517 1512                  bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen);
1518 1513                  kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0';
1519 1514                  kmem_free(log_buffer, MAXPATHLEN);
1520 1515  
1521 1516                  tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1522 1517                  if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN,
1523 1518                      &kex->ex_taglen)) {
1524 1519                          kmem_free(tagbuf, MAXPATHLEN);
1525 1520                          error = EFAULT;
1526 1521                          goto out3;
1527 1522                  }
1528 1523                  kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP);
1529 1524                  bcopy(tagbuf, kex->ex_tag, kex->ex_taglen);
1530 1525                  kex->ex_tag[kex->ex_taglen] = '\0';
1531 1526                  kmem_free(tagbuf, MAXPATHLEN);
1532 1527          }
1533 1528  
1534 1529          /*
1535 1530           * Load the security information for each flavor
1536 1531           */
1537 1532          allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model);
1538 1533          sp = kmem_zalloc(allocsize, KM_SLEEP);
1539 1534          if (copyin(kex->ex_secinfo, sp, allocsize)) {
1540 1535                  kmem_free(sp, allocsize);
1541 1536                  error = EFAULT;
1542 1537                  goto out4;
1543 1538          }
1544 1539  
1545 1540          /*
1546 1541           * All of these nested structures need to be converted to
1547 1542           * the kernel native format.
1548 1543           */
1549 1544          if (model != DATAMODEL_NATIVE) {
1550 1545                  size_t allocsize2;
1551 1546                  struct secinfo *sp2;
1552 1547  
1553 1548                  allocsize2 = kex->ex_seccnt * sizeof (struct secinfo);
1554 1549                  sp2 = kmem_zalloc(allocsize2, KM_SLEEP);
1555 1550  
1556 1551                  for (i = 0; i < kex->ex_seccnt; i++) {
1557 1552                          STRUCT_HANDLE(secinfo, usi);
1558 1553  
1559 1554                          STRUCT_SET_HANDLE(usi, model,
1560 1555                              (struct secinfo *)((caddr_t)sp +
1561 1556                              (i * SIZEOF_STRUCT(secinfo, model))));
1562 1557                          bcopy(STRUCT_FGET(usi, s_secinfo.sc_name),
1563 1558                              sp2[i].s_secinfo.sc_name, MAX_NAME_LEN);
1564 1559                          sp2[i].s_secinfo.sc_nfsnum =
1565 1560                              STRUCT_FGET(usi, s_secinfo.sc_nfsnum);
1566 1561                          sp2[i].s_secinfo.sc_rpcnum =
1567 1562                              STRUCT_FGET(usi, s_secinfo.sc_rpcnum);
1568 1563                          bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech),
1569 1564                              sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN);
1570 1565                          sp2[i].s_secinfo.sc_gss_mech_type =
1571 1566                              STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type);
1572 1567                          sp2[i].s_secinfo.sc_qop =
1573 1568                              STRUCT_FGET(usi, s_secinfo.sc_qop);
1574 1569                          sp2[i].s_secinfo.sc_service =
1575 1570                              STRUCT_FGET(usi, s_secinfo.sc_service);
1576 1571  
1577 1572                          sp2[i].s_flags = STRUCT_FGET(usi, s_flags);
1578 1573                          sp2[i].s_window = STRUCT_FGET(usi, s_window);
1579 1574                          sp2[i].s_rootid = STRUCT_FGET(usi, s_rootid);
1580 1575                          sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt);
1581 1576                          sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames);
1582 1577                  }
1583 1578                  kmem_free(sp, allocsize);
1584 1579                  sp = sp2;
1585 1580                  allocsize = allocsize2;
1586 1581          }
1587 1582  
1588 1583          kex->ex_secinfo = sp;
1589 1584  
1590 1585          /*
1591 1586           * And now copy rootnames for each individual secinfo.
1592 1587           */
1593 1588          callback = 0;
1594 1589          allocd_seccnt = 0;
1595 1590          while (allocd_seccnt < kex->ex_seccnt) {
1596 1591  
1597 1592                  exs = &sp[allocd_seccnt];
1598 1593                  if (exs->s_rootcnt > 0) {
1599 1594                          if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum,
1600 1595                              exs->s_rootcnt, &exs->s_rootnames, model)) {
1601 1596                                  error = EFAULT;
1602 1597                                  goto out5;
1603 1598                          }
1604 1599                  }
1605 1600  
1606 1601                  if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
1607 1602                          rpc_gss_OID mech_tmp;
1608 1603                          STRUCT_DECL(rpc_gss_OID_s, umech_tmp);
1609 1604                          caddr_t elements_tmp;
1610 1605  
1611 1606                          /* Copyin mechanism type */
1612 1607                          STRUCT_INIT(umech_tmp, model);
1613 1608                          mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP);
1614 1609                          if (copyin(exs->s_secinfo.sc_gss_mech_type,
1615 1610                              STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) {
1616 1611                                  kmem_free(mech_tmp, sizeof (*mech_tmp));
1617 1612                                  error = EFAULT;
1618 1613                                  goto out5;
1619 1614                          }
1620 1615                          mech_tmp->length = STRUCT_FGET(umech_tmp, length);
1621 1616                          mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements);
1622 1617  
1623 1618                          elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP);
1624 1619                          if (copyin(mech_tmp->elements, elements_tmp,
1625 1620                              mech_tmp->length)) {
1626 1621                                  kmem_free(elements_tmp, mech_tmp->length);
1627 1622                                  kmem_free(mech_tmp, sizeof (*mech_tmp));
1628 1623                                  error = EFAULT;
1629 1624                                  goto out5;
1630 1625                          }
1631 1626                          mech_tmp->elements = elements_tmp;
1632 1627                          exs->s_secinfo.sc_gss_mech_type = mech_tmp;
1633 1628                          allocd_seccnt++;
1634 1629  
1635 1630                          callback = 1;
1636 1631                  } else
1637 1632                          allocd_seccnt++;
1638 1633          }
1639 1634  
1640 1635          /*
1641 1636           * Init the secinfo reference count and mark these flavors
1642 1637           * explicitly exported flavors.
1643 1638           */
1644 1639          for (i = 0; i < kex->ex_seccnt; i++) {
1645 1640                  kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED;
1646 1641                  kex->ex_secinfo[i].s_refcnt = 1;
1647 1642          }
1648 1643  
1649 1644          /*
1650 1645           *  Set up rpcsec_gss callback routine entry if any.
1651 1646           */
1652 1647          if (callback) {
1653 1648                  cb.callback = rfs_gsscallback;
1654 1649                  cb.program = NFS_ACL_PROGRAM;
1655 1650                  for (cb.version = NFS_ACL_VERSMIN;
1656 1651                      cb.version <= NFS_ACL_VERSMAX; cb.version++) {
1657 1652                          (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1658 1653                              (void *)&cb);
1659 1654                  }
1660 1655  
1661 1656                  cb.program = NFS_PROGRAM;
1662 1657                  for (cb.version = NFS_VERSMIN;
1663 1658                      cb.version <= NFS_VERSMAX; cb.version++) {
1664 1659                          (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1665 1660                              (void *)&cb);
1666 1661                  }
1667 1662          }
1668 1663  
1669 1664          /*
1670 1665           * Check the index flag. Do this here to avoid holding the
1671 1666           * lock while dealing with the index option (as we do with
1672 1667           * the public option).
1673 1668           */
1674 1669          if (kex->ex_flags & EX_INDEX) {
1675 1670                  if (!kex->ex_index) {   /* sanity check */
1676 1671                          error = EINVAL;
1677 1672                          goto out5;
1678 1673                  }
1679 1674                  if (error = loadindex(kex))
1680 1675                          goto out5;
1681 1676          }
1682 1677  
1683 1678          if (kex->ex_flags & EX_LOG) {
1684 1679                  if (error = nfslog_setup(exi))
1685 1680                          goto out6;
1686 1681          }
1687 1682  
1688 1683          /*
1689 1684           * Insert the new entry at the front of the export list
1690 1685           */
1691 1686          rw_enter(&ne->exported_lock, RW_WRITER);
1692 1687          DTRACE_PROBE(nfss__i__exported_lock3_start);
1693 1688  
1694 1689          export_link(ne, exi);
1695 1690  
1696 1691          /*
1697 1692           * Check the rest of the list for an old entry for the fs.
1698 1693           * If one is found then unlink it, wait until this is the
1699 1694           * only reference and then free it.
1700 1695           */
1701 1696          for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) {
1702 1697                  if (ex != ne->exi_root && VN_CMP(ex->exi_vp, vp)) {
1703 1698                          mutex_enter(&nfs_exi_id_lock);
1704 1699                          avl_remove(&exi_id_tree, ex);
1705 1700                          mutex_exit(&nfs_exi_id_lock);
1706 1701                          export_unlink(ne, ex);
1707 1702                          break;
1708 1703                  }
1709 1704          }
1710 1705  
1711 1706          /*
1712 1707           * If the public filehandle is pointing at the
1713 1708           * old entry, then point it back at the root.
1714 1709           */
1715 1710          if (ex != NULL && ex == ne->exi_public)
1716 1711                  ne->exi_public = ne->exi_root;
1717 1712  
1718 1713          /*
1719 1714           * If the public flag is on, make the global exi_public
1720 1715           * point to this entry and turn off the public bit so that
1721 1716           * we can distinguish it from the place holder export.
1722 1717           */
1723 1718          if (kex->ex_flags & EX_PUBLIC) {
1724 1719                  ne->exi_public = exi;
1725 1720                  kex->ex_flags &= ~EX_PUBLIC;
1726 1721          }
1727 1722  
1728 1723  #ifdef VOLATILE_FH_TEST
1729 1724          /*
1730 1725           * Set up the volatile_id value if volatile on share.
1731 1726           * The list of volatile renamed filehandles is always destroyed,
1732 1727           * if the fs was reshared.
1733 1728           */
1734 1729          if (kex->ex_flags & EX_VOLFH)
1735 1730                  exi->exi_volatile_id = gethrestime_sec();
1736 1731  
1737 1732          mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
1738 1733  #endif /* VOLATILE_FH_TEST */
1739 1734  
1740 1735          /*
1741 1736           * If this is a new export, then climb up
1742 1737           * the tree and check if any pseudo exports
1743 1738           * need to be created to provide a path for
1744 1739           * NFS v4 clients.
1745 1740           */
1746 1741          if (ex == NULL) {
1747 1742                  error = treeclimb_export(exi);
1748 1743                  if (error)
1749 1744                          goto out7;
1750 1745          } else {
1751 1746                  /* If it's a re-export update namespace tree */
1752 1747                  exi->exi_tree = ex->exi_tree;
1753 1748                  exi->exi_tree->tree_exi = exi;
1754 1749  
1755 1750                  /* Update the change timestamp */
1756 1751                  tree_update_change(ne, exi->exi_tree, NULL);
1757 1752          }
1758 1753  
1759 1754          /*
1760 1755           * build a unique flavor list from the flavors specified
1761 1756           * in the share cmd.  unique means that each flavor only
1762 1757           * appears once in the secinfo list -- no duplicates allowed.
1763 1758           */
1764 1759          newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
1765 1760  
1766 1761          srv_secinfo_treeclimb(ne, exi, newsec, newcnt, TRUE);
1767 1762  
1768 1763          /*
1769 1764           * If re-sharing an old export entry, update the secinfo data
1770 1765           * depending on if the old entry is a pseudo node or not.
1771 1766           */
1772 1767          if (ex != NULL) {
1773 1768                  oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
1774 1769                  if (PSEUDO(ex)) {
1775 1770                          /*
1776 1771                           * The dir being shared is a pseudo export root (which
1777 1772                           * will be transformed into a real export root).  The
1778 1773                           * flavor(s) of the new share were propagated to the
1779 1774                           * ancestors by srv_secinfo_treeclimb() above.  Now
1780 1775                           * transfer the implicit flavor refs from the old
1781 1776                           * pseudo exprot root to the new (real) export root.
1782 1777                           */
1783 1778                          srv_secinfo_add(&exi->exi_export.ex_secinfo,
1784 1779                              &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
1785 1780                  } else {
1786 1781                          /*
1787 1782                           * First transfer implicit flavor refs to new export.
1788 1783                           * Remove old flavor refs last.
1789 1784                           */
1790 1785                          srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
1791 1786                          srv_secinfo_treeclimb(ne, ex, oldsec, oldcnt, FALSE);
1792 1787                  }
1793 1788          }
1794 1789  
1795 1790          /*
1796 1791           * If it's a re-export and the old entry has a pseudonode list,
1797 1792           * transfer it to the new export.
1798 1793           */
1799 1794          if (ex != NULL && (ex->exi_visible != NULL)) {
1800 1795                  exi->exi_visible = ex->exi_visible;
1801 1796                  ex->exi_visible = NULL;
1802 1797          }
1803 1798  
1804 1799          /*
1805 1800           * Initialize exi_id and exi_kstats
1806 1801           */
1807 1802          if (ex != NULL) {
1808 1803                  exi->exi_id = ex->exi_id;
1809 1804          } else {
1810 1805                  mutex_enter(&nfs_exi_id_lock);
1811 1806                  exi->exi_id = exi_id_get_next();
1812 1807                  mutex_exit(&nfs_exi_id_lock);
1813 1808          }
1814 1809          mutex_enter(&nfs_exi_id_lock);
1815 1810          avl_add(&exi_id_tree, exi);
1816 1811          mutex_exit(&nfs_exi_id_lock);
1817 1812  
1818 1813          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1819 1814          rw_exit(&ne->exported_lock);
1820 1815  
1821 1816          if (ne->exi_public == exi || kex->ex_flags & EX_LOG) {
1822 1817                  /*
1823 1818                   * Log share operation to this buffer only.
1824 1819                   */
1825 1820                  nfslog_share_record(exi, cr);
1826 1821          }
1827 1822  
1828 1823          if (ex != NULL)
1829 1824                  exi_rele(ex);
1830 1825  
1831 1826          return (0);
1832 1827  
1833 1828  out7:
1834 1829          /* Unlink the new export in exptable. */
1835 1830          export_unlink(ne, exi);
1836 1831          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1837 1832          rw_exit(&ne->exported_lock);
1838 1833  out6:
1839 1834          if (kex->ex_flags & EX_INDEX)
1840 1835                  kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1841 1836  out5:
1842 1837          /* free partially completed allocation */
1843 1838          while (--allocd_seccnt >= 0) {
1844 1839                  exs = &kex->ex_secinfo[allocd_seccnt];
1845 1840                  srv_secinfo_entry_free(exs);
1846 1841          }
1847 1842  
1848 1843          if (kex->ex_secinfo) {
1849 1844                  kmem_free(kex->ex_secinfo,
1850 1845                      kex->ex_seccnt * sizeof (struct secinfo));
1851 1846          }
1852 1847  
1853 1848  out4:
1854 1849          if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
1855 1850                  kmem_free(kex->ex_tag, kex->ex_taglen + 1);
1856 1851  out3:
1857 1852          if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
1858 1853                  kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1);
1859 1854  out2:
1860 1855          kmem_free(kex->ex_path, kex->ex_pathlen + 1);
1861 1856  out1:
1862 1857          VN_RELE(vp);
1863 1858          if (dvp != NULL)
1864 1859                  VN_RELE(dvp);
1865 1860          mutex_destroy(&exi->exi_lock);
1866 1861          rw_destroy(&exi->exi_cache_lock);
1867 1862          for (i = 0; i < AUTH_TABLESIZE; i++) {
1868 1863                  avl_destroy(exi->exi_cache[i]);
1869 1864                  kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
1870 1865          }
1871 1866  
1872 1867          kmem_free(exi, sizeof (*exi));
1873 1868  
1874 1869          return (error);
1875 1870  }
1876 1871  
  
    | 
      ↓ open down ↓ | 
    449 lines elided | 
    
      ↑ open up ↑ | 
  
1877 1872  /*
1878 1873   * Remove the exportinfo from the export list
1879 1874   */
1880 1875  void
1881 1876  export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1882 1877  {
1883 1878          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1884 1879  
1885 1880          exp_hash_unlink(exi, fid_hash);
1886 1881          exp_hash_unlink(exi, path_hash);
     1882 +        ASSERT3P(exi->exi_ne, ==, ne);
     1883 +        exi->exi_ne = NULL;
1887 1884  }
1888 1885  
1889 1886  /*
1890 1887   * Unexport an exported filesystem
1891 1888   */
1892 1889  static int
1893 1890  unexport(nfs_export_t *ne, struct exportinfo *exi)
1894 1891  {
1895 1892          struct secinfo cursec[MAX_FLAVORS];
1896 1893          int curcnt;
1897 1894  
1898 1895          rw_enter(&ne->exported_lock, RW_WRITER);
1899 1896  
1900 1897          /* Check if exi is still linked in the export table */
1901 1898          if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1902 1899                  rw_exit(&ne->exported_lock);
1903 1900                  return (EINVAL);
1904 1901          }
1905 1902  
1906 1903          mutex_enter(&nfs_exi_id_lock);
1907 1904          avl_remove(&exi_id_tree, exi);
1908 1905          mutex_exit(&nfs_exi_id_lock);
1909 1906          export_unlink(ne, exi);
1910 1907  
1911 1908          /*
1912 1909           * Remove security flavors before treeclimb_unexport() is called
1913 1910           * because srv_secinfo_treeclimb needs the namespace tree
1914 1911           */
1915 1912          curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1916 1913          srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1917 1914  
1918 1915          /*
1919 1916           * If there's a visible list, then need to leave
1920 1917           * a pseudo export here to retain the visible list
  
    | 
      ↓ open down ↓ | 
    24 lines elided | 
    
      ↑ open up ↑ | 
  
1921 1918           * for paths to exports below.
1922 1919           */
1923 1920          if (exi->exi_visible != NULL) {
1924 1921                  struct exportinfo *newexi;
1925 1922  
1926 1923                  newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1927 1924                      exi->exi_visible, &exi->exi_export);
1928 1925                  exi->exi_visible = NULL;
1929 1926  
1930 1927                  /* interconnect the existing treenode with the new exportinfo */
1931      -                newexi->exi_zone = exi->exi_zone; /* XXX KEBE SAYS LOSE ME */
1932 1928                  newexi->exi_tree = exi->exi_tree;
1933 1929                  newexi->exi_tree->tree_exi = newexi;
1934 1930  
1935 1931                  /* Update the change timestamp */
1936 1932                  tree_update_change(ne, exi->exi_tree, NULL);
1937 1933          } else {
1938 1934                  treeclimb_unexport(ne, exi);
1939 1935          }
1940 1936  
1941 1937          rw_exit(&ne->exported_lock);
1942 1938  
1943 1939          /*
1944 1940           * Need to call into the NFSv4 server and release all data
1945 1941           * held on this particular export.  This is important since
1946 1942           * the v4 server may be holding file locks or vnodes under
1947 1943           * this export.
1948 1944           */
1949 1945          rfs4_clean_state_exi(ne, exi);
1950 1946  
1951 1947          /*
1952 1948           * Notify the lock manager that the filesystem is being
1953 1949           * unexported.
1954 1950           */
1955 1951          lm_unexport(exi);
1956 1952  
1957 1953          /*
1958 1954           * If this was a public export, restore
1959 1955           * the public filehandle to the root.
1960 1956           */
1961 1957  
1962 1958          /*
1963 1959           * XXX KEBE ASKS --> Should CRED() instead be
1964 1960           * exi->exi_zone->zone_kcred?
1965 1961           */
1966 1962          if (exi == ne->exi_public) {
1967 1963                  ne->exi_public = ne->exi_root;
1968 1964  
1969 1965                  nfslog_share_record(ne->exi_public, CRED());
1970 1966          }
1971 1967  
1972 1968          if (exi->exi_export.ex_flags & EX_LOG)
1973 1969                  nfslog_unshare_record(exi, CRED());
1974 1970  
1975 1971          exi_rele(exi);
1976 1972          return (0);
1977 1973  }
1978 1974  
1979 1975  /*
1980 1976   * Get file handle system call.
1981 1977   * Takes file name and returns a file handle for it.
1982 1978   * Credentials must be verified before calling.
1983 1979   */
1984 1980  int
1985 1981  nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1986 1982  {
1987 1983          nfs_fh3 fh;
1988 1984          char buf[NFS3_MAXFHSIZE];
1989 1985          char *logptr, logbuf[NFS3_MAXFHSIZE];
1990 1986          int l = NFS3_MAXFHSIZE;
1991 1987          vnode_t *vp;
1992 1988          vnode_t *dvp;
1993 1989          struct exportinfo *exi;
1994 1990          int error;
1995 1991          int vers;
1996 1992          STRUCT_HANDLE(nfs_getfh_args, uap);
1997 1993  
1998 1994  #ifdef lint
1999 1995          model = model;          /* STRUCT macros don't always use it */
2000 1996  #endif
2001 1997  
2002 1998          STRUCT_SET_HANDLE(uap, model, args);
2003 1999  
2004 2000          error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
2005 2001              FOLLOW, &dvp, &vp);
2006 2002          if (error == EINVAL) {
2007 2003                  /*
2008 2004                   * if fname resolves to / we get EINVAL error
2009 2005                   * since we wanted the parent vnode. Try again
2010 2006                   * with NULL dvp.
2011 2007                   */
2012 2008                  error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
2013 2009                      FOLLOW, NULL, &vp);
2014 2010                  dvp = NULL;
2015 2011          }
2016 2012          if (!error && vp == NULL) {
2017 2013                  /*
2018 2014                   * Last component of fname not found
2019 2015                   */
2020 2016                  if (dvp != NULL) {
2021 2017                          VN_RELE(dvp);
2022 2018                  }
2023 2019                  error = ENOENT;
2024 2020          }
2025 2021          if (error)
2026 2022                  return (error);
2027 2023  
2028 2024          /*
2029 2025           * 'vp' may be an AUTOFS node, so we perform a
2030 2026           * VOP_ACCESS() to trigger the mount of the
2031 2027           * intended filesystem, so we can share the intended
2032 2028           * filesystem instead of the AUTOFS filesystem.
2033 2029           */
2034 2030          (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
2035 2031  
2036 2032          /*
2037 2033           * We're interested in the top most filesystem.
2038 2034           * This is specially important when uap->dname is a trigger
2039 2035           * AUTOFS node, since we're really interested in sharing the
2040 2036           * filesystem AUTOFS mounted as result of the VOP_ACCESS()
2041 2037           * call not the AUTOFS node itself.
2042 2038           */
2043 2039          if (vn_mountedvfs(vp) != NULL) {
2044 2040                  if (error = traverse(&vp)) {
2045 2041                          VN_RELE(vp);
2046 2042                          if (dvp != NULL)
2047 2043                                  VN_RELE(dvp);
2048 2044                          return (error);
2049 2045                  }
2050 2046          }
2051 2047  
2052 2048          vers = STRUCT_FGET(uap, vers);
2053 2049          exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE);
2054 2050          if (!error) {
2055 2051                  if (vers == NFS_VERSION) {
2056 2052                          error = makefh((fhandle_t *)buf, vp, exi);
2057 2053                          l = NFS_FHSIZE;
2058 2054                          logptr = buf;
2059 2055                  } else if (vers == NFS_V3) {
2060 2056                          int i, sz, pad;
2061 2057  
2062 2058                          error = makefh3(&fh, vp, exi);
2063 2059                          l = RNDUP(fh.fh3_length);
2064 2060                          if (!error && (l > sizeof (fhandle3_t)))
2065 2061                                  error = EREMOTE;
2066 2062                          logptr = logbuf;
2067 2063                          if (!error) {
2068 2064                                  i = 0;
2069 2065                                  sz = sizeof (fsid_t);
2070 2066                                  bcopy(&fh.fh3_fsid, &buf[i], sz);
2071 2067                                  i += sz;
2072 2068  
2073 2069                                  /*
2074 2070                                   * For backwards compatibility, the
2075 2071                                   * fid length may be less than
2076 2072                                   * NFS_FHMAXDATA, but it was always
2077 2073                                   * encoded as NFS_FHMAXDATA bytes.
2078 2074                                   */
2079 2075  
2080 2076                                  sz = sizeof (ushort_t);
2081 2077                                  bcopy(&fh.fh3_len, &buf[i], sz);
2082 2078                                  i += sz;
2083 2079                                  bcopy(fh.fh3_data, &buf[i], fh.fh3_len);
2084 2080                                  i += fh.fh3_len;
2085 2081                                  pad = (NFS_FHMAXDATA - fh.fh3_len);
2086 2082                                  if (pad > 0) {
2087 2083                                          bzero(&buf[i], pad);
2088 2084                                          i += pad;
2089 2085                                          l += pad;
2090 2086                                  }
2091 2087  
2092 2088                                  sz = sizeof (ushort_t);
2093 2089                                  bcopy(&fh.fh3_xlen, &buf[i], sz);
2094 2090                                  i += sz;
2095 2091                                  bcopy(fh.fh3_xdata, &buf[i], fh.fh3_xlen);
2096 2092                                  i += fh.fh3_xlen;
2097 2093                                  pad = (NFS_FHMAXDATA - fh.fh3_xlen);
2098 2094                                  if (pad > 0) {
2099 2095                                          bzero(&buf[i], pad);
2100 2096                                          i += pad;
2101 2097                                          l += pad;
2102 2098                                  }
2103 2099                          }
2104 2100                          /*
2105 2101                           * If we need to do NFS logging, the filehandle
2106 2102                           * must be downsized to 32 bytes.
2107 2103                           */
2108 2104                          if (!error && exi->exi_export.ex_flags & EX_LOG) {
2109 2105                                  i = 0;
2110 2106                                  sz = sizeof (fsid_t);
2111 2107                                  bcopy(&fh.fh3_fsid, &logbuf[i], sz);
2112 2108                                  i += sz;
2113 2109                                  sz = sizeof (ushort_t);
2114 2110                                  bcopy(&fh.fh3_len, &logbuf[i], sz);
2115 2111                                  i += sz;
2116 2112                                  sz = NFS_FHMAXDATA;
2117 2113                                  bcopy(fh.fh3_data, &logbuf[i], sz);
2118 2114                                  i += sz;
2119 2115                                  sz = sizeof (ushort_t);
2120 2116                                  bcopy(&fh.fh3_xlen, &logbuf[i], sz);
2121 2117                                  i += sz;
2122 2118                                  sz = NFS_FHMAXDATA;
2123 2119                                  bcopy(fh.fh3_xdata, &logbuf[i], sz);
2124 2120                                  i += sz;
2125 2121                          }
2126 2122                  }
2127 2123                  if (!error && exi->exi_export.ex_flags & EX_LOG) {
2128 2124                          nfslog_getfh(exi, (fhandle_t *)logptr,
2129 2125                              STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr);
2130 2126                  }
2131 2127                  exi_rele(exi);
2132 2128                  if (!error) {
2133 2129                          if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int)))
2134 2130                                  error = EFAULT;
2135 2131                          if (copyout(buf, STRUCT_FGETP(uap, fhp), l))
2136 2132                                  error = EFAULT;
2137 2133                  }
2138 2134          }
2139 2135          VN_RELE(vp);
2140 2136          if (dvp != NULL) {
2141 2137                  VN_RELE(dvp);
2142 2138          }
2143 2139          return (error);
2144 2140  }
2145 2141  
2146 2142  /*
2147 2143   * Strategy: if vp is in the export list, then
2148 2144   * return the associated file handle. Otherwise, ".."
2149 2145   * once up the vp and try again, until the root of the
2150 2146   * filesystem is reached.
2151 2147   */
2152 2148  struct   exportinfo *
2153 2149  nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
2154 2150      int *err, bool_t v4srv)
2155 2151  {
2156 2152          fid_t fid;
2157 2153          int error;
2158 2154          struct exportinfo *exi;
2159 2155  
2160 2156          ASSERT(vp);
2161 2157          VN_HOLD(vp);
2162 2158          if (dvp != NULL) {
2163 2159                  VN_HOLD(dvp);
2164 2160          }
2165 2161          if (walk != NULL)
2166 2162                  *walk = 0;
2167 2163  
2168 2164          for (;;) {
2169 2165                  bzero(&fid, sizeof (fid));
2170 2166                  fid.fid_len = MAXFIDSZ;
2171 2167                  error = vop_fid_pseudo(vp, &fid);
2172 2168                  if (error) {
2173 2169                          /*
2174 2170                           * If vop_fid_pseudo returns ENOSPC then the fid
2175 2171                           * supplied is too small. For now we simply
2176 2172                           * return EREMOTE.
2177 2173                           */
2178 2174                          if (error == ENOSPC)
2179 2175                                  error = EREMOTE;
2180 2176                          break;
2181 2177                  }
2182 2178  
2183 2179                  if (v4srv)
2184 2180                          exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2185 2181                  else
2186 2182                          exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
2187 2183  
2188 2184                  if (exi != NULL) {
2189 2185                          /*
2190 2186                           * Found the export info
2191 2187                           */
2192 2188                          break;
2193 2189                  }
2194 2190  
2195 2191                  /*
2196 2192                   * We have just failed finding a matching export.
2197 2193                   * If we're at the root of this filesystem, then
2198 2194                   * it's time to stop (with failure).
2199 2195                   */
2200 2196                  ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
2201 2197                  if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
2202 2198                          error = EINVAL;
2203 2199                          break;
2204 2200                  }
2205 2201  
2206 2202                  if (walk != NULL)
2207 2203                          (*walk)++;
2208 2204  
2209 2205                  /*
2210 2206                   * Now, do a ".." up vp. If dvp is supplied, use it,
2211 2207                   * otherwise, look it up.
2212 2208                   */
2213 2209                  if (dvp == NULL) {
2214 2210                          error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
2215 2211                              NULL, NULL, NULL);
2216 2212                          if (error)
2217 2213                                  break;
2218 2214                  }
2219 2215                  VN_RELE(vp);
2220 2216                  vp = dvp;
2221 2217                  dvp = NULL;
2222 2218          }
2223 2219          VN_RELE(vp);
2224 2220          if (dvp != NULL) {
2225 2221                  VN_RELE(dvp);
2226 2222          }
2227 2223          if (error != 0) {
2228 2224                  if (err != NULL)
2229 2225                          *err = error;
2230 2226                  return (NULL);
2231 2227          }
2232 2228          return (exi);
2233 2229  }
2234 2230  
2235 2231  int
2236 2232  chk_clnt_sec(exportinfo_t *exi, struct svc_req *req)
2237 2233  {
2238 2234          int i, nfsflavor;
2239 2235          struct secinfo *sp;
2240 2236  
2241 2237          /*
2242 2238           *  Get the nfs flavor number from xprt.
2243 2239           */
2244 2240          nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
2245 2241  
2246 2242          sp = exi->exi_export.ex_secinfo;
2247 2243          for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2248 2244                  if ((nfsflavor == sp[i].s_secinfo.sc_nfsnum) &&
2249 2245                      SEC_REF_EXPORTED(sp + i))
2250 2246                          return (TRUE);
2251 2247          }
2252 2248          return (FALSE);
2253 2249  }
2254 2250  
2255 2251  /*
2256 2252   * Make an fhandle from a vnode
2257 2253   */
2258 2254  int
2259 2255  makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi)
2260 2256  {
2261 2257          int error;
2262 2258  
2263 2259          *fh = exi->exi_fh;      /* struct copy */
2264 2260  
2265 2261          error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL);
2266 2262          if (error) {
2267 2263                  /*
2268 2264                   * Should be something other than EREMOTE
2269 2265                   */
2270 2266                  return (EREMOTE);
2271 2267          }
2272 2268          return (0);
2273 2269  }
2274 2270  
2275 2271  /*
2276 2272   * This routine makes an overloaded V2 fhandle which contains
2277 2273   * sec modes.
2278 2274   *
2279 2275   * Note that the first four octets contain the length octet,
2280 2276   * the status octet, and two padded octets to make them XDR
2281 2277   * four-octet aligned.
2282 2278   *
2283 2279   *   1   2   3   4                                          32
2284 2280   * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
2285 2281   * | l | s |   |   |     sec_1     |...|     sec_n     |...|   |
2286 2282   * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
2287 2283   *
2288 2284   * where
2289 2285   *
2290 2286   *   the status octet s indicates whether there are more security
2291 2287   *   flavors (1 means yes, 0 means no) that require the client to
2292 2288   *   perform another 0x81 LOOKUP to get them,
2293 2289   *
2294 2290   *   the length octet l is the length describing the number of
2295 2291   *   valid octets that follow.  (l = 4 * n, where n is the number
2296 2292   *   of security flavors sent in the current overloaded filehandle.)
2297 2293   *
2298 2294   *   sec_index should always be in the inclusive range: [1 - ex_seccnt],
2299 2295   *   and it tells server where to start within the secinfo array.
2300 2296   *   Usually it will always be 1; however, if more flavors are used
2301 2297   *   for the public export than can be encoded in the overloaded FH
2302 2298   *   (7 for NFS2), subsequent SNEGO MCLs will have a larger index
2303 2299   *   so the server will pick up where it left off from the previous
2304 2300   *   MCL reply.
2305 2301   *
2306 2302   *   With NFS4 support, implicitly allowed flavors are also in
2307 2303   *   the secinfo array; however, they should not be returned in
2308 2304   *   SNEGO MCL replies.
2309 2305   */
2310 2306  int
2311 2307  makefh_ol(fhandle_t *fh, exportinfo_t *exi, uint_t sec_index)
2312 2308  {
2313 2309          secinfo_t sec[MAX_FLAVORS];
2314 2310          int totalcnt, i, *ipt, cnt, seccnt, secidx, fh_max_cnt;
2315 2311          char *c;
2316 2312  
2317 2313          if (fh == NULL || exi == NULL || sec_index < 1)
2318 2314                  return (EREMOTE);
2319 2315  
2320 2316          /*
2321 2317           * WebNFS clients need to know the unique set of explicitly
2322 2318           * shared flavors in used for the public export. When
2323 2319           * "TRUE" is passed to build_seclist_nodups(), only explicitly
2324 2320           * shared flavors are included in the list.
2325 2321           */
2326 2322          seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2327 2323          if (sec_index > seccnt)
2328 2324                  return (EREMOTE);
2329 2325  
2330 2326          fh_max_cnt = (NFS_FHSIZE / sizeof (int)) - 1;
2331 2327          totalcnt = seccnt - sec_index + 1;
2332 2328          cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2333 2329  
2334 2330          c = (char *)fh;
2335 2331          /*
2336 2332           * Encode the length octet representing the number of
2337 2333           * security flavors (in bytes) in this overloaded fh.
2338 2334           */
2339 2335          *c = cnt * sizeof (int);
2340 2336  
2341 2337          /*
2342 2338           * Encode the status octet that indicates whether there
2343 2339           * are more security flavors the client needs to get.
2344 2340           */
2345 2341          *(c + 1) = totalcnt > fh_max_cnt;
2346 2342  
2347 2343          /*
2348 2344           * put security flavors in the overloaded fh
2349 2345           */
2350 2346          ipt = (int *)(c + sizeof (int32_t));
2351 2347          secidx = sec_index - 1;
2352 2348          for (i = 0; i < cnt; i++) {
2353 2349                  ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2354 2350          }
2355 2351          return (0);
2356 2352  }
2357 2353  
2358 2354  /*
2359 2355   * Make an nfs_fh3 from a vnode
2360 2356   */
2361 2357  int
2362 2358  makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
2363 2359  {
2364 2360          int error;
2365 2361          fid_t fid;
2366 2362  
2367 2363          bzero(&fid, sizeof (fid));
2368 2364          fid.fid_len = sizeof (fh->fh3_data);
2369 2365          error = VOP_FID(vp, &fid, NULL);
2370 2366          if (error)
2371 2367                  return (EREMOTE);
2372 2368  
2373 2369          bzero(fh, sizeof (nfs_fh3));
2374 2370          fh->fh3_fsid = exi->exi_fsid;
2375 2371          fh->fh3_len = fid.fid_len;
2376 2372          bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len);
2377 2373  
2378 2374          fh->fh3_xlen = exi->exi_fid.fid_len;
2379 2375          ASSERT(fh->fh3_xlen <= sizeof (fh->fh3_xdata));
2380 2376          bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen);
2381 2377  
2382 2378          fh->fh3_length = sizeof (fh->fh3_fsid)
2383 2379              + sizeof (fh->fh3_len) + fh->fh3_len
2384 2380              + sizeof (fh->fh3_xlen) + fh->fh3_xlen;
2385 2381          fh->fh3_flags = 0;
2386 2382  
2387 2383          return (0);
2388 2384  }
2389 2385  
2390 2386  /*
2391 2387   * This routine makes an overloaded V3 fhandle which contains
2392 2388   * sec modes.
2393 2389   *
2394 2390   *  1        4
2395 2391   * +--+--+--+--+
2396 2392   * |    len    |
2397 2393   * +--+--+--+--+
2398 2394   *                                               up to 64
2399 2395   * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
2400 2396   * |s |  |  |  |   sec_1   |   sec_2   | ... |   sec_n   |
2401 2397   * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
2402 2398   *
2403 2399   * len = 4 * (n+1), where n is the number of security flavors
2404 2400   * sent in the current overloaded filehandle.
2405 2401   *
2406 2402   * the status octet s indicates whether there are more security
2407 2403   * mechanisms (1 means yes, 0 means no) that require the client
2408 2404   * to perform another 0x81 LOOKUP to get them.
2409 2405   *
2410 2406   * Three octets are padded after the status octet.
2411 2407   */
2412 2408  int
2413 2409  makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index)
2414 2410  {
2415 2411          secinfo_t sec[MAX_FLAVORS];
2416 2412          int totalcnt, cnt, *ipt, i, seccnt, fh_max_cnt, secidx;
2417 2413          char *c;
2418 2414  
2419 2415          if (fh == NULL || exi == NULL || sec_index < 1)
2420 2416                  return (EREMOTE);
2421 2417  
2422 2418          /*
2423 2419           * WebNFS clients need to know the unique set of explicitly
2424 2420           * shared flavors in used for the public export. When
2425 2421           * "TRUE" is passed to build_seclist_nodups(), only explicitly
2426 2422           * shared flavors are included in the list.
2427 2423           */
2428 2424          seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2429 2425  
2430 2426          if (sec_index > seccnt)
2431 2427                  return (EREMOTE);
2432 2428  
2433 2429          fh_max_cnt = (NFS3_FHSIZE / sizeof (int)) - 1;
2434 2430          totalcnt = seccnt - sec_index + 1;
2435 2431          cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2436 2432  
2437 2433          /*
2438 2434           * Place the length in fh3_length representing the number
2439 2435           * of security flavors (in bytes) in this overloaded fh.
2440 2436           */
2441 2437          fh->fh3_flags = FH_WEBNFS;
2442 2438          fh->fh3_length = (cnt+1) * sizeof (int32_t);
2443 2439  
2444 2440          c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i;
2445 2441          /*
2446 2442           * Encode the status octet that indicates whether there
2447 2443           * are more security flavors the client needs to get.
2448 2444           */
2449 2445          *c = totalcnt > fh_max_cnt;
2450 2446  
2451 2447          /*
2452 2448           * put security flavors in the overloaded fh
2453 2449           */
2454 2450          secidx = sec_index - 1;
2455 2451          ipt = (int *)(c + sizeof (int32_t));
2456 2452          for (i = 0; i < cnt; i++) {
2457 2453                  ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2458 2454          }
2459 2455          return (0);
2460 2456  }
2461 2457  
2462 2458  /*
2463 2459   * Make an nfs_fh4 from a vnode
2464 2460   */
2465 2461  int
2466 2462  makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi)
2467 2463  {
2468 2464          int error;
2469 2465          nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2470 2466          fid_t fid;
2471 2467  
2472 2468          bzero(&fid, sizeof (fid));
2473 2469          fid.fid_len = MAXFIDSZ;
2474 2470          /*
2475 2471           * vop_fid_pseudo() is used to set up NFSv4 namespace, so
2476 2472           * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
2477 2473           */
2478 2474          error = vop_fid_pseudo(vp, &fid);
2479 2475          if (error)
2480 2476                  return (error);
2481 2477  
2482 2478          fh->nfs_fh4_len = NFS_FH4_LEN;
2483 2479  
2484 2480          fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid;
2485 2481          fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen;
2486 2482  
2487 2483          bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data));
2488 2484          bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata));
2489 2485          ASSERT(exi->exi_fh.fh_xlen <= sizeof (fh_fmtp->fh4_i.fhx_xdata));
2490 2486          bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata,
2491 2487              exi->exi_fh.fh_xlen);
2492 2488  
2493 2489          fh_fmtp->fh4_len = fid.fid_len;
2494 2490          ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data));
2495 2491          bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len);
2496 2492          fh_fmtp->fh4_flag = 0;
2497 2493  
2498 2494  #ifdef VOLATILE_FH_TEST
2499 2495          /*
2500 2496           * XXX (temporary?)
2501 2497           * Use the rnode volatile_id value to add volatility to the fh.
2502 2498           *
2503 2499           * For testing purposes there are currently two scenarios, based
2504 2500           * on whether the filesystem was shared with "volatile_fh"
2505 2501           * or "expire_on_rename". In the first case, use the value of
2506 2502           * export struct share_time as the volatile_id. In the second
2507 2503           * case use the vnode volatile_id value (which is set to the
2508 2504           * time in which the file was renamed).
2509 2505           *
2510 2506           * Note that the above are temporary constructs for testing only
2511 2507           * XXX
2512 2508           */
2513 2509          if (exi->exi_export.ex_flags & EX_VOLRNM) {
2514 2510                  fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh);
2515 2511          } else if (exi->exi_export.ex_flags & EX_VOLFH) {
2516 2512                  fh_fmtp->fh4_volatile_id = exi->exi_volatile_id;
2517 2513          } else {
2518 2514                  fh_fmtp->fh4_volatile_id = 0;
2519 2515          }
2520 2516  #endif /* VOLATILE_FH_TEST */
2521 2517  
2522 2518          return (0);
2523 2519  }
2524 2520  
2525 2521  /*
2526 2522   * Convert an fhandle into a vnode.
2527 2523   * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2528 2524   * WARNING: users of this routine must do a VN_RELE on the vnode when they
2529 2525   * are done with it.
2530 2526   */
2531 2527  vnode_t *
2532 2528  nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi)
2533 2529  {
2534 2530          vfs_t *vfsp;
2535 2531          vnode_t *vp;
2536 2532          int error;
2537 2533          fid_t *fidp;
2538 2534  
2539 2535          TRACE_0(TR_FAC_NFS, TR_FHTOVP_START,
2540 2536              "fhtovp_start");
2541 2537  
2542 2538          if (exi == NULL) {
2543 2539                  TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2544 2540                      "fhtovp_end:(%S)", "exi NULL");
2545 2541                  return (NULL);  /* not exported */
2546 2542          }
2547 2543  
2548 2544          ASSERT(exi->exi_vp != NULL);
2549 2545  
2550 2546          if (PUBLIC_FH2(fh)) {
2551 2547                  if (exi->exi_export.ex_flags & EX_PUBLIC) {
2552 2548                          TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2553 2549                              "fhtovp_end:(%S)", "root not exported");
2554 2550                          return (NULL);
2555 2551                  }
2556 2552                  vp = exi->exi_vp;
2557 2553                  VN_HOLD(vp);
2558 2554                  return (vp);
2559 2555          }
2560 2556  
2561 2557          vfsp = exi->exi_vp->v_vfsp;
2562 2558          ASSERT(vfsp != NULL);
2563 2559          fidp = (fid_t *)&fh->fh_len;
2564 2560  
2565 2561          error = VFS_VGET(vfsp, &vp, fidp);
2566 2562          if (error || vp == NULL) {
2567 2563                  TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2568 2564                      "fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2569 2565                  return (NULL);
2570 2566          }
2571 2567          TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2572 2568              "fhtovp_end:(%S)", "end");
2573 2569          return (vp);
2574 2570  }
2575 2571  
2576 2572  /*
2577 2573   * Convert an nfs_fh3 into a vnode.
2578 2574   * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2579 2575   * WARNING: users of this routine must do a VN_RELE on the vnode when they
2580 2576   * are done with it.
2581 2577   */
2582 2578  vnode_t *
2583 2579  nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi)
2584 2580  {
2585 2581          vfs_t *vfsp;
2586 2582          vnode_t *vp;
2587 2583          int error;
2588 2584          fid_t *fidp;
2589 2585  
2590 2586          if (exi == NULL)
2591 2587                  return (NULL);  /* not exported */
2592 2588  
2593 2589          ASSERT(exi->exi_vp != NULL);
2594 2590  
2595 2591          if (PUBLIC_FH3(fh)) {
2596 2592                  if (exi->exi_export.ex_flags & EX_PUBLIC)
2597 2593                          return (NULL);
2598 2594                  vp = exi->exi_vp;
2599 2595                  VN_HOLD(vp);
2600 2596                  return (vp);
2601 2597          }
2602 2598  
2603 2599          if (fh->fh3_length < NFS3_OLDFHSIZE ||
2604 2600              fh->fh3_length > NFS3_MAXFHSIZE)
2605 2601                  return (NULL);
2606 2602  
2607 2603          vfsp = exi->exi_vp->v_vfsp;
2608 2604          ASSERT(vfsp != NULL);
2609 2605          fidp = FH3TOFIDP(fh);
2610 2606  
2611 2607          error = VFS_VGET(vfsp, &vp, fidp);
2612 2608          if (error || vp == NULL)
2613 2609                  return (NULL);
2614 2610  
2615 2611          return (vp);
2616 2612  }
2617 2613  
2618 2614  /*
2619 2615   * Convert an nfs_fh4 into a vnode.
2620 2616   * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2621 2617   * WARNING: users of this routine must do a VN_RELE on the vnode when they
2622 2618   * are done with it.
2623 2619   */
2624 2620  vnode_t *
2625 2621  nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp)
2626 2622  {
2627 2623          vfs_t *vfsp;
2628 2624          vnode_t *vp = NULL;
2629 2625          int error;
2630 2626          fid_t *fidp;
2631 2627          nfs_fh4_fmt_t *fh_fmtp;
2632 2628  #ifdef VOLATILE_FH_TEST
2633 2629          uint32_t volatile_id = 0;
2634 2630  #endif /* VOLATILE_FH_TEST */
2635 2631  
2636 2632          if (exi == NULL) {
2637 2633                  *statp = NFS4ERR_STALE;
2638 2634                  return (NULL);  /* not exported */
2639 2635          }
2640 2636          ASSERT(exi->exi_vp != NULL);
2641 2637  
2642 2638          /* caller should have checked this */
2643 2639          ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN);
2644 2640  
2645 2641          fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2646 2642          vfsp = exi->exi_vp->v_vfsp;
2647 2643          ASSERT(vfsp != NULL);
2648 2644          fidp = (fid_t *)&fh_fmtp->fh4_len;
2649 2645  
2650 2646  #ifdef VOLATILE_FH_TEST
2651 2647          /* XXX check if volatile - should be changed later */
2652 2648          if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) {
2653 2649                  /*
2654 2650                   * Filesystem is shared with volatile filehandles
2655 2651                   */
2656 2652                  if (exi->exi_export.ex_flags & EX_VOLRNM)
2657 2653                          volatile_id = find_volrnm_fh_id(exi, fh);
2658 2654                  else
2659 2655                          volatile_id = exi->exi_volatile_id;
2660 2656  
2661 2657                  if (fh_fmtp->fh4_volatile_id != volatile_id) {
2662 2658                          *statp = NFS4ERR_FHEXPIRED;
2663 2659                          return (NULL);
2664 2660                  }
2665 2661          }
2666 2662          /*
2667 2663           * XXX even if test_volatile_fh false, the fh may contain a
2668 2664           * volatile id if obtained when the test was set.
2669 2665           */
2670 2666          fh_fmtp->fh4_volatile_id = (uchar_t)0;
2671 2667  #endif /* VOLATILE_FH_TEST */
2672 2668  
2673 2669          error = VFS_VGET(vfsp, &vp, fidp);
2674 2670          /*
2675 2671           * If we can not get vp from VFS_VGET, perhaps this is
2676 2672           * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2677 2673           * Check it out.
2678 2674           */
2679 2675          if (error && PSEUDO(exi))
2680 2676                  error = nfs4_vget_pseudo(exi, &vp, fidp);
2681 2677  
2682 2678          if (error || vp == NULL) {
2683 2679                  *statp = NFS4ERR_STALE;
2684 2680                  return (NULL);
2685 2681          }
2686 2682          /* XXX - disgusting hack */
2687 2683          if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
2688 2684                  vp->v_type = VDIR;
2689 2685          *statp = NFS4_OK;
2690 2686          return (vp);
2691 2687  }
2692 2688  
2693 2689  /*
2694 2690   * Find the export structure associated with the given filesystem.
2695 2691   * If found, then increment the ref count (exi_count).
2696 2692   */
2697 2693  struct exportinfo *
2698 2694  checkexport(fsid_t *fsid, fid_t *fid)
2699 2695  {
2700 2696          struct exportinfo *exi;
2701 2697          nfs_export_t *ne = nfs_get_export();
2702 2698  
2703 2699          rw_enter(&ne->exported_lock, RW_READER);
2704 2700          for (exi = ne->exptable[exptablehash(fsid, fid)];
2705 2701              exi != NULL;
2706 2702              exi = exi->fid_hash.next) {
2707 2703                  if (exportmatch(exi, fsid, fid)) {
2708 2704                          /*
2709 2705                           * If this is the place holder for the
2710 2706                           * public file handle, then return the
2711 2707                           * real export entry for the public file
2712 2708                           * handle.
2713 2709                           */
2714 2710                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2715 2711                                  exi = ne->exi_public;
2716 2712                          }
2717 2713  
2718 2714                          exi_hold(exi);
2719 2715                          rw_exit(&ne->exported_lock);
2720 2716                          return (exi);
2721 2717                  }
2722 2718          }
2723 2719          rw_exit(&ne->exported_lock);
2724 2720          return (NULL);
2725 2721  }
2726 2722  
2727 2723  
2728 2724  /*
2729 2725   * "old school" version of checkexport() for NFS4.  NFS4
2730 2726   * rfs4_compound holds exported_lock for duration of compound
2731 2727   * processing.  This version doesn't manipulate exi_count
2732 2728   * since NFS4 breaks fundamental assumptions in the exi_count
2733 2729   * design.
2734 2730   */
2735 2731  struct exportinfo *
2736 2732  checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2737 2733  {
2738 2734          struct exportinfo *exi;
2739 2735          nfs_export_t *ne = nfs_get_export();
2740 2736  
2741 2737          ASSERT(RW_LOCK_HELD(&ne->exported_lock));
2742 2738  
2743 2739          for (exi = ne->exptable[exptablehash(fsid, fid)];
2744 2740              exi != NULL;
2745 2741              exi = exi->fid_hash.next) {
2746 2742                  if (exportmatch(exi, fsid, fid)) {
2747 2743                          /*
2748 2744                           * If this is the place holder for the
2749 2745                           * public file handle, then return the
2750 2746                           * real export entry for the public file
2751 2747                           * handle.
2752 2748                           */
2753 2749                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2754 2750                                  exi = ne->exi_public;
2755 2751                          }
2756 2752  
2757 2753                          /*
2758 2754                           * If vp is given, check if vp is the
2759 2755                           * same vnode as the exported node.
2760 2756                           *
2761 2757                           * Since VOP_FID of a lofs node returns the
2762 2758                           * fid of its real node (ufs), the exported
2763 2759                           * node for lofs and (pseudo) ufs may have
2764 2760                           * the same fsid and fid.
2765 2761                           */
2766 2762                          if (vp == NULL || vp == exi->exi_vp)
2767 2763                                  return (exi);
2768 2764                  }
2769 2765          }
2770 2766  
2771 2767          return (NULL);
2772 2768  }
2773 2769  
2774 2770  /*
2775 2771   * Free an entire export list node
2776 2772   */
2777 2773  void
2778 2774  exportfree(struct exportinfo *exi)
2779 2775  {
2780 2776          struct exportdata *ex;
2781 2777          struct charset_cache *cache;
2782 2778          int i;
2783 2779  
2784 2780          ex = &exi->exi_export;
2785 2781  
2786 2782          ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC));
2787 2783          VN_RELE(exi->exi_vp);
2788 2784          if (exi->exi_dvp != NULL)
2789 2785                  VN_RELE(exi->exi_dvp);
2790 2786  
2791 2787          if (ex->ex_flags & EX_INDEX)
2792 2788                  kmem_free(ex->ex_index, strlen(ex->ex_index) + 1);
2793 2789  
2794 2790          kmem_free(ex->ex_path, ex->ex_pathlen + 1);
2795 2791          nfsauth_cache_free(exi);
2796 2792  
2797 2793          /*
2798 2794           * if there is a character set mapping cached, clean it up.
2799 2795           */
2800 2796          for (cache = exi->exi_charset; cache != NULL;
2801 2797              cache = exi->exi_charset) {
2802 2798                  if (cache->inbound != (kiconv_t)-1)
2803 2799                          (void) kiconv_close(cache->inbound);
2804 2800                  if (cache->outbound != (kiconv_t)-1)
2805 2801                          (void) kiconv_close(cache->outbound);
2806 2802                  exi->exi_charset = cache->next;
2807 2803                  kmem_free(cache, sizeof (struct charset_cache));
2808 2804          }
2809 2805  
2810 2806          if (exi->exi_logbuffer != NULL)
2811 2807                  nfslog_disable(exi);
2812 2808  
2813 2809          if (ex->ex_flags & EX_LOG) {
2814 2810                  kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1);
2815 2811                  kmem_free(ex->ex_tag, ex->ex_taglen + 1);
2816 2812          }
2817 2813  
2818 2814          if (exi->exi_visible)
2819 2815                  free_visible(exi->exi_visible);
2820 2816  
2821 2817          srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt);
2822 2818  
2823 2819  #ifdef VOLATILE_FH_TEST
2824 2820          free_volrnm_list(exi);
2825 2821          mutex_destroy(&exi->exi_vol_rename_lock);
2826 2822  #endif /* VOLATILE_FH_TEST */
2827 2823  
2828 2824          mutex_destroy(&exi->exi_lock);
2829 2825          rw_destroy(&exi->exi_cache_lock);
2830 2826          /*
2831 2827           * All nodes in the exi_cache AVL trees were removed and freed in the
2832 2828           * nfsauth_cache_free() call above.  We will just destroy and free the
2833 2829           * empty AVL trees here.
2834 2830           */
2835 2831          for (i = 0; i < AUTH_TABLESIZE; i++) {
2836 2832                  avl_destroy(exi->exi_cache[i]);
2837 2833                  kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
2838 2834          }
2839 2835  
2840 2836          kmem_free(exi, sizeof (*exi));
2841 2837  }
2842 2838  
2843 2839  /*
2844 2840   * load the index file from user space into kernel space.
2845 2841   */
2846 2842  static int
2847 2843  loadindex(struct exportdata *kex)
2848 2844  {
2849 2845          int error;
2850 2846          char index[MAXNAMELEN+1];
2851 2847          size_t len;
2852 2848  
2853 2849          /*
2854 2850           * copyinstr copies the complete string including the NULL and
2855 2851           * returns the len with the NULL byte included in the calculation
2856 2852           * as long as the max length is not exceeded.
2857 2853           */
2858 2854          if (error = copyinstr(kex->ex_index, index, sizeof (index), &len))
2859 2855                  return (error);
2860 2856  
2861 2857          kex->ex_index = kmem_alloc(len, KM_SLEEP);
2862 2858          bcopy(index, kex->ex_index, len);
2863 2859  
2864 2860          return (0);
2865 2861  }
2866 2862  
2867 2863  void
2868 2864  exi_hold(struct exportinfo *exi)
2869 2865  {
2870 2866          mutex_enter(&exi->exi_lock);
2871 2867          exi->exi_count++;
2872 2868          mutex_exit(&exi->exi_lock);
2873 2869  }
2874 2870  
2875 2871  /*
2876 2872   * When a thread completes using exi, it should call exi_rele().
2877 2873   * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2878 2874   * if this is the last user of exi and exi is not on exportinfo list anymore
2879 2875   */
2880 2876  void
2881 2877  exi_rele(struct exportinfo *exi)
2882 2878  {
2883 2879          mutex_enter(&exi->exi_lock);
2884 2880          exi->exi_count--;
2885 2881          if (exi->exi_count == 0) {
2886 2882                  mutex_exit(&exi->exi_lock);
2887 2883                  exportfree(exi);
2888 2884          } else
2889 2885                  mutex_exit(&exi->exi_lock);
2890 2886  }
2891 2887  
2892 2888  #ifdef VOLATILE_FH_TEST
2893 2889  /*
2894 2890   * Test for volatile fh's - add file handle to list and set its volatile id
2895 2891   * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2896 2892   * the vol_rename queue is purged.
2897 2893   *
2898 2894   * XXX This code is for unit testing purposes only... To correctly use it, it
2899 2895   * needs to tie a rename list to the export struct and (more
2900 2896   * important), protect access to the exi rename list using a write lock.
2901 2897   */
2902 2898  
2903 2899  /*
2904 2900   * get the fh vol record if it's in the volatile on rename list. Don't check
2905 2901   * volatile_id in the file handle - compare only the file handles.
2906 2902   */
2907 2903  static struct ex_vol_rename *
2908 2904  find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p)
2909 2905  {
2910 2906          struct ex_vol_rename *p = NULL;
2911 2907          fhandle4_t *fhp;
2912 2908  
2913 2909          /* XXX shouldn't we assert &exported_lock held? */
2914 2910          ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock));
2915 2911  
2916 2912          if (fh4p->nfs_fh4_len != NFS_FH4_LEN) {
2917 2913                  return (NULL);
2918 2914          }
2919 2915          fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i;
2920 2916          for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) {
2921 2917                  if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i,
2922 2918                      sizeof (fhandle4_t)) == 0)
2923 2919                          break;
2924 2920          }
2925 2921          return (p);
2926 2922  }
2927 2923  
2928 2924  /*
2929 2925   * get the volatile id for the fh (if there is - else return 0). Ignore the
2930 2926   * volatile_id in the file handle - compare only the file handles.
2931 2927   */
2932 2928  static uint32_t
2933 2929  find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p)
2934 2930  {
2935 2931          struct ex_vol_rename *p;
2936 2932          uint32_t volatile_id;
2937 2933  
2938 2934          mutex_enter(&exi->exi_vol_rename_lock);
2939 2935          p = find_volrnm_fh(exi, fh4p);
2940 2936          volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id :
2941 2937              exi->exi_volatile_id);
2942 2938          mutex_exit(&exi->exi_vol_rename_lock);
2943 2939          return (volatile_id);
2944 2940  }
2945 2941  
2946 2942  /*
2947 2943   * Free the volatile on rename list - will be called if a filesystem is
2948 2944   * unshared or reshared without EX_VOLRNM
2949 2945   */
2950 2946  static void
2951 2947  free_volrnm_list(struct exportinfo *exi)
2952 2948  {
2953 2949          struct ex_vol_rename *p, *pnext;
2954 2950  
2955 2951          /* no need to hold mutex lock - this one is called from exportfree */
2956 2952          for (p = exi->exi_vol_rename; p != NULL; p = pnext) {
2957 2953                  pnext = p->vrn_next;
2958 2954                  kmem_free(p, sizeof (*p));
2959 2955          }
2960 2956          exi->exi_vol_rename = NULL;
2961 2957  }
2962 2958  
2963 2959  /*
2964 2960   * Add a file handle to the volatile on rename list.
2965 2961   */
2966 2962  void
2967 2963  add_volrnm_fh(struct exportinfo *exi, vnode_t *vp)
2968 2964  {
2969 2965          struct ex_vol_rename *p;
2970 2966          char fhbuf[NFS4_FHSIZE];
2971 2967          nfs_fh4 fh4;
2972 2968          int error;
2973 2969  
2974 2970          fh4.nfs_fh4_val = fhbuf;
2975 2971          error = makefh4(&fh4, vp, exi);
2976 2972          if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) {
2977 2973                  return;
2978 2974          }
2979 2975  
2980 2976          mutex_enter(&exi->exi_vol_rename_lock);
2981 2977  
2982 2978          p = find_volrnm_fh(exi, &fh4);
2983 2979  
2984 2980          if (p == NULL) {
2985 2981                  p = kmem_alloc(sizeof (*p), KM_SLEEP);
2986 2982                  bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt));
2987 2983                  p->vrn_next = exi->exi_vol_rename;
2988 2984                  exi->exi_vol_rename = p;
2989 2985          }
2990 2986  
2991 2987          p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec();
2992 2988          mutex_exit(&exi->exi_vol_rename_lock);
2993 2989  }
2994 2990  
2995 2991  #endif /* VOLATILE_FH_TEST */
  
    | 
      ↓ open down ↓ | 
    1054 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX