Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/dev/sdev_vnops.c
          +++ new/usr/src/uts/common/fs/dev/sdev_vnops.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   * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   */
  24   24  /*
  25   25   * Copyright 2016, Joyent, Inc.
  26   26   */
  27   27  
  28   28  /*
  29   29   * vnode ops for the /dev filesystem
  30   30   *
  31   31   * - VDIR, VCHR, CBLK, and VLNK are considered must supported files
  32   32   * - VREG and VDOOR are used for some internal implementations in
  33   33   *    the global zone, e.g. devname and devfsadm communication
  34   34   * - other file types are unusual in this namespace and
  35   35   *    not supported for now
  36   36   */
  37   37  
  38   38  /*
  39   39   * sdev has a few basic goals:
  40   40   *   o Provide /dev for the global zone as well as various non-global zones.
  41   41   *   o Provide the basic functionality that devfsadm might need (mknod,
  42   42   *     symlinks, etc.)
  43   43   *   o Allow persistent permissions on files in /dev.
  44   44   *   o Allow for dynamic directories and nodes for use by various services (pts,
  45   45   *     zvol, net, etc.)
  46   46   *
  47   47   * The sdev file system is primarily made up of sdev_node_t's which is sdev's
  48   48   * counterpart to the vnode_t. There are two different classes of sdev_node_t's
  49   49   * that we generally care about, dynamic and otherwise.
  50   50   *
  51   51   * Persisting Information
  52   52   * ----------------------
  53   53   *
  54   54   * When sdev is mounted, it keeps track of the underlying file system it is
  55   55   * mounted over. In certain situations, sdev will go and create entries in that
  56   56   * underlying file system. These underlying 'back end' nodes are used as proxies
  57   57   * for various changes in permissions. While specific sets of nodes, such as
  58   58   * dynamic ones, are exempt, this process stores permission changes against
  59   59   * these back end nodes. The point of all of this is to allow for these settings
  60   60   * to persist across host and zone reboots. As an example, consider the entry
  61   61   * /dev/dsk/c0t0d0 which is a character device and that / is in UFS. Upon
  62   62   * changing the permissions on c0t0d0 you'd have the following logical
  63   63   * relationships:
  64   64   *
  65   65   *    +------------------+   sdev_vnode     +--------------+
  66   66   *    | sdev_node_t      |<---------------->| vnode_t      |
  67   67   *    | /dev/dsk/c0t0d0  |<---------------->| for sdev     |
  68   68   *    +------------------+                  +--------------+
  69   69   *           |
  70   70   *           | sdev_attrvp
  71   71   *           |
  72   72   *           |    +---------------------+
  73   73   *           +--->| vnode_t for UFS|ZFS |
  74   74   *                | /dev/dsk/c0t0d0     |
  75   75   *                +---------------------+
  76   76   *
  77   77   * sdev is generally in memory. Therefore when a lookup happens and there is no
  78   78   * entry already inside of a directory cache, it will next check the backing
  79   79   * store. If the backing store exists, we will reconstitute the sdev_node based
  80   80   * on the information that we persisted. When we create the backing store node,
  81   81   * we use the struct vattr information that we already have in sdev_node_t.
  82   82   * Because of this, we already know if the entry was previously a symlink,
  83   83   * directory, or some other kind of type. Note that not all types of nodes are
  84   84   * supported. Currently only VDIR, VCHR, VBLK, VREG, VDOOR, and VLNK are
  85   85   * eligible to be persisted.
  86   86   *
  87   87   * When the sdev_node is created and the lookup is done, we grab a hold on the
  88   88   * underlying vnode as part of the call to VOP_LOOKUP. That reference is held
  89   89   * until the sdev_node becomes inactive. Once its reference count reaches one
  90   90   * and the VOP_INACTIVE callback fires leading to the destruction of the node,
  91   91   * the reference on the underlying vnode will be released.
  92   92   *
  93   93   * The backing store node will be deleted only when the node itself is deleted
  94   94   * through the means of a VOP_REMOVE, VOP_RMDIR, or similar call.
  95   95   *
  96   96   * Not everything can be persisted, see The Rules section for more details.
  97   97   *
  98   98   * Dynamic Nodes
  99   99   * -------------
 100  100   *
 101  101   * Dynamic nodes allow for specific interactions with various kernel subsystems
 102  102   * when looking up directory entries. This allows the lookup and readdir
 103  103   * functions to check against the kernel subsystem's for validity. eg. does a
 104  104   * zvol or nic still exist.
 105  105   *
 106  106   * More specifically, when we create various directories we check if the
 107  107   * directory name matches that of one of the names in the vtab[] (sdev_subr.c).
 108  108   * If it does, we swap out the vnode operations into a new set which combine the
 109  109   * normal sdev vnode operations with the dynamic set here.
 110  110   *
 111  111   * In addition, various dynamic nodes implement a verification entry point. This
 112  112   * verification entry is used as a part of lookup and readdir. The goal for
 113  113   * these dynamic nodes is to allow them to check with the underlying subsystems
 114  114   * to ensure that these devices are still present, or if they have gone away, to
 115  115   * remove them from the results. This is indicated by using the SDEV_VTOR flag
 116  116   * in vtab[].
 117  117   *
 118  118   * Dynamic nodes have additional restrictions placed upon them. They may only
 119  119   * appear at the top level directory of the file system. In addition, users
 120  120   * cannot create dirents below any leve of a dynamic node aside from its special
 121  121   * vnops.
 122  122   *
 123  123   * Profiles
 124  124   * --------
 125  125   *
 126  126   * Profiles exist for the purpose of non-global zones. They work with the zone
 127  127   * brands and zoneadmd to set up a filter of allowed devices that can appear in
 128  128   * a non-global zone's /dev. These are sent to sdev by means of libdevinfo and a
 129  129   * modctl system call. Specifically it allows one to add patterns of device
 130  130   * paths to include and exclude. It allows for a collection of symlinks to be
 131  131   * added and it allows for remapping names.
 132  132   *
 133  133   * When operating in a non-global zone, several of the sdev vnops are redirected
 134  134   * to the profile versions. These impose additional restrictions such as
 135  135   * enforcing that a non-global zone's /dev is read only.
 136  136   *
 137  137   * sdev_node_t States
 138  138   * ------------------
 139  139   *
 140  140   * A given sdev_node_t has a field called the sdev_state which describes where
 141  141   * in the sdev life cycle it is. There are three primary states: SDEV_INIT,
 142  142   * SDEV_READY, and SDEV_ZOMBIE.
 143  143   *
 144  144   *      SDEV_INIT: When a new /dev file is first looked up, a sdev_node
 145  145   *                 is allocated, initialized and added to the directory's
 146  146   *                 sdev_node cache. A node at this state will also
 147  147   *                 have the SDEV_LOOKUP flag set.
 148  148   *
 149  149   *                 Other threads that are trying to look up a node at
 150  150   *                 this state will be blocked until the SDEV_LOOKUP flag
 151  151   *                 is cleared.
 152  152   *
 153  153   *                 When the SDEV_LOOKUP flag is cleared, the node may
 154  154   *                 transition into the SDEV_READY state for a successful
 155  155   *                 lookup or the node is removed from the directory cache
 156  156   *                 and destroyed if the named node can not be found.
 157  157   *                 An ENOENT error is returned for the second case.
 158  158   *
 159  159   *      SDEV_READY: A /dev file has been successfully looked up and
 160  160   *                  associated with a vnode. The /dev file is available
 161  161   *                  for the supported /dev file system operations.
 162  162   *
 163  163   *      SDEV_ZOMBIE: Deletion of a /dev file has been explicitly issued
 164  164   *                  to an SDEV_READY node. The node is transitioned into
 165  165   *                  the SDEV_ZOMBIE state if the vnode reference count
 166  166   *                  is still held. A SDEV_ZOMBIE node does not support
 167  167   *                  any of the /dev file system operations. A SDEV_ZOMBIE
 168  168   *                  node is immediately removed from the directory cache
 169  169   *                  and destroyed once the reference count reaches zero.
 170  170   *
 171  171   * Historically nodes that were marked SDEV_ZOMBIE were not removed from the
 172  172   * underlying directory caches. This has been the source of numerous bugs and
 173  173   * thus to better mimic what happens on a real file system, it is no longer the
 174  174   * case.
 175  175   *
 176  176   * The following state machine describes the life cycle of a given node and its
 177  177   * associated states:
 178  178   *
 179  179   * node is . . . . .
 180  180   * allocated via   .     +-------------+         . . . . . . . vnode_t refcount
 181  181   * sdev_nodeinit() .     | Unallocated |         .             reaches zero and
 182  182   *        +--------*-----|   Memory    |<--------*---+         sdev_inactive is
 183  183   *        |              +-------------+             |         called.
 184  184   *        |       +------------^                     |         called.
 185  185   *        v       |                                  |
 186  186   *  +-----------+ * . . sdev_nodeready()      +-------------+
 187  187   *  | SDEV_INIT | |     or related setup      | SDEV_ZOMBIE |
 188  188   *  +-----------+ |     failure               +-------------+
 189  189   *        |       |                                  ^
 190  190   *        |       |      +------------+              |
 191  191   *        +-*----------->| SDEV_READY |--------*-----+
 192  192   *          .            +------------+        .          The node is no longer
 193  193   *          . . node successfully              . . . . .  valid or we've been
 194  194   *              inserted into the                         asked to remove it.
 195  195   *              directory cache                           This happens via
 196  196   *              and sdev_nodready()                       sdev_dirdelete().
 197  197   *              call successful.
 198  198   *
 199  199   * Adding and Removing Dirents, Zombie Nodes
 200  200   * -----------------------------------------
 201  201   *
 202  202   * As part of doing a lookup, readdir, or an explicit creation operation like
 203  203   * mkdir or create, nodes may be created. Every directory has an avl tree which
 204  204   * contains its children, the sdev_entries tree. This is only used if the type
 205  205   * is VDIR. Access to this is controlled by the sdev_node_t's contents_lock and
 206  206   * it is managed through sdev_cache_update().
 207  207   *
 208  208   * Every sdev_node_t has a field sdev_state, which describes the current state
 209  209   * of the node. A node is generally speaking in the SDEV_READY state. When it is
 210  210   * there, it can be looked up, accessed, and operations performed on it. When a
 211  211   * node is going to be removed from the directory cache it is marked as a
 212  212   * zombie. Once a node becomes a zombie, no other file system operations will
 213  213   * succeed and it will continue to exist as a node until the vnode count on the
 214  214   * node reaches zero. At that point, the node will be freed.  However, once a
 215  215   * node has been marked as a zombie, it will be removed immediately from the
 216  216   * directory cache such that no one else may find it again.  This means that
 217  217   * someone else can insert a new entry into that directory with the same name
 218  218   * and without a problem.
 219  219   *
 220  220   * To remove a node, see the section on that in The Rules.
 221  221   *
 222  222   * The Rules
 223  223   * ---------
 224  224   * These are the rules to live by when working in sdev. These are not
 225  225   * exhaustive.
 226  226   *
 227  227   * - Set 1: Working with Backing Nodes
 228  228   *   o If there is a SDEV_READY sdev_node_t, it knows about its backing node.
 229  229   *   o If we find a backing node when looking up an sdev_node_t for the first
 230  230   *     time, we use its attributes to build our sdev_node_t.
 231  231   *   o If there is a found backing node, or we create a backing node, that's
 232  232   *     when we grab the hold on its vnode.
 233  233   *   o If we mark an sdev_node_t a ZOMBIE, we must remove its backing node from
 234  234   *     the underlying file system. It must not be searchable or findable.
 235  235   *   o We release our hold on the backing node vnode when we destroy the
 236  236   *     sdev_node_t.
 237  237   *
 238  238   * - Set 2: Locking rules for sdev (not exhaustive)
 239  239   *   o The majority of nodes contain an sdev_contents rw lock. You must hold it
 240  240   *     for read or write if manipulating its contents appropriately.
 241  241   *   o You must lock your parent before yourself.
 242  242   *   o If you need your vnode's v_lock and the sdev_contents rw lock, you must
 243  243   *     grab the v_lock before the sdev_contents rw_lock.
 244  244   *   o If you release a lock on the node as a part of upgrading it, you must
 245  245   *     verify that the node has not become a zombie as a part of this process.
 246  246   *
 247  247   * - Set 3: Zombie Status and What it Means
 248  248   *   o If you encounter a node that is a ZOMBIE, that means that it has been
 249  249   *     unlinked from the backing store.
 250  250   *   o If you release your contents lock and acquire it again (say as part of
 251  251   *     trying to grab a write lock) you must check that the node has not become
 252  252   *     a zombie.
 253  253   *   o You should VERIFY that a looked up node is not a zombie. This follows
 254  254   *     from the following logic. To mark something as a zombie means that it is
 255  255   *     removed from the parents directory cache. To do that, you must have a
 256  256   *     write lock on the parent's sdev_contents. To lookup through that
 257  257   *     directory you must have a read lock. This then becomes a simple ordering
 258  258   *     problem. If you've been granted the lock then the other operation cannot
 259  259   *     be in progress or must have already succeeded.
 260  260   *
 261  261   * - Set 4: Removing Directory Entries (aka making nodes Zombies)
 262  262   *   o Write lock must be held on the directory
 263  263   *   o Write lock must be held on the node
 264  264   *   o Remove the sdev_node_t from its parent cache
 265  265   *   o Remove the corresponding backing store node, if it exists, eg. use
 266  266   *     VOP_REMOVE or VOP_RMDIR.
 267  267   *   o You must NOT make any change in the vnode reference count! Nodes should
 268  268   *     only be cleaned up through VOP_INACTIVE callbacks.
 269  269   *   o VOP_INACTIVE is the only one responsible for doing the final vn_rele of
 270  270   *     the backing store vnode that was grabbed during lookup.
 271  271   *
 272  272   * - Set 5: What Nodes may be Persisted
 273  273   *   o The root, /dev is always persisted
 274  274   *   o Any node in vtab which is marked SDEV_DYNAMIC, may not be persisted
 275  275   *     unless it is also marked SDEV_PERSIST
 276  276   *   o Anything whose parent directory is marked SDEV_PERSIST will pass that
 277  277   *     along to the child as long as it does not contradict the above rules
 278  278   */
 279  279  
 280  280  #include <sys/types.h>
 281  281  #include <sys/param.h>
 282  282  #include <sys/t_lock.h>
 283  283  #include <sys/systm.h>
 284  284  #include <sys/sysmacros.h>
 285  285  #include <sys/user.h>
 286  286  #include <sys/time.h>
 287  287  #include <sys/vfs.h>
 288  288  #include <sys/vnode.h>
 289  289  #include <sys/vfs_opreg.h>
 290  290  #include <sys/file.h>
 291  291  #include <sys/fcntl.h>
 292  292  #include <sys/flock.h>
 293  293  #include <sys/kmem.h>
 294  294  #include <sys/uio.h>
 295  295  #include <sys/errno.h>
 296  296  #include <sys/stat.h>
 297  297  #include <sys/cred.h>
 298  298  #include <sys/dirent.h>
 299  299  #include <sys/pathname.h>
 300  300  #include <sys/cmn_err.h>
 301  301  #include <sys/debug.h>
 302  302  #include <sys/policy.h>
 303  303  #include <vm/hat.h>
 304  304  #include <vm/seg_vn.h>
 305  305  #include <vm/seg_map.h>
 306  306  #include <vm/seg.h>
 307  307  #include <vm/as.h>
 308  308  #include <vm/page.h>
 309  309  #include <sys/proc.h>
 310  310  #include <sys/mode.h>
 311  311  #include <sys/sunndi.h>
 312  312  #include <sys/ptms.h>
 313  313  #include <fs/fs_subr.h>
 314  314  #include <sys/fs/dv_node.h>
 315  315  #include <sys/fs/sdev_impl.h>
 316  316  
 317  317  /*ARGSUSED*/
 318  318  static int
 319  319  sdev_open(struct vnode **vpp, int flag, struct cred *cred, caller_context_t *ct)
 320  320  {
 321  321          struct sdev_node *dv = VTOSDEV(*vpp);
 322  322          struct sdev_node *ddv = dv->sdev_dotdot;
 323  323          int error = 0;
 324  324  
 325  325          if ((*vpp)->v_type == VDIR)
 326  326                  return (0);
 327  327  
 328  328          if (!SDEV_IS_GLOBAL(dv))
 329  329                  return (ENOTSUP);
 330  330  
 331  331          if ((*vpp)->v_type == VLNK)
 332  332                  return (ENOENT);
 333  333          ASSERT((*vpp)->v_type == VREG);
 334  334          if ((*vpp)->v_type != VREG)
 335  335                  return (ENOTSUP);
 336  336  
 337  337          ASSERT(ddv);
 338  338          rw_enter(&ddv->sdev_contents, RW_READER);
 339  339          if (dv->sdev_attrvp == NULL) {
 340  340                  rw_exit(&ddv->sdev_contents);
 341  341                  return (ENOENT);
 342  342          }
 343  343          error = VOP_OPEN(&(dv->sdev_attrvp), flag, cred, ct);
 344  344          rw_exit(&ddv->sdev_contents);
 345  345          return (error);
 346  346  }
 347  347  
 348  348  /*ARGSUSED1*/
 349  349  static int
 350  350  sdev_close(struct vnode *vp, int flag, int count,
 351  351      offset_t offset, struct cred *cred, caller_context_t *ct)
 352  352  {
 353  353          struct sdev_node *dv = VTOSDEV(vp);
 354  354  
 355  355          if (vp->v_type == VDIR) {
 356  356                  cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
 357  357                  cleanshares(vp, ttoproc(curthread)->p_pid);
 358  358                  return (0);
 359  359          }
 360  360  
 361  361          if (!SDEV_IS_GLOBAL(dv))
 362  362                  return (ENOTSUP);
 363  363  
 364  364          ASSERT(vp->v_type == VREG);
 365  365          if (vp->v_type != VREG)
 366  366                  return (ENOTSUP);
 367  367  
 368  368          ASSERT(dv->sdev_attrvp);
 369  369          return (VOP_CLOSE(dv->sdev_attrvp, flag, count, offset, cred, ct));
 370  370  }
 371  371  
 372  372  /*ARGSUSED*/
 373  373  static int
 374  374  sdev_read(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
 375  375          struct caller_context *ct)
 376  376  {
 377  377          struct sdev_node *dv = (struct sdev_node *)VTOSDEV(vp);
 378  378          int     error;
 379  379  
 380  380          if (!SDEV_IS_GLOBAL(dv))
 381  381                  return (EINVAL);
 382  382  
 383  383          if (vp->v_type == VDIR)
 384  384                  return (EISDIR);
 385  385  
 386  386          /* only supporting regular files in /dev */
 387  387          ASSERT(vp->v_type == VREG);
 388  388          if (vp->v_type != VREG)
 389  389                  return (EINVAL);
 390  390  
 391  391          ASSERT(RW_READ_HELD(&VTOSDEV(vp)->sdev_contents));
 392  392          ASSERT(dv->sdev_attrvp);
 393  393          (void) VOP_RWLOCK(dv->sdev_attrvp, 0, ct);
 394  394          error = VOP_READ(dv->sdev_attrvp, uio, ioflag, cred, ct);
 395  395          VOP_RWUNLOCK(dv->sdev_attrvp, 0, ct);
 396  396          return (error);
 397  397  }
 398  398  
 399  399  /*ARGSUSED*/
 400  400  static int
 401  401  sdev_write(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
 402  402          struct caller_context *ct)
 403  403  {
 404  404          struct sdev_node *dv = VTOSDEV(vp);
 405  405          int     error = 0;
 406  406  
 407  407          if (!SDEV_IS_GLOBAL(dv))
 408  408                  return (EINVAL);
 409  409  
 410  410          if (vp->v_type == VDIR)
 411  411                  return (EISDIR);
 412  412  
 413  413          /* only supporting regular files in /dev */
 414  414          ASSERT(vp->v_type == VREG);
 415  415          if (vp->v_type != VREG)
 416  416                  return (EINVAL);
 417  417  
 418  418          ASSERT(dv->sdev_attrvp);
 419  419  
 420  420          (void) VOP_RWLOCK(dv->sdev_attrvp, 1, ct);
 421  421          error = VOP_WRITE(dv->sdev_attrvp, uio, ioflag, cred, ct);
 422  422          VOP_RWUNLOCK(dv->sdev_attrvp, 1, ct);
 423  423          if (error == 0) {
 424  424                  sdev_update_timestamps(dv->sdev_attrvp, kcred,
 425  425                      AT_MTIME);
 426  426          }
 427  427          return (error);
 428  428  }
 429  429  
 430  430  /*ARGSUSED*/
 431  431  static int
 432  432  sdev_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
 433  433      struct cred *cred, int *rvalp,  caller_context_t *ct)
 434  434  {
 435  435          struct sdev_node *dv = VTOSDEV(vp);
 436  436  
 437  437          if (!SDEV_IS_GLOBAL(dv) || (vp->v_type == VDIR))
 438  438                  return (ENOTTY);
 439  439  
 440  440          ASSERT(vp->v_type == VREG);
 441  441          if (vp->v_type != VREG)
 442  442                  return (EINVAL);
 443  443  
 444  444          ASSERT(dv->sdev_attrvp);
 445  445          return (VOP_IOCTL(dv->sdev_attrvp, cmd, arg, flag, cred, rvalp, ct));
 446  446  }
 447  447  
 448  448  static int
 449  449  sdev_getattr(struct vnode *vp, struct vattr *vap, int flags,
 450  450      struct cred *cr, caller_context_t *ct)
 451  451  {
 452  452          int                     error = 0;
 453  453          struct sdev_node        *dv = VTOSDEV(vp);
 454  454          struct sdev_node        *parent = dv->sdev_dotdot;
 455  455  
 456  456          ASSERT(parent);
 457  457  
 458  458          rw_enter(&parent->sdev_contents, RW_READER);
 459  459          ASSERT(dv->sdev_attr || dv->sdev_attrvp);
 460  460  
 461  461          /*
 462  462           * search order:
 463  463           *      - for persistent nodes (SDEV_PERSIST): backstore
 464  464           *      - for non-persistent nodes: module ops if global, then memory
 465  465           */
 466  466          if (dv->sdev_attrvp) {
 467  467                  rw_exit(&parent->sdev_contents);
 468  468                  error = VOP_GETATTR(dv->sdev_attrvp, vap, flags, cr, ct);
 469  469                  sdev_vattr_merge(dv, vap);
 470  470          } else {
 471  471                  ASSERT(dv->sdev_attr);
 472  472                  *vap = *dv->sdev_attr;
 473  473                  sdev_vattr_merge(dv, vap);
 474  474                  rw_exit(&parent->sdev_contents);
 475  475          }
 476  476  
 477  477          return (error);
 478  478  }
 479  479  
 480  480  /*ARGSUSED4*/
 481  481  static int
 482  482  sdev_setattr(struct vnode *vp, struct vattr *vap, int flags,
 483  483      struct cred *cred, caller_context_t *ctp)
 484  484  {
 485  485          return (devname_setattr_func(vp, vap, flags, cred, NULL, 0));
 486  486  }
 487  487  
 488  488  static int
 489  489  sdev_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
 490  490      struct cred *cr, caller_context_t *ct)
 491  491  {
 492  492          int     error;
 493  493          struct sdev_node *dv = VTOSDEV(vp);
 494  494          struct vnode *avp = dv->sdev_attrvp;
 495  495  
 496  496          if (avp == NULL) {
 497  497                  /* return fs_fab_acl() if flavor matches, else do nothing */
 498  498                  if ((SDEV_ACL_FLAVOR(vp) == _ACL_ACLENT_ENABLED &&
 499  499                      (vsap->vsa_mask & (VSA_ACLCNT | VSA_DFACLCNT))) ||
 500  500                      (SDEV_ACL_FLAVOR(vp) == _ACL_ACE_ENABLED &&
 501  501                      (vsap->vsa_mask & (VSA_ACECNT | VSA_ACE))))
 502  502                          return (fs_fab_acl(vp, vsap, flags, cr, ct));
 503  503  
 504  504                  return (ENOSYS);
 505  505          }
 506  506  
 507  507          (void) VOP_RWLOCK(avp, 1, ct);
 508  508          error = VOP_GETSECATTR(avp, vsap, flags, cr, ct);
 509  509          VOP_RWUNLOCK(avp, 1, ct);
 510  510          return (error);
 511  511  }
 512  512  
 513  513  static int
 514  514  sdev_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
 515  515      struct cred *cr, caller_context_t *ct)
 516  516  {
 517  517          int     error;
 518  518          struct sdev_node *dv = VTOSDEV(vp);
 519  519          struct vnode *avp = dv->sdev_attrvp;
 520  520  
 521  521          if (dv->sdev_state == SDEV_ZOMBIE)
 522  522                  return (0);
 523  523  
 524  524          if (avp == NULL) {
 525  525                  if (SDEV_IS_GLOBAL(dv) && !SDEV_IS_PERSIST(dv))
 526  526                          return (fs_nosys());
 527  527                  ASSERT(dv->sdev_attr);
 528  528                  /*
 529  529                   * if coming in directly, the acl system call will
 530  530                   * have held the read-write lock via VOP_RWLOCK()
 531  531                   * If coming in via specfs, specfs will have
 532  532                   * held the rw lock on the realvp i.e. us.
 533  533                   */
 534  534                  ASSERT(RW_WRITE_HELD(&dv->sdev_contents));
 535  535                  sdev_vattr_merge(dv, dv->sdev_attr);
 536  536                  error = sdev_shadow_node(dv, cr);
 537  537                  if (error) {
 538  538                          return (fs_nosys());
 539  539                  }
 540  540  
 541  541                  ASSERT(dv->sdev_attrvp);
 542  542                  /* clean out the memory copy if any */
 543  543                  if (dv->sdev_attr) {
 544  544                          kmem_free(dv->sdev_attr, sizeof (struct vattr));
 545  545                          dv->sdev_attr = NULL;
 546  546                  }
 547  547                  avp = dv->sdev_attrvp;
 548  548          }
 549  549          ASSERT(avp);
 550  550  
 551  551          (void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, ct);
 552  552          error = VOP_SETSECATTR(avp, vsap, flags, cr, ct);
 553  553          VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, ct);
 554  554          return (error);
 555  555  }
 556  556  
 557  557  /*
 558  558   * There are two different unlocked routines. This one is not static as it is
 559  559   * used as part of the secpolicy_vnode_setattr calls in sdev_subr.c. Because it
 560  560   * is used in that function it has to have a specific signature.
 561  561   */
 562  562  int
 563  563  sdev_unlocked_access(void *vdv, int mode, struct cred *cr)
 564  564  {
 565  565          struct sdev_node        *dv = vdv;
 566  566          int                     shift = 0;
 567  567          uid_t                   owner = dv->sdev_attr->va_uid;
 568  568  
 569  569          if (crgetuid(cr) != owner) {
 570  570                  shift += 3;
 571  571                  if (groupmember(dv->sdev_attr->va_gid, cr) == 0)
 572  572                          shift += 3;
 573  573          }
 574  574  
 575  575          return (secpolicy_vnode_access2(cr, SDEVTOV(dv), owner,
 576  576              dv->sdev_attr->va_mode << shift, mode));
 577  577  }
 578  578  
 579  579  static int
 580  580  sdev_self_access(sdev_node_t *dv, int mode, int flags, struct cred *cr,
 581  581      caller_context_t *ct)
 582  582  {
 583  583          int ret;
 584  584  
 585  585          ASSERT(dv->sdev_attr || dv->sdev_attrvp);
 586  586          if (dv->sdev_attrvp) {
 587  587                  ret = VOP_ACCESS(dv->sdev_attrvp, mode, flags, cr, ct);
 588  588          } else if (dv->sdev_attr) {
 589  589                  ret = sdev_unlocked_access(dv, mode, cr);
 590  590                  if (ret)
 591  591                          ret = EACCES;
 592  592          }
 593  593  
 594  594          return (ret);
 595  595  }
 596  596  
 597  597  static int
 598  598  sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr,
 599  599      caller_context_t *ct)
 600  600  {
 601  601          struct sdev_node *dv = VTOSDEV(vp);
 602  602          int ret;
 603  603  
 604  604          rw_enter(&dv->sdev_contents, RW_READER);
 605  605          ret = sdev_self_access(dv, mode, flags, cr, ct);
 606  606          rw_exit(&dv->sdev_contents);
 607  607  
 608  608          return (ret);
 609  609  }
 610  610  
 611  611  /*
 612  612   * Lookup
 613  613   */
 614  614  /*ARGSUSED3*/
 615  615  static int
 616  616  sdev_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
 617  617      struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
 618  618      caller_context_t *ct, int *direntflags, pathname_t *realpnp)
 619  619  {
 620  620          struct sdev_node *parent;
 621  621          int error;
 622  622  
 623  623          parent = VTOSDEV(dvp);
 624  624          ASSERT(parent);
 625  625  
 626  626          /* execute access is required to search the directory */
 627  627          if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
 628  628                  return (error);
 629  629  
 630  630          if (!SDEV_IS_GLOBAL(parent))
 631  631                  return (prof_lookup(dvp, nm, vpp, cred));
 632  632          return (devname_lookup_func(parent, nm, vpp, cred, NULL, 0));
 633  633  }
 634  634  
 635  635  /*ARGSUSED2*/
 636  636  static int
 637  637  sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
 638  638      int mode, struct vnode **vpp, struct cred *cred, int flag,
 639  639      caller_context_t *ct, vsecattr_t *vsecp)
 640  640  {
 641  641          struct vnode            *vp = NULL;
 642  642          struct vnode            *avp;
 643  643          struct sdev_node        *parent;
 644  644          struct sdev_node        *self = NULL;
 645  645          int                     error = 0;
 646  646          vtype_t                 type = vap->va_type;
 647  647  
 648  648          ASSERT(type != VNON && type != VBAD);
 649  649  
 650  650          if ((type == VFIFO) || (type == VSOCK) ||
 651  651              (type == VPROC) || (type == VPORT))
 652  652                  return (ENOTSUP);
 653  653  
 654  654          parent = VTOSDEV(dvp);
 655  655          ASSERT(parent);
 656  656  
 657  657          rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER);
 658  658          if (parent->sdev_state == SDEV_ZOMBIE) {
 659  659                  rw_exit(&parent->sdev_dotdot->sdev_contents);
 660  660                  return (ENOENT);
 661  661          }
 662  662  
 663  663          /* non-global do not allow pure node creation */
 664  664          if (!SDEV_IS_GLOBAL(parent)) {
 665  665                  rw_exit(&parent->sdev_dotdot->sdev_contents);
 666  666                  return (prof_lookup(dvp, nm, vpp, cred));
 667  667          }
 668  668          rw_exit(&parent->sdev_dotdot->sdev_contents);
 669  669  
 670  670          /* execute access is required to search the directory */
 671  671          if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
 672  672                  return (error);
 673  673  
 674  674          /* check existing name */
 675  675  /* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
 676  676          error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
 677  677  
 678  678          /* name found */
 679  679          if (error == 0) {
 680  680                  ASSERT(vp);
 681  681                  if (excl == EXCL) {
 682  682                          error = EEXIST;
 683  683                  } else if ((vp->v_type == VDIR) && (mode & VWRITE)) {
 684  684                          /* allowing create/read-only an existing directory */
 685  685                          error = EISDIR;
 686  686                  } else {
 687  687                          error = VOP_ACCESS(vp, mode, 0, cred, ct);
 688  688                  }
 689  689  
 690  690                  if (error) {
 691  691                          VN_RELE(vp);
 692  692                          return (error);
 693  693                  }
 694  694  
 695  695                  /* truncation first */
 696  696                  if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) &&
 697  697                      (vap->va_size == 0)) {
 698  698                          ASSERT(parent->sdev_attrvp);
 699  699                          error = VOP_CREATE(parent->sdev_attrvp,
 700  700                              nm, vap, excl, mode, &avp, cred, flag, ct, vsecp);
 701  701  
 702  702                          if (error) {
 703  703                                  VN_RELE(vp);
 704  704                                  return (error);
 705  705                          }
 706  706                  }
 707  707  
 708  708                  sdev_update_timestamps(vp, kcred,
 709  709                      AT_CTIME|AT_MTIME|AT_ATIME);
 710  710                  *vpp = vp;
 711  711                  return (0);
 712  712          }
 713  713  
 714  714          /* bail out early */
 715  715          if (error != ENOENT)
 716  716                  return (error);
 717  717  
 718  718          /* verify write access - compliance specifies ENXIO */
 719  719          if ((error = VOP_ACCESS(dvp, VEXEC|VWRITE, 0, cred, ct)) != 0) {
 720  720                  if (error == EACCES)
 721  721                          error = ENXIO;
 722  722                  return (error);
 723  723          }
 724  724  
 725  725          /*
 726  726           * For memory-based (ROFS) directory:
 727  727           *      - either disallow node creation;
 728  728           *      - or implement VOP_CREATE of its own
 729  729           */
 730  730          rw_enter(&parent->sdev_contents, RW_WRITER);
 731  731          if (!SDEV_IS_PERSIST(parent)) {
 732  732                  rw_exit(&parent->sdev_contents);
 733  733                  return (ENOTSUP);
 734  734          }
 735  735          ASSERT(parent->sdev_attrvp);
 736  736          error = sdev_mknode(parent, nm, &self, vap, NULL, NULL,
 737  737              cred, SDEV_READY);
 738  738          if (error) {
 739  739                  rw_exit(&parent->sdev_contents);
 740  740                  if (self)
 741  741                          SDEV_RELE(self);
 742  742                  return (error);
 743  743          }
 744  744          rw_exit(&parent->sdev_contents);
 745  745  
 746  746          ASSERT(self);
 747  747          /* take care the timestamps for the node and its parent */
 748  748          sdev_update_timestamps(SDEVTOV(self), kcred,
 749  749              AT_CTIME|AT_MTIME|AT_ATIME);
 750  750          sdev_update_timestamps(dvp, kcred, AT_MTIME|AT_ATIME);
 751  751          if (SDEV_IS_GLOBAL(parent))
 752  752                  atomic_inc_ulong(&parent->sdev_gdir_gen);
 753  753  
 754  754          /* wake up other threads blocked on looking up this node */
 755  755          mutex_enter(&self->sdev_lookup_lock);
 756  756          SDEV_UNBLOCK_OTHERS(self, SDEV_LOOKUP);
 757  757          mutex_exit(&self->sdev_lookup_lock);
 758  758          error = sdev_to_vp(self, vpp);
 759  759          return (error);
 760  760  }
 761  761  
 762  762  static int
 763  763  sdev_remove(struct vnode *dvp, char *nm, struct cred *cred,
 764  764      caller_context_t *ct, int flags)
 765  765  {
 766  766          int     error;
 767  767          struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
 768  768          struct vnode *vp = NULL;
 769  769          struct sdev_node *dv = NULL;
 770  770          int len;
 771  771          int bkstore;
 772  772  
 773  773          /* bail out early */
 774  774          len = strlen(nm);
 775  775          if (nm[0] == '.') {
 776  776                  if (len == 1) {
 777  777                          return (EINVAL);
 778  778                  } else if (len == 2 && nm[1] == '.') {
 779  779                          return (EEXIST);
 780  780                  }
 781  781          }
 782  782  
 783  783          ASSERT(parent);
 784  784          rw_enter(&parent->sdev_contents, RW_READER);
 785  785          if (!SDEV_IS_GLOBAL(parent)) {
 786  786                  rw_exit(&parent->sdev_contents);
 787  787                  return (ENOTSUP);
 788  788          }
 789  789  
 790  790          /* execute access is required to search the directory */
 791  791          if ((error = sdev_self_access(parent, VEXEC, 0, cred, ct)) != 0) {
 792  792                  rw_exit(&parent->sdev_contents);
 793  793                  return (error);
 794  794          }
 795  795  
 796  796          /* check existence first */
 797  797          dv = sdev_cache_lookup(parent, nm);
 798  798          if (dv == NULL) {
 799  799                  rw_exit(&parent->sdev_contents);
 800  800                  return (ENOENT);
 801  801          }
 802  802  
 803  803          vp = SDEVTOV(dv);
 804  804          if ((dv->sdev_state == SDEV_INIT) ||
 805  805              (dv->sdev_state == SDEV_ZOMBIE)) {
 806  806                  rw_exit(&parent->sdev_contents);
 807  807                  VN_RELE(vp);
 808  808                  return (ENOENT);
 809  809          }
 810  810  
 811  811          /* write access is required to remove an entry */
 812  812          if ((error = sdev_self_access(parent, VWRITE, 0, cred, ct)) != 0) {
 813  813                  rw_exit(&parent->sdev_contents);
 814  814                  VN_RELE(vp);
 815  815                  return (error);
 816  816          }
 817  817  
 818  818          bkstore = SDEV_IS_PERSIST(dv) ? 1 : 0;
 819  819          if (!rw_tryupgrade(&parent->sdev_contents)) {
 820  820                  rw_exit(&parent->sdev_contents);
 821  821                  rw_enter(&parent->sdev_contents, RW_WRITER);
 822  822                  /* Make sure we didn't become a zombie */
 823  823                  if (parent->sdev_state == SDEV_ZOMBIE) {
 824  824                          rw_exit(&parent->sdev_contents);
 825  825                          VN_RELE(vp);
 826  826                          return (ENOENT);
 827  827                  }
 828  828          }
 829  829  
 830  830          /* we do not support unlinking a non-empty directory */
 831  831          if (vp->v_type == VDIR && dv->sdev_nlink > 2) {
 832  832                  rw_exit(&parent->sdev_contents);
 833  833                  VN_RELE(vp);
 834  834                  return (EBUSY);
 835  835          }
 836  836  
 837  837          /*
 838  838           * sdev_dirdelete does the real job of:
 839  839           *  - make sure no open ref count
 840  840           *  - destroying the sdev_node
 841  841           *  - releasing the hold on attrvp
 842  842           */
 843  843          sdev_cache_update(parent, &dv, nm, SDEV_CACHE_DELETE);
 844  844          VN_RELE(vp);
 845  845          rw_exit(&parent->sdev_contents);
 846  846  
 847  847          /*
 848  848           * best efforts clean up the backing store
 849  849           */
 850  850          if (bkstore) {
 851  851                  ASSERT(parent->sdev_attrvp);
 852  852                  error = VOP_REMOVE(parent->sdev_attrvp, nm, cred,
 853  853                      ct, flags);
 854  854                  /*
 855  855                   * do not report BUSY error
 856  856                   * because the backing store ref count is released
 857  857                   * when the last ref count on the sdev_node is
 858  858                   * released.
 859  859                   */
 860  860                  if (error == EBUSY) {
 861  861                          sdcmn_err2(("sdev_remove: device %s is still on"
 862  862                              "disk %s\n", nm, parent->sdev_path));
 863  863                          error = 0;
 864  864                  }
 865  865          }
 866  866  
 867  867          if (error == 0)
 868  868                  i_ddi_di_cache_invalidate();
 869  869  
 870  870          return (error);
 871  871  }
 872  872  
 873  873  /*
 874  874   * Some restrictions for this file system:
 875  875   *  - both oldnm and newnm are in the scope of /dev file system,
 876  876   *    to simply the namespace management model.
 877  877   */
 878  878  /*ARGSUSED6*/
 879  879  static int
 880  880  sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
 881  881      struct cred *cred, caller_context_t *ct, int flags)
 882  882  {
 883  883          struct sdev_node        *fromparent = NULL;
 884  884          struct vattr            vattr;
 885  885          struct sdev_node        *toparent;
 886  886          struct sdev_node        *fromdv = NULL; /* source node */
 887  887          struct vnode            *ovp = NULL;    /* source vnode */
 888  888          struct sdev_node        *todv = NULL;   /* destination node */
 889  889          struct vnode            *nvp = NULL;    /* destination vnode */
 890  890          int                     samedir = 0;    /* set if odvp == ndvp */
 891  891          struct vnode            *realvp;
 892  892          int error = 0;
 893  893          dev_t fsid;
 894  894          int bkstore = 0;
 895  895          vtype_t type;
 896  896  
 897  897          /* prevent modifying "." and ".." */
 898  898          if ((onm[0] == '.' &&
 899  899              (onm[1] == '\0' || (onm[1] == '.' && onm[2] == '\0'))) ||
 900  900              (nnm[0] == '.' &&
 901  901              (nnm[1] == '\0' || (nnm[1] == '.' && nnm[2] == '\0')))) {
 902  902                  return (EINVAL);
 903  903          }
 904  904  
 905  905          fromparent = VTOSDEV(odvp);
 906  906          toparent = VTOSDEV(ndvp);
 907  907  
 908  908          /* ZOMBIE parent doesn't allow new node creation */
 909  909          rw_enter(&fromparent->sdev_dotdot->sdev_contents, RW_READER);
 910  910          if (fromparent->sdev_state == SDEV_ZOMBIE) {
 911  911                  rw_exit(&fromparent->sdev_dotdot->sdev_contents);
 912  912                  return (ENOENT);
 913  913          }
 914  914  
 915  915          /* renaming only supported for global device nodes */
 916  916          if (!SDEV_IS_GLOBAL(fromparent)) {
 917  917                  rw_exit(&fromparent->sdev_dotdot->sdev_contents);
 918  918                  return (ENOTSUP);
 919  919          }
 920  920          rw_exit(&fromparent->sdev_dotdot->sdev_contents);
 921  921  
 922  922          rw_enter(&toparent->sdev_dotdot->sdev_contents, RW_READER);
 923  923          if (toparent->sdev_state == SDEV_ZOMBIE) {
 924  924                  rw_exit(&toparent->sdev_dotdot->sdev_contents);
 925  925                  return (ENOENT);
 926  926          }
 927  927          rw_exit(&toparent->sdev_dotdot->sdev_contents);
 928  928  
 929  929          /*
 930  930           * acquire the global lock to prevent
 931  931           * mount/unmount/other rename activities.
 932  932           */
 933  933          mutex_enter(&sdev_lock);
 934  934  
 935  935          /* check existence of the source node */
 936  936  /* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
 937  937          error = VOP_LOOKUP(odvp, onm, &ovp, NULL, 0, NULL, cred, ct,
 938  938              NULL, NULL);
 939  939          if (error) {
 940  940                  sdcmn_err2(("sdev_rename: the source node %s exists\n",
 941  941                      onm));
 942  942                  mutex_exit(&sdev_lock);
 943  943                  return (error);
 944  944          }
 945  945  
 946  946          if (VOP_REALVP(ovp, &realvp, ct) == 0) {
 947  947                  VN_HOLD(realvp);
 948  948                  VN_RELE(ovp);
 949  949                  ovp = realvp;
 950  950          }
 951  951  
 952  952          /* check existence of destination */
 953  953  /* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
 954  954          error = VOP_LOOKUP(ndvp, nnm, &nvp, NULL, 0, NULL, cred, ct,
 955  955              NULL, NULL);
 956  956          if (error && (error != ENOENT)) {
 957  957                  mutex_exit(&sdev_lock);
 958  958                  VN_RELE(ovp);
 959  959                  return (error);
 960  960          }
 961  961  
 962  962          if (nvp && (VOP_REALVP(nvp, &realvp, ct) == 0)) {
 963  963                  VN_HOLD(realvp);
 964  964                  VN_RELE(nvp);
 965  965                  nvp = realvp;
 966  966          }
 967  967  
 968  968          /*
 969  969           * make sure the source and the destination are
 970  970           * in the same dev filesystem
 971  971           */
 972  972          if (odvp != ndvp) {
 973  973                  vattr.va_mask = AT_FSID;
 974  974                  if (error = VOP_GETATTR(odvp, &vattr, 0, cred, ct)) {
 975  975                          mutex_exit(&sdev_lock);
 976  976                          VN_RELE(ovp);
 977  977                          if (nvp != NULL)
 978  978                                  VN_RELE(nvp);
 979  979                          return (error);
 980  980                  }
 981  981                  fsid = vattr.va_fsid;
 982  982                  vattr.va_mask = AT_FSID;
 983  983                  if (error = VOP_GETATTR(ndvp, &vattr, 0, cred, ct)) {
 984  984                          mutex_exit(&sdev_lock);
 985  985                          VN_RELE(ovp);
 986  986                          if (nvp != NULL)
 987  987                                  VN_RELE(nvp);
 988  988                          return (error);
 989  989                  }
 990  990                  if (fsid != vattr.va_fsid) {
 991  991                          mutex_exit(&sdev_lock);
 992  992                          VN_RELE(ovp);
 993  993                          if (nvp != NULL)
 994  994                                  VN_RELE(nvp);
 995  995                          return (EXDEV);
 996  996                  }
 997  997          }
 998  998  
 999  999          /* make sure the old entry can be deleted */
1000 1000          error = VOP_ACCESS(odvp, VWRITE, 0, cred, ct);
1001 1001          if (error) {
1002 1002                  mutex_exit(&sdev_lock);
1003 1003                  VN_RELE(ovp);
1004 1004                  if (nvp != NULL)
1005 1005                          VN_RELE(nvp);
1006 1006                  return (error);
1007 1007          }
1008 1008  
1009 1009          /* make sure the destination allows creation */
1010 1010          samedir = (fromparent == toparent);
1011 1011          if (!samedir) {
1012 1012                  error = VOP_ACCESS(ndvp, VEXEC|VWRITE, 0, cred, ct);
1013 1013                  if (error) {
1014 1014                          mutex_exit(&sdev_lock);
1015 1015                          VN_RELE(ovp);
1016 1016                          if (nvp != NULL)
1017 1017                                  VN_RELE(nvp);
1018 1018                          return (error);
1019 1019                  }
1020 1020          }
1021 1021  
1022 1022          fromdv = VTOSDEV(ovp);
1023 1023          ASSERT(fromdv);
1024 1024  
1025 1025          /* destination file exists */
1026 1026          if (nvp != NULL) {
1027 1027                  todv = VTOSDEV(nvp);
1028 1028                  ASSERT(todv);
1029 1029          }
1030 1030  
1031 1031          if ((fromdv->sdev_flags & SDEV_DYNAMIC) != 0 ||
1032 1032              (todv != NULL && (todv->sdev_flags & SDEV_DYNAMIC) != 0)) {
1033 1033                  mutex_exit(&sdev_lock);
1034 1034                  if (nvp != NULL)
1035 1035                          VN_RELE(nvp);
1036 1036                  VN_RELE(ovp);
1037 1037                  return (EACCES);
1038 1038          }
1039 1039  
1040 1040          /*
1041 1041           * link source to new target in the memory. Regardless of failure, we
1042 1042           * must rele our hold on nvp.
1043 1043           */
1044 1044          error = sdev_rnmnode(fromparent, fromdv, toparent, &todv, nnm, cred);
1045 1045          if (nvp != NULL)
1046 1046                  VN_RELE(nvp);
1047 1047          if (error) {
1048 1048                  sdcmn_err2(("sdev_rename: renaming %s to %s failed "
1049 1049                      " with error %d\n", onm, nnm, error));
1050 1050                  mutex_exit(&sdev_lock);
1051 1051                  VN_RELE(ovp);
1052 1052                  return (error);
1053 1053          }
1054 1054  
1055 1055          /*
1056 1056           * unlink from source
1057 1057           */
1058 1058          rw_enter(&fromparent->sdev_contents, RW_READER);
1059 1059          fromdv = sdev_cache_lookup(fromparent, onm);
1060 1060          if (fromdv == NULL) {
1061 1061                  rw_exit(&fromparent->sdev_contents);
1062 1062                  mutex_exit(&sdev_lock);
1063 1063                  VN_RELE(ovp);
1064 1064                  sdcmn_err2(("sdev_rename: the source is deleted already\n"));
1065 1065                  return (0);
1066 1066          }
1067 1067  
1068 1068          if (fromdv->sdev_state == SDEV_ZOMBIE) {
1069 1069                  rw_exit(&fromparent->sdev_contents);
1070 1070                  mutex_exit(&sdev_lock);
1071 1071                  VN_RELE(SDEVTOV(fromdv));
1072 1072                  VN_RELE(ovp);
1073 1073                  sdcmn_err2(("sdev_rename: the source is being deleted\n"));
1074 1074                  return (0);
1075 1075          }
1076 1076          rw_exit(&fromparent->sdev_contents);
1077 1077          ASSERT(SDEVTOV(fromdv) == ovp);
1078 1078          VN_RELE(ovp);
1079 1079  
1080 1080          /* clean out the directory contents before it can be removed */
1081 1081          type = SDEVTOV(fromdv)->v_type;
1082 1082          if (type == VDIR) {
1083 1083                  error = sdev_cleandir(fromdv, NULL, 0);
1084 1084                  sdcmn_err2(("sdev_rename: cleandir finished with %d\n",
1085 1085                      error));
1086 1086                  if (error == EBUSY)
1087 1087                          error = 0;
1088 1088          }
1089 1089  
1090 1090          rw_enter(&fromparent->sdev_contents, RW_WRITER);
1091 1091          bkstore = SDEV_IS_PERSIST(fromdv) ? 1 : 0;
1092 1092          sdev_cache_update(fromparent, &fromdv, onm,
1093 1093              SDEV_CACHE_DELETE);
1094 1094          VN_RELE(SDEVTOV(fromdv));
1095 1095  
1096 1096          /* best effforts clean up the backing store */
1097 1097          if (bkstore) {
1098 1098                  ASSERT(fromparent->sdev_attrvp);
1099 1099                  if (type != VDIR) {
1100 1100  /* XXXci - We may need to translate the C-I flags on VOP_REMOVE */
1101 1101                          error = VOP_REMOVE(fromparent->sdev_attrvp,
1102 1102                              onm, kcred, ct, 0);
1103 1103                  } else {
1104 1104  /* XXXci - We may need to translate the C-I flags on VOP_RMDIR */
1105 1105                          error = VOP_RMDIR(fromparent->sdev_attrvp,
1106 1106                              onm, fromparent->sdev_attrvp, kcred, ct, 0);
1107 1107                  }
1108 1108  
1109 1109                  if (error) {
1110 1110                          sdcmn_err2(("sdev_rename: device %s is "
1111 1111                              "still on disk %s\n", onm,
1112 1112                              fromparent->sdev_path));
1113 1113                          error = 0;
1114 1114                  }
1115 1115          }
1116 1116          rw_exit(&fromparent->sdev_contents);
1117 1117          mutex_exit(&sdev_lock);
1118 1118  
1119 1119          /* once reached to this point, the rename is regarded successful */
1120 1120          return (0);
1121 1121  }
1122 1122  
1123 1123  /*
1124 1124   * dev-fs version of "ln -s path dev-name"
1125 1125   *      tnm - path, e.g. /devices/... or /dev/...
1126 1126   *      lnm - dev_name
1127 1127   */
1128 1128  /*ARGSUSED6*/
1129 1129  static int
1130 1130  sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
1131 1131      char *tnm, struct cred *cred, caller_context_t *ct, int flags)
1132 1132  {
1133 1133          int error;
1134 1134          struct vnode *vp = NULL;
1135 1135          struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
1136 1136          struct sdev_node *self = (struct sdev_node *)NULL;
1137 1137  
1138 1138          ASSERT(parent);
1139 1139          rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER);
1140 1140          if (parent->sdev_state == SDEV_ZOMBIE) {
1141 1141                  rw_exit(&parent->sdev_dotdot->sdev_contents);
1142 1142                  sdcmn_err2(("sdev_symlink: parent %s is ZOMBIED \n",
1143 1143                      parent->sdev_name));
1144 1144                  return (ENOENT);
1145 1145          }
1146 1146  
1147 1147          if (!SDEV_IS_GLOBAL(parent)) {
1148 1148                  rw_exit(&parent->sdev_dotdot->sdev_contents);
1149 1149                  return (ENOTSUP);
1150 1150          }
1151 1151          rw_exit(&parent->sdev_dotdot->sdev_contents);
1152 1152  
1153 1153          /* execute access is required to search a directory */
1154 1154          if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
1155 1155                  return (error);
1156 1156  
1157 1157          /* find existing name */
1158 1158  /* XXXci - We may need to translate the C-I flags here */
1159 1159          error = VOP_LOOKUP(dvp, lnm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
1160 1160          if (error == 0) {
1161 1161                  ASSERT(vp);
1162 1162                  VN_RELE(vp);
1163 1163                  sdcmn_err2(("sdev_symlink: node %s already exists\n", lnm));
1164 1164                  return (EEXIST);
1165 1165          }
1166 1166          if (error != ENOENT)
1167 1167                  return (error);
1168 1168  
1169 1169          /* write access is required to create a symlink */
1170 1170          if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0)
1171 1171                  return (error);
1172 1172  
1173 1173          /* put it into memory cache */
1174 1174          rw_enter(&parent->sdev_contents, RW_WRITER);
1175 1175          error = sdev_mknode(parent, lnm, &self, tva, NULL, (void *)tnm,
1176 1176              cred, SDEV_READY);
1177 1177          if (error) {
1178 1178                  rw_exit(&parent->sdev_contents);
1179 1179                  sdcmn_err2(("sdev_symlink: node %s creation failed\n", lnm));
1180 1180                  if (self)
1181 1181                          SDEV_RELE(self);
1182 1182  
1183 1183                  return (error);
1184 1184          }
1185 1185          ASSERT(self && (self->sdev_state == SDEV_READY));
1186 1186          rw_exit(&parent->sdev_contents);
1187 1187  
1188 1188          /* take care the timestamps for the node and its parent */
1189 1189          sdev_update_timestamps(SDEVTOV(self), kcred,
1190 1190              AT_CTIME|AT_MTIME|AT_ATIME);
1191 1191          sdev_update_timestamps(dvp, kcred, AT_MTIME|AT_ATIME);
1192 1192          if (SDEV_IS_GLOBAL(parent))
1193 1193                  atomic_inc_ulong(&parent->sdev_gdir_gen);
1194 1194          i_ddi_di_cache_invalidate();
1195 1195  
1196 1196          /* wake up other threads blocked on looking up this node */
1197 1197          mutex_enter(&self->sdev_lookup_lock);
1198 1198          SDEV_UNBLOCK_OTHERS(self, SDEV_LOOKUP);
1199 1199          mutex_exit(&self->sdev_lookup_lock);
1200 1200          SDEV_RELE(self);        /* don't return with vnode held */
1201 1201          return (0);
1202 1202  }
1203 1203  
1204 1204  /*ARGSUSED6*/
1205 1205  static int
1206 1206  sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
1207 1207      struct cred *cred, caller_context_t *ct, int flags, vsecattr_t *vsecp)
1208 1208  {
1209 1209          int error;
1210 1210          struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
1211 1211          struct sdev_node *self = NULL;
1212 1212          struct vnode    *vp = NULL;
1213 1213  
1214 1214          ASSERT(parent && parent->sdev_dotdot);
1215 1215          rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER);
1216 1216          if (parent->sdev_state == SDEV_ZOMBIE) {
1217 1217                  rw_exit(&parent->sdev_dotdot->sdev_contents);
1218 1218                  return (ENOENT);
1219 1219          }
1220 1220  
1221 1221          /* non-global do not allow pure directory creation */
1222 1222          if (!SDEV_IS_GLOBAL(parent)) {
1223 1223                  rw_exit(&parent->sdev_dotdot->sdev_contents);
1224 1224                  return (prof_lookup(dvp, nm, vpp, cred));
1225 1225          }
1226 1226          rw_exit(&parent->sdev_dotdot->sdev_contents);
1227 1227  
1228 1228          /* execute access is required to search the directory */
1229 1229          if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0) {
1230 1230                  return (error);
1231 1231          }
1232 1232  
1233 1233          /* find existing name */
1234 1234  /* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
1235 1235          error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
1236 1236          if (error == 0) {
1237 1237                  VN_RELE(vp);
1238 1238                  return (EEXIST);
1239 1239          }
1240 1240          if (error != ENOENT)
1241 1241                  return (error);
1242 1242  
1243 1243          /* require write access to create a directory */
1244 1244          if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0) {
1245 1245                  return (error);
1246 1246          }
1247 1247  
1248 1248          /* put it into memory */
1249 1249          rw_enter(&parent->sdev_contents, RW_WRITER);
1250 1250          error = sdev_mknode(parent, nm, &self,
1251 1251              va, NULL, NULL, cred, SDEV_READY);
1252 1252          if (error) {
1253 1253                  rw_exit(&parent->sdev_contents);
1254 1254                  if (self)
1255 1255                          SDEV_RELE(self);
1256 1256                  return (error);
1257 1257          }
1258 1258          ASSERT(self && (self->sdev_state == SDEV_READY));
1259 1259          rw_exit(&parent->sdev_contents);
1260 1260  
1261 1261          /* take care the timestamps for the node and its parent */
1262 1262          sdev_update_timestamps(SDEVTOV(self), kcred,
1263 1263              AT_CTIME|AT_MTIME|AT_ATIME);
1264 1264          sdev_update_timestamps(dvp, kcred, AT_MTIME|AT_ATIME);
1265 1265          if (SDEV_IS_GLOBAL(parent))
1266 1266                  atomic_inc_ulong(&parent->sdev_gdir_gen);
1267 1267          i_ddi_di_cache_invalidate();
1268 1268  
1269 1269          /* wake up other threads blocked on looking up this node */
1270 1270          mutex_enter(&self->sdev_lookup_lock);
1271 1271          SDEV_UNBLOCK_OTHERS(self, SDEV_LOOKUP);
1272 1272          mutex_exit(&self->sdev_lookup_lock);
1273 1273          *vpp = SDEVTOV(self);
1274 1274          return (0);
1275 1275  }
1276 1276  
1277 1277  /*
1278 1278   * allowing removing an empty directory under /dev
1279 1279   */
1280 1280  /*ARGSUSED*/
1281 1281  static int
1282 1282  sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred,
1283 1283      caller_context_t *ct, int flags)
1284 1284  {
1285 1285          int error = 0;
1286 1286          struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
1287 1287          struct sdev_node *self = NULL;
1288 1288          struct vnode *vp = NULL;
1289 1289  
1290 1290          /* bail out early */
1291 1291          if (strcmp(nm, ".") == 0)
1292 1292                  return (EINVAL);
1293 1293          if (strcmp(nm, "..") == 0)
1294 1294                  return (EEXIST); /* should be ENOTEMPTY */
1295 1295  
1296 1296          /* no destruction of non-global node */
1297 1297          ASSERT(parent && parent->sdev_dotdot);
1298 1298          rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER);
1299 1299          if (!SDEV_IS_GLOBAL(parent)) {
1300 1300                  rw_exit(&parent->sdev_dotdot->sdev_contents);
1301 1301                  return (ENOTSUP);
1302 1302          }
1303 1303          rw_exit(&parent->sdev_dotdot->sdev_contents);
1304 1304  
1305 1305          /* execute access is required to search the directory */
1306 1306          if ((error = VOP_ACCESS(dvp, VEXEC|VWRITE, 0, cred, ct)) != 0)
1307 1307                  return (error);
1308 1308  
1309 1309          /* check existing name */
1310 1310          rw_enter(&parent->sdev_contents, RW_WRITER);
1311 1311          self = sdev_cache_lookup(parent, nm);
1312 1312          if (self == NULL) {
1313 1313                  rw_exit(&parent->sdev_contents);
1314 1314                  return (ENOENT);
1315 1315          }
1316 1316  
1317 1317          vp = SDEVTOV(self);
1318 1318          if ((self->sdev_state == SDEV_INIT) ||
1319 1319              (self->sdev_state == SDEV_ZOMBIE)) {
1320 1320                  rw_exit(&parent->sdev_contents);
1321 1321                  VN_RELE(vp);
1322 1322                  return (ENOENT);
1323 1323          }
1324 1324  
1325 1325          /* some sanity checks */
1326 1326          if (vp == dvp || vp == cdir) {
1327 1327                  rw_exit(&parent->sdev_contents);
1328 1328                  VN_RELE(vp);
1329 1329                  return (EINVAL);
1330 1330          }
1331 1331  
1332 1332          if (vp->v_type != VDIR) {
1333 1333                  rw_exit(&parent->sdev_contents);
1334 1334                  VN_RELE(vp);
1335 1335                  return (ENOTDIR);
1336 1336          }
1337 1337  
1338 1338          if (vn_vfswlock(vp)) {
1339 1339                  rw_exit(&parent->sdev_contents);
1340 1340                  VN_RELE(vp);
1341 1341                  return (EBUSY);
1342 1342          }
1343 1343  
1344 1344          if (vn_mountedvfs(vp) != NULL) {
1345 1345                  rw_exit(&parent->sdev_contents);
1346 1346                  vn_vfsunlock(vp);
1347 1347                  VN_RELE(vp);
1348 1348                  return (EBUSY);
1349 1349          }
1350 1350  
1351 1351          self = VTOSDEV(vp);
1352 1352          /* bail out on a non-empty directory */
1353 1353          rw_enter(&self->sdev_contents, RW_READER);
1354 1354          if (self->sdev_nlink > 2) {
1355 1355                  rw_exit(&self->sdev_contents);
1356 1356                  rw_exit(&parent->sdev_contents);
1357 1357                  vn_vfsunlock(vp);
1358 1358                  VN_RELE(vp);
1359 1359                  return (ENOTEMPTY);
1360 1360          }
1361 1361          rw_exit(&self->sdev_contents);
1362 1362  
1363 1363          /* unlink it from the directory cache */
1364 1364          sdev_cache_update(parent, &self, nm, SDEV_CACHE_DELETE);
1365 1365          rw_exit(&parent->sdev_contents);
1366 1366          vn_vfsunlock(vp);
1367 1367          VN_RELE(vp);
1368 1368  
1369 1369          /* best effort to clean up the backing store */
1370 1370          if (SDEV_IS_PERSIST(parent)) {
1371 1371                  ASSERT(parent->sdev_attrvp);
1372 1372                  error = VOP_RMDIR(parent->sdev_attrvp, nm,
1373 1373                      parent->sdev_attrvp, kcred, ct, flags);
1374 1374  
1375 1375                  if (error)
1376 1376                          sdcmn_err2(("sdev_rmdir: cleaning device %s is on"
1377 1377                              " disk error %d\n", parent->sdev_path, error));
1378 1378                  if (error == EBUSY)
1379 1379                          error = 0;
1380 1380  
1381 1381          }
1382 1382  
1383 1383          if (error == 0)
1384 1384                  i_ddi_di_cache_invalidate();
1385 1385  
1386 1386          return (error);
1387 1387  }
1388 1388  
1389 1389  /*
1390 1390   * read the contents of a symbolic link
1391 1391   */
1392 1392  static int
1393 1393  sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred,
1394 1394      caller_context_t *ct)
1395 1395  {
1396 1396          struct sdev_node *dv;
1397 1397          int     error = 0;
1398 1398  
1399 1399          ASSERT(vp->v_type == VLNK);
1400 1400  
1401 1401          dv = VTOSDEV(vp);
1402 1402  
1403 1403          if (dv->sdev_attrvp) {
1404 1404                  /* non-NULL attrvp implys a persisted node at READY state */
1405 1405                  return (VOP_READLINK(dv->sdev_attrvp, uiop, cred, ct));
1406 1406          } else if (dv->sdev_symlink != NULL) {
1407 1407                  /* memory nodes, e.g. local nodes */
1408 1408                  rw_enter(&dv->sdev_contents, RW_READER);
1409 1409                  sdcmn_err2(("sdev_readlink link is %s\n", dv->sdev_symlink));
1410 1410                  error = uiomove(dv->sdev_symlink, strlen(dv->sdev_symlink),
1411 1411                      UIO_READ, uiop);
1412 1412                  rw_exit(&dv->sdev_contents);
1413 1413                  return (error);
1414 1414          }
1415 1415  
1416 1416          return (ENOENT);
1417 1417  }
1418 1418  
1419 1419  /*ARGSUSED4*/
1420 1420  static int
1421 1421  sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp,
1422 1422      caller_context_t *ct, int flags)
1423 1423  {
1424 1424          struct sdev_node *parent = VTOSDEV(dvp);
1425 1425          int error;
1426 1426  
1427 1427          /*
1428 1428           * We must check that we have execute access to search the directory --
1429 1429           * but because our sdev_contents lock is already held as a reader (the
1430 1430           * caller must have done a VOP_RWLOCK()), we call directly into the
1431 1431           * underlying access routine if sdev_attr is non-NULL.
1432 1432           */
1433 1433          if (parent->sdev_attr != NULL) {
1434 1434                  VERIFY(RW_READ_HELD(&parent->sdev_contents));
1435 1435  
1436 1436                  if (sdev_unlocked_access(parent, VEXEC, cred) != 0)
1437 1437                          return (EACCES);
1438 1438          } else {
1439 1439                  if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
1440 1440                          return (error);
1441 1441          }
1442 1442  
1443 1443          ASSERT(parent);
1444 1444          if (!SDEV_IS_GLOBAL(parent))
1445 1445                  prof_filldir(parent);
1446 1446          return (devname_readdir_func(dvp, uiop, cred, eofp, SDEV_BROWSE));
1447 1447  }
1448 1448  
1449 1449  /*ARGSUSED1*/
1450 1450  static void
1451 1451  sdev_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct)
1452 1452  {
1453 1453          devname_inactive_func(vp, cred, NULL);
1454 1454  }
1455 1455  
1456 1456  /*ARGSUSED2*/
1457 1457  static int
1458 1458  sdev_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
1459 1459  {
1460 1460          struct sdev_node        *dv = VTOSDEV(vp);
1461 1461          struct sdev_fid *sdev_fid;
1462 1462  
1463 1463          if (fidp->fid_len < (sizeof (struct sdev_fid) - sizeof (ushort_t))) {
1464 1464                  fidp->fid_len = sizeof (struct sdev_fid) - sizeof (ushort_t);
1465 1465                  return (ENOSPC);
1466 1466          }
1467 1467  
1468 1468          sdev_fid = (struct sdev_fid *)fidp;
1469 1469          bzero(sdev_fid, sizeof (struct sdev_fid));
1470 1470          sdev_fid->sdevfid_len =
1471 1471              (int)sizeof (struct sdev_fid) - sizeof (ushort_t);
1472 1472          sdev_fid->sdevfid_ino = dv->sdev_ino;
1473 1473  
1474 1474          return (0);
1475 1475  }
1476 1476  
1477 1477  /*
1478 1478   * This pair of routines bracket all VOP_READ, VOP_WRITE
1479 1479   * and VOP_READDIR requests.  The contents lock stops things
1480 1480   * moving around while we're looking at them.
1481 1481   */
1482 1482  /*ARGSUSED2*/
1483 1483  static int
1484 1484  sdev_rwlock(struct vnode *vp, int write_flag, caller_context_t *ctp)
1485 1485  {
1486 1486          rw_enter(&VTOSDEV(vp)->sdev_contents,
1487 1487              write_flag ? RW_WRITER : RW_READER);
1488 1488          return (write_flag ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE);
1489 1489  }
1490 1490  
1491 1491  /*ARGSUSED1*/
1492 1492  static void
1493 1493  sdev_rwunlock(struct vnode *vp, int write_flag, caller_context_t *ctp)
1494 1494  {
1495 1495          rw_exit(&VTOSDEV(vp)->sdev_contents);
1496 1496  }
1497 1497  
1498 1498  /*ARGSUSED1*/
1499 1499  static int
1500 1500  sdev_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
1501 1501      caller_context_t *ct)
1502 1502  {
1503 1503          struct vnode *attrvp = VTOSDEV(vp)->sdev_attrvp;
1504 1504  
1505 1505          ASSERT(vp->v_type != VCHR &&
1506 1506              vp->v_type != VBLK && vp->v_type != VLNK);
1507 1507  
1508 1508          if (vp->v_type == VDIR)
1509 1509                  return (fs_seek(vp, ooff, noffp, ct));
1510 1510  
1511 1511          ASSERT(attrvp);
1512 1512          return (VOP_SEEK(attrvp, ooff, noffp, ct));
1513 1513  }
1514 1514  
1515 1515  /*ARGSUSED1*/
1516 1516  static int
1517 1517  sdev_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
1518 1518      offset_t offset, struct flk_callback *flk_cbp, struct cred *cr,
1519 1519      caller_context_t *ct)
1520 1520  {
1521 1521          int error;
1522 1522          struct sdev_node *dv = VTOSDEV(vp);
1523 1523  
1524 1524          ASSERT(dv);
1525 1525          ASSERT(dv->sdev_attrvp);
1526 1526          error = VOP_FRLOCK(dv->sdev_attrvp, cmd, bfp, flag, offset,
1527 1527              flk_cbp, cr, ct);
1528 1528  
1529 1529          return (error);
1530 1530  }
1531 1531  
1532 1532  static int
1533 1533  sdev_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
1534 1534      caller_context_t *ct)
1535 1535  {
1536 1536          switch (cmd) {
1537 1537          case _PC_ACL_ENABLED:
1538 1538                  *valp = SDEV_ACL_FLAVOR(vp);
1539 1539                  return (0);
1540 1540          }
1541 1541  
1542 1542          return (fs_pathconf(vp, cmd, valp, cr, ct));
1543 1543  }
1544 1544  
1545 1545  vnodeops_t *sdev_vnodeops;
1546 1546  
1547 1547  const fs_operation_def_t sdev_vnodeops_tbl[] = {
1548 1548          VOPNAME_OPEN,           { .vop_open = sdev_open },
1549 1549          VOPNAME_CLOSE,          { .vop_close = sdev_close },
1550 1550          VOPNAME_READ,           { .vop_read = sdev_read },
1551 1551          VOPNAME_WRITE,          { .vop_write = sdev_write },
1552 1552          VOPNAME_IOCTL,          { .vop_ioctl = sdev_ioctl },
1553 1553          VOPNAME_GETATTR,        { .vop_getattr = sdev_getattr },
1554 1554          VOPNAME_SETATTR,        { .vop_setattr = sdev_setattr },
1555 1555          VOPNAME_ACCESS,         { .vop_access = sdev_access },
1556 1556          VOPNAME_LOOKUP,         { .vop_lookup = sdev_lookup },
1557 1557          VOPNAME_CREATE,         { .vop_create = sdev_create },
1558 1558          VOPNAME_RENAME,         { .vop_rename = sdev_rename },
1559 1559          VOPNAME_REMOVE,         { .vop_remove = sdev_remove },
1560 1560          VOPNAME_MKDIR,          { .vop_mkdir = sdev_mkdir },
1561 1561          VOPNAME_RMDIR,          { .vop_rmdir = sdev_rmdir },
1562 1562          VOPNAME_READDIR,        { .vop_readdir = sdev_readdir },
1563 1563          VOPNAME_SYMLINK,        { .vop_symlink = sdev_symlink },
1564 1564          VOPNAME_READLINK,       { .vop_readlink = sdev_readlink },
1565 1565          VOPNAME_INACTIVE,       { .vop_inactive = sdev_inactive },
1566 1566          VOPNAME_FID,            { .vop_fid = sdev_fid },
1567 1567          VOPNAME_RWLOCK,         { .vop_rwlock = sdev_rwlock },
1568 1568          VOPNAME_RWUNLOCK,       { .vop_rwunlock = sdev_rwunlock },
1569 1569          VOPNAME_SEEK,           { .vop_seek = sdev_seek },
1570 1570          VOPNAME_FRLOCK,         { .vop_frlock = sdev_frlock },
1571 1571          VOPNAME_PATHCONF,       { .vop_pathconf = sdev_pathconf },
1572 1572          VOPNAME_SETSECATTR,     { .vop_setsecattr = sdev_setsecattr },
1573 1573          VOPNAME_GETSECATTR,     { .vop_getsecattr = sdev_getsecattr },
1574 1574          NULL,                   NULL
1575 1575  };
1576 1576  
1577 1577  int sdev_vnodeops_tbl_size = sizeof (sdev_vnodeops_tbl);
  
    | 
      ↓ open down ↓ | 
    1577 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX