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  10097      Eric  * 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  * utility routines for the /dev fs
     28   2621     llai1  */
     29   2621     llai1 
     30   2621     llai1 #include <sys/types.h>
     31   2621     llai1 #include <sys/param.h>
     32   2621     llai1 #include <sys/t_lock.h>
     33   2621     llai1 #include <sys/systm.h>
     34   2621     llai1 #include <sys/sysmacros.h>
     35   2621     llai1 #include <sys/user.h>
     36   2621     llai1 #include <sys/time.h>
     37   2621     llai1 #include <sys/vfs.h>
     38   2621     llai1 #include <sys/vnode.h>
     39   2621     llai1 #include <sys/file.h>
     40   2621     llai1 #include <sys/fcntl.h>
     41   2621     llai1 #include <sys/flock.h>
     42   2621     llai1 #include <sys/kmem.h>
     43   2621     llai1 #include <sys/uio.h>
     44   2621     llai1 #include <sys/errno.h>
     45   2621     llai1 #include <sys/stat.h>
     46   2621     llai1 #include <sys/cred.h>
     47   2621     llai1 #include <sys/dirent.h>
     48   2621     llai1 #include <sys/pathname.h>
     49   2621     llai1 #include <sys/cmn_err.h>
     50   2621     llai1 #include <sys/debug.h>
     51   2621     llai1 #include <sys/mode.h>
     52   2621     llai1 #include <sys/policy.h>
     53   2621     llai1 #include <fs/fs_subr.h>
     54   2621     llai1 #include <sys/mount.h>
     55   2621     llai1 #include <sys/fs/snode.h>
     56   2621     llai1 #include <sys/fs/dv_node.h>
     57   2621     llai1 #include <sys/fs/sdev_impl.h>
     58   2621     llai1 #include <sys/sunndi.h>
     59   2621     llai1 #include <sys/sunmdi.h>
     60   2621     llai1 #include <sys/conf.h>
     61   2621     llai1 #include <sys/proc.h>
     62   2621     llai1 #include <sys/user.h>
     63   2621     llai1 #include <sys/modctl.h>
     64   2621     llai1 
     65   2621     llai1 #ifdef DEBUG
     66   2621     llai1 int sdev_debug = 0x00000001;
     67   2621     llai1 int sdev_debug_cache_flags = 0;
     68   2621     llai1 #endif
     69   2621     llai1 
     70   2621     llai1 /*
     71   2621     llai1  * globals
     72   2621     llai1  */
     73   2621     llai1 /* prototype memory vattrs */
     74   2621     llai1 vattr_t sdev_vattr_dir = {
     75   2621     llai1 	AT_TYPE|AT_MODE|AT_UID|AT_GID,		/* va_mask */
     76   2621     llai1 	VDIR,					/* va_type */
     77   2621     llai1 	SDEV_DIRMODE_DEFAULT,			/* va_mode */
     78   2621     llai1 	SDEV_UID_DEFAULT,			/* va_uid */
     79   2621     llai1 	SDEV_GID_DEFAULT,			/* va_gid */
     80   2621     llai1 	0,					/* va_fsid */
     81   2621     llai1 	0,					/* va_nodeid */
     82   2621     llai1 	0,					/* va_nlink */
     83   2621     llai1 	0,					/* va_size */
     84   2621     llai1 	0,					/* va_atime */
     85   2621     llai1 	0,					/* va_mtime */
     86   2621     llai1 	0,					/* va_ctime */
     87   2621     llai1 	0,					/* va_rdev */
     88   2621     llai1 	0,					/* va_blksize */
     89   2621     llai1 	0,					/* va_nblocks */
     90   2621     llai1 	0					/* va_vcode */
     91   2621     llai1 };
     92   2621     llai1 
     93   2621     llai1 vattr_t sdev_vattr_lnk = {
     94   2621     llai1 	AT_TYPE|AT_MODE,			/* va_mask */
     95   2621     llai1 	VLNK,					/* va_type */
     96   2621     llai1 	SDEV_LNKMODE_DEFAULT,			/* va_mode */
     97   2621     llai1 	SDEV_UID_DEFAULT,			/* va_uid */
     98   2621     llai1 	SDEV_GID_DEFAULT,			/* va_gid */
     99   2621     llai1 	0,					/* va_fsid */
    100   2621     llai1 	0,					/* va_nodeid */
    101   2621     llai1 	0,					/* va_nlink */
    102   2621     llai1 	0,					/* va_size */
    103   2621     llai1 	0,					/* va_atime */
    104   2621     llai1 	0,					/* va_mtime */
    105   2621     llai1 	0,					/* va_ctime */
    106   2621     llai1 	0,					/* va_rdev */
    107   2621     llai1 	0,					/* va_blksize */
    108   2621     llai1 	0,					/* va_nblocks */
    109   2621     llai1 	0					/* va_vcode */
    110   2621     llai1 };
    111   2621     llai1 
    112   2621     llai1 vattr_t sdev_vattr_blk = {
    113   2621     llai1 	AT_TYPE|AT_MODE|AT_UID|AT_GID,		/* va_mask */
    114   2621     llai1 	VBLK,					/* va_type */
    115   2621     llai1 	S_IFBLK | SDEV_DEVMODE_DEFAULT,		/* va_mode */
    116   2621     llai1 	SDEV_UID_DEFAULT,			/* va_uid */
    117   2621     llai1 	SDEV_GID_DEFAULT,			/* va_gid */
    118   2621     llai1 	0,					/* va_fsid */
    119   2621     llai1 	0,					/* va_nodeid */
    120   2621     llai1 	0,					/* va_nlink */
    121   2621     llai1 	0,					/* va_size */
    122   2621     llai1 	0,					/* va_atime */
    123   2621     llai1 	0,					/* va_mtime */
    124   2621     llai1 	0,					/* va_ctime */
    125   2621     llai1 	0,					/* va_rdev */
    126   2621     llai1 	0,					/* va_blksize */
    127   2621     llai1 	0,					/* va_nblocks */
    128   2621     llai1 	0					/* va_vcode */
    129   2621     llai1 };
    130   2621     llai1 
    131   2621     llai1 vattr_t sdev_vattr_chr = {
    132   2621     llai1 	AT_TYPE|AT_MODE|AT_UID|AT_GID,		/* va_mask */
    133   2621     llai1 	VCHR,					/* va_type */
    134   2621     llai1 	S_IFCHR | SDEV_DEVMODE_DEFAULT,		/* va_mode */
    135   2621     llai1 	SDEV_UID_DEFAULT,			/* va_uid */
    136   2621     llai1 	SDEV_GID_DEFAULT,			/* va_gid */
    137   2621     llai1 	0,					/* va_fsid */
    138   2621     llai1 	0,					/* va_nodeid */
    139   2621     llai1 	0,					/* va_nlink */
    140   2621     llai1 	0,					/* va_size */
    141   2621     llai1 	0,					/* va_atime */
    142   2621     llai1 	0,					/* va_mtime */
    143   2621     llai1 	0,					/* va_ctime */
    144   2621     llai1 	0,					/* va_rdev */
    145   2621     llai1 	0,					/* va_blksize */
    146   2621     llai1 	0,					/* va_nblocks */
    147   2621     llai1 	0					/* va_vcode */
    148   2621     llai1 };
    149   2621     llai1 
    150   2621     llai1 kmem_cache_t	*sdev_node_cache;	/* sdev_node cache */
    151   2621     llai1 int		devtype;		/* fstype */
    152   2621     llai1 
    153   2621     llai1 /* static */
    154   2621     llai1 static struct vnodeops *sdev_get_vop(struct sdev_node *);
    155  10588      Eric static void sdev_set_no_negcache(struct sdev_node *);
    156   2621     llai1 static fs_operation_def_t *sdev_merge_vtab(const fs_operation_def_t []);
    157   2621     llai1 static void sdev_free_vtab(fs_operation_def_t *);
    158   2621     llai1 
    159   2621     llai1 static void
    160   2621     llai1 sdev_prof_free(struct sdev_node *dv)
    161   2621     llai1 {
    162   2621     llai1 	ASSERT(!SDEV_IS_GLOBAL(dv));
    163   2621     llai1 	if (dv->sdev_prof.dev_name)
    164   2621     llai1 		nvlist_free(dv->sdev_prof.dev_name);
    165   2621     llai1 	if (dv->sdev_prof.dev_map)
    166   2621     llai1 		nvlist_free(dv->sdev_prof.dev_map);
    167   2621     llai1 	if (dv->sdev_prof.dev_symlink)
    168   2621     llai1 		nvlist_free(dv->sdev_prof.dev_symlink);
    169   2621     llai1 	if (dv->sdev_prof.dev_glob_incdir)
    170   2621     llai1 		nvlist_free(dv->sdev_prof.dev_glob_incdir);
    171   2621     llai1 	if (dv->sdev_prof.dev_glob_excdir)
    172   2621     llai1 		nvlist_free(dv->sdev_prof.dev_glob_excdir);
    173   2621     llai1 	bzero(&dv->sdev_prof, sizeof (dv->sdev_prof));
    174   2621     llai1 }
    175   2621     llai1 
    176   6712     tomee /* sdev_node cache constructor */
    177   2621     llai1 /*ARGSUSED1*/
    178   2621     llai1 static int
    179   2621     llai1 i_sdev_node_ctor(void *buf, void *cfarg, int flag)
    180   2621     llai1 {
    181   2621     llai1 	struct sdev_node *dv = (struct sdev_node *)buf;
    182   2621     llai1 	struct vnode *vp;
    183   2621     llai1 
    184   2621     llai1 	bzero(buf, sizeof (struct sdev_node));
    185   6712     tomee 	vp = dv->sdev_vnode = vn_alloc(flag);
    186   6712     tomee 	if (vp == NULL) {
    187   6712     tomee 		return (-1);
    188   6712     tomee 	}
    189   6712     tomee 	vp->v_data = dv;
    190   2621     llai1 	rw_init(&dv->sdev_contents, NULL, RW_DEFAULT, NULL);
    191   2621     llai1 	return (0);
    192   2621     llai1 }
    193   2621     llai1 
    194   6712     tomee /* sdev_node cache destructor */
    195   2621     llai1 /*ARGSUSED1*/
    196   2621     llai1 static void
    197   2621     llai1 i_sdev_node_dtor(void *buf, void *arg)
    198   2621     llai1 {
    199   2621     llai1 	struct sdev_node *dv = (struct sdev_node *)buf;
    200   2621     llai1 	struct vnode *vp = SDEVTOV(dv);
    201   2621     llai1 
    202   2621     llai1 	rw_destroy(&dv->sdev_contents);
    203   2621     llai1 	vn_free(vp);
    204   2621     llai1 }
    205   2621     llai1 
    206   2621     llai1 /* initialize sdev_node cache */
    207   2621     llai1 void
    208   2621     llai1 sdev_node_cache_init()
    209   2621     llai1 {
    210   2621     llai1 	int flags = 0;
    211   2621     llai1 
    212   2621     llai1 #ifdef	DEBUG
    213   2621     llai1 	flags = sdev_debug_cache_flags;
    214   2621     llai1 	if (flags)
    215   2621     llai1 		sdcmn_err(("cache debug flags 0x%x\n", flags));
    216   2621     llai1 #endif	/* DEBUG */
    217   2621     llai1 
    218   2621     llai1 	ASSERT(sdev_node_cache == NULL);
    219   2621     llai1 	sdev_node_cache = kmem_cache_create("sdev_node_cache",
    220   2621     llai1 	    sizeof (struct sdev_node), 0, i_sdev_node_ctor, i_sdev_node_dtor,
    221   2621     llai1 	    NULL, NULL, NULL, flags);
    222   2621     llai1 }
    223   2621     llai1 
    224   2621     llai1 /* destroy sdev_node cache */
    225   2621     llai1 void
    226   2621     llai1 sdev_node_cache_fini()
    227   2621     llai1 {
    228   2621     llai1 	ASSERT(sdev_node_cache != NULL);
    229   2621     llai1 	kmem_cache_destroy(sdev_node_cache);
    230   2621     llai1 	sdev_node_cache = NULL;
    231   2621     llai1 }
    232   2621     llai1 
    233   6260        jg /*
    234   6260        jg  * Compare two nodes lexographically to balance avl tree
    235   6260        jg  */
    236   6260        jg static int
    237   6260        jg sdev_compare_nodes(const struct sdev_node *dv1, const struct sdev_node *dv2)
    238   6260        jg {
    239   6260        jg 	int rv;
    240   6260        jg 	if ((rv = strcmp(dv1->sdev_name, dv2->sdev_name)) == 0)
    241   6260        jg 		return (0);
    242   6260        jg 	return ((rv < 0) ? -1 : 1);
    243   6260        jg }
    244   6260        jg 
    245   2621     llai1 void
    246   2621     llai1 sdev_set_nodestate(struct sdev_node *dv, sdev_node_state_t state)
    247   2621     llai1 {
    248   2621     llai1 	ASSERT(dv);
    249   2621     llai1 	ASSERT(RW_WRITE_HELD(&dv->sdev_contents));
    250   2621     llai1 	dv->sdev_state = state;
    251   2621     llai1 }
    252   2621     llai1 
    253   2621     llai1 static void
    254   2621     llai1 sdev_attrinit(struct sdev_node *dv, vattr_t *vap)
    255   2621     llai1 {
    256   2621     llai1 	timestruc_t now;
    257   2621     llai1 
    258   2621     llai1 	ASSERT(vap);
    259   2621     llai1 
    260   2621     llai1 	dv->sdev_attr = kmem_zalloc(sizeof (struct vattr), KM_SLEEP);
    261   2621     llai1 	*dv->sdev_attr = *vap;
    262   2621     llai1 
    263   2621     llai1 	dv->sdev_attr->va_mode = MAKEIMODE(vap->va_type, vap->va_mode);
    264   2621     llai1 
    265   2621     llai1 	gethrestime(&now);
    266   2621     llai1 	dv->sdev_attr->va_atime = now;
    267   2621     llai1 	dv->sdev_attr->va_mtime = now;
    268   2621     llai1 	dv->sdev_attr->va_ctime = now;
    269   2621     llai1 }
    270   2621     llai1 
    271   2621     llai1 /* alloc and initialize a sdev_node */
    272   2621     llai1 int
    273   2621     llai1 sdev_nodeinit(struct sdev_node *ddv, char *nm, struct sdev_node **newdv,
    274   2621     llai1     vattr_t *vap)
    275   2621     llai1 {
    276   2621     llai1 	struct sdev_node *dv = NULL;
    277   2621     llai1 	struct vnode *vp;
    278   2621     llai1 	size_t nmlen, len;
    279   2621     llai1 	devname_handle_t  *dhl;
    280   2621     llai1 
    281   2621     llai1 	nmlen = strlen(nm) + 1;
    282   2621     llai1 	if (nmlen > MAXNAMELEN) {
    283   2621     llai1 		sdcmn_err9(("sdev_nodeinit: node name %s"
    284   2621     llai1 		    " too long\n", nm));
    285   2621     llai1 		*newdv = NULL;
    286   2621     llai1 		return (ENAMETOOLONG);
    287   2621     llai1 	}
    288   2621     llai1 
    289   2621     llai1 	dv = kmem_cache_alloc(sdev_node_cache, KM_SLEEP);
    290   2621     llai1 
    291   2621     llai1 	dv->sdev_name = kmem_alloc(nmlen, KM_SLEEP);
    292   2621     llai1 	bcopy(nm, dv->sdev_name, nmlen);
    293   2621     llai1 	dv->sdev_namelen = nmlen - 1;	/* '\0' not included */
    294   2621     llai1 	len = strlen(ddv->sdev_path) + strlen(nm) + 2;
    295   2621     llai1 	dv->sdev_path = kmem_alloc(len, KM_SLEEP);
    296   2621     llai1 	(void) snprintf(dv->sdev_path, len, "%s/%s", ddv->sdev_path, nm);
    297   2621     llai1 	/* overwritten for VLNK nodes */
    298   2621     llai1 	dv->sdev_symlink = NULL;
    299   2621     llai1 
    300   2621     llai1 	vp = SDEVTOV(dv);
    301   2621     llai1 	vn_reinit(vp);
    302   2621     llai1 	vp->v_vfsp = SDEVTOV(ddv)->v_vfsp;
    303   2621     llai1 	if (vap)
    304   2621     llai1 		vp->v_type = vap->va_type;
    305   2621     llai1 
    306   2621     llai1 	/*
    307   2621     llai1 	 * initialized to the parent's vnodeops.
    308   2621     llai1 	 * maybe overwriten for a VDIR
    309   2621     llai1 	 */
    310   2621     llai1 	vn_setops(vp, vn_getops(SDEVTOV(ddv)));
    311   2621     llai1 	vn_exists(vp);
    312   2621     llai1 
    313   2621     llai1 	dv->sdev_dotdot = NULL;
    314   2621     llai1 	dv->sdev_attrvp = NULL;
    315   2621     llai1 	if (vap) {
    316   2621     llai1 		sdev_attrinit(dv, vap);
    317   2621     llai1 	} else {
    318   2621     llai1 		dv->sdev_attr = NULL;
    319   2621     llai1 	}
    320   2621     llai1 
    321   2621     llai1 	dv->sdev_ino = sdev_mkino(dv);
    322   2621     llai1 	dv->sdev_nlink = 0;		/* updated on insert */
    323   2621     llai1 	dv->sdev_flags = ddv->sdev_flags; /* inherit from the parent first */
    324   2621     llai1 	dv->sdev_flags |= SDEV_BUILD;
    325   2621     llai1 	mutex_init(&dv->sdev_lookup_lock, NULL, MUTEX_DEFAULT, NULL);
    326   2621     llai1 	cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL);
    327   2621     llai1 	if (SDEV_IS_GLOBAL(ddv)) {
    328   2621     llai1 		dv->sdev_flags |= SDEV_GLOBAL;
    329   2621     llai1 		dhl = &(dv->sdev_handle);
    330   2621     llai1 		dhl->dh_data = dv;
    331   2621     llai1 		dhl->dh_args = NULL;
    332  10588      Eric 		sdev_set_no_negcache(dv);
    333   2621     llai1 		dv->sdev_gdir_gen = 0;
    334   2621     llai1 	} else {
    335   2621     llai1 		dv->sdev_flags &= ~SDEV_GLOBAL;
    336   2621     llai1 		dv->sdev_origin = NULL; /* set later */
    337   2621     llai1 		bzero(&dv->sdev_prof, sizeof (dv->sdev_prof));
    338   2621     llai1 		dv->sdev_ldir_gen = 0;
    339   2621     llai1 		dv->sdev_devtree_gen = 0;
    340   2621     llai1 	}
    341   2621     llai1 
    342   2621     llai1 	rw_enter(&dv->sdev_contents, RW_WRITER);
    343   2621     llai1 	sdev_set_nodestate(dv, SDEV_INIT);
    344   2621     llai1 	rw_exit(&dv->sdev_contents);
    345   2621     llai1 	*newdv = dv;
    346   2621     llai1 
    347   2621     llai1 	return (0);
    348   2621     llai1 }
    349   2621     llai1 
    350   2621     llai1 /*
    351   2621     llai1  * transition a sdev_node into SDEV_READY state
    352   2621     llai1  */
    353   2621     llai1 int
    354   2621     llai1 sdev_nodeready(struct sdev_node *dv, struct vattr *vap, struct vnode *avp,
    355   2621     llai1     void *args, struct cred *cred)
    356   2621     llai1 {
    357   2621     llai1 	int error = 0;
    358   2621     llai1 	struct vnode *vp = SDEVTOV(dv);
    359   2621     llai1 	vtype_t type;
    360   2621     llai1 
    361   2621     llai1 	ASSERT(dv && (dv->sdev_state != SDEV_READY) && vap);
    362   2621     llai1 
    363   2621     llai1 	type = vap->va_type;
    364   2621     llai1 	vp->v_type = type;
    365   2621     llai1 	vp->v_rdev = vap->va_rdev;
    366   2621     llai1 	rw_enter(&dv->sdev_contents, RW_WRITER);
    367   2621     llai1 	if (type == VDIR) {
    368   2621     llai1 		dv->sdev_nlink = 2;
    369   2621     llai1 		dv->sdev_flags &= ~SDEV_PERSIST;
    370   2621     llai1 		dv->sdev_flags &= ~SDEV_DYNAMIC;
    371   2621     llai1 		vn_setops(vp, sdev_get_vop(dv)); /* from internal vtab */
    372   2621     llai1 		ASSERT(dv->sdev_dotdot);
    373   2621     llai1 		ASSERT(SDEVTOV(dv->sdev_dotdot)->v_type == VDIR);
    374   2621     llai1 		vp->v_rdev = SDEVTOV(dv->sdev_dotdot)->v_rdev;
    375   6260        jg 		avl_create(&dv->sdev_entries,
    376   6260        jg 		    (int (*)(const void *, const void *))sdev_compare_nodes,
    377   6260        jg 		    sizeof (struct sdev_node),
    378   6260        jg 		    offsetof(struct sdev_node, sdev_avllink));
    379   2621     llai1 	} else if (type == VLNK) {
    380   2621     llai1 		ASSERT(args);
    381   2621     llai1 		dv->sdev_nlink = 1;
    382   2621     llai1 		dv->sdev_symlink = i_ddi_strdup((char *)args, KM_SLEEP);
    383   2621     llai1 	} else {
    384   2621     llai1 		dv->sdev_nlink = 1;
    385   2621     llai1 	}
    386   2621     llai1 
    387   2621     llai1 	if (!(SDEV_IS_GLOBAL(dv))) {
    388   2621     llai1 		dv->sdev_origin = (struct sdev_node *)args;
    389   2621     llai1 		dv->sdev_flags &= ~SDEV_PERSIST;
    390   2621     llai1 	}
    391   2621     llai1 
    392   2621     llai1 	/*
    393   2621     llai1 	 * shadow node is created here OR
    394   2621     llai1 	 * if failed (indicated by dv->sdev_attrvp == NULL),
    395   2621     llai1 	 * created later in sdev_setattr
    396   2621     llai1 	 */
    397   2621     llai1 	if (avp) {
    398   2621     llai1 		dv->sdev_attrvp = avp;
    399   2621     llai1 	} else {
    400   2621     llai1 		if (dv->sdev_attr == NULL)
    401   2621     llai1 			sdev_attrinit(dv, vap);
    402   2621     llai1 		else
    403   2621     llai1 			*dv->sdev_attr = *vap;
    404   2621     llai1 
    405  10588      Eric 		if ((dv->sdev_attrvp == NULL) && SDEV_IS_PERSIST(dv))
    406   2621     llai1 			error = sdev_shadow_node(dv, cred);
    407   2621     llai1 	}
    408   2621     llai1 
    409   6335        jg 	if (error == 0) {
    410   6335        jg 		/* transition to READY state */
    411   6335        jg 		sdev_set_nodestate(dv, SDEV_READY);
    412   6335        jg 		sdev_nc_node_exists(dv);
    413   6335        jg 	} else {
    414   6335        jg 		sdev_set_nodestate(dv, SDEV_ZOMBIE);
    415   6335        jg 	}
    416   2621     llai1 	rw_exit(&dv->sdev_contents);
    417   2621     llai1 	return (error);
    418   2621     llai1 }
    419   2621     llai1 
    420   2621     llai1 /*
    421   2621     llai1  * setting ZOMBIE state
    422   2621     llai1  */
    423   2621     llai1 static int
    424   2621     llai1 sdev_nodezombied(struct sdev_node *dv)
    425   2621     llai1 {
    426   2621     llai1 	rw_enter(&dv->sdev_contents, RW_WRITER);
    427   2621     llai1 	sdev_set_nodestate(dv, SDEV_ZOMBIE);
    428   2621     llai1 	rw_exit(&dv->sdev_contents);
    429   2621     llai1 	return (0);
    430   2621     llai1 }
    431   2621     llai1 
    432   2621     llai1 /*
    433   2621     llai1  * Build the VROOT sdev_node.
    434   2621     llai1  */
    435   2621     llai1 /*ARGSUSED*/
    436   2621     llai1 struct sdev_node *
    437   2621     llai1 sdev_mkroot(struct vfs *vfsp, dev_t devdev, struct vnode *mvp,
    438   2621     llai1     struct vnode *avp, struct cred *cred)
    439   2621     llai1 {
    440   2621     llai1 	struct sdev_node *dv;
    441   2621     llai1 	struct vnode *vp;
    442   2621     llai1 	char devdir[] = "/dev";
    443   2621     llai1 
    444   2621     llai1 	ASSERT(sdev_node_cache != NULL);
    445   2621     llai1 	ASSERT(avp);
    446   2621     llai1 	dv = kmem_cache_alloc(sdev_node_cache, KM_SLEEP);
    447   2621     llai1 	vp = SDEVTOV(dv);
    448   2621     llai1 	vn_reinit(vp);
    449   2621     llai1 	vp->v_flag |= VROOT;
    450   2621     llai1 	vp->v_vfsp = vfsp;
    451   2621     llai1 	vp->v_type = VDIR;
    452   2621     llai1 	vp->v_rdev = devdev;
    453   2621     llai1 	vn_setops(vp, sdev_vnodeops); /* apply the default vnodeops at /dev */
    454   2621     llai1 	vn_exists(vp);
    455   2621     llai1 
    456   2621     llai1 	if (vfsp->vfs_mntpt)
    457   2621     llai1 		dv->sdev_name = i_ddi_strdup(
    458   2621     llai1 		    (char *)refstr_value(vfsp->vfs_mntpt), KM_SLEEP);
    459   2621     llai1 	else
    460   2621     llai1 		/* vfs_mountdev1 set mount point later */
    461   2621     llai1 		dv->sdev_name = i_ddi_strdup("/dev", KM_SLEEP);
    462   2621     llai1 	dv->sdev_namelen = strlen(dv->sdev_name); /* '\0' not included */
    463   2621     llai1 	dv->sdev_path = i_ddi_strdup(devdir, KM_SLEEP);
    464   2621     llai1 	dv->sdev_ino = SDEV_ROOTINO;
    465   2621     llai1 	dv->sdev_nlink = 2;		/* name + . (no sdev_insert) */
    466   2621     llai1 	dv->sdev_dotdot = dv;		/* .. == self */
    467   2621     llai1 	dv->sdev_attrvp = avp;
    468   2621     llai1 	dv->sdev_attr = NULL;
    469   2621     llai1 	mutex_init(&dv->sdev_lookup_lock, NULL, MUTEX_DEFAULT, NULL);
    470   2621     llai1 	cv_init(&dv->sdev_lookup_cv, NULL, CV_DEFAULT, NULL);
    471   2621     llai1 	if (strcmp(dv->sdev_name, "/dev") == 0) {
    472   2621     llai1 		dv->sdev_flags = SDEV_BUILD|SDEV_GLOBAL|SDEV_PERSIST;
    473   2621     llai1 		bzero(&dv->sdev_handle, sizeof (dv->sdev_handle));
    474   2621     llai1 		dv->sdev_gdir_gen = 0;
    475   2621     llai1 	} else {
    476   2621     llai1 		dv->sdev_flags = SDEV_BUILD;
    477   2621     llai1 		dv->sdev_flags &= ~SDEV_PERSIST;
    478   2621     llai1 		bzero(&dv->sdev_prof, sizeof (dv->sdev_prof));
    479   2621     llai1 		dv->sdev_ldir_gen = 0;
    480   2621     llai1 		dv->sdev_devtree_gen = 0;
    481   2621     llai1 	}
    482   6260        jg 
    483   6260        jg 	avl_create(&dv->sdev_entries,
    484   6260        jg 	    (int (*)(const void *, const void *))sdev_compare_nodes,
    485   6260        jg 	    sizeof (struct sdev_node),
    486   6260        jg 	    offsetof(struct sdev_node, sdev_avllink));
    487   2621     llai1 
    488   2621     llai1 	rw_enter(&dv->sdev_contents, RW_WRITER);
    489   2621     llai1 	sdev_set_nodestate(dv, SDEV_READY);
    490   2621     llai1 	rw_exit(&dv->sdev_contents);
    491   2621     llai1 	sdev_nc_node_exists(dv);
    492   2621     llai1 	return (dv);
    493   2621     llai1 }
    494   2621     llai1 
    495   2621     llai1 /* directory dependent vop table */
    496   2621     llai1 struct sdev_vop_table {
    497   2621     llai1 	char *vt_name;				/* subdirectory name */
    498   2621     llai1 	const fs_operation_def_t *vt_service;	/* vnodeops table */
    499   2621     llai1 	struct vnodeops *vt_vops;		/* constructed vop */
    500   2621     llai1 	struct vnodeops **vt_global_vops;	/* global container for vop */
    501   2621     llai1 	int (*vt_vtor)(struct sdev_node *);	/* validate sdev_node */
    502   2621     llai1 	int vt_flags;
    503   2621     llai1 };
    504   2621     llai1 
    505   2621     llai1 /*
    506   2621     llai1  * A nice improvement would be to provide a plug-in mechanism
    507   2621     llai1  * for this table instead of a const table.
    508   2621     llai1  */
    509   2621     llai1 static struct sdev_vop_table vtab[] =
    510   2621     llai1 {
    511   2621     llai1 	{ "pts", devpts_vnodeops_tbl, NULL, &devpts_vnodeops, devpts_validate,
    512   7688     Aaron 	SDEV_DYNAMIC | SDEV_VTOR },
    513   7688     Aaron 
    514   7688     Aaron 	{ "vt", devvt_vnodeops_tbl, NULL, &devvt_vnodeops, devvt_validate,
    515   2621     llai1 	SDEV_DYNAMIC | SDEV_VTOR },
    516   2621     llai1 
    517  10588      Eric 	{ "zvol", devzvol_vnodeops_tbl, NULL, &devzvol_vnodeops,
    518  10588      Eric 	devzvol_validate, SDEV_DYNAMIC | SDEV_VTOR | SDEV_SUBDIR },
    519  10588      Eric 
    520   2621     llai1 	{ "zcons", NULL, NULL, NULL, NULL, SDEV_NO_NCACHE },
    521   5895  yz147064 
    522   5895  yz147064 	{ "net", devnet_vnodeops_tbl, NULL, &devnet_vnodeops, devnet_validate,
    523   5895  yz147064 	SDEV_DYNAMIC | SDEV_VTOR },
    524   8023      Phil 
    525   8023      Phil 	{ "ipnet", devipnet_vnodeops_tbl, NULL, &devipnet_vnodeops,
    526   8023      Phil 	devipnet_validate, SDEV_DYNAMIC | SDEV_VTOR | SDEV_NO_NCACHE },
    527   2621     llai1 
    528   2621     llai1 	{ NULL, NULL, NULL, NULL, NULL, 0}
    529   2621     llai1 };
    530   2621     llai1 
    531  10588      Eric struct sdev_vop_table *
    532  10588      Eric sdev_match(struct sdev_node *dv)
    533  10588      Eric {
    534  10588      Eric 	int vlen;
    535  10588      Eric 	int i;
    536  10588      Eric 
    537  10588      Eric 	for (i = 0; vtab[i].vt_name; i++) {
    538  10588      Eric 		if (strcmp(vtab[i].vt_name, dv->sdev_name) == 0)
    539  10588      Eric 			return (&vtab[i]);
    540  10588      Eric 		if (vtab[i].vt_flags & SDEV_SUBDIR) {
    541  10588      Eric 			char *ptr;
    542  10588      Eric 
    543  10588      Eric 			ASSERT(strlen(dv->sdev_path) > 5);
    544  10588      Eric 			ptr = dv->sdev_path + 5;
    545  10588      Eric 			vlen = strlen(vtab[i].vt_name);
    546  10588      Eric 			if ((strncmp(vtab[i].vt_name, ptr,
    547  10588      Eric 			    vlen - 1) == 0) && ptr[vlen] == '/')
    548  10588      Eric 				return (&vtab[i]);
    549  10588      Eric 		}
    550  10588      Eric 
    551  10588      Eric 	}
    552  10588      Eric 	return (NULL);
    553  10588      Eric }
    554   2621     llai1 
    555   2621     llai1 /*
    556   2621     llai1  *  sets a directory's vnodeops if the directory is in the vtab;
    557   2621     llai1  */
    558   2621     llai1 static struct vnodeops *
    559   2621     llai1 sdev_get_vop(struct sdev_node *dv)
    560   2621     llai1 {
    561  10588      Eric 	struct sdev_vop_table *vtp;
    562   2621     llai1 	char *path;
    563   2621     llai1 
    564   2621     llai1 	path = dv->sdev_path;
    565   2621     llai1 	ASSERT(path);
    566   2621     llai1 
    567   2621     llai1 	/* gets the relative path to /dev/ */
    568   2621     llai1 	path += 5;
    569   2621     llai1 
    570  10588      Eric 	/* gets the vtab entry it matches */
    571  10588      Eric 	if ((vtp = sdev_match(dv)) != NULL) {
    572  10588      Eric 		dv->sdev_flags |= vtp->vt_flags;
    573   2621     llai1 
    574  10588      Eric 		if (vtp->vt_vops) {
    575  10588      Eric 			if (vtp->vt_global_vops)
    576  10588      Eric 				*(vtp->vt_global_vops) = vtp->vt_vops;
    577  10588      Eric 			return (vtp->vt_vops);
    578   2621     llai1 		}
    579   2621     llai1 
    580  10588      Eric 		if (vtp->vt_service) {
    581   2621     llai1 			fs_operation_def_t *templ;
    582  10588      Eric 			templ = sdev_merge_vtab(vtp->vt_service);
    583  10588      Eric 			if (vn_make_ops(vtp->vt_name,
    584   2621     llai1 			    (const fs_operation_def_t *)templ,
    585  10588      Eric 			    &vtp->vt_vops) != 0) {
    586   2621     llai1 				cmn_err(CE_PANIC, "%s: malformed vnode ops\n",
    587  10588      Eric 				    vtp->vt_name);
    588   2621     llai1 				/*NOTREACHED*/
    589   2621     llai1 			}
    590  10588      Eric 			if (vtp->vt_global_vops) {
    591  10588      Eric 				*(vtp->vt_global_vops) = vtp->vt_vops;
    592   2621     llai1 			}
    593   2621     llai1 			sdev_free_vtab(templ);
    594  10588      Eric 			return (vtp->vt_vops);
    595   2621     llai1 		}
    596   2621     llai1 		return (sdev_vnodeops);
    597   2621     llai1 	}
    598   2621     llai1 
    599   2621     llai1 	/* child inherits the persistence of the parent */
    600   2621     llai1 	if (SDEV_IS_PERSIST(dv->sdev_dotdot))
    601   2621     llai1 		dv->sdev_flags |= SDEV_PERSIST;
    602   2621     llai1 
    603   2621     llai1 	return (sdev_vnodeops);
    604   2621     llai1 }
    605   2621     llai1 
    606   2621     llai1 static void
    607  10588      Eric sdev_set_no_negcache(struct sdev_node *dv)
    608   2621     llai1 {
    609   2621     llai1 	int i;
    610   2621     llai1 	char *path;
    611   2621     llai1 
    612   2621     llai1 	ASSERT(dv->sdev_path);
    613   2621     llai1 	path = dv->sdev_path + strlen("/dev/");
    614   2621     llai1 
    615   2621     llai1 	for (i = 0; vtab[i].vt_name; i++) {
    616   2621     llai1 		if (strcmp(vtab[i].vt_name, path) == 0) {
    617   2621     llai1 			if (vtab[i].vt_flags & SDEV_NO_NCACHE)
    618   2621     llai1 				dv->sdev_flags |= SDEV_NO_NCACHE;
    619   2621     llai1 			break;
    620   2621     llai1 		}
    621   2621     llai1 	}
    622   2621     llai1 }
    623   2621     llai1 
    624   2621     llai1 void *
    625   2621     llai1 sdev_get_vtor(struct sdev_node *dv)
    626   2621     llai1 {
    627  10588      Eric 	struct sdev_vop_table *vtp;
    628   2621     llai1 
    629  10588      Eric 	vtp = sdev_match(dv);
    630  10588      Eric 	if (vtp)
    631  10588      Eric 		return ((void *)vtp->vt_vtor);
    632  10588      Eric 	else
    633  10588      Eric 		return (NULL);
    634   2621     llai1 }
    635   2621     llai1 
    636   2621     llai1 /*
    637   2621     llai1  * Build the base root inode
    638   2621     llai1  */
    639   2621     llai1 ino_t
    640   2621     llai1 sdev_mkino(struct sdev_node *dv)
    641   2621     llai1 {
    642   2621     llai1 	ino_t	ino;
    643   2621     llai1 
    644   2621     llai1 	/*
    645   2621     llai1 	 * for now, follow the lead of tmpfs here
    646   2621     llai1 	 * need to someday understand the requirements here
    647   2621     llai1 	 */
    648   2621     llai1 	ino = (ino_t)(uint32_t)((uintptr_t)dv >> 3);
    649   2621     llai1 	ino += SDEV_ROOTINO + 1;
    650   2621     llai1 
    651   2621     llai1 	return (ino);
    652   2621     llai1 }
    653   2621     llai1 
    654  10588      Eric int
    655   2621     llai1 sdev_getlink(struct vnode *linkvp, char **link)
    656   2621     llai1 {
    657   2621     llai1 	int err;
    658   2621     llai1 	char *buf;
    659   2621     llai1 	struct uio uio = {0};
    660   2621     llai1 	struct iovec iov = {0};
    661   2621     llai1 
    662   2621     llai1 	if (linkvp == NULL)
    663   2621     llai1 		return (ENOENT);
    664   2621     llai1 	ASSERT(linkvp->v_type == VLNK);
    665   2621     llai1 
    666   2621     llai1 	buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
    667   2621     llai1 	iov.iov_base = buf;
    668   2621     llai1 	iov.iov_len = MAXPATHLEN;
    669   2621     llai1 	uio.uio_iov = &iov;
    670   2621     llai1 	uio.uio_iovcnt = 1;
    671   2621     llai1 	uio.uio_resid = MAXPATHLEN;
    672   2621     llai1 	uio.uio_segflg = UIO_SYSSPACE;
    673   2621     llai1 	uio.uio_llimit = MAXOFFSET_T;
    674   2621     llai1 
    675   5331       amw 	err = VOP_READLINK(linkvp, &uio, kcred, NULL);
    676   2621     llai1 	if (err) {
    677   2621     llai1 		cmn_err(CE_WARN, "readlink %s failed in dev\n", buf);
    678   2621     llai1 		kmem_free(buf, MAXPATHLEN);
    679   2621     llai1 		return (ENOENT);
    680   2621     llai1 	}
    681   2621     llai1 
    682   2621     llai1 	/* mission complete */
    683   2621     llai1 	*link = i_ddi_strdup(buf, KM_SLEEP);
    684   2621     llai1 	kmem_free(buf, MAXPATHLEN);
    685   2621     llai1 	return (0);
    686   2621     llai1 }
    687   2621     llai1 
    688   2621     llai1 /*
    689   2621     llai1  * A convenient wrapper to get the devfs node vnode for a device
    690   2621     llai1  * minor functionality: readlink() of a /dev symlink
    691   2621     llai1  * Place the link into dv->sdev_symlink
    692   2621     llai1  */
    693   2621     llai1 static int
    694   2621     llai1 sdev_follow_link(struct sdev_node *dv)
    695   2621     llai1 {
    696   2621     llai1 	int err;
    697   2621     llai1 	struct vnode *linkvp;
    698   2621     llai1 	char *link = NULL;
    699   2621     llai1 
    700   2621     llai1 	linkvp = SDEVTOV(dv);
    701   2621     llai1 	if (linkvp == NULL)
    702   2621     llai1 		return (ENOENT);
    703   2621     llai1 	ASSERT(linkvp->v_type == VLNK);
    704   2621     llai1 	err = sdev_getlink(linkvp, &link);
    705   2621     llai1 	if (err) {
    706   2621     llai1 		(void) sdev_nodezombied(dv);
    707   2621     llai1 		dv->sdev_symlink = NULL;
    708   2621     llai1 		return (ENOENT);
    709   2621     llai1 	}
    710   2621     llai1 
    711   2621     llai1 	ASSERT(link != NULL);
    712   2621     llai1 	dv->sdev_symlink = link;
    713   2621     llai1 	return (0);
    714   2621     llai1 }
    715   2621     llai1 
    716   2621     llai1 static int
    717   2621     llai1 sdev_node_check(struct sdev_node *dv, struct vattr *nvap, void *nargs)
    718   2621     llai1 {
    719   2621     llai1 	vtype_t otype = SDEVTOV(dv)->v_type;
    720   2621     llai1 
    721   2621     llai1 	/*
    722   2621     llai1 	 * existing sdev_node has a different type.
    723   2621     llai1 	 */
    724   2621     llai1 	if (otype != nvap->va_type) {
    725   2621     llai1 		sdcmn_err9(("sdev_node_check: existing node "
    726   2621     llai1 		    "  %s type %d does not match new node type %d\n",
    727   2621     llai1 		    dv->sdev_name, otype, nvap->va_type));
    728   2621     llai1 		return (EEXIST);
    729   2621     llai1 	}
    730   2621     llai1 
    731   2621     llai1 	/*
    732   2621     llai1 	 * For a symlink, the target should be the same.
    733   2621     llai1 	 */
    734   2621     llai1 	if (otype == VLNK) {
    735   2621     llai1 		ASSERT(nargs != NULL);
    736   2621     llai1 		ASSERT(dv->sdev_symlink != NULL);
    737   2621     llai1 		if (strcmp(dv->sdev_symlink, (char *)nargs) != 0) {
    738   2621     llai1 			sdcmn_err9(("sdev_node_check: existing node "
    739   2621     llai1 			    " %s has different symlink %s as new node "
    740   2621     llai1 			    " %s\n", dv->sdev_name, dv->sdev_symlink,
    741   2621     llai1 			    (char *)nargs));
    742   2621     llai1 			return (EEXIST);
    743   2621     llai1 		}
    744   2621     llai1 	}
    745   2621     llai1 
    746   2621     llai1 	return (0);
    747   2621     llai1 }
    748   2621     llai1 
    749   2621     llai1 /*
    750   2621     llai1  * sdev_mknode - a wrapper for sdev_nodeinit(), sdev_nodeready()
    751   2621     llai1  *
    752   2621     llai1  * arguments:
    753   2621     llai1  *	- ddv (parent)
    754   2621     llai1  *	- nm (child name)
    755   2621     llai1  *	- newdv (sdev_node for nm is returned here)
    756   2621     llai1  *	- vap (vattr for the node to be created, va_type should be set.
    757   6335        jg  *	- avp (attribute vnode)
    758   2621     llai1  *	  the defaults should be used if unknown)
    759   2621     llai1  *	- cred
    760   2621     llai1  *	- args
    761   2621     llai1  *	    . tnm (for VLNK)
    762   2621     llai1  *	    . global sdev_node (for !SDEV_GLOBAL)
    763   2621     llai1  * 	- state: SDEV_INIT, SDEV_READY
    764   2621     llai1  *
    765   2621     llai1  * only ddv, nm, newddv, vap, cred are required for sdev_mknode(SDEV_INIT)
    766   2621     llai1  *
    767   2621     llai1  * NOTE:  directory contents writers lock needs to be held before
    768   2621     llai1  *	  calling this routine.
    769   2621     llai1  */
    770   2621     llai1 int
    771   2621     llai1 sdev_mknode(struct sdev_node *ddv, char *nm, struct sdev_node **newdv,
    772   2621     llai1     struct vattr *vap, struct vnode *avp, void *args, struct cred *cred,
    773   2621     llai1     sdev_node_state_t state)
    774   2621     llai1 {
    775   2621     llai1 	int error = 0;
    776   2621     llai1 	sdev_node_state_t node_state;
    777   2621     llai1 	struct sdev_node *dv = NULL;
    778   2621     llai1 
    779   2621     llai1 	ASSERT(state != SDEV_ZOMBIE);
    780   2621     llai1 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
    781   2621     llai1 
    782   2621     llai1 	if (*newdv) {
    783   2621     llai1 		dv = *newdv;
    784   2621     llai1 	} else {
    785   2621     llai1 		/* allocate and initialize a sdev_node */
    786   2621     llai1 		if (ddv->sdev_state == SDEV_ZOMBIE) {
    787   2621     llai1 			sdcmn_err9(("sdev_mknode: parent %s ZOMBIEd\n",
    788   2621     llai1 			    ddv->sdev_path));
    789   2621     llai1 			return (ENOENT);
    790   2621     llai1 		}
    791   2621     llai1 
    792   2621     llai1 		error = sdev_nodeinit(ddv, nm, &dv, vap);
    793   2621     llai1 		if (error != 0) {
    794   2621     llai1 			sdcmn_err9(("sdev_mknode: error %d,"
    795   2621     llai1 			    " name %s can not be initialized\n",
    796   2621     llai1 			    error, nm));
    797   6335        jg 			return (error);
    798   2621     llai1 		}
    799   2621     llai1 		ASSERT(dv);
    800   2621     llai1 
    801   2621     llai1 		/* insert into the directory cache */
    802   2621     llai1 		error = sdev_cache_update(ddv, &dv, nm, SDEV_CACHE_ADD);
    803   2621     llai1 		if (error) {
    804   2621     llai1 			sdcmn_err9(("sdev_mknode: node %s can not"
    805   2621     llai1 			    " be added into directory cache\n", nm));
    806   2621     llai1 			return (ENOENT);
    807   2621     llai1 		}
    808   2621     llai1 	}
    809   2621     llai1 
    810   2621     llai1 	ASSERT(dv);
    811   2621     llai1 	node_state = dv->sdev_state;
    812   2621     llai1 	ASSERT(node_state != SDEV_ZOMBIE);
    813   2621     llai1 
    814   2621     llai1 	if (state == SDEV_READY) {
    815   2621     llai1 		switch (node_state) {
    816   2621     llai1 		case SDEV_INIT:
    817   2621     llai1 			error = sdev_nodeready(dv, vap, avp, args, cred);
    818   2621     llai1 			if (error) {
    819   2621     llai1 				sdcmn_err9(("sdev_mknode: node %s can NOT"
    820   2621     llai1 				    " be transitioned into READY state, "
    821   2621     llai1 				    "error %d\n", nm, error));
    822   2621     llai1 			}
    823   2621     llai1 			break;
    824   2621     llai1 		case SDEV_READY:
    825   2621     llai1 			/*
    826   2621     llai1 			 * Do some sanity checking to make sure
    827   2621     llai1 			 * the existing sdev_node is what has been
    828   2621     llai1 			 * asked for.
    829   2621     llai1 			 */
    830   2621     llai1 			error = sdev_node_check(dv, vap, args);
    831   2621     llai1 			break;
    832   2621     llai1 		default:
    833   2621     llai1 			break;
    834   2621     llai1 		}
    835   2621     llai1 	}
    836   2621     llai1 
    837   2621     llai1 	if (!error) {
    838   2621     llai1 		*newdv = dv;
    839   2621     llai1 		ASSERT((*newdv)->sdev_state != SDEV_ZOMBIE);
    840   2621     llai1 	} else {
    841   2621     llai1 		SDEV_SIMPLE_RELE(dv);
    842   2621     llai1 		*newdv = NULL;
    843   2621     llai1 	}
    844   2621     llai1 
    845   2621     llai1 	return (error);
    846   2621     llai1 }
    847   2621     llai1 
    848   2621     llai1 /*
    849   6335        jg  * convenient wrapper to change vp's ATIME, CTIME and MTIME
    850   2621     llai1  */
    851   2621     llai1 void
    852   2621     llai1 sdev_update_timestamps(struct vnode *vp, cred_t *cred, uint_t mask)
    853   2621     llai1 {
    854   2621     llai1 	struct vattr attr;
    855   2621     llai1 	timestruc_t now;
    856   2621     llai1 	int err;
    857   2621     llai1 
    858   2621     llai1 	ASSERT(vp);
    859   2621     llai1 	gethrestime(&now);
    860   2621     llai1 	if (mask & AT_CTIME)
    861   2621     llai1 		attr.va_ctime = now;
    862   2621     llai1 	if (mask & AT_MTIME)
    863   2621     llai1 		attr.va_mtime = now;
    864   2621     llai1 	if (mask & AT_ATIME)
    865   2621     llai1 		attr.va_atime = now;
    866   2621     llai1 
    867   2621     llai1 	attr.va_mask = (mask & AT_TIMES);
    868   2621     llai1 	err = VOP_SETATTR(vp, &attr, 0, cred, NULL);
    869   2621     llai1 	if (err && (err != EROFS)) {
    870   2621     llai1 		sdcmn_err(("update timestamps error %d\n", err));
    871   2621     llai1 	}
    872   2621     llai1 }
    873   2621     llai1 
    874   2621     llai1 /*
    875   2621     llai1  * the backing store vnode is released here
    876   2621     llai1  */
    877   2621     llai1 /*ARGSUSED1*/
    878   2621     llai1 void
    879   2621     llai1 sdev_nodedestroy(struct sdev_node *dv, uint_t flags)
    880   2621     llai1 {
    881   2621     llai1 	/* no references */
    882   2621     llai1 	ASSERT(dv->sdev_nlink == 0);
    883   2621     llai1 
    884   2621     llai1 	if (dv->sdev_attrvp != NULLVP) {
    885   2621     llai1 		VN_RELE(dv->sdev_attrvp);
    886   2621     llai1 		/*
    887   2621     llai1 		 * reset the attrvp so that no more
    888   2621     llai1 		 * references can be made on this already
    889   2621     llai1 		 * vn_rele() vnode
    890   2621     llai1 		 */
    891   2621     llai1 		dv->sdev_attrvp = NULLVP;
    892   2621     llai1 	}
    893   2621     llai1 
    894   2621     llai1 	if (dv->sdev_attr != NULL) {
    895   2621     llai1 		kmem_free(dv->sdev_attr, sizeof (struct vattr));
    896   2621     llai1 		dv->sdev_attr = NULL;
    897   2621     llai1 	}
    898   2621     llai1 
    899   2621     llai1 	if (dv->sdev_name != NULL) {
    900   2621     llai1 		kmem_free(dv->sdev_name, dv->sdev_namelen + 1);
    901   2621     llai1 		dv->sdev_name = NULL;
    902   2621     llai1 	}
    903   2621     llai1 
    904   2621     llai1 	if (dv->sdev_symlink != NULL) {
    905   2621     llai1 		kmem_free(dv->sdev_symlink, strlen(dv->sdev_symlink) + 1);
    906   2621     llai1 		dv->sdev_symlink = NULL;
    907   2621     llai1 	}
    908   2621     llai1 
    909   2621     llai1 	if (dv->sdev_path) {
    910   2621     llai1 		kmem_free(dv->sdev_path, strlen(dv->sdev_path) + 1);
    911   2621     llai1 		dv->sdev_path = NULL;
    912   2621     llai1 	}
    913   2621     llai1 
    914   2621     llai1 	if (!SDEV_IS_GLOBAL(dv))
    915   2621     llai1 		sdev_prof_free(dv);
    916   2621     llai1 
    917   6260        jg 	if (SDEVTOV(dv)->v_type == VDIR) {
    918   6260        jg 		ASSERT(SDEV_FIRST_ENTRY(dv) == NULL);
    919   6260        jg 		avl_destroy(&dv->sdev_entries);
    920   6260        jg 	}
    921   6260        jg 
    922   2621     llai1 	mutex_destroy(&dv->sdev_lookup_lock);
    923   2621     llai1 	cv_destroy(&dv->sdev_lookup_cv);
    924   2621     llai1 
    925   2621     llai1 	/* return node to initial state as per constructor */
    926   2621     llai1 	(void) memset((void *)&dv->sdev_instance_data, 0,
    927   2621     llai1 	    sizeof (dv->sdev_instance_data));
    928   2621     llai1 	vn_invalid(SDEVTOV(dv));
    929   2621     llai1 	kmem_cache_free(sdev_node_cache, dv);
    930   2621     llai1 }
    931   2621     llai1 
    932   2621     llai1 /*
    933   2621     llai1  * DIRECTORY CACHE lookup
    934   2621     llai1  */
    935   2621     llai1 struct sdev_node *
    936   2621     llai1 sdev_findbyname(struct sdev_node *ddv, char *nm)
    937   2621     llai1 {
    938   2621     llai1 	struct sdev_node *dv;
    939   6260        jg 	struct sdev_node dvtmp;
    940   6260        jg 	avl_index_t	where;
    941   2621     llai1 
    942   2621     llai1 	ASSERT(RW_LOCK_HELD(&ddv->sdev_contents));
    943   2621     llai1 
    944   6260        jg 	dvtmp.sdev_name = nm;
    945   6260        jg 	dv = avl_find(&ddv->sdev_entries, &dvtmp, &where);
    946   6260        jg 	if (dv) {
    947   6260        jg 		ASSERT(dv->sdev_dotdot == ddv);
    948   6260        jg 		ASSERT(strcmp(dv->sdev_name, nm) == 0);
    949   6347        jg 		SDEV_HOLD(dv);
    950   6347        jg 		return (dv);
    951   2621     llai1 	}
    952   2621     llai1 	return (NULL);
    953   2621     llai1 }
    954   2621     llai1 
    955   2621     llai1 /*
    956   2621     llai1  * Inserts a new sdev_node in a parent directory
    957   2621     llai1  */
    958   2621     llai1 void
    959   2621     llai1 sdev_direnter(struct sdev_node *ddv, struct sdev_node *dv)
    960   2621     llai1 {
    961   6260        jg 	avl_index_t where;
    962   6260        jg 
    963   2621     llai1 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
    964   2621     llai1 	ASSERT(SDEVTOV(ddv)->v_type == VDIR);
    965   2621     llai1 	ASSERT(ddv->sdev_nlink >= 2);
    966   2621     llai1 	ASSERT(dv->sdev_nlink == 0);
    967   2621     llai1 
    968   2621     llai1 	dv->sdev_dotdot = ddv;
    969   6260        jg 	VERIFY(avl_find(&ddv->sdev_entries, dv, &where) == NULL);
    970   6260        jg 	avl_insert(&ddv->sdev_entries, dv, where);
    971   2621     llai1 	ddv->sdev_nlink++;
    972   2621     llai1 }
    973   2621     llai1 
    974   2621     llai1 /*
    975   2621     llai1  * The following check is needed because while sdev_nodes are linked
    976   2621     llai1  * in SDEV_INIT state, they have their link counts incremented only
    977   2621     llai1  * in SDEV_READY state.
    978   2621     llai1  */
    979   2621     llai1 static void
    980   2621     llai1 decr_link(struct sdev_node *dv)
    981   2621     llai1 {
    982   2621     llai1 	if (dv->sdev_state != SDEV_INIT)
    983   2621     llai1 		dv->sdev_nlink--;
    984   2621     llai1 	else
    985   2621     llai1 		ASSERT(dv->sdev_nlink == 0);
    986   2621     llai1 }
    987   2621     llai1 
    988   2621     llai1 /*
    989   2621     llai1  * Delete an existing dv from directory cache
    990   2621     llai1  *
    991   2621     llai1  * In the case of a node is still held by non-zero reference count,
    992   2621     llai1  *     the node is put into ZOMBIE state. Once the reference count
    993   2621     llai1  *     reaches "0", the node is unlinked and destroyed,
    994   2621     llai1  *     in sdev_inactive().
    995   2621     llai1  */
    996   2621     llai1 static int
    997   2621     llai1 sdev_dirdelete(struct sdev_node *ddv, struct sdev_node *dv)
    998   2621     llai1 {
    999   2621     llai1 	struct vnode *vp;
   1000   2621     llai1 
   1001   2621     llai1 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
   1002   2621     llai1 
   1003   2621     llai1 	vp = SDEVTOV(dv);
   1004   2621     llai1 	mutex_enter(&vp->v_lock);
   1005   2621     llai1 
   1006   2621     llai1 	/* dv is held still */
   1007   2621     llai1 	if (vp->v_count > 1) {
   1008   2621     llai1 		rw_enter(&dv->sdev_contents, RW_WRITER);
   1009   2621     llai1 		if (dv->sdev_state == SDEV_READY) {
   1010   2621     llai1 			sdcmn_err9((
   1011  10588      Eric 			    "sdev_dirdelete: node %s busy with count %d\n",
   1012   2621     llai1 			    dv->sdev_name, vp->v_count));
   1013   2621     llai1 			dv->sdev_state = SDEV_ZOMBIE;
   1014   2621     llai1 		}
   1015   2621     llai1 		rw_exit(&dv->sdev_contents);
   1016   2621     llai1 		--vp->v_count;
   1017   2621     llai1 		mutex_exit(&vp->v_lock);
   1018   2621     llai1 		return (EBUSY);
   1019   2621     llai1 	}
   1020   2621     llai1 	ASSERT(vp->v_count == 1);
   1021   2621     llai1 
   1022   2621     llai1 	/* unlink from the memory cache */
   1023   2621     llai1 	ddv->sdev_nlink--;	/* .. to above */
   1024   2621     llai1 	if (vp->v_type == VDIR) {
   1025   2621     llai1 		decr_link(dv);		/* . to self */
   1026   2621     llai1 	}
   1027   2621     llai1 
   1028   6260        jg 	avl_remove(&ddv->sdev_entries, dv);
   1029   2621     llai1 	decr_link(dv);	/* name, back to zero */
   1030   2621     llai1 	vp->v_count--;
   1031   2621     llai1 	mutex_exit(&vp->v_lock);
   1032   2621     llai1 
   1033   2621     llai1 	/* destroy the node */
   1034   2621     llai1 	sdev_nodedestroy(dv, 0);
   1035   2621     llai1 	return (0);
   1036   2621     llai1 }
   1037   2621     llai1 
   1038   2621     llai1 /*
   1039   2621     llai1  * check if the source is in the path of the target
   1040   2621     llai1  *
   1041   2621     llai1  * source and target are different
   1042   2621     llai1  */
   1043   2621     llai1 /*ARGSUSED2*/
   1044   2621     llai1 static int
   1045   2621     llai1 sdev_checkpath(struct sdev_node *sdv, struct sdev_node *tdv, struct cred *cred)
   1046   2621     llai1 {
   1047   2621     llai1 	int error = 0;
   1048   2621     llai1 	struct sdev_node *dotdot, *dir;
   1049   2621     llai1 
   1050   2621     llai1 	dotdot = tdv->sdev_dotdot;
   1051   2621     llai1 	ASSERT(dotdot);
   1052   2621     llai1 
   1053   2621     llai1 	/* fs root */
   1054   2621     llai1 	if (dotdot == tdv) {
   1055   2621     llai1 		return (0);
   1056   2621     llai1 	}
   1057   2621     llai1 
   1058   2621     llai1 	for (;;) {
   1059   2621     llai1 		/*
   1060   2621     llai1 		 * avoid error cases like
   1061   2621     llai1 		 *	mv a a/b
   1062   2621     llai1 		 *	mv a a/b/c
   1063   2621     llai1 		 *	etc.
   1064   2621     llai1 		 */
   1065   2621     llai1 		if (dotdot == sdv) {
   1066   2621     llai1 			error = EINVAL;
   1067   2621     llai1 			break;
   1068   2621     llai1 		}
   1069   2621     llai1 
   1070   2621     llai1 		dir = dotdot;
   1071   2621     llai1 		dotdot = dir->sdev_dotdot;
   1072   2621     llai1 
   1073   2621     llai1 		/* done checking because root is reached */
   1074   2621     llai1 		if (dir == dotdot) {
   1075   2621     llai1 			break;
   1076   2621     llai1 		}
   1077   2621     llai1 	}
   1078   2621     llai1 	return (error);
   1079   2621     llai1 }
   1080   2621     llai1 
   1081   2621     llai1 int
   1082   2621     llai1 sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv,
   1083   2621     llai1     struct sdev_node *nddv, struct sdev_node **ndvp, char *nnm,
   1084   2621     llai1     struct cred *cred)
   1085   2621     llai1 {
   1086   2621     llai1 	int error = 0;
   1087   2621     llai1 	struct vnode *ovp = SDEVTOV(odv);
   1088   2621     llai1 	struct vnode *nvp;
   1089   2621     llai1 	struct vattr vattr;
   1090   2621     llai1 	int doingdir = (ovp->v_type == VDIR);
   1091   2621     llai1 	char *link = NULL;
   1092   2729     llai1 	int samedir = (oddv == nddv) ? 1 : 0;
   1093   2729     llai1 	int bkstore = 0;
   1094   2729     llai1 	struct sdev_node *idv = NULL;
   1095   2729     llai1 	struct sdev_node *ndv = NULL;
   1096   2729     llai1 	timestruc_t now;
   1097   2729     llai1 
   1098   2729     llai1 	vattr.va_mask = AT_MODE|AT_UID|AT_GID;
   1099   5331       amw 	error = VOP_GETATTR(ovp, &vattr, 0, cred, NULL);
   1100   2729     llai1 	if (error)
   1101   2729     llai1 		return (error);
   1102   2729     llai1 
   1103   2729     llai1 	if (!samedir)
   1104   2729     llai1 		rw_enter(&oddv->sdev_contents, RW_WRITER);
   1105   2729     llai1 	rw_enter(&nddv->sdev_contents, RW_WRITER);
   1106   2729     llai1 
   1107   2729     llai1 	/*
   1108   2729     llai1 	 * the source may have been deleted by another thread before
   1109   2729     llai1 	 * we gets here.
   1110   2729     llai1 	 */
   1111   2729     llai1 	if (odv->sdev_state != SDEV_READY) {
   1112   2729     llai1 		error = ENOENT;
   1113   2729     llai1 		goto err_out;
   1114   2729     llai1 	}
   1115   2729     llai1 
   1116   2729     llai1 	if (doingdir && (odv == nddv)) {
   1117   2729     llai1 		error = EINVAL;
   1118   2729     llai1 		goto err_out;
   1119   2729     llai1 	}
   1120   2621     llai1 
   1121   2621     llai1 	/*
   1122   2621     llai1 	 * If renaming a directory, and the parents are different (".." must be
   1123   2621     llai1 	 * changed) then the source dir must not be in the dir hierarchy above
   1124   2621     llai1 	 * the target since it would orphan everything below the source dir.
   1125   2621     llai1 	 */
   1126   2621     llai1 	if (doingdir && (oddv != nddv)) {
   1127   2621     llai1 		error = sdev_checkpath(odv, nddv, cred);
   1128   2621     llai1 		if (error)
   1129   2729     llai1 			goto err_out;
   1130   2621     llai1 	}
   1131   2621     llai1 
   1132   2729     llai1 	/* destination existing */
   1133   2621     llai1 	if (*ndvp) {
   1134   2621     llai1 		nvp = SDEVTOV(*ndvp);
   1135   2621     llai1 		ASSERT(nvp);
   1136   2621     llai1 
   1137   2621     llai1 		/* handling renaming to itself */
   1138   2729     llai1 		if (odv == *ndvp) {
   1139   2729     llai1 			error = 0;
   1140   2729     llai1 			goto err_out;
   1141   2729     llai1 		}
   1142   2621     llai1 
   1143   2729     llai1 		if (nvp->v_type == VDIR) {
   1144   2729     llai1 			if (!doingdir) {
   1145   2729     llai1 				error = EISDIR;
   1146   2729     llai1 				goto err_out;
   1147   2729     llai1 			}
   1148   2729     llai1 
   1149   2729     llai1 			if (vn_vfswlock(nvp)) {
   1150   2729     llai1 				error = EBUSY;
   1151   2729     llai1 				goto err_out;
   1152   2729     llai1 			}
   1153   2729     llai1 
   1154   2729     llai1 			if (vn_mountedvfs(nvp) != NULL) {
   1155   2729     llai1 				vn_vfsunlock(nvp);
   1156   2729     llai1 				error = EBUSY;
   1157   2729     llai1 				goto err_out;
   1158   2729     llai1 			}
   1159   2729     llai1 
   1160   2729     llai1 			/* in case dir1 exists in dir2 and "mv dir1 dir2" */
   1161   2729     llai1 			if ((*ndvp)->sdev_nlink > 2) {
   1162   2729     llai1 				vn_vfsunlock(nvp);
   1163   2729     llai1 				error = EEXIST;
   1164   2729     llai1 				goto err_out;
   1165   2729     llai1 			}
   1166   2729     llai1 			vn_vfsunlock(nvp);
   1167   2729     llai1 
   1168   2729     llai1 			(void) sdev_dirdelete(nddv, *ndvp);
   1169   2729     llai1 			*ndvp = NULL;
   1170   6335        jg 			ASSERT(nddv->sdev_attrvp);
   1171   2729     llai1 			error = VOP_RMDIR(nddv->sdev_attrvp, nnm,
   1172   6065       cth 			    nddv->sdev_attrvp, cred, NULL, 0);
   1173   2729     llai1 			if (error)
   1174   2729     llai1 				goto err_out;
   1175   2729     llai1 		} else {
   1176   2729     llai1 			if (doingdir) {
   1177   2729     llai1 				error = ENOTDIR;
   1178   2729     llai1 				goto err_out;
   1179   2729     llai1 			}
   1180   2729     llai1 
   1181   2729     llai1 			if (SDEV_IS_PERSIST((*ndvp))) {
   1182   2729     llai1 				bkstore = 1;
   1183   2729     llai1 			}
   1184   2621     llai1 
   1185   2621     llai1 			/*
   1186   2729     llai1 			 * get rid of the node from the directory cache
   1187   2729     llai1 			 * note, in case EBUSY is returned, the ZOMBIE
   1188   2729     llai1 			 * node is taken care in sdev_mknode.
   1189   2621     llai1 			 */
   1190   2729     llai1 			(void) sdev_dirdelete(nddv, *ndvp);
   1191   2729     llai1 			*ndvp = NULL;
   1192   2729     llai1 			if (bkstore) {
   1193   6335        jg 				ASSERT(nddv->sdev_attrvp);
   1194   2729     llai1 				error = VOP_REMOVE(nddv->sdev_attrvp,
   1195   5331       amw 				    nnm, cred, NULL, 0);
   1196   2729     llai1 				if (error)
   1197   6065       cth 					goto err_out;
   1198   2621     llai1 			}
   1199   2621     llai1 		}
   1200   2621     llai1 	}
   1201   2621     llai1 
   1202   2621     llai1 	/* fix the source for a symlink */
   1203   2621     llai1 	if (vattr.va_type == VLNK) {
   1204   2621     llai1 		if (odv->sdev_symlink == NULL) {
   1205   2621     llai1 			error = sdev_follow_link(odv);
   1206   2729     llai1 			if (error) {
   1207   2729     llai1 				error = ENOENT;
   1208   2729     llai1 				goto err_out;
   1209   2729     llai1 			}
   1210   2621     llai1 		}
   1211   2621     llai1 		ASSERT(odv->sdev_symlink);
   1212   2621     llai1 		link = i_ddi_strdup(odv->sdev_symlink, KM_SLEEP);
   1213   2621     llai1 	}
   1214   2621     llai1 
   1215   2729     llai1 	/*
   1216   2729     llai1 	 * make a fresh node from the source attrs
   1217   2729     llai1 	 */
   1218   2729     llai1 	ASSERT(RW_WRITE_HELD(&nddv->sdev_contents));
   1219   2729     llai1 	error = sdev_mknode(nddv, nnm, ndvp, &vattr,
   1220   2729     llai1 	    NULL, (void *)link, cred, SDEV_READY);
   1221   2621     llai1 
   1222   2621     llai1 	if (link)
   1223   2621     llai1 		kmem_free(link, strlen(link) + 1);
   1224   2621     llai1 
   1225   2729     llai1 	if (error)
   1226   2729     llai1 		goto err_out;
   1227   2729     llai1 	ASSERT(*ndvp);
   1228   2729     llai1 	ASSERT((*ndvp)->sdev_state == SDEV_READY);
   1229   2729     llai1 
   1230   2729     llai1 	/* move dir contents */
   1231   2729     llai1 	if (doingdir) {
   1232   6260        jg 		for (idv = SDEV_FIRST_ENTRY(odv); idv;
   1233   6260        jg 		    idv = SDEV_NEXT_ENTRY(odv, idv)) {
   1234   2729     llai1 			error = sdev_rnmnode(odv, idv,
   1235   2729     llai1 			    (struct sdev_node *)(*ndvp), &ndv,
   1236   2729     llai1 			    idv->sdev_name, cred);
   1237   2729     llai1 			if (error)
   1238   2729     llai1 				goto err_out;
   1239   2729     llai1 			ndv = NULL;
   1240   2729     llai1 		}
   1241   2729     llai1 	}
   1242   2729     llai1 
   1243   2729     llai1 	if ((*ndvp)->sdev_attrvp) {
   1244   2729     llai1 		sdev_update_timestamps((*ndvp)->sdev_attrvp, kcred,
   1245   2729     llai1 		    AT_CTIME|AT_ATIME);
   1246   2729     llai1 	} else {
   1247   2729     llai1 		ASSERT((*ndvp)->sdev_attr);
   1248   2729     llai1 		gethrestime(&now);
   1249   2729     llai1 		(*ndvp)->sdev_attr->va_ctime = now;
   1250   2729     llai1 		(*ndvp)->sdev_attr->va_atime = now;
   1251   2729     llai1 	}
   1252   2729     llai1 
   1253   2729     llai1 	if (nddv->sdev_attrvp) {
   1254   2729     llai1 		sdev_update_timestamps(nddv->sdev_attrvp, kcred,
   1255   2729     llai1 		    AT_MTIME|AT_ATIME);
   1256   2729     llai1 	} else {
   1257   2729     llai1 		ASSERT(nddv->sdev_attr);
   1258   2729     llai1 		gethrestime(&now);
   1259   2729     llai1 		nddv->sdev_attr->va_mtime = now;
   1260   2729     llai1 		nddv->sdev_attr->va_atime = now;
   1261   2729     llai1 	}
   1262   2729     llai1 	rw_exit(&nddv->sdev_contents);
   1263   2729     llai1 	if (!samedir)
   1264   2729     llai1 		rw_exit(&oddv->sdev_contents);
   1265   2729     llai1 
   1266   2621     llai1 	SDEV_RELE(*ndvp);
   1267   2729     llai1 	return (error);
   1268   2729     llai1 
   1269   2729     llai1 err_out:
   1270   2729     llai1 	rw_exit(&nddv->sdev_contents);
   1271   2729     llai1 	if (!samedir)
   1272   2729     llai1 		rw_exit(&oddv->sdev_contents);
   1273   2729     llai1 	return (error);
   1274   2621     llai1 }
   1275   2621     llai1 
   1276   2621     llai1 /*
   1277   2621     llai1  * Merge sdev_node specific information into an attribute structure.
   1278   2621     llai1  *
   1279   2621     llai1  * note: sdev_node is not locked here
   1280   2621     llai1  */
   1281   2621     llai1 void
   1282   2621     llai1 sdev_vattr_merge(struct sdev_node *dv, struct vattr *vap)
   1283   2621     llai1 {
   1284   2621     llai1 	struct vnode *vp = SDEVTOV(dv);
   1285   2621     llai1 
   1286   2621     llai1 	vap->va_nlink = dv->sdev_nlink;
   1287   2621     llai1 	vap->va_nodeid = dv->sdev_ino;
   1288   2621     llai1 	vap->va_fsid = SDEVTOV(dv->sdev_dotdot)->v_rdev;
   1289   2621     llai1 	vap->va_type = vp->v_type;
   1290   2621     llai1 
   1291   2621     llai1 	if (vp->v_type == VDIR) {
   1292   2621     llai1 		vap->va_rdev = 0;
   1293   2621     llai1 		vap->va_fsid = vp->v_rdev;
   1294   2621     llai1 	} else if (vp->v_type == VLNK) {
   1295   2621     llai1 		vap->va_rdev = 0;
   1296   2621     llai1 		vap->va_mode  &= ~S_IFMT;
   1297   2621     llai1 		vap->va_mode |= S_IFLNK;
   1298   2621     llai1 	} else if ((vp->v_type == VCHR) || (vp->v_type == VBLK)) {
   1299   2621     llai1 		vap->va_rdev = vp->v_rdev;
   1300   2621     llai1 		vap->va_mode &= ~S_IFMT;
   1301   2621     llai1 		if (vap->va_type == VCHR)
   1302   2621     llai1 			vap->va_mode |= S_IFCHR;
   1303   2621     llai1 		else
   1304   2621     llai1 			vap->va_mode |= S_IFBLK;
   1305   2621     llai1 	} else {
   1306   2621     llai1 		vap->va_rdev = 0;
   1307   2621     llai1 	}
   1308   2621     llai1 }
   1309   2621     llai1 
   1310  10588      Eric struct vattr *
   1311   2621     llai1 sdev_getdefault_attr(enum vtype type)
   1312   2621     llai1 {
   1313   2621     llai1 	if (type == VDIR)
   1314   2621     llai1 		return (&sdev_vattr_dir);
   1315   2621     llai1 	else if (type == VCHR)
   1316   2621     llai1 		return (&sdev_vattr_chr);
   1317   2621     llai1 	else if (type == VBLK)
   1318   2621     llai1 		return (&sdev_vattr_blk);
   1319   2621     llai1 	else if (type == VLNK)
   1320   2621     llai1 		return (&sdev_vattr_lnk);
   1321   2621     llai1 	else
   1322   2621     llai1 		return (NULL);
   1323   2621     llai1 }
   1324   2621     llai1 int
   1325   2621     llai1 sdev_to_vp(struct sdev_node *dv, struct vnode **vpp)
   1326   2621     llai1 {
   1327   2621     llai1 	int rv = 0;
   1328   2621     llai1 	struct vnode *vp = SDEVTOV(dv);
   1329   2621     llai1 
   1330   2621     llai1 	switch (vp->v_type) {
   1331   2621     llai1 	case VCHR:
   1332   2621     llai1 	case VBLK:
   1333   2621     llai1 		/*
   1334   2621     llai1 		 * If vnode is a device, return special vnode instead
   1335   2621     llai1 		 * (though it knows all about -us- via sp->s_realvp)
   1336   2621     llai1 		 */
   1337   2621     llai1 		*vpp = specvp(vp, vp->v_rdev, vp->v_type, kcred);
   1338   2621     llai1 		VN_RELE(vp);
   1339   2621     llai1 		if (*vpp == NULLVP)
   1340   2621     llai1 			rv = ENOSYS;
   1341   2621     llai1 		break;
   1342   2621     llai1 	default:	/* most types are returned as is */
   1343   2621     llai1 		*vpp = vp;
   1344   2621     llai1 		break;
   1345   2621     llai1 	}
   1346   2621     llai1 	return (rv);
   1347   2621     llai1 }
   1348   2621     llai1 
   1349   2621     llai1 /*
   1350   2621     llai1  * junction between devname and root file system, e.g. ufs
   1351   2621     llai1  */
   1352   2621     llai1 int
   1353   2621     llai1 devname_backstore_lookup(struct sdev_node *ddv, char *nm, struct vnode **rvp)
   1354   2621     llai1 {
   1355   2621     llai1 	struct vnode *rdvp = ddv->sdev_attrvp;
   1356   2621     llai1 	int rval = 0;
   1357   2621     llai1 
   1358   2621     llai1 	ASSERT(rdvp);
   1359   2621     llai1 
   1360   5331       amw 	rval = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, kcred, NULL, NULL,
   1361   5331       amw 	    NULL);
   1362   2621     llai1 	return (rval);
   1363   2621     llai1 }
   1364   2621     llai1 
   1365   2621     llai1 static int
   1366   2621     llai1 sdev_filldir_from_store(struct sdev_node *ddv, int dlen, struct cred *cred)
   1367   2621     llai1 {
   1368   2621     llai1 	struct sdev_node *dv = NULL;
   1369   2621     llai1 	char	*nm;
   1370   2621     llai1 	struct vnode *dirvp;
   1371   2621     llai1 	int	error;
   1372   2621     llai1 	vnode_t	*vp;
   1373   2621     llai1 	int eof;
   1374   2621     llai1 	struct iovec iov;
   1375   2621     llai1 	struct uio uio;
   1376   2621     llai1 	struct dirent64 *dp;
   1377   2621     llai1 	dirent64_t *dbuf;
   1378   2621     llai1 	size_t dbuflen;
   1379   2621     llai1 	struct vattr vattr;
   1380   2621     llai1 	char *link = NULL;
   1381   2621     llai1 
   1382   2621     llai1 	if (ddv->sdev_attrvp == NULL)
   1383   2621     llai1 		return (0);
   1384   2621     llai1 	if (!(ddv->sdev_flags & SDEV_BUILD))
   1385   2621     llai1 		return (0);
   1386   2621     llai1 
   1387   2621     llai1 	dirvp = ddv->sdev_attrvp;
   1388   2621     llai1 	VN_HOLD(dirvp);
   1389   2621     llai1 	dbuf = kmem_zalloc(dlen, KM_SLEEP);
   1390   2621     llai1 
   1391   2621     llai1 	uio.uio_iov = &iov;
   1392   2621     llai1 	uio.uio_iovcnt = 1;
   1393   2621     llai1 	uio.uio_segflg = UIO_SYSSPACE;
   1394   2621     llai1 	uio.uio_fmode = 0;
   1395   2621     llai1 	uio.uio_extflg = UIO_COPY_CACHED;
   1396   2621     llai1 	uio.uio_loffset = 0;
   1397   2621     llai1 	uio.uio_llimit = MAXOFFSET_T;
   1398   2621     llai1 
   1399   2621     llai1 	eof = 0;
   1400   2621     llai1 	error = 0;
   1401   2621     llai1 	while (!error && !eof) {
   1402   2621     llai1 		uio.uio_resid = dlen;
   1403   2621     llai1 		iov.iov_base = (char *)dbuf;
   1404   2621     llai1 		iov.iov_len = dlen;
   1405   2621     llai1 		(void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
   1406   5331       amw 		error = VOP_READDIR(dirvp, &uio, kcred, &eof, NULL, 0);
   1407   2621     llai1 		VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
   1408   2621     llai1 
   1409   2621     llai1 		dbuflen = dlen - uio.uio_resid;
   1410   2621     llai1 		if (error || dbuflen == 0)
   1411   2621     llai1 			break;
   1412   2621     llai1 
   1413  10588      Eric 		if (!(ddv->sdev_flags & SDEV_BUILD))
   1414   2621     llai1 			break;
   1415   2621     llai1 
   1416   2621     llai1 		for (dp = dbuf; ((intptr_t)dp <
   1417   2621     llai1 		    (intptr_t)dbuf + dbuflen);
   1418   2621     llai1 		    dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) {
   1419   2621     llai1 			nm = dp->d_name;
   1420   2621     llai1 
   1421   2621     llai1 			if (strcmp(nm, ".") == 0 ||
   1422   2621     llai1 			    strcmp(nm, "..") == 0)
   1423   2621     llai1 				continue;
   1424   2621     llai1 
   1425   2621     llai1 			vp = NULLVP;
   1426   2621     llai1 			dv = sdev_cache_lookup(ddv, nm);
   1427   2621     llai1 			if (dv) {
   1428   2621     llai1 				if (dv->sdev_state != SDEV_ZOMBIE) {
   1429   2621     llai1 					SDEV_SIMPLE_RELE(dv);
   1430   2621     llai1 				} else {
   1431   2621     llai1 					/*
   1432   2621     llai1 					 * A ZOMBIE node may not have been
   1433   2621     llai1 					 * cleaned up from the backing store,
   1434   2621     llai1 					 * bypass this entry in this case,
   1435   2621     llai1 					 * and clean it up from the directory
   1436   2621     llai1 					 * cache if this is the last call.
   1437   2621     llai1 					 */
   1438   2621     llai1 					(void) sdev_dirdelete(ddv, dv);
   1439   2621     llai1 				}
   1440   2621     llai1 				continue;
   1441   2621     llai1 			}
   1442   2621     llai1 
   1443   2621     llai1 			/* refill the cache if not already */
   1444   2621     llai1 			error = devname_backstore_lookup(ddv, nm, &vp);
   1445   2621     llai1 			if (error)
   1446   2621     llai1 				continue;
   1447   2621     llai1 
   1448   2621     llai1 			vattr.va_mask = AT_MODE|AT_UID|AT_GID;
   1449   5331       amw 			error = VOP_GETATTR(vp, &vattr, 0, cred, NULL);
   1450   2621     llai1 			if (error)
   1451   2621     llai1 				continue;
   1452   2621     llai1 
   1453   2621     llai1 			if (vattr.va_type == VLNK) {
   1454   2621     llai1 				error = sdev_getlink(vp, &link);
   1455   2621     llai1 				if (error) {
   1456   2621     llai1 					continue;
   1457   2621     llai1 				}
   1458   2621     llai1 				ASSERT(link != NULL);
   1459   2621     llai1 			}
   1460   2621     llai1 
   1461   2621     llai1 			if (!rw_tryupgrade(&ddv->sdev_contents)) {
   1462   2621     llai1 				rw_exit(&ddv->sdev_contents);
   1463   2621     llai1 				rw_enter(&ddv->sdev_contents, RW_WRITER);
   1464   2621     llai1 			}
   1465   2621     llai1 			error = sdev_mknode(ddv, nm, &dv, &vattr, vp, link,
   1466   2621     llai1 			    cred, SDEV_READY);
   1467   2621     llai1 			rw_downgrade(&ddv->sdev_contents);
   1468   2621     llai1 
   1469   2621     llai1 			if (link != NULL) {
   1470   2621     llai1 				kmem_free(link, strlen(link) + 1);
   1471   2621     llai1 				link = NULL;
   1472   2621     llai1 			}
   1473   2621     llai1 
   1474   2621     llai1 			if (!error) {
   1475   2621     llai1 				ASSERT(dv);
   1476   2621     llai1 				ASSERT(dv->sdev_state != SDEV_ZOMBIE);
   1477   2621     llai1 				SDEV_SIMPLE_RELE(dv);
   1478   2621     llai1 			}
   1479   2621     llai1 			vp = NULL;
   1480   2621     llai1 			dv = NULL;
   1481   2621     llai1 		}
   1482   2621     llai1 	}
   1483   2621     llai1 
   1484   2621     llai1 done:
   1485   2621     llai1 	VN_RELE(dirvp);
   1486   2621     llai1 	kmem_free(dbuf, dlen);
   1487   2621     llai1 
   1488   2621     llai1 	return (error);
   1489   2621     llai1 }
   1490   2621     llai1 
   1491   3843        jg void
   1492   2621     llai1 sdev_filldir_dynamic(struct sdev_node *ddv)
   1493   2621     llai1 {
   1494   2621     llai1 	int error;
   1495   2621     llai1 	int i;
   1496   2621     llai1 	struct vattr *vap;
   1497   2621     llai1 	char *nm = NULL;
   1498   2621     llai1 	struct sdev_node *dv = NULL;
   1499   2621     llai1 
   1500   3843        jg 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
   1501   3843        jg 	ASSERT((ddv->sdev_flags & SDEV_BUILD));
   1502   2621     llai1 
   1503   2621     llai1 	vap = sdev_getdefault_attr(VDIR);
   1504  10588      Eric 	gethrestime(&vap->va_atime);
   1505  10588      Eric 	vap->va_mtime = vap->va_atime;
   1506  10588      Eric 	vap->va_ctime = vap->va_atime;
   1507   2621     llai1 	for (i = 0; vtab[i].vt_name != NULL; i++) {
   1508   2621     llai1 		nm = vtab[i].vt_name;
   1509   2621     llai1 		ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
   1510   3843        jg 		dv = NULL;
   1511   2621     llai1 		error = sdev_mknode(ddv, nm, &dv, vap, NULL,
   1512   2621     llai1 		    NULL, kcred, SDEV_READY);
   1513   3843        jg 		if (error) {
   1514   3843        jg 			cmn_err(CE_WARN, "%s/%s: error %d\n",
   1515   3843        jg 			    ddv->sdev_name, nm, error);
   1516   3843        jg 		} else {
   1517   3843        jg 			ASSERT(dv);
   1518   3843        jg 			ASSERT(dv->sdev_state != SDEV_ZOMBIE);
   1519   3843        jg 			SDEV_SIMPLE_RELE(dv);
   1520   3843        jg 		}
   1521   2621     llai1 	}
   1522   2621     llai1 }
   1523   2621     llai1 
   1524   2621     llai1 /*
   1525   2621     llai1  * Creating a backing store entry based on sdev_attr.
   1526   2621     llai1  * This is called either as part of node creation in a persistent directory
   1527   2621     llai1  * or from setattr/setsecattr to persist access attributes across reboot.
   1528   2621     llai1  */
   1529   2621     llai1 int
   1530   2621     llai1 sdev_shadow_node(struct sdev_node *dv, struct cred *cred)
   1531   2621     llai1 {
   1532   2621     llai1 	int error = 0;
   1533   2621     llai1 	struct vnode *dvp = SDEVTOV(dv->sdev_dotdot);
   1534   2621     llai1 	struct vnode *rdvp = VTOSDEV(dvp)->sdev_attrvp;
   1535   2621     llai1 	struct vattr *vap = dv->sdev_attr;
   1536   2621     llai1 	char *nm = dv->sdev_name;
   1537   2621     llai1 	struct vnode *tmpvp, **rvp = &tmpvp, *rrvp = NULL;
   1538   2621     llai1 
   1539   2621     llai1 	ASSERT(dv && dv->sdev_name && rdvp);
   1540   2621     llai1 	ASSERT(RW_WRITE_HELD(&dv->sdev_contents) && dv->sdev_attrvp == NULL);
   1541   2621     llai1 
   1542   2621     llai1 lookup:
   1543   2621     llai1 	/* try to find it in the backing store */
   1544   5331       amw 	error = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, cred, NULL, NULL,
   1545   5331       amw 	    NULL);
   1546   2621     llai1 	if (error == 0) {
   1547   5331       amw 		if (VOP_REALVP(*rvp, &rrvp, NULL) == 0) {
   1548   2621     llai1 			VN_HOLD(rrvp);
   1549   2621     llai1 			VN_RELE(*rvp);
   1550   2621     llai1 			*rvp = rrvp;
   1551   2621     llai1 		}
   1552   2621     llai1 
   1553   2621     llai1 		kmem_free(dv->sdev_attr, sizeof (vattr_t));
   1554   2621     llai1 		dv->sdev_attr = NULL;
   1555   2621     llai1 		dv->sdev_attrvp = *rvp;
   1556   2621     llai1 		return (0);
   1557   2621     llai1 	}
   1558   2621     llai1 
   1559   2621     llai1 	/* let's try to persist the node */
   1560   2621     llai1 	gethrestime(&vap->va_atime);
   1561   2621     llai1 	vap->va_mtime = vap->va_atime;
   1562   2621     llai1 	vap->va_ctime = vap->va_atime;
   1563   2621     llai1 	vap->va_mask |= AT_TYPE|AT_MODE;
   1564   2621     llai1 	switch (vap->va_type) {
   1565   2621     llai1 	case VDIR:
   1566   5331       amw 		error = VOP_MKDIR(rdvp, nm, vap, rvp, cred, NULL, 0, NULL);
   1567   2621     llai1 		sdcmn_err9(("sdev_shadow_node: mkdir vp %p error %d\n",
   1568   2621     llai1 		    (void *)(*rvp), error));
   1569   2621     llai1 		break;
   1570   2621     llai1 	case VCHR:
   1571   2621     llai1 	case VBLK:
   1572   2621     llai1 	case VREG:
   1573   2621     llai1 	case VDOOR:
   1574   2621     llai1 		error = VOP_CREATE(rdvp, nm, vap, NONEXCL, VREAD|VWRITE,
   1575   5331       amw 		    rvp, cred, 0, NULL, NULL);
   1576   2621     llai1 		sdcmn_err9(("sdev_shadow_node: create vp %p, error %d\n",
   1577   2621     llai1 		    (void *)(*rvp), error));
   1578   2621     llai1 		if (!error)
   1579   2621     llai1 			VN_RELE(*rvp);
   1580   2621     llai1 		break;
   1581   2621     llai1 	case VLNK:
   1582   2621     llai1 		ASSERT(dv->sdev_symlink);
   1583   5331       amw 		error = VOP_SYMLINK(rdvp, nm, vap, dv->sdev_symlink, cred,
   1584   5331       amw 		    NULL, 0);
   1585   2621     llai1 		sdcmn_err9(("sdev_shadow_node: create symlink error %d\n",
   1586   2621     llai1 		    error));
   1587   2621     llai1 		break;
   1588   2621     llai1 	default:
   1589   2621     llai1 		cmn_err(CE_PANIC, "dev: %s: sdev_shadow_node "
   1590   2621     llai1 		    "create\n", nm);
   1591   2621     llai1 		/*NOTREACHED*/
   1592   2621     llai1 	}
   1593   2621     llai1 
   1594   2621     llai1 	/* go back to lookup to factor out spec node and set attrvp */
   1595   2621     llai1 	if (error == 0)
   1596   2621     llai1 		goto lookup;
   1597   2621     llai1 
   1598   6335        jg 	sdcmn_err(("cannot persist %s - error %d\n", dv->sdev_path, error));
   1599   2621     llai1 	return (error);
   1600   2621     llai1 }
   1601   2621     llai1 
   1602   2621     llai1 static int
   1603   2621     llai1 sdev_cache_add(struct sdev_node *ddv, struct sdev_node **dv, char *nm)
   1604   2621     llai1 {
   1605   2621     llai1 	int error = 0;
   1606   2621     llai1 	struct sdev_node *dup = NULL;
   1607   2621     llai1 
   1608   2621     llai1 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
   1609   2621     llai1 	if ((dup = sdev_findbyname(ddv, nm)) == NULL) {
   1610   2621     llai1 		sdev_direnter(ddv, *dv);
   1611   2621     llai1 	} else {
   1612   2621     llai1 		if (dup->sdev_state == SDEV_ZOMBIE) {
   1613   2621     llai1 			error = sdev_dirdelete(ddv, dup);
   1614   2621     llai1 			/*
   1615   2621     llai1 			 * The ZOMBIE node is still hanging
   1616   2621     llai1 			 * around with more than one reference counts.
   1617   2621     llai1 			 * Fail the new node creation so that
   1618   2621     llai1 			 * the directory cache won't have
   1619   2621     llai1 			 * duplicate entries for the same named node
   1620   2621     llai1 			 */
   1621   2621     llai1 			if (error == EBUSY) {
   1622   2621     llai1 				SDEV_SIMPLE_RELE(*dv);
   1623   2621     llai1 				sdev_nodedestroy(*dv, 0);
   1624   2621     llai1 				*dv = NULL;
   1625   2621     llai1 				return (error);
   1626   2621     llai1 			}
   1627   2621     llai1 			sdev_direnter(ddv, *dv);
   1628   2621     llai1 		} else {
   1629   2621     llai1 			ASSERT((*dv)->sdev_state != SDEV_ZOMBIE);
   1630   2621     llai1 			SDEV_SIMPLE_RELE(*dv);
   1631   2621     llai1 			sdev_nodedestroy(*dv, 0);
   1632   2621     llai1 			*dv = dup;
   1633   2621     llai1 		}
   1634   2621     llai1 	}
   1635   2621     llai1 
   1636   2621     llai1 	return (0);
   1637   2621     llai1 }
   1638   2621     llai1 
   1639   2621     llai1 static int
   1640   2621     llai1 sdev_cache_delete(struct sdev_node *ddv, struct sdev_node **dv)
   1641   2621     llai1 {
   1642   2621     llai1 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
   1643   2621     llai1 	return (sdev_dirdelete(ddv, *dv));
   1644   2621     llai1 }
   1645   2621     llai1 
   1646   2621     llai1 /*
   1647   2621     llai1  * update the in-core directory cache
   1648   2621     llai1  */
   1649   2621     llai1 int
   1650   2621     llai1 sdev_cache_update(struct sdev_node *ddv, struct sdev_node **dv, char *nm,
   1651   2621     llai1     sdev_cache_ops_t ops)
   1652   2621     llai1 {
   1653   2621     llai1 	int error = 0;
   1654   2621     llai1 
   1655   2621     llai1 	ASSERT((SDEV_HELD(*dv)));
   1656   2621     llai1 
   1657   2621     llai1 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
   1658   2621     llai1 	switch (ops) {
   1659   2621     llai1 	case SDEV_CACHE_ADD:
   1660   2621     llai1 		error = sdev_cache_add(ddv, dv, nm);
   1661   2621     llai1 		break;
   1662   2621     llai1 	case SDEV_CACHE_DELETE:
   1663   2621     llai1 		error = sdev_cache_delete(ddv, dv);
   1664   2621     llai1 		break;
   1665   2621     llai1 	default:
   1666   2621     llai1 		break;
   1667   2621     llai1 	}
   1668   2621     llai1 
   1669   2621     llai1 	return (error);
   1670   2621     llai1 }
   1671   2621     llai1 
   1672   2621     llai1 /*
   1673   5331       amw  * retrieve the named entry from the directory cache
   1674   2621     llai1  */
   1675   2621     llai1 struct sdev_node *
   1676   2621     llai1 sdev_cache_lookup(struct sdev_node *ddv, char *nm)
   1677   2621     llai1 {
   1678   2621     llai1 	struct sdev_node *dv = NULL;
   1679   2621     llai1 
   1680   2621     llai1 	ASSERT(RW_LOCK_HELD(&ddv->sdev_contents));
   1681   2621     llai1 	dv = sdev_findbyname(ddv, nm);
   1682   2621     llai1 
   1683   2621     llai1 	return (dv);
   1684   2621     llai1 }
   1685   2621     llai1 
   1686   2621     llai1 /*
   1687   2621     llai1  * Implicit reconfig for nodes constructed by a link generator
   1688   2621     llai1  * Start devfsadm if needed, or if devfsadm is in progress,
   1689   2621     llai1  * prepare to block on devfsadm either completing or
   1690   2621     llai1  * constructing the desired node.  As devfsadmd is global
   1691   2621     llai1  * in scope, constructing all necessary nodes, we only
   1692   2621     llai1  * need to initiate it once.
   1693   2621     llai1  */
   1694   2621     llai1 static int
   1695   2621     llai1 sdev_call_devfsadmd(struct sdev_node *ddv, struct sdev_node *dv, char *nm)
   1696   2621     llai1 {
   1697   2621     llai1 	int error = 0;
   1698   2621     llai1 
   1699   2621     llai1 	if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state)) {
   1700   2621     llai1 		sdcmn_err6(("lookup: waiting for %s/%s, 0x%x\n",
   1701   2621     llai1 		    ddv->sdev_name, nm, devfsadm_state));
   1702   2621     llai1 		mutex_enter(&dv->sdev_lookup_lock);
   1703   2621     llai1 		SDEV_BLOCK_OTHERS(dv, (SDEV_LOOKUP | SDEV_LGWAITING));
   1704   2621     llai1 		mutex_exit(&dv->sdev_lookup_lock);
   1705   2621     llai1 		error = 0;
   1706   2621     llai1 	} else if (!DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state)) {
   1707   2621     llai1 		sdcmn_err6(("lookup %s/%s starting devfsadm, 0x%x\n",
   1708   6065       cth 		    ddv->sdev_name, nm, devfsadm_state));
   1709   2621     llai1 
   1710   2621     llai1 		sdev_devfsadmd_thread(ddv, dv, kcred);
   1711   2621     llai1 		mutex_enter(&dv->sdev_lookup_lock);
   1712   2621     llai1 		SDEV_BLOCK_OTHERS(dv,
   1713   2621     llai1 		    (SDEV_LOOKUP | SDEV_LGWAITING));
   1714   2621     llai1 		mutex_exit(&dv->sdev_lookup_lock);
   1715   2621     llai1 		error = 0;
   1716   2621     llai1 	} else {
   1717   2621     llai1 		error = -1;
   1718   2621     llai1 	}
   1719   2621     llai1 
   1720   2621     llai1 	return (error);
   1721   2621     llai1 }
   1722   2621     llai1 
   1723   2621     llai1 /*
   1724   2621     llai1  *  Support for specialized device naming construction mechanisms
   1725   2621     llai1  */
   1726   2621     llai1 static int
   1727   2621     llai1 sdev_call_dircallback(struct sdev_node *ddv, struct sdev_node **dvp, char *nm,
   1728   2621     llai1     int (*callback)(struct sdev_node *, char *, void **, struct cred *,
   1729   2621     llai1     void *, char *), int flags, struct cred *cred)
   1730   2621     llai1 {
   1731   2621     llai1 	int rv = 0;
   1732   2621     llai1 	char *physpath = NULL;
   1733   2621     llai1 	struct vattr vattr;
   1734   2621     llai1 	struct vattr *vap;
   1735  10588      Eric 	struct sdev_node *dv = NULL;
   1736   2621     llai1 
   1737  10588      Eric 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
   1738  10588      Eric 	if (flags & SDEV_VLINK) {
   1739   7688     Aaron 		physpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   1740   7688     Aaron 		rv = callback(ddv, nm, (void *)&physpath, kcred, NULL,
   1741   7688     Aaron 		    NULL);
   1742   7688     Aaron 		if (rv) {
   1743   7688     Aaron 			kmem_free(physpath, MAXPATHLEN);
   1744   7688     Aaron 			return (-1);
   1745   7688     Aaron 		}
   1746   7688     Aaron 
   1747   7688     Aaron 		vap = sdev_getdefault_attr(VLNK);
   1748   7688     Aaron 		vap->va_size = strlen(physpath);
   1749  10588      Eric 		gethrestime(&vap->va_atime);
   1750  10588      Eric 		vap->va_mtime = vap->va_atime;
   1751  10588      Eric 		vap->va_ctime = vap->va_atime;
   1752   7688     Aaron 
   1753   7688     Aaron 		rv = sdev_mknode(ddv, nm, &dv, vap, NULL,
   1754   7688     Aaron 		    (void *)physpath, cred, SDEV_READY);
   1755   7688     Aaron 		kmem_free(physpath, MAXPATHLEN);
   1756   7688     Aaron 		if (rv)
   1757   7688     Aaron 			return (rv);
   1758   2621     llai1 	} else if (flags & SDEV_VATTR) {
   1759   2621     llai1 		/*
   1760   2621     llai1 		 * /dev/pts
   1761   2621     llai1 		 *
   1762   2621     llai1 		 * callback is responsible to set the basic attributes,
   1763   2621     llai1 		 * e.g. va_type/va_uid/va_gid/
   1764   2621     llai1 		 *    dev_t if VCHR or VBLK/
   1765   2621     llai1 		 */
   1766   2621     llai1 		ASSERT(callback);
   1767   2621     llai1 		rv = callback(ddv, nm, (void *)&vattr, kcred, NULL, NULL);
   1768   2621     llai1 		if (rv) {
   1769   2621     llai1 			sdcmn_err3(("devname_lookup_func: SDEV_NONE "
   1770   2621     llai1 			    "callback failed \n"));
   1771   2621     llai1 			return (-1);
   1772   2621     llai1 		}
   1773   2621     llai1 
   1774   2621     llai1 		rv = sdev_mknode(ddv, nm, &dv, &vattr, NULL, NULL,
   1775   2621     llai1 		    cred, SDEV_READY);
   1776   2621     llai1 
   1777   2621     llai1 		if (rv)
   1778   2621     llai1 			return (rv);
   1779   2621     llai1 
   1780   2621     llai1 	} else {
   1781   2621     llai1 		impossible(("lookup: %s/%s by %s not supported (%d)\n",
   1782   2621     llai1 		    SDEVTOV(ddv)->v_path, nm, curproc->p_user.u_comm,
   1783   2621     llai1 		    __LINE__));
   1784   2621     llai1 		rv = -1;
   1785   2621     llai1 	}
   1786   2621     llai1 
   1787   2621     llai1 	*dvp = dv;
   1788   2621     llai1 	return (rv);
   1789   2621     llai1 }
   1790   2621     llai1 
   1791   2621     llai1 static int
   1792   2621     llai1 is_devfsadm_thread(char *exec_name)
   1793   2621     llai1 {
   1794   2621     llai1 	/*
   1795   2621     llai1 	 * note: because devfsadmd -> /usr/sbin/devfsadm
   1796   2621     llai1 	 * it is safe to use "devfsadm" to capture the lookups
   1797   2621     llai1 	 * from devfsadm and its daemon version.
   1798   2621     llai1 	 */
   1799   2621     llai1 	if (strcmp(exec_name, "devfsadm") == 0)
   1800   2621     llai1 		return (1);
   1801   2621     llai1 	return (0);
   1802   2621     llai1 }
   1803   2621     llai1 
   1804   2621     llai1 /*
   1805   2621     llai1  * Lookup Order:
   1806   2621     llai1  *	sdev_node cache;
   1807   2621     llai1  *	backing store (SDEV_PERSIST);
   1808   2621     llai1  *	DBNR: a. dir_ops implemented in the loadable modules;
   1809   2621     llai1  *	      b. vnode ops in vtab.
   1810   2621     llai1  */
   1811   2621     llai1 int
   1812   2621     llai1 devname_lookup_func(struct sdev_node *ddv, char *nm, struct vnode **vpp,
   1813   2621     llai1     struct cred *cred, int (*callback)(struct sdev_node *, char *, void **,
   1814   2621     llai1     struct cred *, void *, char *), int flags)
   1815   2621     llai1 {
   1816   2621     llai1 	int rv = 0, nmlen;
   1817   2621     llai1 	struct vnode *rvp = NULL;
   1818   2621     llai1 	struct sdev_node *dv = NULL;
   1819   2621     llai1 	int	retried = 0;
   1820   2621     llai1 	int	error = 0;
   1821   2621     llai1 	struct vattr vattr;
   1822   2621     llai1 	char *lookup_thread = curproc->p_user.u_comm;
   1823   2621     llai1 	int failed_flags = 0;
   1824   2621     llai1 	int (*vtor)(struct sdev_node *) = NULL;
   1825   2621     llai1 	int state;
   1826   2621     llai1 	int parent_state;
   1827   2621     llai1 	char *link = NULL;
   1828   2621     llai1 
   1829   2621     llai1 	if (SDEVTOV(ddv)->v_type != VDIR)
   1830   2621     llai1 		return (ENOTDIR);
   1831   2621     llai1 
   1832   2621     llai1 	/*
   1833   2621     llai1 	 * Empty name or ., return node itself.
   1834   2621     llai1 	 */
   1835   2621     llai1 	nmlen = strlen(nm);
   1836   2621     llai1 	if ((nmlen == 0) || ((nmlen == 1) && (nm[0] == '.'))) {
   1837   2621     llai1 		*vpp = SDEVTOV(ddv);
   1838   2621     llai1 		VN_HOLD(*vpp);
   1839   2621     llai1 		return (0);
   1840   2621     llai1 	}
   1841   2621     llai1 
   1842   2621     llai1 	/*
   1843   2621     llai1 	 * .., return the parent directory
   1844   2621     llai1 	 */
   1845   2621     llai1 	if ((nmlen == 2) && (strcmp(nm, "..") == 0)) {
   1846   2621     llai1 		*vpp = SDEVTOV(ddv->sdev_dotdot);
   1847   2621     llai1 		VN_HOLD(*vpp);
   1848   2621     llai1 		return (0);
   1849   2621     llai1 	}
   1850   2621     llai1 
   1851   2621     llai1 	rw_enter(&ddv->sdev_contents, RW_READER);
   1852   2621     llai1 	if (ddv->sdev_flags & SDEV_VTOR) {
   1853   2621     llai1 		vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
   1854   2621     llai1 		ASSERT(vtor);
   1855   2621     llai1 	}
   1856   2621     llai1 
   1857   2621     llai1 tryagain:
   1858   2621     llai1 	/*
   1859   2621     llai1 	 * (a) directory cache lookup:
   1860   2621     llai1 	 */
   1861   2621     llai1 	ASSERT(RW_READ_HELD(&ddv->sdev_contents));
   1862   2621     llai1 	parent_state = ddv->sdev_state;
   1863   2621     llai1 	dv = sdev_cache_lookup(ddv, nm);
   1864   2621     llai1 	if (dv) {
   1865   2621     llai1 		state = dv->sdev_state;
   1866   2621     llai1 		switch (state) {
   1867   2621     llai1 		case SDEV_INIT:
   1868   2621     llai1 			if (is_devfsadm_thread(lookup_thread))
   1869   2621     llai1 				break;
   1870   2621     llai1 
   1871   2621     llai1 			/* ZOMBIED parent won't allow node creation */
   1872   2621     llai1 			if (parent_state == SDEV_ZOMBIE) {
   1873   2621     llai1 				SD_TRACE_FAILED_LOOKUP(ddv, nm,
   1874   2621     llai1 				    retried);
   1875   2621     llai1 				goto nolock_notfound;
   1876   2621     llai1 			}
   1877   2621     llai1 
   1878   2621     llai1 			mutex_enter(&dv->sdev_lookup_lock);
   1879   2621     llai1 			/* compensate the threads started after devfsadm */
   1880   2621     llai1 			if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) &&
   1881   2621     llai1 			    !(SDEV_IS_LOOKUP(dv)))
   1882   2621     llai1 				SDEV_BLOCK_OTHERS(dv,
   1883   2621     llai1 				    (SDEV_LOOKUP | SDEV_LGWAITING));
   1884   2621     llai1 
   1885   2621     llai1 			if (SDEV_IS_LOOKUP(dv)) {
   1886   2621     llai1 				failed_flags |= SLF_REBUILT;
   1887   2621     llai1 				rw_exit(&ddv->sdev_contents);
   1888   2621     llai1 				error = sdev_wait4lookup(dv, SDEV_LOOKUP);
   1889   2621     llai1 				mutex_exit(&dv->sdev_lookup_lock);
   1890   2621     llai1 				rw_enter(&ddv->sdev_contents, RW_READER);
   1891   2621     llai1 
   1892   2621     llai1 				if (error != 0) {
   1893   2621     llai1 					SD_TRACE_FAILED_LOOKUP(ddv, nm,
   1894   2621     llai1 					    retried);
   1895   2621     llai1 					goto nolock_notfound;
   1896   2621     llai1 				}
   1897   2621     llai1 
   1898   2621     llai1 				state = dv->sdev_state;
   1899   2621     llai1 				if (state == SDEV_INIT) {
   1900   2621     llai1 					SD_TRACE_FAILED_LOOKUP(ddv, nm,
   1901   2621     llai1 					    retried);
   1902   2621     llai1 					goto nolock_notfound;
   1903   2621     llai1 				} else if (state == SDEV_READY) {
   1904   2621     llai1 					goto found;
   1905   2621     llai1 				} else if (state == SDEV_ZOMBIE) {
   1906   2621     llai1 					rw_exit(&ddv->sdev_contents);
   1907   2621     llai1 					SD_TRACE_FAILED_LOOKUP(ddv, nm,
   1908   2621     llai1 					    retried);
   1909   2621     llai1 					SDEV_RELE(dv);
   1910   2621     llai1 					goto lookup_failed;
   1911   2621     llai1 				}
   1912   2621     llai1 			} else {
   1913   2621     llai1 				mutex_exit(&dv->sdev_lookup_lock);
   1914   2621     llai1 			}
   1915   2621     llai1 			break;
   1916   2621     llai1 		case SDEV_READY:
   1917   2621     llai1 			goto found;
   1918   2621     llai1 		case SDEV_ZOMBIE:
   1919   2621     llai1 			rw_exit(&ddv->sdev_contents);
   1920   2621     llai1 			SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   1921   2621     llai1 			SDEV_RELE(dv);
   1922   2621     llai1 			goto lookup_failed;
   1923   2621     llai1 		default:
   1924   2621     llai1 			rw_exit(&ddv->sdev_contents);
   1925   2621     llai1 			SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   1926   2621     llai1 			sdev_lookup_failed(ddv, nm, failed_flags);
   1927   2621     llai1 			*vpp = NULLVP;
   1928   2621     llai1 			return (ENOENT);
   1929   2621     llai1 		}
   1930   2621     llai1 	}
   1931   2621     llai1 	ASSERT(RW_READ_HELD(&ddv->sdev_contents));
   1932   2621     llai1 
   1933   2621     llai1 	/*
   1934   2621     llai1 	 * ZOMBIED parent does not allow new node creation.
   1935   2621     llai1 	 * bail out early
   1936   2621     llai1 	 */
   1937   2621     llai1 	if (parent_state == SDEV_ZOMBIE) {
   1938   2621     llai1 		rw_exit(&ddv->sdev_contents);
   1939  10588      Eric 		*vpp = NULLVP;
   1940   2621     llai1 		SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   1941   2621     llai1 		return (ENOENT);
   1942   2621     llai1 	}
   1943   2621     llai1 
   1944   2621     llai1 	/*
   1945   2621     llai1 	 * (b0): backing store lookup
   1946   2621     llai1 	 *	SDEV_PERSIST is default except:
   1947   2621     llai1 	 *		1) pts nodes
   1948   2621     llai1 	 *		2) non-chmod'ed local nodes
   1949  10588      Eric 	 *		3) zvol nodes
   1950   2621     llai1 	 */
   1951   2621     llai1 	if (SDEV_IS_PERSIST(ddv)) {
   1952   2621     llai1 		error = devname_backstore_lookup(ddv, nm, &rvp);
   1953   2621     llai1 
   1954   2621     llai1 		if (!error) {
   1955   2621     llai1 
   1956   2621     llai1 			vattr.va_mask = AT_MODE|AT_UID|AT_GID;
   1957   5331       amw 			error = VOP_GETATTR(rvp, &vattr, 0, cred, NULL);
   1958   2621     llai1 			if (error) {
   1959   2621     llai1 				rw_exit(&ddv->sdev_contents);
   1960   2621     llai1 				if (dv)
   1961   2621     llai1 					SDEV_RELE(dv);
   1962   2621     llai1 				SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   1963   2621     llai1 				sdev_lookup_failed(ddv, nm, failed_flags);
   1964   2621     llai1 				*vpp = NULLVP;
   1965   2621     llai1 				return (ENOENT);
   1966   2621     llai1 			}
   1967   2621     llai1 
   1968   2621     llai1 			if (vattr.va_type == VLNK) {
   1969   2621     llai1 				error = sdev_getlink(rvp, &link);
   1970   2621     llai1 				if (error) {
   1971   2621     llai1 					rw_exit(&ddv->sdev_contents);
   1972   2621     llai1 					if (dv)
   1973   2621     llai1 						SDEV_RELE(dv);
   1974   2621     llai1 					SD_TRACE_FAILED_LOOKUP(ddv, nm,
   1975   2621     llai1 					    retried);
   1976   2621     llai1 					sdev_lookup_failed(ddv, nm,
   1977   2621     llai1 					    failed_flags);
   1978   2621     llai1 					*vpp = NULLVP;
   1979   2621     llai1 					return (ENOENT);
   1980   2621     llai1 				}
   1981   2621     llai1 				ASSERT(link != NULL);
   1982   2621     llai1 			}
   1983   2621     llai1 
   1984   2621     llai1 			if (!rw_tryupgrade(&ddv->sdev_contents)) {
   1985   2621     llai1 				rw_exit(&ddv->sdev_contents);
   1986   2621     llai1 				rw_enter(&ddv->sdev_contents, RW_WRITER);
   1987   2621     llai1 			}
   1988   2621     llai1 			error = sdev_mknode(ddv, nm, &dv, &vattr,
   1989   2621     llai1 			    rvp, link, cred, SDEV_READY);
   1990   2621     llai1 			rw_downgrade(&ddv->sdev_contents);
   1991   2621     llai1 
   1992   2621     llai1 			if (link != NULL) {
   1993   2621     llai1 				kmem_free(link, strlen(link) + 1);
   1994   2621     llai1 				link = NULL;
   1995   2621     llai1 			}
   1996   2621     llai1 
   1997   2621     llai1 			if (error) {
   1998   2621     llai1 				SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   1999   2621     llai1 				rw_exit(&ddv->sdev_contents);
   2000   2621     llai1 				if (dv)
   2001   2621     llai1 					SDEV_RELE(dv);
   2002   2621     llai1 				goto lookup_failed;
   2003   2621     llai1 			} else {
   2004   2621     llai1 				goto found;
   2005   2621     llai1 			}
   2006   2621     llai1 		} else if (retried) {
   2007   2621     llai1 			rw_exit(&ddv->sdev_contents);
   2008   2621     llai1 			sdcmn_err3(("retry of lookup of %s/%s: failed\n",
   2009   2621     llai1 			    ddv->sdev_name, nm));
   2010   2621     llai1 			if (dv)
   2011   2621     llai1 				SDEV_RELE(dv);
   2012   2621     llai1 			SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2013   2621     llai1 			sdev_lookup_failed(ddv, nm, failed_flags);
   2014   2621     llai1 			*vpp = NULLVP;
   2015   2621     llai1 			return (ENOENT);
   2016   2621     llai1 		}
   2017   2621     llai1 	}
   2018   2621     llai1 
   2019   8023      Phil lookup_create_node:
   2020   2621     llai1 	/* first thread that is doing the lookup on this node */
   2021  10588      Eric 	if (callback) {
   2022  10588      Eric 		ASSERT(dv == NULL);
   2023  10588      Eric 		if (!rw_tryupgrade(&ddv->sdev_contents)) {
   2024  10588      Eric 			rw_exit(&ddv->sdev_contents);
   2025  10588      Eric 			rw_enter(&ddv->sdev_contents, RW_WRITER);
   2026  10588      Eric 		}
   2027  10588      Eric 		error = sdev_call_dircallback(ddv, &dv, nm, callback,
   2028  10588      Eric 		    flags, cred);
   2029  10588      Eric 		rw_downgrade(&ddv->sdev_contents);
   2030  10588      Eric 		if (error == 0) {
   2031  10588      Eric 			goto found;
   2032  10588      Eric 		} else {
   2033  10588      Eric 			SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2034  10588      Eric 			rw_exit(&ddv->sdev_contents);
   2035  10588      Eric 			goto lookup_failed;
   2036  10588      Eric 		}
   2037  10588      Eric 	}
   2038   2621     llai1 	if (!dv) {
   2039   2621     llai1 		if (!rw_tryupgrade(&ddv->sdev_contents)) {
   2040   2621     llai1 			rw_exit(&ddv->sdev_contents);
   2041   2621     llai1 			rw_enter(&ddv->sdev_contents, RW_WRITER);
   2042   2621     llai1 		}
   2043   2621     llai1 		error = sdev_mknode(ddv, nm, &dv, NULL, NULL, NULL,
   2044   2621     llai1 		    cred, SDEV_INIT);
   2045   2621     llai1 		if (!dv) {
   2046   2621     llai1 			rw_exit(&ddv->sdev_contents);
   2047   2621     llai1 			SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2048   2621     llai1 			sdev_lookup_failed(ddv, nm, failed_flags);
   2049   2621     llai1 			*vpp = NULLVP;
   2050   2621     llai1 			return (ENOENT);
   2051   2621     llai1 		}
   2052   2621     llai1 		rw_downgrade(&ddv->sdev_contents);
   2053   2621     llai1 	}
   2054   2621     llai1 
   2055   2621     llai1 	/*
   2056   2621     llai1 	 * (b1) invoking devfsadm once per life time for devfsadm nodes
   2057   2621     llai1 	 */
   2058  10588      Eric 	ASSERT(SDEV_HELD(dv));
   2059   2621     llai1 
   2060  10588      Eric 	if (SDEV_IS_NO_NCACHE(dv))
   2061  10588      Eric 		failed_flags |= SLF_NO_NCACHE;
   2062  10588      Eric 	if (sdev_reconfig_boot || !i_ddi_io_initialized() ||
   2063  10588      Eric 	    SDEV_IS_DYNAMIC(ddv) || SDEV_IS_NO_NCACHE(dv) ||
   2064  10588      Eric 	    ((moddebug & MODDEBUG_FINI_EBUSY) != 0)) {
   2065  10588      Eric 		ASSERT(SDEV_HELD(dv));
   2066  10588      Eric 		SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2067  10588      Eric 		goto nolock_notfound;
   2068   2621     llai1 	}
   2069   2621     llai1 
   2070   2621     llai1 	/*
   2071  10588      Eric 	 * filter out known non-existent devices recorded
   2072  10588      Eric 	 * during initial reconfiguration boot for which
   2073  10588      Eric 	 * reconfig should not be done and lookup may
   2074  10588      Eric 	 * be short-circuited now.
   2075   2621     llai1 	 */
   2076  10588      Eric 	if (sdev_lookup_filter(ddv, nm)) {
   2077  10588      Eric 		SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2078  10588      Eric 		goto nolock_notfound;
   2079  10588      Eric 	}
   2080  10588      Eric 
   2081  10588      Eric 	/* bypassing devfsadm internal nodes */
   2082  10588      Eric 	if (is_devfsadm_thread(lookup_thread)) {
   2083  10588      Eric 		SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2084  10588      Eric 		goto nolock_notfound;
   2085  10588      Eric 	}
   2086  10588      Eric 
   2087  10588      Eric 	if (sdev_reconfig_disable) {
   2088  10588      Eric 		SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2089  10588      Eric 		goto nolock_notfound;
   2090  10588      Eric 	}
   2091  10588      Eric 
   2092  10588      Eric 	error = sdev_call_devfsadmd(ddv, dv, nm);
   2093  10588      Eric 	if (error == 0) {
   2094  10588      Eric 		sdcmn_err8(("lookup of %s/%s by %s: reconfig\n",
   2095  10588      Eric 		    ddv->sdev_name, nm, curproc->p_user.u_comm));
   2096  10588      Eric 		if (sdev_reconfig_verbose) {
   2097  10588      Eric 			cmn_err(CE_CONT,
   2098  10588      Eric 			    "?lookup of %s/%s by %s: reconfig\n",
   2099  10588      Eric 			    ddv->sdev_name, nm, curproc->p_user.u_comm);
   2100   2621     llai1 		}
   2101  10588      Eric 		retried = 1;
   2102  10588      Eric 		failed_flags |= SLF_REBUILT;
   2103  10588      Eric 		ASSERT(dv->sdev_state != SDEV_ZOMBIE);
   2104  10588      Eric 		SDEV_SIMPLE_RELE(dv);
   2105  10588      Eric 		goto tryagain;
   2106  10588      Eric 	} else {
   2107  10588      Eric 		SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2108  10588      Eric 		goto nolock_notfound;
   2109   2621     llai1 	}
   2110   2621     llai1 
   2111   2621     llai1 found:
   2112   2621     llai1 	ASSERT(!(dv->sdev_flags & SDEV_STALE));
   2113   2621     llai1 	ASSERT(dv->sdev_state == SDEV_READY);
   2114   2621     llai1 	if (vtor) {
   2115   2621     llai1 		/*
   2116   2621     llai1 		 * Check validity of returned node
   2117   2621     llai1 		 */
   2118   2621     llai1 		switch (vtor(dv)) {
   2119   2621     llai1 		case SDEV_VTOR_VALID:
   2120   2621     llai1 			break;
   2121   8023      Phil 		case SDEV_VTOR_STALE:
   2122   8023      Phil 			/*
   2123   8023      Phil 			 * The name exists, but the cache entry is
   2124   8023      Phil 			 * stale and needs to be re-created.
   2125   8023      Phil 			 */
   2126   8023      Phil 			ASSERT(RW_READ_HELD(&ddv->sdev_contents));
   2127   8023      Phil 			if (rw_tryupgrade(&ddv->sdev_contents) == 0) {
   2128   8023      Phil 				rw_exit(&ddv->sdev_contents);
   2129   8023      Phil 				rw_enter(&ddv->sdev_contents, RW_WRITER);
   2130   8023      Phil 			}
   2131   8023      Phil 			error = sdev_cache_update(ddv, &dv, nm,
   2132   8023      Phil 			    SDEV_CACHE_DELETE);
   2133   8023      Phil 			rw_downgrade(&ddv->sdev_contents);
   2134   8023      Phil 			if (error == 0) {
   2135   8023      Phil 				dv = NULL;
   2136   8023      Phil 				goto lookup_create_node;
   2137   8023      Phil 			}
   2138   8023      Phil 			/* FALLTHRU */
   2139   2621     llai1 		case SDEV_VTOR_INVALID:
   2140   2621     llai1 			SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2141   2621     llai1 			sdcmn_err7(("lookup: destroy invalid "
   2142   2621     llai1 			    "node: %s(%p)\n", dv->sdev_name, (void *)dv));
   2143   2621     llai1 			goto nolock_notfound;
   2144   2621     llai1 		case SDEV_VTOR_SKIP:
   2145   2621     llai1 			sdcmn_err7(("lookup: node not applicable - "
   2146   2621     llai1 			    "skipping: %s(%p)\n", dv->sdev_name, (void *)dv));
   2147   2621     llai1 			rw_exit(&ddv->sdev_contents);
   2148   2621     llai1 			SD_TRACE_FAILED_LOOKUP(ddv, nm, retried);
   2149   2621     llai1 			SDEV_RELE(dv);
   2150   2621     llai1 			goto lookup_failed;
   2151   2621     llai1 		default:
   2152   2621     llai1 			cmn_err(CE_PANIC,
   2153   2621     llai1 			    "dev fs: validator failed: %s(%p)\n",
   2154   2621     llai1 			    dv->sdev_name, (void *)dv);
   2155   2621     llai1 			break;
   2156   2621     llai1 		}
   2157   2621     llai1 	}
   2158   2621     llai1 
   2159   2621     llai1 	rw_exit(&ddv->sdev_contents);
   2160   2621     llai1 	rv = sdev_to_vp(dv, vpp);
   2161   2621     llai1 	sdcmn_err3(("devname_lookup_func: returning vp %p v_count %d state %d "
   2162   2621     llai1 	    "for nm %s, error %d\n", (void *)*vpp, (*vpp)->v_count,
   2163   2621     llai1 	    dv->sdev_state, nm, rv));
   2164   2621     llai1 	return (rv);
   2165   2621     llai1 
   2166   2621     llai1 nolock_notfound:
   2167   2621     llai1 	/*
   2168   2621     llai1 	 * Destroy the node that is created for synchronization purposes.
   2169   2621     llai1 	 */
   2170   2621     llai1 	sdcmn_err3(("devname_lookup_func: %s with state %d\n",
   2171   2621     llai1 	    nm, dv->sdev_state));
   2172   2621     llai1 	ASSERT(RW_READ_HELD(&ddv->sdev_contents));
   2173   2621     llai1 	if (dv->sdev_state == SDEV_INIT) {
   2174   2621     llai1 		if (!rw_tryupgrade(&ddv->sdev_contents)) {
   2175   2621     llai1 			rw_exit(&ddv->sdev_contents);
   2176   2621     llai1 			rw_enter(&ddv->sdev_contents, RW_WRITER);
   2177   2621     llai1 		}
   2178   2621     llai1 
   2179   2621     llai1 		/*
   2180   2621     llai1 		 * Node state may have changed during the lock
   2181   2621     llai1 		 * changes. Re-check.
   2182   2621     llai1 		 */
   2183   2621     llai1 		if (dv->sdev_state == SDEV_INIT) {
   2184   2621     llai1 			(void) sdev_dirdelete(ddv, dv);
   2185   2621     llai1 			rw_exit(&ddv->sdev_contents);
   2186   2621     llai1 			sdev_lookup_failed(ddv, nm, failed_flags);
   2187   2621     llai1 			*vpp = NULL;
   2188   2621     llai1 			return (ENOENT);
   2189   2621     llai1 		}
   2190   2621     llai1 	}
   2191   2621     llai1 
   2192   2621     llai1 	rw_exit(&ddv->sdev_contents);
   2193   2621     llai1 	SDEV_RELE(dv);
   2194   2621     llai1 
   2195   2621     llai1 lookup_failed:
   2196   2621     llai1 	sdev_lookup_failed(ddv, nm, failed_flags);
   2197   2621     llai1 	*vpp = NULL;
   2198   2621     llai1 	return (ENOENT);
   2199   2621     llai1 }
   2200   2621     llai1 
   2201   2621     llai1 /*
   2202   2621     llai1  * Given a directory node, mark all nodes beneath as
   2203   2621     llai1  * STALE, i.e. nodes that don't exist as far as new
   2204   6347        jg  * consumers are concerned.  Remove them from the
   2205   6347        jg  * list of directory entries so that no lookup or
   2206   6347        jg  * directory traversal will find them.  The node
   2207   6347        jg  * not deallocated so existing holds are not affected.
   2208   2621     llai1  */
   2209   2621     llai1 void
   2210   2621     llai1 sdev_stale(struct sdev_node *ddv)
   2211   2621     llai1 {
   2212   2621     llai1 	struct sdev_node *dv;
   2213   2621     llai1 	struct vnode *vp;
   2214   2621     llai1 
   2215   2621     llai1 	ASSERT(SDEVTOV(ddv)->v_type == VDIR);
   2216   2621     llai1 
   2217   2621     llai1 	rw_enter(&ddv->sdev_contents, RW_WRITER);
   2218   6260        jg 	for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = SDEV_NEXT_ENTRY(ddv, dv)) {
   2219   2621     llai1 		vp = SDEVTOV(dv);
   2220   2621     llai1 		if (vp->v_type == VDIR)
   2221   2621     llai1 			sdev_stale(dv);
   2222   2621     llai1 
   2223   2621     llai1 		sdcmn_err9(("sdev_stale: setting stale %s\n",
   2224   6347        jg 		    dv->sdev_path));
   2225   2621     llai1 		dv->sdev_flags |= SDEV_STALE;
   2226   6347        jg 		avl_remove(&ddv->sdev_entries, dv);
   2227   2621     llai1 	}
   2228   2621     llai1 	ddv->sdev_flags |= SDEV_BUILD;
   2229   2621     llai1 	rw_exit(&ddv->sdev_contents);
   2230   2621     llai1 }
   2231   2621     llai1 
   2232   2621     llai1 /*
   2233   2621     llai1  * Given a directory node, clean out all the nodes beneath.
   2234   2621     llai1  * If expr is specified, clean node with names matching expr.
   2235   2621     llai1  * If SDEV_ENFORCE is specified in flags, busy nodes are made stale,
   2236   2621     llai1  *	so they are excluded from future lookups.
   2237   2621     llai1  */
   2238   2621     llai1 int
   2239   2621     llai1 sdev_cleandir(struct sdev_node *ddv, char *expr, uint_t flags)
   2240   2621     llai1 {
   2241   2621     llai1 	int error = 0;
   2242   2621     llai1 	int busy = 0;
   2243   2621     llai1 	struct vnode *vp;
   2244   2621     llai1 	struct sdev_node *dv, *next = NULL;
   2245   2621     llai1 	int bkstore = 0;
   2246   2621     llai1 	int len = 0;
   2247   2621     llai1 	char *bks_name = NULL;
   2248   2621     llai1 
   2249   2621     llai1 	ASSERT(SDEVTOV(ddv)->v_type == VDIR);
   2250   2621     llai1 
   2251   2621     llai1 	/*
   2252   2621     llai1 	 * We try our best to destroy all unused sdev_node's
   2253   2621     llai1 	 */
   2254   2621     llai1 	rw_enter(&ddv->sdev_contents, RW_WRITER);
   2255   6260        jg 	for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
   2256   6260        jg 		next = SDEV_NEXT_ENTRY(ddv, dv);
   2257   2621     llai1 		vp = SDEVTOV(dv);
   2258   2621     llai1 
   2259   2621     llai1 		if (expr && gmatch(dv->sdev_name, expr) == 0)
   2260   2621     llai1 			continue;
   2261   2621     llai1 
   2262   2621     llai1 		if (vp->v_type == VDIR &&
   2263   2621     llai1 		    sdev_cleandir(dv, NULL, flags) != 0) {
   2264   2621     llai1 			sdcmn_err9(("sdev_cleandir: dir %s busy\n",
   2265   2621     llai1 			    dv->sdev_name));
   2266   2621     llai1 			busy++;
   2267   2621     llai1 			continue;
   2268   2621     llai1 		}
   2269   2621     llai1 
   2270   2621     llai1 		if (vp->v_count > 0 && (flags & SDEV_ENFORCE) == 0) {
   2271   2621     llai1 			sdcmn_err9(("sdev_cleandir: dir %s busy\n",
   2272   2621     llai1 			    dv->sdev_name));
   2273   2621     llai1 			busy++;
   2274   2621     llai1 			continue;
   2275   2621     llai1 		}
   2276   2621     llai1 
   2277   2621     llai1 		/*
   2278   2621     llai1 		 * at this point, either dv is not held or SDEV_ENFORCE
   2279   2621     llai1 		 * is specified. In either case, dv needs to be deleted
   2280   2621     llai1 		 */
   2281   2621     llai1 		SDEV_HOLD(dv);
   2282   2621     llai1 
   2283   2621     llai1 		bkstore = SDEV_IS_PERSIST(dv) ? 1 : 0;
   2284   2621     llai1 		if (bkstore && (vp->v_type == VDIR))
   2285   2621     llai1 			bkstore += 1;
   2286   2621     llai1 
   2287   2621     llai1 		if (bkstore) {
   2288   2621     llai1 			len = strlen(dv->sdev_name) + 1;
   2289   2621     llai1 			bks_name = kmem_alloc(len, KM_SLEEP);
   2290   2621     llai1 			bcopy(dv->sdev_name, bks_name, len);
   2291   2621     llai1 		}
   2292   2621     llai1 
   2293   2621     llai1 		error = sdev_dirdelete(ddv, dv);
   2294   2621     llai1 
   2295   2621     llai1 		if (error == EBUSY) {
   2296   2621     llai1 			sdcmn_err9(("sdev_cleandir: dir busy\n"));
   2297   2621     llai1 			busy++;
   2298   2621     llai1 		}
   2299   2621     llai1 
   2300   2621     llai1 		/* take care the backing store clean up */
   2301   2621     llai1 		if (bkstore && (error == 0)) {
   2302   2621     llai1 			ASSERT(bks_name);
   2303   2621     llai1 			ASSERT(ddv->sdev_attrvp);
   2304   2621     llai1 
   2305   2621     llai1 			if (bkstore == 1) {
   2306   2621     llai1 				error = VOP_REMOVE(ddv->sdev_attrvp,
   2307   5331       amw 				    bks_name, kcred, NULL, 0);
   2308   2621     llai1 			} else if (bkstore == 2) {
   2309   2621     llai1 				error = VOP_RMDIR(ddv->sdev_attrvp,
   2310   5331       amw 				    bks_name, ddv->sdev_attrvp, kcred, NULL, 0);
   2311   2621     llai1 			}
   2312   2621     llai1 
   2313   2621     llai1 			/* do not propagate the backing store errors */
   2314   2621     llai1 			if (error) {
   2315   2621     llai1 				sdcmn_err9(("sdev_cleandir: backing store"
   2316   2621     llai1 				    "not cleaned\n"));
   2317   2621     llai1 				error = 0;
   2318   2621     llai1 			}
   2319   2621     llai1 
   2320   2621     llai1 			bkstore = 0;
   2321   2621     llai1 			kmem_free(bks_name, len);
   2322   2621     llai1 			bks_name = NULL;
   2323   2621     llai1 			len = 0;
   2324   2621     llai1 		}
   2325   2621     llai1 	}
   2326   2621     llai1 
   2327   2621     llai1 	ddv->sdev_flags |= SDEV_BUILD;
   2328   2621     llai1 	rw_exit(&ddv->sdev_contents);
   2329   2621     llai1 
   2330   2621     llai1 	if (busy) {
   2331   2621     llai1 		error = EBUSY;
   2332   2621     llai1 	}
   2333   2621     llai1 
   2334   2621     llai1 	return (error);
   2335   2621     llai1 }
   2336   2621     llai1 
   2337   2621     llai1 /*
   2338   2621     llai1  * a convenient wrapper for readdir() funcs
   2339   2621     llai1  */
   2340   2621     llai1 size_t
   2341   2621     llai1 add_dir_entry(dirent64_t *de, char *nm, size_t size, ino_t ino, offset_t off)
   2342   2621     llai1 {
   2343   2621     llai1 	size_t reclen = DIRENT64_RECLEN(strlen(nm));
   2344   2621     llai1 	if (reclen > size)
   2345   2621     llai1 		return (0);
   2346   2621     llai1 
   2347   2621     llai1 	de->d_ino = (ino64_t)ino;
   2348   2621     llai1 	de->d_off = (off64_t)off + 1;
   2349   2621     llai1 	de->d_reclen = (ushort_t)reclen;
   2350   2621     llai1 	(void) strncpy(de->d_name, nm, DIRENT64_NAMELEN(reclen));
   2351   2621     llai1 	return (reclen);
   2352   2621     llai1 }
   2353   2621     llai1 
   2354   2621     llai1 /*
   2355   2621     llai1  * sdev_mount service routines
   2356   2621     llai1  */
   2357   2621     llai1 int
   2358   2621     llai1 sdev_copyin_mountargs(struct mounta *uap, struct sdev_mountargs *args)
   2359   2621     llai1 {
   2360   2621     llai1 	int	error;
   2361   2621     llai1 
   2362   2621     llai1 	if (uap->datalen != sizeof (*args))
   2363   2621     llai1 		return (EINVAL);
   2364   2621     llai1 
   2365   2621     llai1 	if (error = copyin(uap->dataptr, args, sizeof (*args))) {
   2366   2621     llai1 		cmn_err(CE_WARN, "sdev_copyin_mountargs: can not"
   2367   2621     llai1 		    "get user data. error %d\n", error);
   2368   2621     llai1 		return (EFAULT);
   2369   2621     llai1 	}
   2370   2621     llai1 
   2371   2621     llai1 	return (0);
   2372   2621     llai1 }
   2373   2621     llai1 
   2374   2621     llai1 #ifdef nextdp
   2375   2621     llai1 #undef nextdp
   2376   2621     llai1 #endif
   2377   3133        jg #define	nextdp(dp)	((struct dirent64 *) \
   2378   3133        jg 			    (intptr_t)((char *)(dp) + (dp)->d_reclen))
   2379   2621     llai1 
   2380   2621     llai1 /*
   2381   2621     llai1  * readdir helper func
   2382   2621     llai1  */
   2383   2621     llai1 int
   2384   2621     llai1 devname_readdir_func(vnode_t *vp, uio_t *uiop, cred_t *cred, int *eofp,
   2385   2621     llai1     int flags)
   2386   2621     llai1 {
   2387   2621     llai1 	struct sdev_node *ddv = VTOSDEV(vp);
   2388   2621     llai1 	struct sdev_node *dv;
   2389   2621     llai1 	dirent64_t	*dp;
   2390   2621     llai1 	ulong_t		outcount = 0;
   2391   2621     llai1 	size_t		namelen;
   2392   2621     llai1 	ulong_t		alloc_count;
   2393   2621     llai1 	void		*outbuf;
   2394   2621     llai1 	struct iovec	*iovp;
   2395   2621     llai1 	int		error = 0;
   2396   2621     llai1 	size_t		reclen;
   2397   2621     llai1 	offset_t	diroff;
   2398   2621     llai1 	offset_t	soff;
   2399   2621     llai1 	int		this_reclen;
   2400   2621     llai1 	int (*vtor)(struct sdev_node *) = NULL;
   2401   2621     llai1 	struct vattr attr;
   2402   2621     llai1 	timestruc_t now;
   2403   2621     llai1 
   2404   2621     llai1 	ASSERT(ddv->sdev_attr || ddv->sdev_attrvp);
   2405   2621     llai1 	ASSERT(RW_READ_HELD(&ddv->sdev_contents));
   2406   2621     llai1 
   2407   2621     llai1 	if (uiop->uio_loffset >= MAXOFF_T) {
   2408   2621     llai1 		if (eofp)
   2409   2621     llai1 			*eofp = 1;
   2410   2621     llai1 		return (0);
   2411   2621     llai1 	}
   2412   2621     llai1 
   2413   2621     llai1 	if (uiop->uio_iovcnt != 1)
   2414   2621     llai1 		return (EINVAL);
   2415   2621     llai1 
   2416   2621     llai1 	if (vp->v_type != VDIR)
   2417   2621     llai1 		return (ENOTDIR);
   2418   2621     llai1 
   2419   2621     llai1 	if (ddv->sdev_flags & SDEV_VTOR) {
   2420   2621     llai1 		vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
   2421   2621     llai1 		ASSERT(vtor);
   2422   2621     llai1 	}
   2423   2621     llai1 
   2424   2621     llai1 	if (eofp != NULL)
   2425   2621     llai1 		*eofp = 0;
   2426   2621     llai1 
   2427   3133        jg 	soff = uiop->uio_loffset;
   2428   2621     llai1 	iovp = uiop->uio_iov;
   2429   2621     llai1 	alloc_count = iovp->iov_len;
   2430   2621     llai1 	dp = outbuf = kmem_alloc(alloc_count, KM_SLEEP);
   2431   2621     llai1 	outcount = 0;
   2432   2621     llai1 
   2433   2621     llai1 	if (ddv->sdev_state == SDEV_ZOMBIE)
   2434   2621     llai1 		goto get_cache;
   2435   2621     llai1 
   2436   2679     szhou 	if (SDEV_IS_GLOBAL(ddv)) {
   2437   2621     llai1 
   2438  10097      Eric 		if ((sdev_boot_state == SDEV_BOOT_STATE_COMPLETE) &&
   2439   2621     llai1 		    !sdev_reconfig_boot && (flags & SDEV_BROWSE) &&
   2440   2621     llai1 		    !SDEV_IS_DYNAMIC(ddv) && !SDEV_IS_NO_NCACHE(ddv) &&
   2441   2621     llai1 		    ((moddebug & MODDEBUG_FINI_EBUSY) == 0) &&
   2442   2621     llai1 		    !DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state) &&
   2443   2621     llai1 		    !DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state) &&
   2444   2621     llai1 		    !sdev_reconfig_disable) {
   2445   2621     llai1 			/*
   2446   2621     llai1 			 * invoking "devfsadm" to do system device reconfig
   2447   2621     llai1 			 */
   2448   2621     llai1 			mutex_enter(&ddv->sdev_lookup_lock);
   2449   2621     llai1 			SDEV_BLOCK_OTHERS(ddv,
   2450   2621     llai1 			    (SDEV_READDIR|SDEV_LGWAITING));
   2451   2621     llai1 			mutex_exit(&ddv->sdev_lookup_lock);
   2452   2621     llai1 
   2453   2621     llai1 			sdcmn_err8(("readdir of %s by %s: reconfig\n",
   2454   2621     llai1 			    ddv->sdev_path, curproc->p_user.u_comm));
   2455   2621     llai1 			if (sdev_reconfig_verbose) {
   2456   2621     llai1 				cmn_err(CE_CONT,
   2457   2621     llai1 				    "?readdir of %s by %s: reconfig\n",
   2458   2621     llai1 				    ddv->sdev_path, curproc->p_user.u_comm);
   2459   2621     llai1 			}
   2460   2621     llai1 
   2461   2621     llai1 			sdev_devfsadmd_thread(ddv, NULL, kcred);
   2462   2621     llai1 		} else if (DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state)) {
   2463   2621     llai1 			/*
   2464   2621     llai1 			 * compensate the "ls" started later than "devfsadm"
   2465   2621     llai1 			 */
   2466   2621     llai1 			mutex_enter(&ddv->sdev_lookup_lock);
   2467   2621     llai1 			SDEV_BLOCK_OTHERS(ddv, (SDEV_READDIR|SDEV_LGWAITING));
   2468   2621     llai1 			mutex_exit(&ddv->sdev_lookup_lock);
   2469   2621     llai1 		}
   2470   2621     llai1 
   2471   2621     llai1 		/*
   2472   2621     llai1 		 * release the contents lock so that
   2473   3843        jg 		 * the cache may be updated by devfsadmd
   2474   2621     llai1 		 */
   2475   2621     llai1 		rw_exit(&ddv->sdev_contents);
   2476   2621     llai1 		mutex_enter(&ddv->sdev_lookup_lock);
   2477   2621     llai1 		if (SDEV_IS_READDIR(ddv))
   2478   2621     llai1 			(void) sdev_wait4lookup(ddv, SDEV_READDIR);
   2479   2621     llai1 		mutex_exit(&ddv->sdev_lookup_lock);
   2480   2621     llai1 		rw_enter(&ddv->sdev_contents, RW_READER);
   2481   2621     llai1 
   2482   2621     llai1 		sdcmn_err4(("readdir of directory %s by %s\n",
   2483   2621     llai1 		    ddv->sdev_name, curproc->p_user.u_comm));
   2484   3843        jg 		if (ddv->sdev_flags & SDEV_BUILD) {
   2485   2621     llai1 			if (SDEV_IS_PERSIST(ddv)) {
   2486   2621     llai1 				error = sdev_filldir_from_store(ddv,
   2487   2621     llai1 				    alloc_count, cred);
   2488   2621     llai1 			}
   2489   3843        jg 			ddv->sdev_flags &= ~SDEV_BUILD;
   2490   2621     llai1 		}
   2491   2621     llai1 	}
   2492   2621     llai1 
   2493   2621     llai1 get_cache:
   2494   2621     llai1 	/* handle "." and ".." */
   2495   2621     llai1 	diroff = 0;
   2496   2621     llai1 	if (soff == 0) {
   2497   2621     llai1 		/* first time */
   2498   2621     llai1 		this_reclen = DIRENT64_RECLEN(1);
   2499   2621     llai1 		if (alloc_count < this_reclen) {
   2500   2621     llai1 			error = EINVAL;
   2501   2621     llai1 			goto done;
   2502   2621     llai1 		}
   2503   2621     llai1 
   2504   2621     llai1 		dp->d_ino = (ino64_t)ddv->sdev_ino;
   2505   2621     llai1 		dp->d_off = (off64_t)1;
   2506   2621     llai1 		dp->d_reclen = (ushort_t)this_reclen;
   2507   2621     llai1 
   2508   2621     llai1 		(void) strncpy(dp->d_name, ".",
   2509   2621     llai1 		    DIRENT64_NAMELEN(this_reclen));
   2510   2621     llai1 		outcount += dp->d_reclen;
   2511   2621     llai1 		dp = nextdp(dp);
   2512   2621     llai1 	}
   2513   2621     llai1 
   2514   2621     llai1 	diroff++;
   2515   2621     llai1 	if (soff <= 1) {
   2516   2621     llai1 		this_reclen = DIRENT64_RECLEN(2);
   2517   2621     llai1 		if (alloc_count < outcount + this_reclen) {
   2518   2621     llai1 			error = EINVAL;
   2519   2621     llai1 			goto done;
   2520   2621     llai1 		}
   2521   2621     llai1 
   2522   2621     llai1 		dp->d_reclen = (ushort_t)this_reclen;
   2523   2621     llai1 		dp->d_ino = (ino64_t)ddv->sdev_dotdot->sdev_ino;
   2524   2621     llai1 		dp->d_off = (off64_t)2;
   2525   2621     llai1 
   2526   2621     llai1 		(void) strncpy(dp->d_name, "..",
   2527   2621     llai1 		    DIRENT64_NAMELEN(this_reclen));
   2528   2621     llai1 		outcount += dp->d_reclen;
   2529   2621     llai1 
   2530   2621     llai1 		dp = nextdp(dp);
   2531   2621     llai1 	}
   2532   2621     llai1 
   2533   2621     llai1 
   2534   2621     llai1 	/* gets the cache */
   2535   2621     llai1 	diroff++;
   2536   6260        jg 	for (dv = SDEV_FIRST_ENTRY(ddv); dv;
   2537   6260        jg 	    dv = SDEV_NEXT_ENTRY(ddv, dv), diroff++) {
   2538   2621     llai1 		sdcmn_err3(("sdev_readdir: diroff %lld soff %lld for '%s' \n",
   2539   2621     llai1 		    diroff, soff, dv->sdev_name));
   2540   2621     llai1 
   2541   2621     llai1 		/* bypassing pre-matured nodes */
   2542   2621     llai1 		if (diroff < soff || (dv->sdev_state != SDEV_READY)) {
   2543   2621     llai1 			sdcmn_err3(("sdev_readdir: pre-mature node  "
   2544  10588      Eric 			    "%s %d\n", dv->sdev_name, dv->sdev_state));
   2545   2621     llai1 			continue;
   2546   2621     llai1 		}
   2547   2621     llai1 
   2548   2621     llai1 		/*
   2549   2621     llai1 		 * Check validity of node
   2550   2621     llai1 		 */
   2551   2621     llai1 		if (vtor) {
   2552   2621     llai1 			switch (vtor(dv)) {
   2553   2621     llai1 			case SDEV_VTOR_VALID:
   2554   2621     llai1 				break;
   2555   2621     llai1 			case SDEV_VTOR_INVALID:
   2556   2621     llai1 			case SDEV_VTOR_SKIP:
   2557   2621     llai1 				continue;
   2558   2621     llai1 			default:
   2559   2621     llai1 				cmn_err(CE_PANIC,
   2560   2621     llai1 				    "dev fs: validator failed: %s(%p)\n",
   2561   2621     llai1 				    dv->sdev_name, (void *)dv);
   2562   2621     llai1 				break;
   2563   2621     llai1 			/*NOTREACHED*/
   2564   2621     llai1 			}
   2565   2621     llai1 		}
   2566   2621     llai1 
   2567   2621     llai1 		namelen = strlen(dv->sdev_name);
   2568   2621     llai1 		reclen = DIRENT64_RECLEN(namelen);
   2569   2621     llai1 		if (outcount + reclen > alloc_count) {
   2570   2621     llai1 			goto full;
   2571   2621     llai1 		}
   2572   2621     llai1 		dp->d_reclen = (ushort_t)reclen;
   2573   2621     llai1 		dp->d_ino = (ino64_t)dv->sdev_ino;
   2574   2621     llai1 		dp->d_off = (off64_t)diroff + 1;
   2575   2621     llai1 		(void) strncpy(dp->d_name, dv->sdev_name,
   2576   2621     llai1 		    DIRENT64_NAMELEN(reclen));
   2577   2621     llai1 		outcount += reclen;
   2578   2621     llai1 		dp = nextdp(dp);
   2579   2621     llai1 	}
   2580   2621     llai1 
   2581   2621     llai1 full:
   2582   2621     llai1 	sdcmn_err4(("sdev_readdir: moving %lu bytes: "
   2583   2621     llai1 	    "diroff %lld, soff %lld, dv %p\n", outcount, diroff, soff,
   2584   2621     llai1 	    (void *)dv));
   2585   2621     llai1 
   2586   2621     llai1 	if (outcount)
   2587   2621     llai1 		error = uiomove(outbuf, outcount, UIO_READ, uiop);
   2588   2621     llai1 
   2589   2621     llai1 	if (!error) {
   2590   3133        jg 		uiop->uio_loffset = diroff;
   2591   2621     llai1 		if (eofp)
   2592   2621     llai1 			*eofp = dv ? 0 : 1;
   2593   2621     llai1 	}
   2594   2621     llai1 
   2595   2621     llai1 
   2596   2621     llai1 	if (ddv->sdev_attrvp) {
   2597   2621     llai1 		gethrestime(&now);
   2598   2621     llai1 		attr.va_ctime = now;
   2599   2621     llai1 		attr.va_atime = now;
   2600   2621     llai1 		attr.va_mask = AT_CTIME|AT_ATIME;
   2601   2621     llai1 
   2602   2621     llai1 		(void) VOP_SETATTR(ddv->sdev_attrvp, &attr, 0, kcred, NULL);
   2603   2621     llai1 	}
   2604   2621     llai1 done:
   2605   2621     llai1 	kmem_free(outbuf, alloc_count);
   2606   2621     llai1 	return (error);
   2607   2621     llai1 }
   2608   2621     llai1 
   2609   2621     llai1 static int
   2610   2621     llai1 sdev_modctl_lookup(const char *path, vnode_t **r_vp)
   2611   2621     llai1 {
   2612   2621     llai1 	vnode_t *vp;
   2613   2621     llai1 	vnode_t *cvp;
   2614   2621     llai1 	struct sdev_node *svp;
   2615   2621     llai1 	char *nm;
   2616   2621     llai1 	struct pathname pn;
   2617   2621     llai1 	int error;
   2618   2621     llai1 	int persisted = 0;
   2619   2621     llai1 
   2620   7988     Jerry 	ASSERT(INGLOBALZONE(curproc));
   2621   7988     Jerry 
   2622   2621     llai1 	if (error = pn_get((char *)path, UIO_SYSSPACE, &pn))
   2623   2621     llai1 		return (error);
   2624   2621     llai1 	nm = kmem_alloc(MAXNAMELEN, KM_SLEEP);
   2625   2621     llai1 
   2626   2621     llai1 	vp = rootdir;
   2627   2621     llai1 	VN_HOLD(vp);
   2628   2621     llai1 
   2629   2621     llai1 	while (pn_pathleft(&pn)) {
   2630   7988     Jerry 		ASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
   2631   2621     llai1 		(void) pn_getcomponent(&pn, nm);
   2632   7988     Jerry 
   2633   7988     Jerry 		/*
   2634   7988     Jerry 		 * Deal with the .. special case where we may be
   2635   7988     Jerry 		 * traversing up across a mount point, to the
   2636   7988     Jerry 		 * root of this filesystem or global root.
   2637   7988     Jerry 		 */
   2638   7988     Jerry 		if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) {
   2639   7988     Jerry checkforroot:
   2640   7988     Jerry 			if (VN_CMP(vp, rootdir)) {
   2641   7988     Jerry 				nm[1] = 0;
   2642   7988     Jerry 			} else if (vp->v_flag & VROOT) {
   2643   7988     Jerry 				vfs_t *vfsp;
   2644   7988     Jerry 				cvp = vp;
   2645   7988     Jerry 				vfsp = cvp->v_vfsp;
   2646   7988     Jerry 				vfs_rlock_wait(vfsp);
   2647   7988     Jerry 				vp = cvp->v_vfsp->vfs_vnodecovered;
   2648   7988     Jerry 				if (vp == NULL ||
   2649   7988     Jerry 				    (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
   2650   7988     Jerry 					vfs_unlock(vfsp);
   2651   7988     Jerry 					VN_RELE(cvp);
   2652   7988     Jerry 					error = EIO;
   2653   7988     Jerry 					break;
   2654   7988     Jerry 				}
   2655   7988     Jerry 				VN_HOLD(vp);
   2656   7988     Jerry 				vfs_unlock(vfsp);
   2657   7988     Jerry 				VN_RELE(cvp);
   2658   7988     Jerry 				cvp = NULL;
   2659   7988     Jerry 				goto checkforroot;
   2660   7988     Jerry 			}
   2661   7988     Jerry 		}
   2662   7988     Jerry 
   2663   5331       amw 		error = VOP_LOOKUP(vp, nm, &cvp, NULL, 0, NULL, kcred, NULL,
   2664   5331       amw 		    NULL, NULL);
   2665   7988     Jerry 		if (error) {
   2666   7988     Jerry 			VN_RELE(vp);
   2667   2621     llai1 			break;
   2668   7988     Jerry 		}
   2669   2621     llai1 
   2670   2621     llai1 		/* traverse mount points encountered on our journey */
   2671   2621     llai1 		if (vn_ismntpt(cvp) && (error = traverse(&cvp)) != 0) {
   2672   7988     Jerry 			VN_RELE(vp);
   2673   2621     llai1 			VN_RELE(cvp);
   2674   2621     llai1 			break;
   2675   2621     llai1 		}
   2676   7988     Jerry 
   2677   7988     Jerry 		/*
   2678   7988     Jerry 		 * symbolic link, can be either relative and absolute
   2679   7988     Jerry 		 */
   2680   7988     Jerry 		if ((cvp->v_type == VLNK) && pn_pathleft(&pn)) {
   2681   7988     Jerry 			struct pathname linkpath;
   2682   7988     Jerry 			pn_alloc(&linkpath);
   2683   7988     Jerry 			if (error = pn_getsymlink(cvp, &linkpath, kcred)) {
   2684   7988     Jerry 				pn_free(&linkpath);
   2685   7988     Jerry 				break;
   2686   7988     Jerry 			}
   2687   7988     Jerry 			if (pn_pathleft(&linkpath) == 0)
   2688   7988     Jerry 				(void) pn_set(&linkpath, ".");
   2689   7988     Jerry 			error = pn_insert(&pn, &linkpath, strlen(nm));
   2690   7988     Jerry 			pn_free(&linkpath);
   2691   7988     Jerry 			if (pn.pn_pathlen == 0) {
   2692   7988     Jerry 				VN_RELE(vp);
   2693   7988     Jerry 				return (ENOENT);
   2694   7988     Jerry 			}
   2695   7988     Jerry 			if (pn.pn_path[0] == '/') {
   2696   7988     Jerry 				pn_skipslash(&pn);
   2697   7988     Jerry 				VN_RELE(vp);
   2698   7988     Jerry 				VN_RELE(cvp);
   2699   7988     Jerry 				vp = rootdir;
   2700   7988     Jerry 				VN_HOLD(vp);
   2701   7988     Jerry 			} else {
   2702   7988     Jerry 				VN_RELE(cvp);
   2703   7988     Jerry 			}
   2704   7988     Jerry 			continue;
   2705   7988     Jerry 		}
   2706   7988     Jerry 
   2707   7988     Jerry 		VN_RELE(vp);
   2708   2621     llai1 
   2709   2621     llai1 		/*
   2710   2621     llai1 		 * Direct the operation to the persisting filesystem
   2711   2621     llai1 		 * underlying /dev.  Bail if we encounter a
   2712   2621     llai1 		 * non-persistent dev entity here.
   2713   2621     llai1 		 */
   2714   2621     llai1 		if (cvp->v_vfsp->vfs_fstype == devtype) {
   2715   2621     llai1 
   2716   2621     llai1 			if ((VTOSDEV(cvp)->sdev_flags & SDEV_PERSIST) == 0) {
   2717   2621     llai1 				error = ENOENT;
   2718   2621     llai1 				VN_RELE(cvp);
   2719   2621     llai1 				break;
   2720   2621     llai1 			}
   2721   2621     llai1 
   2722   2621     llai1 			if (VTOSDEV(cvp) == NULL) {
   2723   2621     llai1 				error = ENOENT;
   2724   2621     llai1 				VN_RELE(cvp);
   2725   2621     llai1 				break;
   2726   2621     llai1 			}
   2727   2621     llai1 			svp = VTOSDEV(cvp);
   2728   2621     llai1 			if ((vp = svp->sdev_attrvp) == NULL) {
   2729   2621     llai1 				error = ENOENT;
   2730   2621     llai1 				VN_RELE(cvp);
   2731   2621     llai1 				break;
   2732   2621     llai1 			}
   2733   2621     llai1 			persisted = 1;
   2734   2621     llai1 			VN_HOLD(vp);
   2735   2621     llai1 			VN_RELE(cvp);
   2736   2621     llai1 			cvp = vp;
   2737   2621     llai1 		}
   2738   2621     llai1 
   2739   2621     llai1 		vp = cvp;
   2740   2621     llai1 		pn_skipslash(&pn);
   2741   2621     llai1 	}
   2742   2621     llai1 
   2743   2621     llai1 	kmem_free(nm, MAXNAMELEN);
   2744   2621     llai1 	pn_free(&pn);
   2745   2621     llai1 
   2746   2621     llai1 	if (error)
   2747   2621     llai1 		return (error);
   2748   2621     llai1 
   2749   2621     llai1 	/*
   2750   2621     llai1 	 * Only return persisted nodes in the filesystem underlying /dev.
   2751   2621     llai1 	 */
   2752   2621     llai1 	if (!persisted) {
   2753   2621     llai1 		VN_RELE(vp);
   2754   2621     llai1 		return (ENOENT);
   2755   2621     llai1 	}
   2756   2621     llai1 
   2757   2621     llai1 	*r_vp = vp;
   2758   2621     llai1 	return (0);
   2759   2621     llai1 }
   2760   2621     llai1 
   2761   2621     llai1 int
   2762   2621     llai1 sdev_modctl_readdir(const char *dir, char ***dirlistp,
   2763   6065       cth 	int *npathsp, int *npathsp_alloc, int checking_empty)
   2764   2621     llai1 {
   2765   2621     llai1 	char	**pathlist = NULL;
   2766   2621     llai1 	char	**newlist = NULL;
   2767   2621     llai1 	int	npaths = 0;
   2768   2621     llai1 	int	npaths_alloc = 0;
   2769   2621     llai1 	dirent64_t *dbuf = NULL;
   2770   2621     llai1 	int	n;
   2771   2621     llai1 	char	*s;
   2772   2621     llai1 	int error;
   2773   2621     llai1 	vnode_t *vp;
   2774   2621     llai1 	int eof;
   2775   2621     llai1 	struct iovec iov;
   2776   2621     llai1 	struct uio uio;
   2777   2621     llai1 	struct dirent64 *dp;
   2778   2621     llai1 	size_t dlen;
   2779   2621     llai1 	size_t dbuflen;
   2780   2621     llai1 	int ndirents = 64;
   2781   2621     llai1 	char *nm;
   2782   2621     llai1 
   2783   2621     llai1 	error = sdev_modctl_lookup(dir, &vp);
   2784   2621     llai1 	sdcmn_err11(("modctl readdir: %s by %s: %s\n",
   2785   2621     llai1 	    dir, curproc->p_user.u_comm,
   2786   2621     llai1 	    (error == 0) ? "ok" : "failed"));
   2787   2621     llai1 	if (error)
   2788   2621     llai1 		return (error);
   2789   2621     llai1 
   2790   2621     llai1 	dlen = ndirents * (sizeof (*dbuf));
   2791   2621     llai1 	dbuf = kmem_alloc(dlen, KM_SLEEP);
   2792   2621     llai1 
   2793   2621     llai1 	uio.uio_iov = &iov;
   2794   2621     llai1 	uio.uio_iovcnt = 1;
   2795   2621     llai1 	uio.uio_segflg = UIO_SYSSPACE;
   2796   2621     llai1 	uio.uio_fmode = 0;
   2797   2621     llai1 	uio.uio_extflg = UIO_COPY_CACHED;
   2798   2621     llai1 	uio.uio_loffset = 0;
   2799   2621     llai1 	uio.uio_llimit = MAXOFFSET_T;
   2800   2621     llai1 
   2801   2621     llai1 	eof = 0;
   2802   2621     llai1 	error = 0;
   2803   2621     llai1 	while (!error && !eof) {
   2804   2621     llai1 		uio.uio_resid = dlen;
   2805   2621     llai1 		iov.iov_base = (char *)dbuf;
   2806   2621     llai1 		iov.iov_len = dlen;
   2807   2621     llai1 
   2808   2621     llai1 		(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
   2809   5331       amw 		error = VOP_READDIR(vp, &uio, kcred, &eof, NULL, 0);
   2810   2621     llai1 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
   2811   2621     llai1 
   2812   2621     llai1 		dbuflen = dlen - uio.uio_resid;
   2813   2621     llai1 
   2814   2621     llai1 		if (error || dbuflen == 0)
   2815   2621     llai1 			break;
   2816   2621     llai1 
   2817   2621     llai1 		for (dp = dbuf; ((intptr_t)dp < (intptr_t)dbuf + dbuflen);
   2818   6065       cth 		    dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) {
   2819   2621     llai1 
   2820   2621     llai1 			nm = dp->d_name;
   2821   2621     llai1 
   2822   2621     llai1 			if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0)
   2823   2621     llai1 				continue;
   2824   2621     llai1 			if (npaths == npaths_alloc) {
   2825   2621     llai1 				npaths_alloc += 64;
   2826   2621     llai1 				newlist = (char **)
   2827   2621     llai1 				    kmem_zalloc((npaths_alloc + 1) *
   2828   6065       cth 				    sizeof (char *), KM_SLEEP);
   2829   2621     llai1 				if (pathlist) {
   2830   2621     llai1 					bcopy(pathlist, newlist,
   2831   2621     llai1 					    npaths * sizeof (char *));
   2832   2621     llai1 					kmem_free(pathlist,
   2833   2621     llai1 					    (npaths + 1) * sizeof (char *));
   2834   2621     llai1 				}
   2835   2621     llai1 				pathlist = newlist;
   2836   2621     llai1 			}
   2837   2621     llai1 			n = strlen(nm) + 1;
   2838   2621     llai1 			s = kmem_alloc(n, KM_SLEEP);
   2839   2621     llai1 			bcopy(nm, s, n);
   2840   2621     llai1 			pathlist[npaths++] = s;
   2841   2621     llai1 			sdcmn_err11(("  %s/%s\n", dir, s));
   2842   6065       cth 
   2843   6065       cth 			/* if checking empty, one entry is as good as many */
   2844   6065       cth 			if (checking_empty) {
   2845   6065       cth 				eof = 1;
   2846   6065       cth 				break;
   2847   6065       cth 			}
   2848   2621     llai1 		}
   2849   2621     llai1 	}
   2850   2621     llai1 
   2851   2621     llai1 exit:
   2852   2621     llai1 	VN_RELE(vp);
   2853   2621     llai1 
   2854   2621     llai1 	if (dbuf)
   2855   2621     llai1 		kmem_free(dbuf, dlen);
   2856   2621     llai1 
   2857   2621     llai1 	if (error)
   2858   2621     llai1 		return (error);
   2859   2621     llai1 
   2860   2621     llai1 	*dirlistp = pathlist;
   2861   2621     llai1 	*npathsp = npaths;
   2862   2621     llai1 	*npathsp_alloc = npaths_alloc;
   2863   2621     llai1 
   2864   2621     llai1 	return (0);
   2865   2621     llai1 }
   2866   2621     llai1 
   2867   2621     llai1 void
   2868   2621     llai1 sdev_modctl_readdir_free(char **pathlist, int npaths, int npaths_alloc)
   2869   2621     llai1 {
   2870   2621     llai1 	int	i, n;
   2871   2621     llai1 
   2872   2621     llai1 	for (i = 0; i < npaths; i++) {
   2873   2621     llai1 		n = strlen(pathlist[i]) + 1;
   2874   2621     llai1 		kmem_free(pathlist[i], n);
   2875   2621     llai1 	}
   2876   2621     llai1 
   2877   2621     llai1 	kmem_free(pathlist, (npaths_alloc + 1) * sizeof (char *));
   2878   2621     llai1 }
   2879   2621     llai1 
   2880   2621     llai1 int
   2881   2621     llai1 sdev_modctl_devexists(const char *path)
   2882   2621     llai1 {
   2883   2621     llai1 	vnode_t *vp;
   2884   2621     llai1 	int error;
   2885   2621     llai1 
   2886   2621     llai1 	error = sdev_modctl_lookup(path, &vp);
   2887   2621     llai1 	sdcmn_err11(("modctl dev exists: %s by %s: %s\n",
   2888   2621     llai1 	    path, curproc->p_user.u_comm,
   2889   2621     llai1 	    (error == 0) ? "ok" : "failed"));
   2890   2621     llai1 	if (error == 0)
   2891   2621     llai1 		VN_RELE(vp);
   2892   2621     llai1 
   2893   2621     llai1 	return (error);
   2894   2621     llai1 }
   2895   2621     llai1 
   2896   2621     llai1 extern int sdev_vnodeops_tbl_size;
   2897   2621     llai1 
   2898   2621     llai1 /*
   2899   2621     llai1  * construct a new template with overrides from vtab
   2900   2621     llai1  */
   2901   2621     llai1 static fs_operation_def_t *
   2902   2621     llai1 sdev_merge_vtab(const fs_operation_def_t tab[])
   2903   2621     llai1 {
   2904   2621     llai1 	fs_operation_def_t *new;
   2905   2621     llai1 	const fs_operation_def_t *tab_entry;
   2906   2621     llai1 
   2907   2621     llai1 	/* make a copy of standard vnode ops table */
   2908   2621     llai1 	new = kmem_alloc(sdev_vnodeops_tbl_size, KM_SLEEP);
   2909   2621     llai1 	bcopy((void *)sdev_vnodeops_tbl, new, sdev_vnodeops_tbl_size);
   2910   2621     llai1 
   2911   2621     llai1 	/* replace the overrides from tab */
   2912   2621     llai1 	for (tab_entry = tab; tab_entry->name != NULL; tab_entry++) {
   2913   2621     llai1 		fs_operation_def_t *std_entry = new;
   2914   2621     llai1 		while (std_entry->name) {
   2915   2621     llai1 			if (strcmp(tab_entry->name, std_entry->name) == 0) {
   2916   2621     llai1 				std_entry->func = tab_entry->func;
   2917   2621     llai1 				break;
   2918   2621     llai1 			}
   2919   2621     llai1 			std_entry++;
   2920   2621     llai1 		}
   2921   2621     llai1 		if (std_entry->name == NULL)
   2922   2621     llai1 			cmn_err(CE_NOTE, "sdev_merge_vtab: entry %s unused.",
   2923   2621     llai1 			    tab_entry->name);
   2924   2621     llai1 	}
   2925   2621     llai1 
   2926   2621     llai1 	return (new);
   2927   2621     llai1 }
   2928   2621     llai1 
   2929   2621     llai1 /* free memory allocated by sdev_merge_vtab */
   2930   2621     llai1 static void
   2931   2621     llai1 sdev_free_vtab(fs_operation_def_t *new)
   2932   2621     llai1 {
   2933   2621     llai1 	kmem_free(new, sdev_vnodeops_tbl_size);
   2934   2621     llai1 }
   2935   2621     llai1 
   2936   2621     llai1 /*
   2937   2621     llai1  * a generic setattr() function
   2938   2621     llai1  *
   2939   2621     llai1  * note: flags only supports AT_UID and AT_GID.
   2940   2621     llai1  *	 Future enhancements can be done for other types, e.g. AT_MODE
   2941   2621     llai1  */
   2942   2621     llai1 int
   2943   2621     llai1 devname_setattr_func(struct vnode *vp, struct vattr *vap, int flags,
   2944   2621     llai1     struct cred *cred, int (*callback)(struct sdev_node *, struct vattr *,
   2945   2621     llai1     int), int protocol)
   2946   2621     llai1 {
   2947   2621     llai1 	struct sdev_node	*dv = VTOSDEV(vp);
   2948   2621     llai1 	struct sdev_node	*parent = dv->sdev_dotdot;
   2949   2621     llai1 	struct vattr		*get;
   2950   2621     llai1 	uint_t			mask = vap->va_mask;
   2951   2621     llai1 	int 			error;
   2952   2621     llai1 
   2953   2621     llai1 	/* some sanity checks */
   2954   2621     llai1 	if (vap->va_mask & AT_NOSET)
   2955   2621     llai1 		return (EINVAL);
   2956   2621     llai1 
   2957   2621     llai1 	if (vap->va_mask & AT_SIZE) {
   2958   2621     llai1 		if (vp->v_type == VDIR) {
   2959   2621     llai1 			return (EISDIR);
   2960   2621     llai1 		}
   2961   2621     llai1 	}
   2962   2621     llai1 
   2963   2621     llai1 	/* no need to set attribute, but do not fail either */
   2964   2621     llai1 	ASSERT(parent);
   2965   2621     llai1 	rw_enter(&parent->sdev_contents, RW_READER);
   2966   2621     llai1 	if (dv->sdev_state == SDEV_ZOMBIE) {
   2967   2621     llai1 		rw_exit(&parent->sdev_contents);
   2968   2621     llai1 		return (0);
   2969   2621     llai1 	}
   2970   2621     llai1 
   2971   2621     llai1 	/* If backing store exists, just set it. */
   2972   2621     llai1 	if (dv->sdev_attrvp) {
   2973   2621     llai1 		rw_exit(&parent->sdev_contents);
   2974   2621     llai1 		return (VOP_SETATTR(dv->sdev_attrvp, vap, flags, cred, NULL));
   2975   2621     llai1 	}
   2976   2621     llai1 
   2977   2621     llai1 	/*
   2978   2621     llai1 	 * Otherwise, for nodes with the persistence attribute, create it.
   2979   2621     llai1 	 */
   2980   2621     llai1 	ASSERT(dv->sdev_attr);
   2981   2621     llai1 	if (SDEV_IS_PERSIST(dv) ||
   2982   2621     llai1 	    ((vap->va_mask & ~AT_TIMES) != 0 && !SDEV_IS_DYNAMIC(dv))) {
   2983   2621     llai1 		sdev_vattr_merge(dv, vap);
   2984   2621     llai1 		rw_enter(&dv->sdev_contents, RW_WRITER);
   2985   2621     llai1 		error = sdev_shadow_node(dv, cred);
   2986   2621     llai1 		rw_exit(&dv->sdev_contents);
   2987   2621     llai1 		rw_exit(&parent->sdev_contents);
   2988   2621     llai1 
   2989   2621     llai1 		if (error)
   2990   2621     llai1 			return (error);
   2991   2621     llai1 		return (VOP_SETATTR(dv->sdev_attrvp, vap, flags, cred, NULL));
   2992   2621     llai1 	}
   2993   2621     llai1 
   2994   2621     llai1 
   2995   2621     llai1 	/*
   2996   2621     llai1 	 * sdev_attr was allocated in sdev_mknode
   2997   2621     llai1 	 */
   2998   2621     llai1 	rw_enter(&dv->sdev_contents, RW_WRITER);
   2999   5331       amw 	error = secpolicy_vnode_setattr(cred, vp, vap,
   3000   5331       amw 	    dv->sdev_attr, flags, sdev_unlocked_access, dv);
   3001   2621     llai1 	if (error) {
   3002   2621     llai1 		rw_exit(&dv->sdev_contents);
   3003   2621     llai1 		rw_exit(&parent->sdev_contents);
   3004   2621     llai1 		return (error);
   3005   2621     llai1 	}
   3006   2621     llai1 
   3007   2621     llai1 	get = dv->sdev_attr;
   3008   2621     llai1 	if (mask & AT_MODE) {
   3009   2621     llai1 		get->va_mode &= S_IFMT;
   3010   2621