xref: /onnv-gate/usr/src/uts/common/fs/dev/sdev_vtops.c (revision 11279:b69054bce66e)
17688SAaron.Zang@Sun.COM /*
27688SAaron.Zang@Sun.COM  * CDDL HEADER START
37688SAaron.Zang@Sun.COM  *
47688SAaron.Zang@Sun.COM  * The contents of this file are subject to the terms of the
57688SAaron.Zang@Sun.COM  * Common Development and Distribution License (the "License").
67688SAaron.Zang@Sun.COM  * You may not use this file except in compliance with the License.
77688SAaron.Zang@Sun.COM  *
87688SAaron.Zang@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97688SAaron.Zang@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107688SAaron.Zang@Sun.COM  * See the License for the specific language governing permissions
117688SAaron.Zang@Sun.COM  * and limitations under the License.
127688SAaron.Zang@Sun.COM  *
137688SAaron.Zang@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147688SAaron.Zang@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157688SAaron.Zang@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167688SAaron.Zang@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177688SAaron.Zang@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187688SAaron.Zang@Sun.COM  *
197688SAaron.Zang@Sun.COM  * CDDL HEADER END
207688SAaron.Zang@Sun.COM  */
217688SAaron.Zang@Sun.COM /*
22*11279SJerry.Gilliam@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237688SAaron.Zang@Sun.COM  * Use is subject to license terms.
247688SAaron.Zang@Sun.COM  */
257688SAaron.Zang@Sun.COM 
267688SAaron.Zang@Sun.COM /*
277688SAaron.Zang@Sun.COM  * vnode ops for the /dev/vt directory
287688SAaron.Zang@Sun.COM  */
297688SAaron.Zang@Sun.COM 
307688SAaron.Zang@Sun.COM #include <sys/types.h>
317688SAaron.Zang@Sun.COM #include <sys/param.h>
327688SAaron.Zang@Sun.COM #include <sys/sysmacros.h>
337688SAaron.Zang@Sun.COM #include <sys/sunndi.h>
347688SAaron.Zang@Sun.COM #include <fs/fs_subr.h>
357688SAaron.Zang@Sun.COM #include <sys/fs/dv_node.h>
367688SAaron.Zang@Sun.COM #include <sys/fs/sdev_impl.h>
377688SAaron.Zang@Sun.COM #include <sys/policy.h>
387688SAaron.Zang@Sun.COM #include <sys/stat.h>
397688SAaron.Zang@Sun.COM #include <sys/vfs_opreg.h>
407688SAaron.Zang@Sun.COM #include <sys/tty.h>
417688SAaron.Zang@Sun.COM #include <sys/vt_impl.h>
427688SAaron.Zang@Sun.COM #include <sys/note.h>
437688SAaron.Zang@Sun.COM 
447688SAaron.Zang@Sun.COM /* warlock in this file only cares about variables shared by vt and devfs */
457688SAaron.Zang@Sun.COM _NOTE(SCHEME_PROTECTS_DATA("Do not care", sdev_node vattr vnode))
467688SAaron.Zang@Sun.COM 
477688SAaron.Zang@Sun.COM #define	DEVVT_UID_DEFAULT	SDEV_UID_DEFAULT
487688SAaron.Zang@Sun.COM #define	DEVVT_GID_DEFAULT	(0)
497688SAaron.Zang@Sun.COM #define	DEVVT_DEVMODE_DEFAULT	(0600)
507688SAaron.Zang@Sun.COM #define	DEVVT_ACTIVE_NAME	"active"
517688SAaron.Zang@Sun.COM 
527688SAaron.Zang@Sun.COM #define	isdigit(ch)	((ch) >= '0' && (ch) <= '9')
537688SAaron.Zang@Sun.COM 
547688SAaron.Zang@Sun.COM /* attributes for VT nodes */
557688SAaron.Zang@Sun.COM static vattr_t devvt_vattr = {
567688SAaron.Zang@Sun.COM 	AT_TYPE|AT_MODE|AT_UID|AT_GID,		/* va_mask */
577688SAaron.Zang@Sun.COM 	VCHR,					/* va_type */
587688SAaron.Zang@Sun.COM 	S_IFCHR | DEVVT_DEVMODE_DEFAULT,	/* va_mode */
597688SAaron.Zang@Sun.COM 	DEVVT_UID_DEFAULT,			/* va_uid */
607688SAaron.Zang@Sun.COM 	DEVVT_GID_DEFAULT,			/* va_gid */
617688SAaron.Zang@Sun.COM 	0					/* 0 hereafter */
627688SAaron.Zang@Sun.COM };
637688SAaron.Zang@Sun.COM 
647688SAaron.Zang@Sun.COM struct vnodeops		*devvt_vnodeops;
657688SAaron.Zang@Sun.COM 
667688SAaron.Zang@Sun.COM struct vnodeops *
677688SAaron.Zang@Sun.COM devvt_getvnodeops(void)
687688SAaron.Zang@Sun.COM {
697688SAaron.Zang@Sun.COM 	return (devvt_vnodeops);
707688SAaron.Zang@Sun.COM }
717688SAaron.Zang@Sun.COM 
727688SAaron.Zang@Sun.COM static int
737688SAaron.Zang@Sun.COM devvt_str2minor(const char *nm, minor_t *mp)
747688SAaron.Zang@Sun.COM {
757688SAaron.Zang@Sun.COM 	long uminor = 0;
767688SAaron.Zang@Sun.COM 	char *endptr = NULL;
777688SAaron.Zang@Sun.COM 
787688SAaron.Zang@Sun.COM 	if (nm == NULL || !isdigit(*nm))
797688SAaron.Zang@Sun.COM 		return (EINVAL);
807688SAaron.Zang@Sun.COM 
817688SAaron.Zang@Sun.COM 	*mp = 0;
827688SAaron.Zang@Sun.COM 	if (ddi_strtol(nm, &endptr, 10, &uminor) != 0 ||
837688SAaron.Zang@Sun.COM 	    *endptr != '\0' || uminor < 0) {
847688SAaron.Zang@Sun.COM 		return (EINVAL);
857688SAaron.Zang@Sun.COM 	}
867688SAaron.Zang@Sun.COM 
877688SAaron.Zang@Sun.COM 	*mp = (minor_t)uminor;
887688SAaron.Zang@Sun.COM 	return (0);
897688SAaron.Zang@Sun.COM }
907688SAaron.Zang@Sun.COM 
917688SAaron.Zang@Sun.COM /*ARGSUSED*/
927688SAaron.Zang@Sun.COM int
937688SAaron.Zang@Sun.COM devvt_validate(struct sdev_node *dv)
947688SAaron.Zang@Sun.COM {
957688SAaron.Zang@Sun.COM 	minor_t min;
967688SAaron.Zang@Sun.COM 	char *nm = dv->sdev_name;
977688SAaron.Zang@Sun.COM 
987688SAaron.Zang@Sun.COM 	ASSERT(!(dv->sdev_flags & SDEV_STALE));
997688SAaron.Zang@Sun.COM 	ASSERT(dv->sdev_state == SDEV_READY);
1007688SAaron.Zang@Sun.COM 
1017688SAaron.Zang@Sun.COM 	/* validate only READY nodes */
1027688SAaron.Zang@Sun.COM 	if (dv->sdev_state != SDEV_READY) {
1037688SAaron.Zang@Sun.COM 		sdcmn_err(("dev fs: skipping: node not ready %s(%p)",
1047688SAaron.Zang@Sun.COM 		    nm, (void *)dv));
1057688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_SKIP);
1067688SAaron.Zang@Sun.COM 	}
1077688SAaron.Zang@Sun.COM 
1087688SAaron.Zang@Sun.COM 	if (vt_wc_attached() == (major_t)-1)
1097688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
1107688SAaron.Zang@Sun.COM 
1117688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
1127688SAaron.Zang@Sun.COM 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1137688SAaron.Zang@Sun.COM 
1147688SAaron.Zang@Sun.COM 		(void) vt_getactive(link, MAXPATHLEN);
1157688SAaron.Zang@Sun.COM 		if (strcmp(link, dv->sdev_symlink) != 0) {
1167688SAaron.Zang@Sun.COM 			kmem_free(dv->sdev_symlink,
1177688SAaron.Zang@Sun.COM 			    strlen(dv->sdev_symlink) + 1);
1187688SAaron.Zang@Sun.COM 			dv->sdev_symlink = i_ddi_strdup(link, KM_SLEEP);
1197688SAaron.Zang@Sun.COM 			dv->sdev_attr->va_size = strlen(link);
1207688SAaron.Zang@Sun.COM 		}
1217688SAaron.Zang@Sun.COM 		kmem_free(link, MAXPATHLEN);
1227688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_VALID);
1237688SAaron.Zang@Sun.COM 	} else if (devvt_str2minor(nm, &min) != 0) {
1247688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
1257688SAaron.Zang@Sun.COM 	}
1267688SAaron.Zang@Sun.COM 
1277688SAaron.Zang@Sun.COM 	if (vt_minor_valid(min) == B_FALSE)
1287688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
1297688SAaron.Zang@Sun.COM 
1307688SAaron.Zang@Sun.COM 	return (SDEV_VTOR_VALID);
1317688SAaron.Zang@Sun.COM }
1327688SAaron.Zang@Sun.COM 
1337688SAaron.Zang@Sun.COM /*
1347688SAaron.Zang@Sun.COM  * This callback is invoked from devname_lookup_func() to create
1357688SAaron.Zang@Sun.COM  * a entry when the node is not found in the cache.
1367688SAaron.Zang@Sun.COM  */
1377688SAaron.Zang@Sun.COM /*ARGSUSED*/
1387688SAaron.Zang@Sun.COM static int
1397688SAaron.Zang@Sun.COM devvt_create_rvp(struct sdev_node *ddv, char *nm,
1407688SAaron.Zang@Sun.COM     void **arg, cred_t *cred, void *whatever, char *whichever)
1417688SAaron.Zang@Sun.COM {
1427688SAaron.Zang@Sun.COM 	minor_t min;
1437688SAaron.Zang@Sun.COM 	major_t maj;
1447688SAaron.Zang@Sun.COM 	struct vattr *vap = (struct vattr *)arg;
1457688SAaron.Zang@Sun.COM 
1467688SAaron.Zang@Sun.COM 	if ((maj = vt_wc_attached()) == (major_t)-1)
1477688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
1487688SAaron.Zang@Sun.COM 
1497688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
1507688SAaron.Zang@Sun.COM 		(void) vt_getactive((char *)*arg, MAXPATHLEN);
1517688SAaron.Zang@Sun.COM 		return (0);
1527688SAaron.Zang@Sun.COM 	}
1537688SAaron.Zang@Sun.COM 
1547688SAaron.Zang@Sun.COM 	if (devvt_str2minor(nm, &min) != 0)
1557688SAaron.Zang@Sun.COM 		return (-1);
1567688SAaron.Zang@Sun.COM 
1577688SAaron.Zang@Sun.COM 	if (vt_minor_valid(min) == B_FALSE)
1587688SAaron.Zang@Sun.COM 		return (-1);
1597688SAaron.Zang@Sun.COM 
1607688SAaron.Zang@Sun.COM 	*vap = devvt_vattr;
1617688SAaron.Zang@Sun.COM 	vap->va_rdev = makedevice(maj, min);
1627688SAaron.Zang@Sun.COM 
1637688SAaron.Zang@Sun.COM 	return (0);
1647688SAaron.Zang@Sun.COM }
1657688SAaron.Zang@Sun.COM 
1667688SAaron.Zang@Sun.COM /*ARGSUSED3*/
1677688SAaron.Zang@Sun.COM static int
1687688SAaron.Zang@Sun.COM devvt_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
1697688SAaron.Zang@Sun.COM     struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
1707688SAaron.Zang@Sun.COM     caller_context_t *ct, int *direntflags, pathname_t *realpnp)
1717688SAaron.Zang@Sun.COM {
1727688SAaron.Zang@Sun.COM 	struct sdev_node *sdvp = VTOSDEV(dvp);
1737688SAaron.Zang@Sun.COM 	struct sdev_node *dv;
1747688SAaron.Zang@Sun.COM 	struct vnode *rvp = NULL;
1757688SAaron.Zang@Sun.COM 	int type, error;
1767688SAaron.Zang@Sun.COM 
1777688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
1787688SAaron.Zang@Sun.COM 		type = SDEV_VLINK;
1797688SAaron.Zang@Sun.COM 	} else {
1807688SAaron.Zang@Sun.COM 		type = SDEV_VATTR;
1817688SAaron.Zang@Sun.COM 	}
1827688SAaron.Zang@Sun.COM 
1837688SAaron.Zang@Sun.COM /* Give warlock a more clear call graph */
1847688SAaron.Zang@Sun.COM #ifndef __lock_lint
1857688SAaron.Zang@Sun.COM 	error = devname_lookup_func(sdvp, nm, vpp, cred,
1867688SAaron.Zang@Sun.COM 	    devvt_create_rvp, type);
1877688SAaron.Zang@Sun.COM #else
1887688SAaron.Zang@Sun.COM 	devvt_create_rvp(0, 0, 0, 0, 0, 0);
1897688SAaron.Zang@Sun.COM #endif
1907688SAaron.Zang@Sun.COM 
1917688SAaron.Zang@Sun.COM 	if (error == 0) {
1927688SAaron.Zang@Sun.COM 		switch ((*vpp)->v_type) {
1937688SAaron.Zang@Sun.COM 		case VCHR:
1947688SAaron.Zang@Sun.COM 			dv = VTOSDEV(VTOS(*vpp)->s_realvp);
1957688SAaron.Zang@Sun.COM 			ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
1967688SAaron.Zang@Sun.COM 			break;
1977688SAaron.Zang@Sun.COM 		case VDIR:
1987688SAaron.Zang@Sun.COM 		case VLNK:
1997688SAaron.Zang@Sun.COM 			dv = VTOSDEV(*vpp);
2007688SAaron.Zang@Sun.COM 			break;
2017688SAaron.Zang@Sun.COM 		default:
2027688SAaron.Zang@Sun.COM 			cmn_err(CE_PANIC, "devvt_lookup: Unsupported node "
2037688SAaron.Zang@Sun.COM 			    "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
2047688SAaron.Zang@Sun.COM 			break;
2057688SAaron.Zang@Sun.COM 		}
2067688SAaron.Zang@Sun.COM 		ASSERT(SDEV_HELD(dv));
2077688SAaron.Zang@Sun.COM 	}
2087688SAaron.Zang@Sun.COM 
2097688SAaron.Zang@Sun.COM 	return (error);
2107688SAaron.Zang@Sun.COM }
2117688SAaron.Zang@Sun.COM 
2127688SAaron.Zang@Sun.COM static void
2137688SAaron.Zang@Sun.COM devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type)
2147688SAaron.Zang@Sun.COM {
2157688SAaron.Zang@Sun.COM 	int error;
2167688SAaron.Zang@Sun.COM 	struct sdev_node *sdv = NULL;
217*11279SJerry.Gilliam@Sun.COM 	struct vattr vattr;
218*11279SJerry.Gilliam@Sun.COM 	struct vattr *vap = &vattr;
2197688SAaron.Zang@Sun.COM 	major_t maj;
2207688SAaron.Zang@Sun.COM 	minor_t min;
2217688SAaron.Zang@Sun.COM 
2227688SAaron.Zang@Sun.COM 	if ((maj = vt_wc_attached()) == (major_t)-1)
2237688SAaron.Zang@Sun.COM 		return;
2247688SAaron.Zang@Sun.COM 
2257688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 &&
2267688SAaron.Zang@Sun.COM 	    devvt_str2minor(nm, &min) != 0)
2277688SAaron.Zang@Sun.COM 		return;
2287688SAaron.Zang@Sun.COM 
2297688SAaron.Zang@Sun.COM 	error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT);
2307688SAaron.Zang@Sun.COM 	if (error || !sdv) {
2317688SAaron.Zang@Sun.COM 		return;
2327688SAaron.Zang@Sun.COM 	}
2337688SAaron.Zang@Sun.COM 
2347688SAaron.Zang@Sun.COM 	mutex_enter(&sdv->sdev_lookup_lock);
2357688SAaron.Zang@Sun.COM 	SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP);
2367688SAaron.Zang@Sun.COM 	mutex_exit(&sdv->sdev_lookup_lock);
2377688SAaron.Zang@Sun.COM 
2387688SAaron.Zang@Sun.COM 	if (type & SDEV_VATTR) {
239*11279SJerry.Gilliam@Sun.COM 		*vap = devvt_vattr;
2407688SAaron.Zang@Sun.COM 		vap->va_rdev = makedevice(maj, min);
2417688SAaron.Zang@Sun.COM 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
2427688SAaron.Zang@Sun.COM 		    NULL, cred, SDEV_READY);
2437688SAaron.Zang@Sun.COM 	} else if (type & SDEV_VLINK) {
2447688SAaron.Zang@Sun.COM 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
2457688SAaron.Zang@Sun.COM 
2467688SAaron.Zang@Sun.COM 		(void) vt_getactive(link, MAXPATHLEN);
247*11279SJerry.Gilliam@Sun.COM 		*vap = sdev_vattr_lnk;
2487688SAaron.Zang@Sun.COM 		vap->va_size = strlen(link);
2497688SAaron.Zang@Sun.COM 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
2507688SAaron.Zang@Sun.COM 		    (void *)link, cred, SDEV_READY);
2517688SAaron.Zang@Sun.COM 
2527688SAaron.Zang@Sun.COM 		kmem_free(link, MAXPATHLEN);
2537688SAaron.Zang@Sun.COM 	}
2547688SAaron.Zang@Sun.COM 
2557688SAaron.Zang@Sun.COM 	mutex_enter(&sdv->sdev_lookup_lock);
2567688SAaron.Zang@Sun.COM 	SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP);
2577688SAaron.Zang@Sun.COM 	mutex_exit(&sdv->sdev_lookup_lock);
2587688SAaron.Zang@Sun.COM 
2597688SAaron.Zang@Sun.COM }
2607688SAaron.Zang@Sun.COM 
2617688SAaron.Zang@Sun.COM static void
2627688SAaron.Zang@Sun.COM devvt_prunedir(struct sdev_node *ddv)
2637688SAaron.Zang@Sun.COM {
2647688SAaron.Zang@Sun.COM 	struct vnode *vp;
2657688SAaron.Zang@Sun.COM 	struct sdev_node *dv, *next = NULL;
2667688SAaron.Zang@Sun.COM 	int (*vtor)(struct sdev_node *) = NULL;
2677688SAaron.Zang@Sun.COM 
2687688SAaron.Zang@Sun.COM 	ASSERT(ddv->sdev_flags & SDEV_VTOR);
2697688SAaron.Zang@Sun.COM 
2707688SAaron.Zang@Sun.COM 	vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
2717688SAaron.Zang@Sun.COM 	ASSERT(vtor);
2727688SAaron.Zang@Sun.COM 
2737688SAaron.Zang@Sun.COM 	for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
2747688SAaron.Zang@Sun.COM 		next = SDEV_NEXT_ENTRY(ddv, dv);
2757688SAaron.Zang@Sun.COM 
2767688SAaron.Zang@Sun.COM 		/* skip stale nodes */
2777688SAaron.Zang@Sun.COM 		if (dv->sdev_flags & SDEV_STALE)
2787688SAaron.Zang@Sun.COM 			continue;
2797688SAaron.Zang@Sun.COM 
2807688SAaron.Zang@Sun.COM 		/* validate and prune only ready nodes */
2817688SAaron.Zang@Sun.COM 		if (dv->sdev_state != SDEV_READY)
2827688SAaron.Zang@Sun.COM 			continue;
2837688SAaron.Zang@Sun.COM 
2847688SAaron.Zang@Sun.COM 		switch (vtor(dv)) {
2857688SAaron.Zang@Sun.COM 		case SDEV_VTOR_VALID:
2867688SAaron.Zang@Sun.COM 		case SDEV_VTOR_SKIP:
2877688SAaron.Zang@Sun.COM 			continue;
2887688SAaron.Zang@Sun.COM 		case SDEV_VTOR_INVALID:
2898023SPhil.Kirk@Sun.COM 		case SDEV_VTOR_STALE:
2907688SAaron.Zang@Sun.COM 			sdcmn_err7(("destroy invalid "
2917688SAaron.Zang@Sun.COM 			    "node: %s(%p)\n", dv->sdev_name, (void *)dv));
2927688SAaron.Zang@Sun.COM 			break;
2937688SAaron.Zang@Sun.COM 		}
2947688SAaron.Zang@Sun.COM 		vp = SDEVTOV(dv);
2957688SAaron.Zang@Sun.COM 		if (vp->v_count > 0)
2967688SAaron.Zang@Sun.COM 			continue;
2977688SAaron.Zang@Sun.COM 		SDEV_HOLD(dv);
2987688SAaron.Zang@Sun.COM 		/* remove the cache node */
2997688SAaron.Zang@Sun.COM 		(void) sdev_cache_update(ddv, &dv, dv->sdev_name,
3007688SAaron.Zang@Sun.COM 		    SDEV_CACHE_DELETE);
3017688SAaron.Zang@Sun.COM 	}
3027688SAaron.Zang@Sun.COM }
3037688SAaron.Zang@Sun.COM 
3047688SAaron.Zang@Sun.COM static void
3057688SAaron.Zang@Sun.COM devvt_cleandir(struct vnode *dvp, struct cred *cred)
3067688SAaron.Zang@Sun.COM {
3077688SAaron.Zang@Sun.COM 	struct sdev_node *sdvp = VTOSDEV(dvp);
3087688SAaron.Zang@Sun.COM 	struct sdev_node *dv, *next = NULL;
3097688SAaron.Zang@Sun.COM 	int min, cnt;
3107688SAaron.Zang@Sun.COM 	int found = 0;
3117688SAaron.Zang@Sun.COM 
3127688SAaron.Zang@Sun.COM 	mutex_enter(&vc_lock);
3137688SAaron.Zang@Sun.COM 	cnt = VC_INSTANCES_COUNT;
3147688SAaron.Zang@Sun.COM 	mutex_exit(&vc_lock);
3157688SAaron.Zang@Sun.COM 
3167688SAaron.Zang@Sun.COM /* We have to fool warlock this way, otherwise it will complain */
3177688SAaron.Zang@Sun.COM #ifndef	__lock_lint
3187688SAaron.Zang@Sun.COM 	if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) {
3197688SAaron.Zang@Sun.COM 		rw_exit(&sdvp->sdev_contents);
3207688SAaron.Zang@Sun.COM 		rw_enter(&sdvp->sdev_contents, RW_WRITER);
3217688SAaron.Zang@Sun.COM 	}
3227688SAaron.Zang@Sun.COM #else
3237688SAaron.Zang@Sun.COM 	rw_enter(&sdvp->sdev_contents, RW_WRITER);
3247688SAaron.Zang@Sun.COM #endif
3257688SAaron.Zang@Sun.COM 
3267688SAaron.Zang@Sun.COM 	/* 1. create missed nodes */
3277688SAaron.Zang@Sun.COM 	for (min = 0; min < cnt; min++) {
3287688SAaron.Zang@Sun.COM 		char nm[16];
3297688SAaron.Zang@Sun.COM 
3307688SAaron.Zang@Sun.COM 		if (vt_minor_valid(min) == B_FALSE)
3317688SAaron.Zang@Sun.COM 			continue;
3327688SAaron.Zang@Sun.COM 
3337688SAaron.Zang@Sun.COM 		(void) snprintf(nm, sizeof (nm), "%d", min);
3347688SAaron.Zang@Sun.COM 		found = 0;
3357688SAaron.Zang@Sun.COM 		for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
3367688SAaron.Zang@Sun.COM 			next = SDEV_NEXT_ENTRY(sdvp, dv);
3377688SAaron.Zang@Sun.COM 
3387688SAaron.Zang@Sun.COM 			/* skip stale nodes */
3397688SAaron.Zang@Sun.COM 			if (dv->sdev_flags & SDEV_STALE)
3407688SAaron.Zang@Sun.COM 				continue;
3417688SAaron.Zang@Sun.COM 			/* validate and prune only ready nodes */
3427688SAaron.Zang@Sun.COM 			if (dv->sdev_state != SDEV_READY)
3437688SAaron.Zang@Sun.COM 				continue;
3447688SAaron.Zang@Sun.COM 			if (strcmp(nm, dv->sdev_name) == 0) {
3457688SAaron.Zang@Sun.COM 				found = 1;
3467688SAaron.Zang@Sun.COM 				break;
3477688SAaron.Zang@Sun.COM 			}
3487688SAaron.Zang@Sun.COM 		}
3497688SAaron.Zang@Sun.COM 		if (!found) {
3507688SAaron.Zang@Sun.COM 			devvt_create_snode(sdvp, nm, cred, SDEV_VATTR);
3517688SAaron.Zang@Sun.COM 		}
3527688SAaron.Zang@Sun.COM 	}
3537688SAaron.Zang@Sun.COM 
3547688SAaron.Zang@Sun.COM 	/* 2. create active link node */
3557688SAaron.Zang@Sun.COM 	found = 0;
3567688SAaron.Zang@Sun.COM 	for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
3577688SAaron.Zang@Sun.COM 		next = SDEV_NEXT_ENTRY(sdvp, dv);
3587688SAaron.Zang@Sun.COM 
3597688SAaron.Zang@Sun.COM 		/* skip stale nodes */
3607688SAaron.Zang@Sun.COM 		if (dv->sdev_flags & SDEV_STALE)
3617688SAaron.Zang@Sun.COM 			continue;
3627688SAaron.Zang@Sun.COM 		/* validate and prune only ready nodes */
3637688SAaron.Zang@Sun.COM 		if (dv->sdev_state != SDEV_READY)
3647688SAaron.Zang@Sun.COM 			continue;
3657688SAaron.Zang@Sun.COM 		if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL)) {
3667688SAaron.Zang@Sun.COM 			found = 1;
3677688SAaron.Zang@Sun.COM 			break;
3687688SAaron.Zang@Sun.COM 		}
3697688SAaron.Zang@Sun.COM 	}
3707688SAaron.Zang@Sun.COM 	if (!found)
3717688SAaron.Zang@Sun.COM 		devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK);
3727688SAaron.Zang@Sun.COM 
3737688SAaron.Zang@Sun.COM 	/* 3. cleanup invalid nodes */
3747688SAaron.Zang@Sun.COM 	devvt_prunedir(sdvp);
3757688SAaron.Zang@Sun.COM 
3767688SAaron.Zang@Sun.COM #ifndef	__lock_lint
3777688SAaron.Zang@Sun.COM 	rw_downgrade(&sdvp->sdev_contents);
3787688SAaron.Zang@Sun.COM #else
3797688SAaron.Zang@Sun.COM 	rw_exit(&sdvp->sdev_contents);
3807688SAaron.Zang@Sun.COM #endif
3817688SAaron.Zang@Sun.COM }
3827688SAaron.Zang@Sun.COM 
3837688SAaron.Zang@Sun.COM /*ARGSUSED4*/
3847688SAaron.Zang@Sun.COM static int
3857688SAaron.Zang@Sun.COM devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
3867688SAaron.Zang@Sun.COM     int *eofp, caller_context_t *ct, int flags)
3877688SAaron.Zang@Sun.COM {
3887688SAaron.Zang@Sun.COM 	if (uiop->uio_offset == 0) {
3897688SAaron.Zang@Sun.COM 		devvt_cleandir(dvp, cred);
3907688SAaron.Zang@Sun.COM 	}
3917688SAaron.Zang@Sun.COM 
3927688SAaron.Zang@Sun.COM 	return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
3937688SAaron.Zang@Sun.COM }
3947688SAaron.Zang@Sun.COM 
3957688SAaron.Zang@Sun.COM /*
3967688SAaron.Zang@Sun.COM  * We allow create to find existing nodes
3977688SAaron.Zang@Sun.COM  *	- if the node doesn't exist - EROFS
3987688SAaron.Zang@Sun.COM  *	- creating an existing dir read-only succeeds, otherwise EISDIR
3997688SAaron.Zang@Sun.COM  *	- exclusive creates fail - EEXIST
4007688SAaron.Zang@Sun.COM  */
4017688SAaron.Zang@Sun.COM /*ARGSUSED2*/
4027688SAaron.Zang@Sun.COM static int
4037688SAaron.Zang@Sun.COM devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
4047688SAaron.Zang@Sun.COM     int mode, struct vnode **vpp, struct cred *cred, int flag,
4057688SAaron.Zang@Sun.COM     caller_context_t *ct, vsecattr_t *vsecp)
4067688SAaron.Zang@Sun.COM {
4077688SAaron.Zang@Sun.COM 	int error;
4087688SAaron.Zang@Sun.COM 	struct vnode *vp;
4097688SAaron.Zang@Sun.COM 
4107688SAaron.Zang@Sun.COM 	*vpp = NULL;
4117688SAaron.Zang@Sun.COM 
4127688SAaron.Zang@Sun.COM 	if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
4137688SAaron.Zang@Sun.COM 	    NULL)) != 0) {
4147688SAaron.Zang@Sun.COM 		if (error == ENOENT)
4157688SAaron.Zang@Sun.COM 			error = EROFS;
4167688SAaron.Zang@Sun.COM 		return (error);
4177688SAaron.Zang@Sun.COM 	}
4187688SAaron.Zang@Sun.COM 
4197688SAaron.Zang@Sun.COM 	if (excl == EXCL)
4207688SAaron.Zang@Sun.COM 		error = EEXIST;
4217688SAaron.Zang@Sun.COM 	else if (vp->v_type == VDIR && (mode & VWRITE))
4227688SAaron.Zang@Sun.COM 		error = EISDIR;
4237688SAaron.Zang@Sun.COM 	else
4247688SAaron.Zang@Sun.COM 		error = VOP_ACCESS(vp, mode, 0, cred, ct);
4257688SAaron.Zang@Sun.COM 
4267688SAaron.Zang@Sun.COM 	if (error) {
4277688SAaron.Zang@Sun.COM 		VN_RELE(vp);
4287688SAaron.Zang@Sun.COM 	} else
4297688SAaron.Zang@Sun.COM 		*vpp = vp;
4307688SAaron.Zang@Sun.COM 
4317688SAaron.Zang@Sun.COM 	return (error);
4327688SAaron.Zang@Sun.COM }
4337688SAaron.Zang@Sun.COM 
4347688SAaron.Zang@Sun.COM const fs_operation_def_t devvt_vnodeops_tbl[] = {
4357688SAaron.Zang@Sun.COM 	VOPNAME_READDIR,	{ .vop_readdir = devvt_readdir },
4367688SAaron.Zang@Sun.COM 	VOPNAME_LOOKUP,		{ .vop_lookup = devvt_lookup },
4377688SAaron.Zang@Sun.COM 	VOPNAME_CREATE,		{ .vop_create = devvt_create },
4387688SAaron.Zang@Sun.COM 	VOPNAME_REMOVE,		{ .error = fs_nosys },
4397688SAaron.Zang@Sun.COM 	VOPNAME_MKDIR,		{ .error = fs_nosys },
4407688SAaron.Zang@Sun.COM 	VOPNAME_RMDIR,		{ .error = fs_nosys },
4417688SAaron.Zang@Sun.COM 	VOPNAME_SYMLINK,	{ .error = fs_nosys },
4427688SAaron.Zang@Sun.COM 	VOPNAME_SETSECATTR,	{ .error = fs_nosys },
4437688SAaron.Zang@Sun.COM 	NULL,			NULL
4447688SAaron.Zang@Sun.COM };
445