Home | History | Annotate | Download | only in dev
      1   2621     llai1 /*
      2   2621     llai1  * CDDL HEADER START
      3   2621     llai1  *
      4   2621     llai1  * The contents of this file are subject to the terms of the
      5   2621     llai1  * Common Development and Distribution License (the "License").
      6   2621     llai1  * You may not use this file except in compliance with the License.
      7   2621     llai1  *
      8   2621     llai1  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9   2621     llai1  * or http://www.opensolaris.org/os/licensing.
     10   2621     llai1  * See the License for the specific language governing permissions
     11   2621     llai1  * and limitations under the License.
     12   2621     llai1  *
     13   2621     llai1  * When distributing Covered Code, include this CDDL HEADER in each
     14   2621     llai1  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15   2621     llai1  * If applicable, add the following below this CDDL HEADER, with the
     16   2621     llai1  * fields enclosed by brackets "[]" replaced with your own identifying
     17   2621     llai1  * information: Portions Copyright [yyyy] [name of copyright owner]
     18   2621     llai1  *
     19   2621     llai1  * CDDL HEADER END
     20   2621     llai1  */
     21   2621     llai1 /*
     22   9198     Jerry  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23   2621     llai1  * Use is subject to license terms.
     24   2621     llai1  */
     25   2621     llai1 
     26   2621     llai1 /*
     27   2621     llai1  * vnode ops for the /dev filesystem
     28   2621     llai1  *
     29   2621     llai1  * - VDIR, VCHR, CBLK, and VLNK are considered must supported files
     30   2621     llai1  * - VREG and VDOOR are used for some internal implementations in
     31   2621     llai1  *    the global zone, e.g. devname and devfsadm communication
     32   2621     llai1  * - other file types are unusual in this namespace and
     33   2621     llai1  *    not supported for now
     34   2621     llai1  */
     35   2621     llai1 
     36   2621     llai1 #include <sys/types.h>
     37   2621     llai1 #include <sys/param.h>
     38   2621     llai1 #include <sys/t_lock.h>
     39   2621     llai1 #include <sys/systm.h>
     40   2621     llai1 #include <sys/sysmacros.h>
     41   2621     llai1 #include <sys/user.h>
     42   2621     llai1 #include <sys/time.h>
     43   2621     llai1 #include <sys/vfs.h>
     44   2621     llai1 #include <sys/vnode.h>
     45   3898       rsb #include <sys/vfs_opreg.h>
     46   2621     llai1 #include <sys/file.h>
     47   2621     llai1 #include <sys/fcntl.h>
     48   2621     llai1 #include <sys/flock.h>
     49   2621     llai1 #include <sys/kmem.h>
     50   2621     llai1 #include <sys/uio.h>
     51   2621     llai1 #include <sys/errno.h>
     52   2621     llai1 #include <sys/stat.h>
     53   2621     llai1 #include <sys/cred.h>
     54   2621     llai1 #include <sys/dirent.h>
     55   2621     llai1 #include <sys/pathname.h>
     56   2621     llai1 #include <sys/cmn_err.h>
     57   2621     llai1 #include <sys/debug.h>
     58   2621     llai1 #include <sys/policy.h>
     59   2621     llai1 #include <vm/hat.h>
     60   2621     llai1 #include <vm/seg_vn.h>
     61   2621     llai1 #include <vm/seg_map.h>
     62   2621     llai1 #include <vm/seg.h>
     63   2621     llai1 #include <vm/as.h>
     64   2621     llai1 #include <vm/page.h>
     65   2621     llai1 #include <sys/proc.h>
     66   2621     llai1 #include <sys/mode.h>
     67   2621     llai1 #include <sys/sunndi.h>
     68   2621     llai1 #include <sys/ptms.h>
     69   2621     llai1 #include <fs/fs_subr.h>
     70   2621     llai1 #include <sys/fs/dv_node.h>
     71   2621     llai1 #include <sys/fs/sdev_impl.h>
     72   2621     llai1 
     73   2621     llai1 /*ARGSUSED*/
     74   2621     llai1 static int
     75   5331       amw sdev_open(struct vnode **vpp, int flag, struct cred *cred, caller_context_t *ct)
     76   2621     llai1 {
     77   2621     llai1 	struct sdev_node *dv = VTOSDEV(*vpp);
     78   2621     llai1 	struct sdev_node *ddv = dv->sdev_dotdot;
     79   2621     llai1 	int error = 0;
     80   2621     llai1 
     81   2621     llai1 	if ((*vpp)->v_type == VDIR)
     82   2621     llai1 		return (0);
     83   2621     llai1 
     84   2621     llai1 	if (!SDEV_IS_GLOBAL(dv))
     85   2621     llai1 		return (ENOTSUP);
     86   2621     llai1 
     87  10588      Eric 	if ((*vpp)->v_type == VLNK)
     88  10588      Eric 		return (ENOENT);
     89   2621     llai1 	ASSERT((*vpp)->v_type == VREG);
     90   2621     llai1 	if ((*vpp)->v_type != VREG)
     91   2621     llai1 		return (ENOTSUP);
     92   2621     llai1 
     93   2621     llai1 	ASSERT(ddv);
     94   2621     llai1 	rw_enter(&ddv->sdev_contents, RW_READER);
     95   2621     llai1 	if (dv->sdev_attrvp == NULL) {
     96   2621     llai1 		rw_exit(&ddv->sdev_contents);
     97   2621     llai1 		return (ENOENT);
     98   2621     llai1 	}
     99   5331       amw 	error = VOP_OPEN(&(dv->sdev_attrvp), flag, cred, ct);
    100   2621     llai1 	rw_exit(&ddv->sdev_contents);
    101   2621     llai1 	return (error);
    102   2621     llai1 }
    103   2621     llai1 
    104   2621     llai1 /*ARGSUSED1*/
    105   2621     llai1 static int
    106   2621     llai1 sdev_close(struct vnode *vp, int flag, int count,
    107   5331       amw     offset_t offset, struct cred *cred, caller_context_t *ct)
    108   2621     llai1 {
    109   2621     llai1 	struct sdev_node *dv = VTOSDEV(vp);
    110   2621     llai1 
    111   2621     llai1 	if (vp->v_type == VDIR) {
    112   2621     llai1 		cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
    113   2621     llai1 		cleanshares(vp, ttoproc(curthread)->p_pid);
    114   2621     llai1 		return (0);
    115   2621     llai1 	}
    116   2621     llai1 
    117   2621     llai1 	if (!SDEV_IS_GLOBAL(dv))
    118   2621     llai1 		return (ENOTSUP);
    119   2621     llai1 
    120   2621     llai1 	ASSERT(vp->v_type == VREG);
    121   2621     llai1 	if (vp->v_type != VREG)
    122   2621     llai1 		return (ENOTSUP);
    123   2621     llai1 
    124   2621     llai1 	ASSERT(dv->sdev_attrvp);
    125   5331       amw 	return (VOP_CLOSE(dv->sdev_attrvp, flag, count, offset, cred, ct));
    126   2621     llai1 }
    127   2621     llai1 
    128   2621     llai1 /*ARGSUSED*/
    129   2621     llai1 static int
    130   2621     llai1 sdev_read(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
    131   2621     llai1 	struct caller_context *ct)
    132   2621     llai1 {
    133   2621     llai1 	struct sdev_node *dv = (struct sdev_node *)VTOSDEV(vp);
    134   2621     llai1 	int	error;
    135   2621     llai1 
    136   2621     llai1 	if (!SDEV_IS_GLOBAL(dv))
    137   2621     llai1 		return (EINVAL);
    138   2621     llai1 
    139   2621     llai1 	if (vp->v_type == VDIR)
    140   2621     llai1 		return (EISDIR);
    141   2621     llai1 
    142   2621     llai1 	/* only supporting regular files in /dev */
    143   2621     llai1 	ASSERT(vp->v_type == VREG);
    144   2621     llai1 	if (vp->v_type != VREG)
    145   2621     llai1 		return (EINVAL);
    146   2621     llai1 
    147   2621     llai1 	ASSERT(RW_READ_HELD(&VTOSDEV(vp)->sdev_contents));
    148   2621     llai1 	ASSERT(dv->sdev_attrvp);
    149   5331       amw 	(void) VOP_RWLOCK(dv->sdev_attrvp, 0, ct);
    150   2621     llai1 	error = VOP_READ(dv->sdev_attrvp, uio, ioflag, cred, ct);
    151   5331       amw 	VOP_RWUNLOCK(dv->sdev_attrvp, 0, ct);
    152   2621     llai1 	return (error);
    153   2621     llai1 }
    154   2621     llai1 
    155   2621     llai1 /*ARGSUSED*/
    156   2621     llai1 static int
    157   2621     llai1 sdev_write(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
    158   2621     llai1 	struct caller_context *ct)
    159   2621     llai1 {
    160   2621     llai1 	struct sdev_node *dv = VTOSDEV(vp);
    161   2621     llai1 	int	error = 0;
    162   2621     llai1 
    163   2621     llai1 	if (!SDEV_IS_GLOBAL(dv))
    164   2621     llai1 		return (EINVAL);
    165   2621     llai1 
    166   2621     llai1 	if (vp->v_type == VDIR)
    167   2621     llai1 		return (EISDIR);
    168   2621     llai1 
    169   2621     llai1 	/* only supporting regular files in /dev */
    170   2621     llai1 	ASSERT(vp->v_type == VREG);
    171   2621     llai1 	if (vp->v_type != VREG)
    172   2621     llai1 		return (EINVAL);
    173   2621     llai1 
    174   2621     llai1 	ASSERT(dv->sdev_attrvp);
    175   2621     llai1 
    176   5331       amw 	(void) VOP_RWLOCK(dv->sdev_attrvp, 1, ct);
    177   2621     llai1 	error = VOP_WRITE(dv->sdev_attrvp, uio, ioflag, cred, ct);
    178   5331       amw 	VOP_RWUNLOCK(dv->sdev_attrvp, 1, ct);
    179   2621     llai1 	if (error == 0) {
    180   2621     llai1 		sdev_update_timestamps(dv->sdev_attrvp, kcred,
    181   2621     llai1 		    AT_MTIME);
    182   2621     llai1 	}
    183   2621     llai1 	return (error);
    184   2621     llai1 }
    185   2621     llai1 
    186   2621     llai1 /*ARGSUSED*/
    187   2621     llai1 static int
    188   2621     llai1 sdev_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
    189   5331       amw     struct cred *cred, int *rvalp,  caller_context_t *ct)
    190   2621     llai1 {
    191   2621     llai1 	struct sdev_node *dv = VTOSDEV(vp);
    192   2621     llai1 
    193   2621     llai1 	if (!SDEV_IS_GLOBAL(dv) || (vp->v_type == VDIR))
    194   2621     llai1 		return (ENOTTY);
    195   2621     llai1 
    196   2621     llai1 	ASSERT(vp->v_type == VREG);
    197   2621     llai1 	if (vp->v_type != VREG)
    198   2621     llai1 		return (EINVAL);
    199   2621     llai1 
    200   2621     llai1 	ASSERT(dv->sdev_attrvp);
    201   5331       amw 	return (VOP_IOCTL(dv->sdev_attrvp, cmd, arg, flag, cred, rvalp, ct));
    202   2621     llai1 }
    203   2621     llai1 
    204   2621     llai1 static int
    205   5331       amw sdev_getattr(struct vnode *vp, struct vattr *vap, int flags,
    206   5331       amw     struct cred *cr, caller_context_t *ct)
    207   2621     llai1 {
    208   2621     llai1 	int			error = 0;
    209   2621     llai1 	struct sdev_node	*dv = VTOSDEV(vp);
    210   2621     llai1 	struct sdev_node	*parent = dv->sdev_dotdot;
    211   2621     llai1 
    212   2621     llai1 	ASSERT(parent);
    213   2621     llai1 
    214   2621     llai1 	rw_enter(&parent->sdev_contents, RW_READER);
    215   2621     llai1 	ASSERT(dv->sdev_attr || dv->sdev_attrvp);
    216   2621     llai1 
    217   2621     llai1 	/*
    218   2621     llai1 	 * search order:
    219   2621     llai1 	 * 	- for persistent nodes (SDEV_PERSIST): backstore
    220   2621     llai1 	 *	- for non-persistent nodes: module ops if global, then memory
    221   2621     llai1 	 */
    222   2621     llai1 	if (dv->sdev_attrvp) {
    223   2621     llai1 		rw_exit(&parent->sdev_contents);
    224   5331       amw 		error = VOP_GETATTR(dv->sdev_attrvp, vap, flags, cr, ct);
    225   2621     llai1 		sdev_vattr_merge(dv, vap);
    226   2621     llai1 	} else {
    227   2621     llai1 		ASSERT(dv->sdev_attr);
    228   2621     llai1 		*vap = *dv->sdev_attr;
    229   2621     llai1 		sdev_vattr_merge(dv, vap);
    230   2621     llai1 		rw_exit(&parent->sdev_contents);
    231   2621     llai1 	}
    232   2621     llai1 
    233   2621     llai1 	return (error);
    234   2621     llai1 }
    235   2621     llai1 
    236   3748        jg /*ARGSUSED4*/
    237   2621     llai1 static int
    238   3748        jg sdev_setattr(struct vnode *vp, struct vattr *vap, int flags,
    239   3748        jg     struct cred *cred, caller_context_t *ctp)
    240   2621     llai1 {
    241   2621     llai1 	return (devname_setattr_func(vp, vap, flags, cred, NULL, 0));
    242   2621     llai1 }
    243   2621     llai1 
    244   2621     llai1 static int
    245   2621     llai1 sdev_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
    246   5331       amw     struct cred *cr, caller_context_t *ct)
    247   2621     llai1 {
    248   2621     llai1 	int	error;
    249   2621     llai1 	struct sdev_node *dv = VTOSDEV(vp);
    250   2621     llai1 	struct vnode *avp = dv->sdev_attrvp;
    251   2621     llai1 
    252   2621     llai1 	if (avp == NULL) {
    253   2621     llai1 		/* return fs_fab_acl() if flavor matches, else do nothing */
    254   2621     llai1 		if ((SDEV_ACL_FLAVOR(vp) == _ACL_ACLENT_ENABLED &&
    255   2621     llai1 		    (vsap->vsa_mask & (VSA_ACLCNT | VSA_DFACLCNT))) ||
    256   2621     llai1 		    (SDEV_ACL_FLAVOR(vp) == _ACL_ACE_ENABLED &&
    257   2621     llai1 		    (vsap->vsa_mask & (VSA_ACECNT | VSA_ACE))))
    258   5331       amw 			return (fs_fab_acl(vp, vsap, flags, cr, ct));
    259   2621     llai1 
    260   2621     llai1 		return (ENOSYS);
    261   2621     llai1 	}
    262   2621     llai1 
    263   5331       amw 	(void) VOP_RWLOCK(avp, 1, ct);
    264   5331       amw 	error = VOP_GETSECATTR(avp, vsap, flags, cr, ct);
    265   5331       amw 	VOP_RWUNLOCK(avp, 1, ct);
    266   2621     llai1 	return (error);
    267   2621     llai1 }
    268   2621     llai1 
    269   2621     llai1 static int
    270   2621     llai1 sdev_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
    271   5331       amw     struct cred *cr, caller_context_t *ct)
    272   2621     llai1 {
    273   2621     llai1 	int	error;
    274   2621     llai1 	struct sdev_node *dv = VTOSDEV(vp);
    275   2621     llai1 	struct vnode *avp = dv->sdev_attrvp;
    276   2621     llai1 
    277   2621     llai1 	if (dv->sdev_state == SDEV_ZOMBIE)
    278   2621     llai1 		return (0);
    279   2621     llai1 
    280   2621     llai1 	if (avp == NULL) {
    281   2621     llai1 		if (SDEV_IS_GLOBAL(dv) && !SDEV_IS_PERSIST(dv))
    282   2621     llai1 			return (fs_nosys());
    283   2621     llai1 		ASSERT(dv->sdev_attr);
    284   2621     llai1 		/*
    285   2621     llai1 		 * if coming in directly, the acl system call will
    286   2621     llai1 		 * have held the read-write lock via VOP_RWLOCK()
    287   2621     llai1 		 * If coming in via specfs, specfs will have
    288   2621     llai1 		 * held the rw lock on the realvp i.e. us.
    289   2621     llai1 		 */
    290   2621     llai1 		ASSERT(RW_WRITE_HELD(&dv->sdev_contents));
    291   2621     llai1 		sdev_vattr_merge(dv, dv->sdev_attr);
    292   5331       amw 		error = sdev_shadow_node(dv, cr);
    293   2621     llai1 		if (error) {
    294   2621     llai1 			return (fs_nosys());
    295   2621     llai1 		}
    296   2621     llai1 
    297   2621     llai1 		ASSERT(dv->sdev_attrvp);
    298   2621     llai1 		/* clean out the memory copy if any */
    299   2621     llai1 		if (dv->sdev_attr) {
    300   2621     llai1 			kmem_free(dv->sdev_attr, sizeof (struct vattr));
    301   2621     llai1 			dv->sdev_attr = NULL;
    302   2621     llai1 		}
    303   2621     llai1 		avp = dv->sdev_attrvp;
    304   2621     llai1 	}
    305   2621     llai1 	ASSERT(avp);
    306   2621     llai1 
    307   5331       amw 	(void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, ct);
    308   5331       amw 	error = VOP_SETSECATTR(avp, vsap, flags, cr, ct);
    309   5331       amw 	VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, ct);
    310   2621     llai1 	return (error);
    311   2621     llai1 }
    312   2621     llai1 
    313   2621     llai1 int
    314   2621     llai1 sdev_unlocked_access(void *vdv, int mode, struct cred *cr)
    315   2621     llai1 {
    316   2621     llai1 	struct sdev_node	*dv = vdv;
    317   2621     llai1 	int			shift = 0;
    318   2621     llai1 	uid_t			owner = dv->sdev_attr->va_uid;
    319   2621     llai1 
    320   2621     llai1 	if (crgetuid(cr) != owner) {
    321   2621     llai1 		shift += 3;
    322   2621     llai1 		if (groupmember(dv->sdev_attr->va_gid, cr) == 0)
    323   2621     llai1 			shift += 3;
    324   2621     llai1 	}
    325   2621     llai1 
    326   2621     llai1 	mode &= ~(dv->sdev_attr->va_mode << shift);
    327   2621     llai1 	if (mode == 0)
    328   2621     llai1 		return (0);
    329   2621     llai1 
    330   2621     llai1 	return (secpolicy_vnode_access(cr, SDEVTOV(dv), owner, mode));
    331   2621     llai1 }
    332   2621     llai1 
    333   2621     llai1 static int
    334   5331       amw sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr,
    335   5331       amw     caller_context_t *ct)
    336   2621     llai1 {
    337   2621     llai1 	struct sdev_node	*dv = VTOSDEV(vp);
    338   2621     llai1 	int ret = 0;
    339   2621     llai1 
    340   2621     llai1 	ASSERT(dv->sdev_attr || dv->sdev_attrvp);
    341   2621     llai1 
    342   2621     llai1 	if (dv->sdev_attrvp) {
    343   5331       amw 		ret = VOP_ACCESS(dv->sdev_attrvp, mode, flags, cr, ct);
    344   2621     llai1 	} else if (dv->sdev_attr) {
    345   2621     llai1 		rw_enter(&dv->sdev_contents, RW_READER);
    346   2621     llai1 		ret = sdev_unlocked_access(dv, mode, cr);
    347   2621     llai1 		if (ret)
    348   2621     llai1 			ret = EACCES;
    349   2621     llai1 		rw_exit(&dv->sdev_contents);
    350   2621     llai1 	}
    351   2621     llai1 
    352   2621     llai1 	return (ret);
    353   2621     llai1 }
    354   2621     llai1 
    355   2621     llai1 /*
    356   2621     llai1  * Lookup
    357   2621     llai1  */
    358   2621     llai1 /*ARGSUSED3*/
    359   2621     llai1 static int
    360   2621     llai1 sdev_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
    361   5331       amw     struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
    362   5331       amw     caller_context_t *ct, int *direntflags, pathname_t *realpnp)
    363   2621     llai1 {
    364   3843        jg 	struct sdev_node *parent;
    365   3843        jg 	int error;
    366   2621     llai1 
    367   2621     llai1 	parent = VTOSDEV(dvp);
    368   2621     llai1 	ASSERT(parent);
    369   3843        jg 
    370   3843        jg 	/* execute access is required to search the directory */
    371   5331       amw 	if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
    372   3843        jg 		return (error);
    373   2621     llai1 
    374   2621     llai1 	if (!SDEV_IS_GLOBAL(parent))
    375   2621     llai1 		return (prof_lookup(dvp, nm, vpp, cred));
    376   2621     llai1 	return (devname_lookup_func(parent, nm, vpp, cred, NULL, 0));
    377   2621     llai1 }
    378   2621     llai1 
    379   2621     llai1 /*ARGSUSED2*/
    380   2621     llai1 static int
    381   2621     llai1 sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
    382   5331       amw     int mode, struct vnode **vpp, struct cred *cred, int flag,
    383   5331       amw     caller_context_t *ct, vsecattr_t *vsecp)
    384   2621     llai1 {
    385   2621     llai1 	struct vnode		*vp = NULL;
    386   2621     llai1 	struct vnode		*avp;
    387   2621     llai1 	struct sdev_node	*parent;
    388   2621     llai1 	struct sdev_node	*self = NULL;
    389   2621     llai1 	int			error = 0;
    390   2621     llai1 	vtype_t			type = vap->va_type;
    391   2621     llai1 
    392   2729     llai1 	ASSERT(type != VNON && type != VBAD);
    393   2621     llai1 
    394   2621     llai1 	if ((type == VFIFO) || (type == VSOCK) ||
    395   2621     llai1 	    (type == VPROC) || (type == VPORT))
    396   2621     llai1 		return (ENOTSUP);
    397   2621     llai1 
    398   2621     llai1 	parent = VTOSDEV(dvp);
    399   2621     llai1 	ASSERT(parent);
    400   2621     llai1 
    401   2621     llai1 	rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER);
    402   2621     llai1 	if (parent->sdev_state == SDEV_ZOMBIE) {
    403   2621     llai1 		rw_exit(&parent->sdev_dotdot->sdev_contents);
    404   2621     llai1 		return (ENOENT);
    405   2621     llai1 	}
    406   2621     llai1 
    407   2621     llai1 	/* non-global do not allow pure node creation */
    408   2621     llai1 	if (!SDEV_IS_GLOBAL(parent)) {
    409   2621     llai1 		rw_exit(&parent->sdev_dotdot->sdev_contents);
    410   2621     llai1 		return (prof_lookup(dvp, nm, vpp, cred));
    411   2621     llai1 	}
    412   2621     llai1 	rw_exit(&parent->sdev_dotdot->sdev_contents);
    413   2621     llai1 
    414   3843        jg 	/* execute access is required to search the directory */
    415   9198     Jerry 	if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
    416   3843        jg 		return (error);
    417   3843        jg 
    418   2621     llai1 	/* check existing name */
    419   5331       amw /* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
    420   5331       amw 	error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
    421   2621     llai1 
    422   2621     llai1 	/* name found */
    423   2621     llai1 	if (error == 0) {
    424   2621     llai1 		ASSERT(vp);
    425   2621     llai1 		if (excl == EXCL) {
    426   2621     llai1 			error = EEXIST;
    427   2621     llai1 		} else if ((vp->v_type == VDIR) && (mode & VWRITE)) {
    428   2621     llai1 			/* allowing create/read-only an existing directory */
    429   2621     llai1 			error = EISDIR;
    430   2621     llai1 		} else {
    431   5686        jg 			error = VOP_ACCESS(vp, mode, 0, cred, ct);
    432   2621     llai1 		}
    433   2621     llai1 
    434   2621     llai1 		if (error) {
    435   2621     llai1 			VN_RELE(vp);
    436   2621     llai1 			return (error);
    437   2621     llai1 		}
    438   2621     llai1 
    439   2621     llai1 		/* truncation first */
    440   2621     llai1 		if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) &&
    441   2621     llai1 		    (vap->va_size == 0)) {
    442   2621     llai1 			ASSERT(parent->sdev_attrvp);
    443   2621     llai1 			error = VOP_CREATE(parent->sdev_attrvp,
    444   5331       amw 			    nm, vap, excl, mode, &avp, cred, flag, ct, vsecp);
    445   2621     llai1 
    446   2621     llai1 			if (error) {
    447   2621     llai1 				VN_RELE(vp);
    448   2621     llai1 				return (error);
    449   2621     llai1 			}
    450   2621     llai1 		}
    451   2621     llai1 
    452   2621     llai1 		sdev_update_timestamps(vp, kcred,
    453   2621     llai1 		    AT_CTIME|AT_MTIME|AT_ATIME);
    454   2621     llai1 		*vpp = vp;
    455   2621     llai1 		return (0);
    456   2621     llai1 	}
    457   2621     llai1 
    458   2621     llai1 	/* bail out early */
    459   2621     llai1 	if (error != ENOENT)
    460   2621     llai1 		return (error);
    461   9198     Jerry 
    462   9198     Jerry 	/* verify write access - compliance specifies ENXIO */
    463   9198     Jerry 	if ((error = VOP_ACCESS(dvp, VEXEC|VWRITE, 0, cred, ct)) != 0) {
    464   9198     Jerry 		if (error == EACCES)
    465   9198     Jerry 			error = ENXIO;
    466   9198     Jerry 		return (error);
    467   9198     Jerry 	}
    468   2621     llai1 
    469   2621     llai1 	/*
    470   2621     llai1 	 * For memory-based (ROFS) directory:
    471   2621     llai1 	 * 	- either disallow node creation;
    472   2621     llai1 	 *	- or implement VOP_CREATE of its own
    473   2621     llai1 	 */
    474   2621     llai1 	rw_enter(&parent->sdev_contents, RW_WRITER);
    475   2621     llai1 	if (!SDEV_IS_PERSIST(parent)) {
    476   2621     llai1 		rw_exit(&parent->sdev_contents);
    477   2621     llai1 		return (ENOTSUP);
    478   2621     llai1 	}
    479   2621     llai1 	ASSERT(parent->sdev_attrvp);
    480   2621     llai1 	error = sdev_mknode(parent, nm, &self, vap, NULL, NULL,
    481   2621     llai1 	    cred, SDEV_READY);
    482   2621     llai1 	if (error) {
    483   2621     llai1 		rw_exit(&parent->sdev_contents);
    484   2621     llai1 		if (self)
    485   2621     llai1 			SDEV_RELE(self);
    486   2621     llai1 		return (error);
    487   2621     llai1 	}
    488   2621     llai1 	rw_exit(&parent->sdev_contents);
    489   2621     llai1 
    490   2621     llai1 	ASSERT(self);
    491   2621     llai1 	/* take care the timestamps for the node and its parent */
    492   2621     llai1 	sdev_update_timestamps(SDEVTOV(self), kcred,
    493   2621     llai1 	    AT_CTIME|AT_MTIME|AT_ATIME);
    494   2621     llai1 	sdev_update_timestamps(dvp, kcred, AT_MTIME|AT_ATIME);
    495   2621     llai1 	if (SDEV_IS_GLOBAL(parent))
    496   2621     llai1 		atomic_inc_ulong(&parent->sdev_gdir_gen);
    497   2621     llai1 
    498   2621     llai1 	/* wake up other threads blocked on looking up this node */
    499   2621     llai1 	mutex_enter(&self->sdev_lookup_lock);
    500   2621     llai1 	SDEV_UNBLOCK_OTHERS(self, SDEV_LOOKUP);
    501   2621     llai1 	mutex_exit(&self->sdev_lookup_lock);
    502   2621     llai1 	error = sdev_to_vp(self, vpp);
    503   2621     llai1 	return (error);
    504   2621     llai1 }
    505   2621     llai1 
    506   2621     llai1 static int
    507   5331       amw sdev_remove(struct vnode *dvp, char *nm, struct cred *cred,
    508   5331       amw     caller_context_t *ct, int flags)
    509   2621     llai1 {
    510   2621     llai1 	int	error;
    511   2621     llai1 	struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
    512   2621     llai1 	struct vnode *vp = NULL;
    513   2621     llai1 	struct sdev_node *dv = NULL;
    514   2621     llai1 	int len;
    515   2621     llai1 	int bkstore = 0;
    516   2621     llai1 
    517   2621     llai1 	/* bail out early */
    518   2621     llai1 	len = strlen(nm);
    519   2621     llai1 	if (nm[0] == '.') {
    520   2621     llai1 		if (len == 1) {
    521   2621     llai1 			return (EINVAL);
    522   2621     llai1 		} else if (len == 2 && nm[1] == '.') {
    523   2621     llai1 			return (EEXIST);
    524   2621     llai1 		}
    525   2621     llai1 	}
    526   2621     llai1 
    527   2621     llai1 	ASSERT(parent);
    528   2621     llai1 	rw_enter(&parent->sdev_contents, RW_READER);
    529   2621     llai1 	if (!SDEV_IS_GLOBAL(parent)) {
    530   2621     llai1 		rw_exit(&parent->sdev_contents);
    531   2621     llai1 		return (ENOTSUP);
    532   2621     llai1 	}
    533   2621     llai1 
    534   3843        jg 	/* execute access is required to search the directory */
    535   5331       amw 	if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0) {
    536   3843        jg 		rw_exit(&parent->sdev_contents);
    537   3843        jg 		return (error);
    538   3843        jg 	}
    539   3843        jg 
    540   2621     llai1 	/* check existence first */
    541   2621     llai1 	dv = sdev_cache_lookup(parent, nm);
    542   2621     llai1 	if (dv == NULL) {
    543   2621     llai1 		rw_exit(&parent->sdev_contents);
    544   2621     llai1 		return (ENOENT);
    545   2621     llai1 	}
    546   2621     llai1 
    547   2621     llai1 	vp = SDEVTOV(dv);
    548   2621     llai1 	if ((dv->sdev_state == SDEV_INIT) ||
    549   2621     llai1 	    (dv->sdev_state == SDEV_ZOMBIE)) {
    550   2621     llai1 		rw_exit(&parent->sdev_contents);
    551   2621     llai1 		VN_RELE(vp);
    552   2621     llai1 		return (ENOENT);
    553   3843        jg 	}
    554   3843        jg 
    555   3843        jg 	/* write access is required to remove an entry */
    556   5331       amw 	if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0) {
    557   3843        jg 		rw_exit(&parent->sdev_contents);
    558   3843        jg 		VN_RELE(vp);
    559   3843        jg 		return (error);
    560   2621     llai1 	}
    561   2621     llai1 
    562   2621     llai1 	/*
    563   2621     llai1 	 * sdev_dirdelete does the real job of:
    564   2621     llai1 	 *  - make sure no open ref count
    565   2621     llai1 	 *  - destroying the sdev_node
    566   2621     llai1 	 *  - releasing the hold on attrvp
    567   2621     llai1 	 */
    568   2621     llai1 	bkstore = SDEV_IS_PERSIST(dv) ? 1 : 0;
    569   2621     llai1 	if (!rw_tryupgrade(&parent->sdev_contents)) {
    570   2621     llai1 		rw_exit(&parent->sdev_contents);
    571   2621     llai1 		rw_enter(&parent->sdev_contents, RW_WRITER);
    572   2621     llai1 	}
    573   2621     llai1 	error = sdev_cache_update(parent, &dv, nm, SDEV_CACHE_DELETE);
    574   2621     llai1 	rw_exit(&parent->sdev_contents);
    575   2621     llai1 
    576   2621     llai1 	sdcmn_err2(("sdev_remove: cache_update error %d\n", error));
    577   2621     llai1 	if (error && (error != EBUSY)) {
    578   2621     llai1 		/* report errors other than EBUSY */
    579   2621     llai1 		VN_RELE(vp);
    580   2621     llai1 	} else {
    581   2621     llai1 		sdcmn_err2(("sdev_remove: cleaning node %s from cache "
    582   2621     llai1 		    " with error %d\n", nm, error));
    583   2621     llai1 
    584   2621     llai1 		/*
    585   2621     llai1 		 * best efforts clean up the backing store
    586   2621     llai1 		 */
    587   2621     llai1 		if (bkstore) {
    588   2621     llai1 			ASSERT(parent->sdev_attrvp);
    589   5331       amw 			error = VOP_REMOVE(parent->sdev_attrvp, nm, cred,
    590   5331       amw 			    ct, flags);
    591   2621     llai1 			/*
    592   2621     llai1 			 * do not report BUSY error
    593   2621     llai1 			 * because the backing store ref count is released
    594   2621     llai1 			 * when the last ref count on the sdev_node is
    595   2621     llai1 			 * released.
    596   2621     llai1 			 */
    597   2621     llai1 			if (error == EBUSY) {
    598   2621     llai1 				sdcmn_err2(("sdev_remove: device %s is still on"
    599   2621     llai1 				    "disk %s\n", nm, parent->sdev_path));
    600   2621     llai1 				error = 0;
    601   2621     llai1 			}
    602   2621     llai1 		}
    603   2621     llai1 
    604   2621     llai1 		if (error == EBUSY)
    605   2621     llai1 			error = 0;
    606   2621     llai1 	}
    607   2621     llai1 
    608   2621     llai1 	return (error);
    609   2621     llai1 }
    610   2621     llai1 
    611   2621     llai1 /*
    612   2621     llai1  * Some restrictions for this file system:
    613   2621     llai1  *  - both oldnm and newnm are in the scope of /dev file system,
    614   2621     llai1  *    to simply the namespace management model.
    615   2621     llai1  */
    616   5331       amw /*ARGSUSED6*/
    617   2621     llai1 static int
    618   2621     llai1 sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
    619   5331       amw     struct cred *cred, caller_context_t *ct, int flags)
    620   2621     llai1 {
    621   2621     llai1 	struct sdev_node	*fromparent = NULL;
    622   2621     llai1 	struct vattr		vattr;
    623   2621     llai1 	struct sdev_node	*toparent;
    624   2621     llai1 	struct sdev_node	*fromdv = NULL;	/* source node */
    625   2729     llai1 	struct vnode 		*ovp = NULL;	/* source vnode */
    626   2621     llai1 	struct sdev_node	*todv = NULL;	/* destination node */
    627   2729     llai1 	struct vnode 		*nvp = NULL;	/* destination vnode */
    628   2621     llai1 	int			samedir = 0;	/* set if odvp == ndvp */
    629   2621     llai1 	struct vnode		*realvp;
    630   2621     llai1 	int error = 0;
    631   2621     llai1 	dev_t fsid;
    632   2621     llai1 	int bkstore = 0;
    633   2729     llai1 	vtype_t type;
    634   2621     llai1 
    635   2621     llai1 	/* prevent modifying "." and ".." */
    636   2621     llai1 	if ((onm[0] == '.' &&
    637   2729     llai1 	    (onm[1] == '\0' || (onm[1] == '.' && onm[2] == '\0'))) ||
    638   2729     llai1 	    (nnm[0] == '.' &&
    639   2729     llai1 	    (nnm[1] == '\0' || (nnm[1] == '.' && nnm[2] == '\0')))) {
    640   2621     llai1 		return (EINVAL);
    641   2621     llai1 	}
    642   2621     llai1 
    643   2621     llai1 	fromparent = VTOSDEV(odvp);
    644   2621     llai1 	toparent = VTOSDEV(ndvp);
    645   2621     llai1 
    646   2621     llai1 	/* ZOMBIE parent doesn't allow new node creation */
    647   2621     llai1 	rw_enter(&fromparent->sdev_dotdot->sdev_contents, RW_READER);
    648   2621     llai1 	if (fromparent->sdev_state == SDEV_ZOMBIE) {
    649   2621     llai1 		rw_exit(&fromparent->sdev_dotdot->sdev_contents);
    650   2621     llai1 		return (ENOENT);
    651   2621     llai1 	}
    652   2621     llai1 
    653   2621     llai1 	/* renaming only supported for global device nodes */
    654   2621     llai1 	if (!SDEV_IS_GLOBAL(fromparent)) {
    655   2621     llai1 		rw_exit(&fromparent->sdev_dotdot->sdev_contents);
    656   2621     llai1 		return (ENOTSUP);
    657   2621     llai1 	}
    658   2621     llai1 	rw_exit(&fromparent->sdev_dotdot->sdev_contents);
    659   2621     llai1 
    660   2621     llai1 	rw_enter(&toparent->sdev_dotdot->sdev_contents, RW_READER);
    661   2621     llai1 	if (toparent->sdev_state == SDEV_ZOMBIE) {
    662   2621     llai1 		rw_exit(&toparent->sdev_dotdot->sdev_contents);
    663   2621     llai1 		return (ENOENT);
    664   2621     llai1 	}
    665   2621     llai1 	rw_exit(&toparent->sdev_dotdot->sdev_contents);
    666   2621     llai1 
    667   2729     llai1 	/*
    668   3843        jg 	 * acquire the global lock to prevent
    669   2729     llai1 	 * mount/unmount/other rename activities.
    670   2729     llai1 	 */
    671   2729     llai1 	mutex_enter(&sdev_lock);
    672   2729     llai1 
    673   2621     llai1 	/* check existence of the source node */
    674   5331       amw /* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
    675   5331       amw 	error = VOP_LOOKUP(odvp, onm, &ovp, NULL, 0, NULL, cred, ct,
    676   5331       amw 	    NULL, NULL);
    677   2621     llai1 	if (error) {
    678   2621     llai1 		sdcmn_err2(("sdev_rename: the source node %s exists\n",
    679   2621     llai1 		    onm));
    680   2729     llai1 		mutex_exit(&sdev_lock);
    681   2621     llai1 		return (error);
    682   2621     llai1 	}
    683   2621     llai1 
    684   5331       amw 	if (VOP_REALVP(ovp, &realvp, ct) == 0) {
    685   2621     llai1 		VN_HOLD(realvp);
    686   2621     llai1 		VN_RELE(ovp);
    687   2621     llai1 		ovp = realvp;
    688   2621     llai1 	}
    689   2621     llai1 
    690   2621     llai1 	/* check existence of destination */
    691   5331       amw /* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
    692   5331       amw 	error = VOP_LOOKUP(ndvp, nnm, &nvp, NULL, 0, NULL, cred, ct,
    693   5331       amw 	    NULL, NULL);
    694   2621     llai1 	if (error && (error != ENOENT)) {
    695   2729     llai1 		mutex_exit(&sdev_lock);
    696   2621     llai1 		VN_RELE(ovp);
    697   2621     llai1 		return (error);
    698   2621     llai1 	}
    699   2621     llai1 
    700   5331       amw 	if (nvp && (VOP_REALVP(nvp, &realvp, ct) == 0)) {
    701   2621     llai1 		VN_HOLD(realvp);
    702   2621     llai1 		VN_RELE(nvp);
    703   2621     llai1 		nvp = realvp;
    704   2621     llai1 	}
    705   2621     llai1 
    706   2621     llai1 	/*
    707   2729     llai1 	 * make sure the source and the destination are
    708   2729     llai1 	 * in the same dev filesystem
    709   2621     llai1 	 */
    710   2621     llai1 	if (odvp != ndvp) {
    711   2621     llai1 		vattr.va_mask = AT_FSID;
    712   5331       amw 		if (error = VOP_GETATTR(odvp, &vattr, 0, cred, ct)) {
    713   2729     llai1 			mutex_exit(&sdev_lock);
    714   2621     llai1 			VN_RELE(ovp);
    715   2621     llai1 			return (error);
    716   2621     llai1 		}
    717   2621     llai1 		fsid = vattr.va_fsid;
    718   2621     llai1 		vattr.va_mask = AT_FSID;
    719   5331       amw 		if (error = VOP_GETATTR(ndvp, &vattr, 0, cred, ct)) {
    720   2729     llai1 			mutex_exit(&sdev_lock);
    721   2621     llai1 			VN_RELE(ovp);
    722   2621     llai1 			return (error);
    723   2621     llai1 		}
    724   2621     llai1 		if (fsid != vattr.va_fsid) {
    725   2729     llai1 			mutex_exit(&sdev_lock);
    726   2621     llai1 			VN_RELE(ovp);
    727   2621     llai1 			return (EXDEV);
    728   2621     llai1 		}
    729   2621     llai1 	}
    730   2621     llai1 
    731   2621     llai1 	/* make sure the old entry can be deleted */
    732   5331       amw 	error = VOP_ACCESS(odvp, VWRITE, 0, cred, ct);
    733   2621     llai1 	if (error) {
    734   2729     llai1 		mutex_exit(&sdev_lock);
    735   2621     llai1 		VN_RELE(ovp);
    736   2621     llai1 		return (error);
    737   2621     llai1 	}
    738   2621     llai1 
    739   2621     llai1 	/* make sure the destination allows creation */
    740   2621     llai1 	samedir = (fromparent == toparent);
    741   2621     llai1 	if (!samedir) {
    742   5331       amw 		error = VOP_ACCESS(ndvp, VEXEC|VWRITE, 0, cred, ct);
    743   2621     llai1 		if (error) {
    744   2729     llai1 			mutex_exit(&sdev_lock);
    745   2621     llai1 			VN_RELE(ovp);
    746   2621     llai1 			return (error);
    747   2621     llai1 		}
    748   2621     llai1 	}
    749   2621     llai1 
    750   2621     llai1 	fromdv = VTOSDEV(ovp);
    751   2621     llai1 	ASSERT(fromdv);
    752   2621     llai1 
    753   2729     llai1 	/* destination file exists */
    754   2621     llai1 	if (nvp) {
    755   2729     llai1 		todv = VTOSDEV(nvp);
    756   2729     llai1 		ASSERT(todv);
    757   2621     llai1 	}
    758   2621     llai1 
    759   2621     llai1 	/*
    760   2621     llai1 	 * link source to new target in the memory
    761   2621     llai1 	 */
    762   2729     llai1 	error = sdev_rnmnode(fromparent, fromdv, toparent, &todv, nnm, cred);
    763   2621     llai1 	if (error) {
    764   2621     llai1 		sdcmn_err2(("sdev_rename: renaming %s to %s failed "
    765   2621     llai1 		    " with error %d\n", onm, nnm, error));
    766   2729     llai1 		mutex_exit(&sdev_lock);
    767   2729     llai1 		if (nvp)
    768   2729     llai1 			VN_RELE(nvp);
    769   2621     llai1 		VN_RELE(ovp);
    770   2729     llai1 		return (error);
    771   2729     llai1 	}
    772   2729     llai1 
    773   2729     llai1 	/*
    774   2729     llai1 	 * unlink from source
    775   2729     llai1 	 */
    776   2729     llai1 	rw_enter(&fromparent->sdev_contents, RW_READER);
    777   2729     llai1 	fromdv = sdev_cache_lookup(fromparent, onm);
    778   2729     llai1 	if (fromdv == NULL) {
    779   2729     llai1 		rw_exit(&fromparent->sdev_contents);
    780   2729     llai1 		mutex_exit(&sdev_lock);
    781   2729     llai1 		sdcmn_err2(("sdev_rename: the source is deleted already\n"));
    782   2729     llai1 		return (0);
    783   2729     llai1 	}
    784   2729     llai1 
    785   2729     llai1 	if (fromdv->sdev_state == SDEV_ZOMBIE) {
    786   2729     llai1 		rw_exit(&fromparent->sdev_contents);
    787   2729     llai1 		mutex_exit(&sdev_lock);
    788   2729     llai1 		VN_RELE(SDEVTOV(fromdv));
    789   2729     llai1 		sdcmn_err2(("sdev_rename: the source is being deleted\n"));
    790   2729     llai1 		return (0);
    791   2729     llai1 	}
    792   2729     llai1 	rw_exit(&fromparent->sdev_contents);
    793   2729     llai1 	ASSERT(SDEVTOV(fromdv) == ovp);
    794   2729     llai1 	VN_RELE(ovp);
    795   2729     llai1 
    796   2729     llai1 	/* clean out the directory contents before it can be removed */
    797   2729     llai1 	type = SDEVTOV(fromdv)->v_type;
    798   2729     llai1 	if (type == VDIR) {
    799   2729     llai1 		error = sdev_cleandir(fromdv, NULL, 0);
    800   2729     llai1 		sdcmn_err2(("sdev_rename: cleandir finished with %d\n",
    801   2729     llai1 		    error));
    802   2729     llai1 		if (error == EBUSY)
    803   2729     llai1 			error = 0;
    804   2729     llai1 	}
    805   2729     llai1 
    806   2729     llai1 	rw_enter(&fromparent->sdev_contents, RW_WRITER);
    807   2729     llai1 	bkstore = SDEV_IS_PERSIST(fromdv) ? 1 : 0;
    808   2729     llai1 	error = sdev_cache_update(fromparent, &fromdv, onm,
    809   2729     llai1 	    SDEV_CACHE_DELETE);
    810   2729     llai1 
    811   2729     llai1 	/* best effforts clean up the backing store */
    812   2729     llai1 	if (bkstore) {
    813   2729     llai1 		ASSERT(fromparent->sdev_attrvp);
    814   2729     llai1 		if (type != VDIR) {
    815   5331       amw /* XXXci - We may need to translate the C-I flags on VOP_REMOVE */
    816   2729     llai1 			error = VOP_REMOVE(fromparent->sdev_attrvp,
    817   5331       amw 			    onm, kcred, ct, 0);
    818   2729     llai1 		} else {
    819   5331       amw /* XXXci - We may need to translate the C-I flags on VOP_RMDIR */
    820   2729     llai1 			error = VOP_RMDIR(fromparent->sdev_attrvp,
    821   5331       amw 			    onm, fromparent->sdev_attrvp, kcred, ct, 0);
    822   2729     llai1 		}
    823   2729     llai1 
    824   2729     llai1 		if (error) {
    825   2729     llai1 			sdcmn_err2(("sdev_rename: device %s is "
    826   2729     llai1 			    "still on disk %s\n", onm,
    827   2729     llai1 			    fromparent->sdev_path));
    828   2729     llai1 			error = 0;
    829   2729     llai1 		}
    830   2729     llai1 	}
    831   2729     llai1 	rw_exit(&fromparent->sdev_contents);
    832   2729     llai1 	mutex_exit(&sdev_lock);
    833   2729     llai1 
    834   2729     llai1 	/* once reached to this point, the rename is regarded successful */
    835   2729     llai1 	return (0);
    836   2621     llai1 }
    837   2621     llai1 
    838   2621     llai1 /*
    839   2621     llai1  * dev-fs version of "ln -s path dev-name"
    840   2621     llai1  *	tnm - path, e.g. /devices/... or /dev/...
    841   2621     llai1  *	lnm - dev_name
    842   2621     llai1  */
    843   5331       amw /*ARGSUSED6*/
    844   2621     llai1 static int
    845   2621     llai1 sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
    846   5331       amw     char *tnm, struct cred *cred, caller_context_t *ct, int flags)
    847   2621     llai1 {
    848   2621     llai1 	int error;
    849   2621     llai1 	struct vnode *vp = NULL;
    850   2621     llai1 	struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
    851   2621     llai1 	struct sdev_node *self = (struct sdev_node *)NULL;
    852   2621     llai1 
    853   2621     llai1 	ASSERT(parent);
    854   2621     llai1 	rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER);
    855   2621     llai1 	if (parent->sdev_state == SDEV_ZOMBIE) {
    856   2621     llai1 		rw_exit(&parent->sdev_dotdot->sdev_contents);
    857   2621     llai1 		sdcmn_err2(("sdev_symlink: parent %s is ZOMBIED \n",
    858   2621     llai1 		    parent->sdev_name));
    859   2621     llai1 		return (ENOENT);
    860   2621     llai1 	}
    861   2621     llai1 
    862   2621     llai1 	if (!SDEV_IS_GLOBAL(parent)) {
    863   2621     llai1 		rw_exit(&parent->sdev_dotdot->sdev_contents);
    864   2621     llai1 		return (ENOTSUP);
    865   2621     llai1 	}
    866   2621     llai1 	rw_exit(&parent->sdev_dotdot->sdev_contents);
    867   2621     llai1 
    868   3843        jg 	/* execute access is required to search a directory */
    869   5331       amw 	if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
    870   3843        jg 		return (error);
    871   3843        jg 
    872   2621     llai1 	/* find existing name */
    873   5331       amw /* XXXci - We may need to translate the C-I flags here */
    874   5331       amw 	error = VOP_LOOKUP(dvp, lnm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
    875   2621     llai1 	if (error == 0) {
    876   2621     llai1 		ASSERT(vp);
    877   2621     llai1 		VN_RELE(vp);
    878   2621     llai1 		sdcmn_err2(("sdev_symlink: node %s already exists\n", lnm));
    879   2621     llai1 		return (EEXIST);
    880   2621     llai1 	}
    881   3843        jg 	if (error != ENOENT)
    882   3843        jg 		return (error);
    883   2621     llai1 
    884   3843        jg 	/* write access is required to create a symlink */
    885   5331       amw 	if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0)
    886   2621     llai1 		return (error);
    887   2621     llai1 
    888   2621     llai1 	/* put it into memory cache */
    889   2621     llai1 	rw_enter(&parent->sdev_contents, RW_WRITER);
    890   2621     llai1 	error = sdev_mknode(parent, lnm, &self, tva, NULL, (void *)tnm,
    891   2621     llai1 	    cred, SDEV_READY);
    892   2621     llai1 	if (error) {
    893   2621     llai1 		rw_exit(&parent->sdev_contents);
    894   2621     llai1 		sdcmn_err2(("sdev_symlink: node %s creation failed\n", lnm));
    895   2621     llai1 		if (self)
    896   2621     llai1 			SDEV_RELE(self);
    897   2621     llai1 
    898   2621     llai1 		return (error);
    899   2621     llai1 	}
    900   2621     llai1 	ASSERT(self && (self->sdev_state == SDEV_READY));
    901   2621     llai1 	rw_exit(&parent->sdev_contents);
    902   2621     llai1 
    903   2621     llai1 	/* take care the timestamps for the node and its parent */
    904   2621     llai1 	sdev_update_timestamps(SDEVTOV(self), kcred,
    905   2621     llai1 	    AT_CTIME|AT_MTIME|AT_ATIME);
    906   2621     llai1 	sdev_update_timestamps(dvp, kcred, AT_MTIME|AT_ATIME);
    907   2621     llai1 	if (SDEV_IS_GLOBAL(parent))
    908   2621     llai1 		atomic_inc_ulong(&parent->sdev_gdir_gen);
    909   2621     llai1 
    910   2621     llai1 	/* wake up other threads blocked on looking up this node */
    911   2621     llai1 	mutex_enter(&self->sdev_lookup_lock);
    912   2621     llai1 	SDEV_UNBLOCK_OTHERS(self, SDEV_LOOKUP);
    913   2621     llai1 	mutex_exit(&self->sdev_lookup_lock);
    914   2621     llai1 	SDEV_RELE(self);	/* don't return with vnode held */
    915   2621     llai1 	return (0);
    916   2621     llai1 }
    917   2621     llai1 
    918   5331       amw /*ARGSUSED6*/
    919   2621     llai1 static int
    920   2621     llai1 sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
    921   5331       amw     struct cred *cred, caller_context_t *ct, int flags, vsecattr_t *vsecp)
    922   2621     llai1 {
    923   2621     llai1 	int error;
    924   2621     llai1 	struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
    925   2621     llai1 	struct sdev_node *self = NULL;
    926   2621     llai1 	struct vnode	*vp = NULL;
    927   2621     llai1 
    928   2621     llai1 	ASSERT(parent && parent->sdev_dotdot);
    929   2621     llai1 	rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER);
    930   2621     llai1 	if (parent->sdev_state == SDEV_ZOMBIE) {
    931   2621     llai1 		rw_exit(&parent->sdev_dotdot->sdev_contents);
    932   2621     llai1 		return (ENOENT);
    933   2621     llai1 	}
    934   2621     llai1 
    935   2621     llai1 	/* non-global do not allow pure directory creation */
    936   2621     llai1 	if (!SDEV_IS_GLOBAL(parent)) {
    937   2621     llai1 		rw_exit(&parent->sdev_dotdot->sdev_contents);
    938   2621     llai1 		return (prof_lookup(dvp, nm, vpp, cred));
    939   2621     llai1 	}
    940   2621     llai1 	rw_exit(&parent->sdev_dotdot->sdev_contents);
    941   2621     llai1 
    942   3843        jg 	/* execute access is required to search the directory */
    943   5331       amw 	if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0) {
    944   3843        jg 		return (error);
    945   3843        jg 	}
    946   3843        jg 
    947   2621     llai1 	/* find existing name */
    948   5331       amw /* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
    949   5331       amw 	error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
    950   2621     llai1 	if (error == 0) {
    951   2621     llai1 		VN_RELE(vp);
    952   2621     llai1 		return (EEXIST);
    953   2621     llai1 	}
    954   2621     llai1 	if (error != ENOENT)
    955   2621     llai1 		return (error);
    956   3843        jg 
    957   3843        jg 	/* require write access to create a directory */
    958   5331       amw 	if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0) {
    959   3843        jg 		return (error);
    960   3843        jg 	}
    961   2621     llai1 
    962   2621     llai1 	/* put it into memory */
    963   2621     llai1 	rw_enter(&parent->sdev_contents, RW_WRITER);
    964   2621     llai1 	error = sdev_mknode(parent, nm, &self,
    965   2621     llai1 	    va, NULL, NULL, cred, SDEV_READY);
    966   2621     llai1 	if (error) {
    967   2621     llai1 		rw_exit(&parent->sdev_contents);
    968   2621     llai1 		if (self)
    969   2621     llai1 			SDEV_RELE(self);
    970   2621     llai1 		return (error);
    971   2621     llai1 	}
    972   2621     llai1 	ASSERT(self && (self->sdev_state == SDEV_READY));
    973   2621     llai1 	rw_exit(&parent->sdev_contents);
    974   2621     llai1 
    975   2621     llai1 	/* take care the timestamps for the node and its parent */
    976   2621     llai1 	sdev_update_timestamps(SDEVTOV(self), kcred,
    977   2621     llai1 	    AT_CTIME|AT_MTIME|AT_ATIME);
    978   2621     llai1 	sdev_update_timestamps(dvp, kcred, AT_MTIME|AT_ATIME);
    979   2621     llai1 	if (SDEV_IS_GLOBAL(parent))
    980   2621     llai1 		atomic_inc_ulong(&parent->sdev_gdir_gen);
    981   2621     llai1 
    982   2621     llai1 	/* wake up other threads blocked on looking up this node */
    983   2621     llai1 	mutex_enter(&self->sdev_lookup_lock);
    984   2621     llai1 	SDEV_UNBLOCK_OTHERS(self, SDEV_LOOKUP);
    985   2621     llai1 	mutex_exit(&self->sdev_lookup_lock);
    986   2621     llai1 	*vpp = SDEVTOV(self);
    987   2621     llai1 	return (0);
    988   2621     llai1 }
    989   2621     llai1 
    990   2621     llai1 /*
    991   2621     llai1  * allowing removing an empty directory under /dev
    992   2621     llai1  */
    993   2621     llai1 /*ARGSUSED*/
    994   2621     llai1 static int
    995   5331       amw sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred,
    996   5331       amw     caller_context_t *ct, int flags)
    997   2621     llai1 {
    998   2621     llai1 	int error = 0;
    999   2621     llai1 	struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
   1000   2621     llai1 	struct sdev_node *self = NULL;
   1001   2621     llai1 	struct vnode *vp = NULL;
   1002   2621     llai1 
   1003   2621     llai1 	/* bail out early */
   1004   2621     llai1 	if (strcmp(nm, ".") == 0)
   1005   2621     llai1 		return (EINVAL);
   1006   2621     llai1 	if (strcmp(nm, "..") == 0)
   1007   2621     llai1 		return (EEXIST); /* should be ENOTEMPTY */
   1008   2621     llai1 
   1009   2621     llai1 	/* no destruction of non-global node */
   1010   2621     llai1 	ASSERT(parent && parent->sdev_dotdot);
   1011   2621     llai1 	rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER);
   1012   2621     llai1 	if (!SDEV_IS_GLOBAL(parent)) {
   1013   2621     llai1 		rw_exit(&parent->sdev_dotdot->sdev_contents);
   1014   2621     llai1 		return (ENOTSUP);
   1015   2621     llai1 	}
   1016   2621     llai1 	rw_exit(&parent->sdev_dotdot->sdev_contents);
   1017   2621     llai1 
   1018   3843        jg 	/* execute access is required to search the directory */
   1019  10588      Eric 	if ((error = VOP_ACCESS(dvp, VEXEC|VWRITE, 0, cred, ct)) != 0)
   1020   3843        jg 		return (error);
   1021   3843        jg 
   1022   2621     llai1 	/* check existing name */
   1023   2621     llai1 	rw_enter(&parent->sdev_contents, RW_WRITER);
   1024   2621     llai1 	self = sdev_cache_lookup(parent, nm);
   1025   2621     llai1 	if (self == NULL) {
   1026   2621     llai1 		rw_exit(&parent->sdev_contents);
   1027   2621     llai1 		return (ENOENT);
   1028   2621     llai1 	}
   1029   2621     llai1 
   1030   2621     llai1 	vp = SDEVTOV(self);
   1031   2621     llai1 	if ((self->sdev_state == SDEV_INIT) ||
   1032   2621     llai1 	    (self->sdev_state == SDEV_ZOMBIE)) {
   1033   2621     llai1 		rw_exit(&parent->sdev_contents);
   1034   2621     llai1 		VN_RELE(vp);
   1035   2621     llai1 		return (ENOENT);
   1036   2621     llai1 	}
   1037   2621     llai1 
   1038   2621     llai1 	/* some sanity checks */
   1039   2621     llai1 	if (vp == dvp || vp == cdir) {
   1040   2621     llai1 		rw_exit(&parent->sdev_contents);
   1041   2621     llai1 		VN_RELE(vp);
   1042   2621     llai1 		return (EINVAL);
   1043   2621     llai1 	}
   1044   2621     llai1 
   1045   2621     llai1 	if (vp->v_type != VDIR) {
   1046   2621     llai1 		rw_exit(&parent->sdev_contents);
   1047   2621     llai1 		VN_RELE(vp);
   1048   2621     llai1 		return (ENOTDIR);
   1049   2621     llai1 	}
   1050   2621     llai1 
   1051   2621     llai1 	if (vn_vfswlock(vp)) {
   1052   2621     llai1 		rw_exit(&parent->sdev_contents);
   1053   2621     llai1 		VN_RELE(vp);
   1054   2621     llai1 		return (EBUSY);
   1055   2621     llai1 	}
   1056   2621     llai1 
   1057   2621     llai1 	if (vn_mountedvfs(vp) != NULL) {
   1058   2621     llai1 		rw_exit(&parent->sdev_contents);
   1059   2621     llai1 		vn_vfsunlock(vp);
   1060   2621     llai1 		VN_RELE(vp);
   1061   2621     llai1 		return (EBUSY);
   1062   2621     llai1 	}
   1063   2621     llai1 
   1064   2621     llai1 	self = VTOSDEV(vp);
   1065   2621     llai1 	/* bail out on a non-empty directory */
   1066   2621     llai1 	rw_enter(&self->sdev_contents, RW_READER);
   1067   2621     llai1 	if (self->sdev_nlink > 2) {
   1068   2621     llai1 		rw_exit(&self->sdev_contents);
   1069   2621     llai1 		rw_exit(&parent->sdev_contents);
   1070   2621     llai1 		vn_vfsunlock(vp);
   1071   2621     llai1 		VN_RELE(vp);
   1072   2621     llai1 		return (ENOTEMPTY);
   1073   2621     llai1 	}
   1074   2621     llai1 	rw_exit(&self->sdev_contents);
   1075   2621     llai1 
   1076   2621     llai1 	/* unlink it from the directory cache */
   1077   2621     llai1 	error = sdev_cache_update(parent, &self, nm, SDEV_CACHE_DELETE);
   1078   2621     llai1 	rw_exit(&parent->sdev_contents);
   1079   2621     llai1 	vn_vfsunlock(vp);
   1080   2621     llai1 
   1081   2621     llai1 	if (error && (error != EBUSY)) {
   1082   2621     llai1 		VN_RELE(vp);
   1083   2621     llai1 	} else {
   1084   2621     llai1 		sdcmn_err2(("sdev_rmdir: cleaning node %s from directory "
   1085   2621     llai1 		    " cache with error %d\n", nm, error));
   1086   2621     llai1 
   1087   2621     llai1 		/* best effort to clean up the backing store */
   1088   2621     llai1 		if (SDEV_IS_PERSIST(parent)) {
   1089   2621     llai1 			ASSERT(parent->sdev_attrvp);
   1090   2621     llai1 			error = VOP_RMDIR(parent->sdev_attrvp, nm,
   1091   5331       amw 			    parent->sdev_attrvp, kcred, ct, flags);
   1092   2621     llai1 			sdcmn_err2(("sdev_rmdir: cleaning device %s is on"
   1093   2621     llai1 			    " disk error %d\n", parent->sdev_path, error));
   1094   2621     llai1 		}
   1095   2621     llai1 
   1096   2621     llai1 		if (error == EBUSY)
   1097   2621     llai1 			error = 0;
   1098   2621     llai1 	}
   1099   2621     llai1 
   1100   2621     llai1 	return (error);
   1101   2621     llai1 }
   1102   2621     llai1 
   1103   2621     llai1 /*
   1104   2621     llai1  * read the contents of a symbolic link
   1105   2621     llai1  */
   1106   2621     llai1 static int
   1107   5331       amw sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred,
   1108   5331       amw     caller_context_t *ct)
   1109   2621     llai1 {
   1110   2621     llai1 	struct sdev_node *dv;
   1111   2621     llai1 	int	error = 0;
   1112   2621     llai1 
   1113   2621     llai1 	ASSERT(vp->v_type == VLNK);
   1114   2621     llai1 
   1115   2621     llai1 	dv = VTOSDEV(vp);
   1116   2621     llai1 
   1117   2621     llai1 	if (dv->sdev_attrvp) {
   1118   2621     llai1 		/* non-NULL attrvp implys a persisted node at READY state */
   1119   5331       amw 		return (VOP_READLINK(dv->sdev_attrvp, uiop, cred, ct));
   1120   2621     llai1 	} else if (dv->sdev_symlink != NULL) {
   1121   2621     llai1 		/* memory nodes, e.g. local nodes */
   1122   2621     llai1 		rw_enter(&dv->sdev_contents, RW_READER);
   1123   2621     llai1 		sdcmn_err2(("sdev_readlink link is %s\n", dv->sdev_symlink));
   1124   2621     llai1 		error = uiomove(dv->sdev_symlink, strlen(dv->sdev_symlink),
   1125   2621     llai1 		    UIO_READ, uiop);
   1126   2621     llai1 		rw_exit(&dv->sdev_contents);
   1127   2621     llai1 		return (error);
   1128   2621     llai1 	}
   1129   2621     llai1 
   1130   2621     llai1 	return (ENOENT);
   1131   2621     llai1 }
   1132   2621     llai1 
   1133   5331       amw /*ARGSUSED4*/
   1134   2621     llai1 static int
   1135   5331       amw sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp,
   1136   5331       amw     caller_context_t *ct, int flags)
   1137   2621     llai1 {
   1138   2679     szhou 	struct sdev_node *parent = VTOSDEV(dvp);
   1139   3843        jg 	int error;
   1140   3843        jg 
   1141   3843        jg 	/* execute access is required to search the directory */
   1142   5331       amw 	if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
   1143   3843        jg 		return (error);
   1144   2679     szhou 
   1145   2679     szhou 	ASSERT(parent);
   1146   2679     szhou 	if (!SDEV_IS_GLOBAL(parent))
   1147   2679     szhou 		prof_filldir(parent);
   1148   2621     llai1 	return (devname_readdir_func(dvp, uiop, cred, eofp, SDEV_BROWSE));
   1149   2621     llai1 }
   1150   2621     llai1 
   1151   2621     llai1 /*ARGSUSED1*/
   1152   2621     llai1 static void
   1153   5331       amw sdev_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct)
   1154   2621     llai1 {
   1155   5895  yz147064 	devname_inactive_func(vp, cred, NULL);
   1156   2621     llai1 }
   1157   2621     llai1 
   1158   5331       amw /*ARGSUSED2*/
   1159   2621     llai1 static int
   1160   5331       amw sdev_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
   1161   2621     llai1 {
   1162   2621     llai1 	struct sdev_node	*dv = VTOSDEV(vp);
   1163   2621     llai1 	struct sdev_fid	*sdev_fid;
   1164   2621     llai1 
   1165   2621     llai1 	if (fidp->fid_len < (sizeof (struct sdev_fid) - sizeof (ushort_t))) {
   1166   2621     llai1 		fidp->fid_len = sizeof (struct sdev_fid) - sizeof (ushort_t);
   1167   2621     llai1 		return (ENOSPC);
   1168   2621     llai1 	}
   1169   2621     llai1 
   1170   2621     llai1 	sdev_fid = (struct sdev_fid *)fidp;
   1171   2621     llai1 	bzero(sdev_fid, sizeof (struct sdev_fid));
   1172   2621     llai1 	sdev_fid->sdevfid_len =
   1173   2621     llai1 	    (int)sizeof (struct sdev_fid) - sizeof (ushort_t);
   1174   2621     llai1 	sdev_fid->sdevfid_ino = dv->sdev_ino;
   1175   2621     llai1 
   1176   2621     llai1 	return (0);
   1177   2621     llai1 }
   1178   2621     llai1 
   1179   2621     llai1 /*
   1180   2621     llai1  * This pair of routines bracket all VOP_READ, VOP_WRITE
   1181   2621     llai1  * and VOP_READDIR requests.  The contents lock stops things
   1182   2621     llai1  * moving around while we're looking at them.
   1183   2621     llai1  */
   1184   3748        jg /*ARGSUSED2*/
   1185   3748        jg static int
   1186   3748        jg sdev_rwlock(struct vnode *vp, int write_flag, caller_context_t *ctp)
   1187   2621     llai1 {
   1188   3748        jg 	rw_enter(&VTOSDEV(vp)->sdev_contents,
   1189   3748        jg 	    write_flag ? RW_WRITER : RW_READER);
   1190   3748        jg 	return (write_flag ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE);
   1191   2621     llai1 }
   1192   2621     llai1 
   1193   2621     llai1 /*ARGSUSED1*/
   1194   2621     llai1 static void
   1195   3748        jg sdev_rwunlock(struct vnode *vp, int write_flag, caller_context_t *ctp)
   1196   2621     llai1 {
   1197   2621     llai1 	rw_exit(&VTOSDEV(vp)->sdev_contents);
   1198   2621     llai1 }
   1199   2621     llai1 
   1200   2621     llai1 /*ARGSUSED1*/
   1201   2621     llai1 static int
   1202   5331       amw sdev_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
   1203   5331       amw     caller_context_t *ct)
   1204   2621     llai1 {
   1205   2621     llai1 	struct vnode *attrvp = VTOSDEV(vp)->sdev_attrvp;
   1206   2621     llai1 
   1207   2621     llai1 	ASSERT(vp->v_type != VCHR &&
   1208   2621     llai1 	    vp->v_type != VBLK && vp->v_type != VLNK);
   1209   2621     llai1 
   1210   2621     llai1 	if (vp->v_type == VDIR)
   1211   5331       amw 		return (fs_seek(vp, ooff, noffp, ct));
   1212   2621     llai1 
   1213   2621     llai1 	ASSERT(attrvp);
   1214   5331       amw 	return (VOP_SEEK(attrvp, ooff, noffp, ct));
   1215   2621     llai1 }
   1216   2621     llai1 
   1217   2621     llai1 /*ARGSUSED1*/
   1218   2621     llai1 static int
   1219   2621     llai1 sdev_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
   1220   5331       amw     offset_t offset, struct flk_callback *flk_cbp, struct cred *cr,
   1221   5331       amw     caller_context_t *ct)
   1222   2621     llai1 {
   1223   2621     llai1 	int error;
   1224   2621     llai1 	struct sdev_node *dv = VTOSDEV(vp);
   1225   2621     llai1 
   1226   2621     llai1 	ASSERT(dv);
   1227   2621     llai1 	ASSERT(dv->sdev_attrvp);
   1228   2621     llai1 	error = VOP_FRLOCK(dv->sdev_attrvp, cmd, bfp, flag, offset,
   1229   5331       amw 	    flk_cbp, cr, ct);
   1230   2621     llai1 
   1231   2621     llai1 	return (error);
   1232   2621     llai1 }
   1233   2621     llai1 
   1234   2621     llai1 static int
   1235   5331       amw sdev_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
   1236   5331       amw     caller_context_t *ct)
   1237   2621     llai1 {
   1238   2621     llai1 	switch (cmd) {
   1239   2621     llai1 	case _PC_ACL_ENABLED:
   1240   2621     llai1 		*valp = SDEV_ACL_FLAVOR(vp);
   1241   2621     llai1 		return (0);
   1242   2621     llai1 	}
   1243   2621     llai1 
   1244   5331       amw 	return (fs_pathconf(vp, cmd, valp, cr, ct));
   1245   2621     llai1 }
   1246   2621     llai1 
   1247   2621     llai1 vnodeops_t *sdev_vnodeops;
   1248   2621     llai1 
   1249   2621     llai1 const fs_operation_def_t sdev_vnodeops_tbl[] = {
   1250   3898       rsb 	VOPNAME_OPEN,		{ .vop_open = sdev_open },
   1251   3898       rsb 	VOPNAME_CLOSE,		{ .vop_close = sdev_close },
   1252   3898       rsb 	VOPNAME_READ,		{ .vop_read = sdev_read },
   1253   3898       rsb 	VOPNAME_WRITE,		{ .vop_write = sdev_write },
   1254   3898       rsb 	VOPNAME_IOCTL,		{ .vop_ioctl = sdev_ioctl },
   1255   3898       rsb 	VOPNAME_GETATTR,	{ .vop_getattr = sdev_getattr },
   1256   3898       rsb 	VOPNAME_SETATTR,	{ .vop_setattr = sdev_setattr },
   1257   3898       rsb 	VOPNAME_ACCESS,		{ .vop_access = sdev_access },
   1258   3898       rsb 	VOPNAME_LOOKUP,		{ .vop_lookup = sdev_lookup },
   1259   3898       rsb 	VOPNAME_CREATE,		{ .vop_create = sdev_create },
   1260   3898       rsb 	VOPNAME_RENAME,		{ .vop_rename = sdev_rename },
   1261   3898       rsb 	VOPNAME_REMOVE,		{ .vop_remove = sdev_remove },
   1262   3898       rsb 	VOPNAME_MKDIR,		{ .vop_mkdir = sdev_mkdir },
   1263   3898       rsb 	VOPNAME_RMDIR,		{ .vop_rmdir = sdev_rmdir },
   1264   3898       rsb 	VOPNAME_READDIR,	{ .vop_readdir = sdev_readdir },
   1265   3898       rsb 	VOPNAME_SYMLINK,	{ .vop_symlink = sdev_symlink },
   1266   3898       rsb 	VOPNAME_READLINK,	{ .vop_readlink = sdev_readlink },
   1267   3898       rsb 	VOPNAME_INACTIVE,	{ .vop_inactive = sdev_inactive },
   1268   3898       rsb 	VOPNAME_FID,		{ .vop_fid = sdev_fid },
   1269   3898       rsb 	VOPNAME_RWLOCK,		{ .vop_rwlock = sdev_rwlock },
   1270   3898       rsb 	VOPNAME_RWUNLOCK,	{ .vop_rwunlock = sdev_rwunlock },
   1271   3898       rsb 	VOPNAME_SEEK,		{ .vop_seek = sdev_seek },
   1272   3898       rsb 	VOPNAME_FRLOCK,		{ .vop_frlock = sdev_frlock },
   1273   3898       rsb 	VOPNAME_PATHCONF,	{ .vop_pathconf = sdev_pathconf },
   1274   3898       rsb 	VOPNAME_SETSECATTR,	{ .vop_setsecattr = sdev_setsecattr },
   1275   3898       rsb 	VOPNAME_GETSECATTR,	{ .vop_getsecattr = sdev_getsecattr },
   1276   3898       rsb 	NULL,			NULL
   1277   2621     llai1 };
   1278   2621     llai1 
   1279   2621     llai1 int sdev_vnodeops_tbl_size = sizeof (sdev_vnodeops_tbl);
   1280