xref: /onnv-gate/usr/src/uts/common/fs/dev/sdev_vtops.c (revision 12717:1cb0b42b763e)
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 /*
2212195SAaron.Zang@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
237688SAaron.Zang@Sun.COM  */
247688SAaron.Zang@Sun.COM 
257688SAaron.Zang@Sun.COM /*
267688SAaron.Zang@Sun.COM  * vnode ops for the /dev/vt directory
277688SAaron.Zang@Sun.COM  */
287688SAaron.Zang@Sun.COM 
297688SAaron.Zang@Sun.COM #include <sys/types.h>
307688SAaron.Zang@Sun.COM #include <sys/param.h>
317688SAaron.Zang@Sun.COM #include <sys/sysmacros.h>
327688SAaron.Zang@Sun.COM #include <sys/sunndi.h>
337688SAaron.Zang@Sun.COM #include <fs/fs_subr.h>
347688SAaron.Zang@Sun.COM #include <sys/fs/dv_node.h>
357688SAaron.Zang@Sun.COM #include <sys/fs/sdev_impl.h>
367688SAaron.Zang@Sun.COM #include <sys/policy.h>
377688SAaron.Zang@Sun.COM #include <sys/stat.h>
387688SAaron.Zang@Sun.COM #include <sys/vfs_opreg.h>
397688SAaron.Zang@Sun.COM #include <sys/tty.h>
407688SAaron.Zang@Sun.COM #include <sys/vt_impl.h>
417688SAaron.Zang@Sun.COM #include <sys/note.h>
427688SAaron.Zang@Sun.COM 
437688SAaron.Zang@Sun.COM /* warlock in this file only cares about variables shared by vt and devfs */
447688SAaron.Zang@Sun.COM _NOTE(SCHEME_PROTECTS_DATA("Do not care", sdev_node vattr vnode))
457688SAaron.Zang@Sun.COM 
467688SAaron.Zang@Sun.COM #define	DEVVT_UID_DEFAULT	SDEV_UID_DEFAULT
477688SAaron.Zang@Sun.COM #define	DEVVT_GID_DEFAULT	(0)
487688SAaron.Zang@Sun.COM #define	DEVVT_DEVMODE_DEFAULT	(0600)
497688SAaron.Zang@Sun.COM #define	DEVVT_ACTIVE_NAME	"active"
5012195SAaron.Zang@Sun.COM #define	DEVVT_CONSUSER_NAME	"console_user"
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 *
devvt_getvnodeops(void)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
devvt_str2minor(const char * nm,minor_t * mp)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 
91*12717SJerry.Gilliam@Sun.COM /*
92*12717SJerry.Gilliam@Sun.COM  * Validate that a node is up-to-date and correct.
93*12717SJerry.Gilliam@Sun.COM  * A validator may not update the node state or
94*12717SJerry.Gilliam@Sun.COM  * contents as a read lock permits entry by
95*12717SJerry.Gilliam@Sun.COM  * multiple threads.
96*12717SJerry.Gilliam@Sun.COM  */
977688SAaron.Zang@Sun.COM int
devvt_validate(struct sdev_node * dv)987688SAaron.Zang@Sun.COM devvt_validate(struct sdev_node *dv)
997688SAaron.Zang@Sun.COM {
1007688SAaron.Zang@Sun.COM 	minor_t min;
1017688SAaron.Zang@Sun.COM 	char *nm = dv->sdev_name;
102*12717SJerry.Gilliam@Sun.COM 	int rval;
1037688SAaron.Zang@Sun.COM 
1047688SAaron.Zang@Sun.COM 	ASSERT(!(dv->sdev_flags & SDEV_STALE));
1057688SAaron.Zang@Sun.COM 	ASSERT(dv->sdev_state == SDEV_READY);
106*12717SJerry.Gilliam@Sun.COM 	ASSERT(RW_LOCK_HELD(&(dv->sdev_dotdot)->sdev_contents));
1077688SAaron.Zang@Sun.COM 
1087688SAaron.Zang@Sun.COM 	/* validate only READY nodes */
1097688SAaron.Zang@Sun.COM 	if (dv->sdev_state != SDEV_READY) {
1107688SAaron.Zang@Sun.COM 		sdcmn_err(("dev fs: skipping: node not ready %s(%p)",
1117688SAaron.Zang@Sun.COM 		    nm, (void *)dv));
1127688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_SKIP);
1137688SAaron.Zang@Sun.COM 	}
1147688SAaron.Zang@Sun.COM 
1157688SAaron.Zang@Sun.COM 	if (vt_wc_attached() == (major_t)-1)
1167688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
1177688SAaron.Zang@Sun.COM 
1187688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
1197688SAaron.Zang@Sun.COM 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1207688SAaron.Zang@Sun.COM 		(void) vt_getactive(link, MAXPATHLEN);
121*12717SJerry.Gilliam@Sun.COM 		rval = (strcmp(link, dv->sdev_symlink) == 0) ?
122*12717SJerry.Gilliam@Sun.COM 		    SDEV_VTOR_VALID : SDEV_VTOR_STALE;
1237688SAaron.Zang@Sun.COM 		kmem_free(link, MAXPATHLEN);
124*12717SJerry.Gilliam@Sun.COM 		return (rval);
12512195SAaron.Zang@Sun.COM 	}
12612195SAaron.Zang@Sun.COM 
12712195SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_CONSUSER_NAME) == 0) {
12812195SAaron.Zang@Sun.COM 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
12912195SAaron.Zang@Sun.COM 		(void) vt_getconsuser(link, MAXPATHLEN);
130*12717SJerry.Gilliam@Sun.COM 		rval = (strcmp(link, dv->sdev_symlink) == 0) ?
131*12717SJerry.Gilliam@Sun.COM 		    SDEV_VTOR_VALID : SDEV_VTOR_STALE;
13212195SAaron.Zang@Sun.COM 		kmem_free(link, MAXPATHLEN);
133*12717SJerry.Gilliam@Sun.COM 		return (rval);
13412195SAaron.Zang@Sun.COM 	}
13512195SAaron.Zang@Sun.COM 
13612195SAaron.Zang@Sun.COM 	if (devvt_str2minor(nm, &min) != 0) {
1377688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
1387688SAaron.Zang@Sun.COM 	}
1397688SAaron.Zang@Sun.COM 
1407688SAaron.Zang@Sun.COM 	if (vt_minor_valid(min) == B_FALSE)
1417688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
1427688SAaron.Zang@Sun.COM 
1437688SAaron.Zang@Sun.COM 	return (SDEV_VTOR_VALID);
1447688SAaron.Zang@Sun.COM }
1457688SAaron.Zang@Sun.COM 
1467688SAaron.Zang@Sun.COM /*
1477688SAaron.Zang@Sun.COM  * This callback is invoked from devname_lookup_func() to create
1487688SAaron.Zang@Sun.COM  * a entry when the node is not found in the cache.
1497688SAaron.Zang@Sun.COM  */
1507688SAaron.Zang@Sun.COM /*ARGSUSED*/
1517688SAaron.Zang@Sun.COM static int
devvt_create_rvp(struct sdev_node * ddv,char * nm,void ** arg,cred_t * cred,void * whatever,char * whichever)1527688SAaron.Zang@Sun.COM devvt_create_rvp(struct sdev_node *ddv, char *nm,
1537688SAaron.Zang@Sun.COM     void **arg, cred_t *cred, void *whatever, char *whichever)
1547688SAaron.Zang@Sun.COM {
1557688SAaron.Zang@Sun.COM 	minor_t min;
1567688SAaron.Zang@Sun.COM 	major_t maj;
1577688SAaron.Zang@Sun.COM 	struct vattr *vap = (struct vattr *)arg;
1587688SAaron.Zang@Sun.COM 
1597688SAaron.Zang@Sun.COM 	if ((maj = vt_wc_attached()) == (major_t)-1)
1607688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
1617688SAaron.Zang@Sun.COM 
1627688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
1637688SAaron.Zang@Sun.COM 		(void) vt_getactive((char *)*arg, MAXPATHLEN);
1647688SAaron.Zang@Sun.COM 		return (0);
1657688SAaron.Zang@Sun.COM 	}
1667688SAaron.Zang@Sun.COM 
16712195SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_CONSUSER_NAME) == 0) {
16812195SAaron.Zang@Sun.COM 		(void) vt_getconsuser((char *)*arg, MAXPATHLEN);
16912195SAaron.Zang@Sun.COM 		return (0);
17012195SAaron.Zang@Sun.COM 	}
1717688SAaron.Zang@Sun.COM 	if (devvt_str2minor(nm, &min) != 0)
1727688SAaron.Zang@Sun.COM 		return (-1);
1737688SAaron.Zang@Sun.COM 
1747688SAaron.Zang@Sun.COM 	if (vt_minor_valid(min) == B_FALSE)
1757688SAaron.Zang@Sun.COM 		return (-1);
1767688SAaron.Zang@Sun.COM 
1777688SAaron.Zang@Sun.COM 	*vap = devvt_vattr;
1787688SAaron.Zang@Sun.COM 	vap->va_rdev = makedevice(maj, min);
1797688SAaron.Zang@Sun.COM 
1807688SAaron.Zang@Sun.COM 	return (0);
1817688SAaron.Zang@Sun.COM }
1827688SAaron.Zang@Sun.COM 
1837688SAaron.Zang@Sun.COM /*ARGSUSED3*/
1847688SAaron.Zang@Sun.COM static int
devvt_lookup(struct vnode * dvp,char * nm,struct vnode ** vpp,struct pathname * pnp,int flags,struct vnode * rdir,struct cred * cred,caller_context_t * ct,int * direntflags,pathname_t * realpnp)1857688SAaron.Zang@Sun.COM devvt_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
1867688SAaron.Zang@Sun.COM     struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
1877688SAaron.Zang@Sun.COM     caller_context_t *ct, int *direntflags, pathname_t *realpnp)
1887688SAaron.Zang@Sun.COM {
1897688SAaron.Zang@Sun.COM 	struct sdev_node *sdvp = VTOSDEV(dvp);
1907688SAaron.Zang@Sun.COM 	struct sdev_node *dv;
1917688SAaron.Zang@Sun.COM 	struct vnode *rvp = NULL;
1927688SAaron.Zang@Sun.COM 	int type, error;
1937688SAaron.Zang@Sun.COM 
19412195SAaron.Zang@Sun.COM 	if ((strcmp(nm, DEVVT_ACTIVE_NAME) == 0) ||
19512195SAaron.Zang@Sun.COM 	    (strcmp(nm, DEVVT_CONSUSER_NAME) == 0)) {
1967688SAaron.Zang@Sun.COM 		type = SDEV_VLINK;
1977688SAaron.Zang@Sun.COM 	} else {
1987688SAaron.Zang@Sun.COM 		type = SDEV_VATTR;
1997688SAaron.Zang@Sun.COM 	}
2007688SAaron.Zang@Sun.COM 
2017688SAaron.Zang@Sun.COM /* Give warlock a more clear call graph */
2027688SAaron.Zang@Sun.COM #ifndef __lock_lint
2037688SAaron.Zang@Sun.COM 	error = devname_lookup_func(sdvp, nm, vpp, cred,
2047688SAaron.Zang@Sun.COM 	    devvt_create_rvp, type);
2057688SAaron.Zang@Sun.COM #else
2067688SAaron.Zang@Sun.COM 	devvt_create_rvp(0, 0, 0, 0, 0, 0);
2077688SAaron.Zang@Sun.COM #endif
2087688SAaron.Zang@Sun.COM 
2097688SAaron.Zang@Sun.COM 	if (error == 0) {
2107688SAaron.Zang@Sun.COM 		switch ((*vpp)->v_type) {
2117688SAaron.Zang@Sun.COM 		case VCHR:
2127688SAaron.Zang@Sun.COM 			dv = VTOSDEV(VTOS(*vpp)->s_realvp);
2137688SAaron.Zang@Sun.COM 			ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
2147688SAaron.Zang@Sun.COM 			break;
2157688SAaron.Zang@Sun.COM 		case VDIR:
2167688SAaron.Zang@Sun.COM 		case VLNK:
2177688SAaron.Zang@Sun.COM 			dv = VTOSDEV(*vpp);
2187688SAaron.Zang@Sun.COM 			break;
2197688SAaron.Zang@Sun.COM 		default:
2207688SAaron.Zang@Sun.COM 			cmn_err(CE_PANIC, "devvt_lookup: Unsupported node "
2217688SAaron.Zang@Sun.COM 			    "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
2227688SAaron.Zang@Sun.COM 			break;
2237688SAaron.Zang@Sun.COM 		}
2247688SAaron.Zang@Sun.COM 		ASSERT(SDEV_HELD(dv));
2257688SAaron.Zang@Sun.COM 	}
2267688SAaron.Zang@Sun.COM 
2277688SAaron.Zang@Sun.COM 	return (error);
2287688SAaron.Zang@Sun.COM }
2297688SAaron.Zang@Sun.COM 
2307688SAaron.Zang@Sun.COM static void
devvt_create_snode(struct sdev_node * ddv,char * nm,struct cred * cred,int type)2317688SAaron.Zang@Sun.COM devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type)
2327688SAaron.Zang@Sun.COM {
2337688SAaron.Zang@Sun.COM 	int error;
2347688SAaron.Zang@Sun.COM 	struct sdev_node *sdv = NULL;
23511279SJerry.Gilliam@Sun.COM 	struct vattr vattr;
23611279SJerry.Gilliam@Sun.COM 	struct vattr *vap = &vattr;
2377688SAaron.Zang@Sun.COM 	major_t maj;
2387688SAaron.Zang@Sun.COM 	minor_t min;
2397688SAaron.Zang@Sun.COM 
240*12717SJerry.Gilliam@Sun.COM 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
241*12717SJerry.Gilliam@Sun.COM 
2427688SAaron.Zang@Sun.COM 	if ((maj = vt_wc_attached()) == (major_t)-1)
2437688SAaron.Zang@Sun.COM 		return;
2447688SAaron.Zang@Sun.COM 
2457688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 &&
24612195SAaron.Zang@Sun.COM 	    strcmp(nm, DEVVT_CONSUSER_NAME) != 0 &&
2477688SAaron.Zang@Sun.COM 	    devvt_str2minor(nm, &min) != 0)
2487688SAaron.Zang@Sun.COM 		return;
2497688SAaron.Zang@Sun.COM 
2507688SAaron.Zang@Sun.COM 	error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT);
2517688SAaron.Zang@Sun.COM 	if (error || !sdv) {
2527688SAaron.Zang@Sun.COM 		return;
2537688SAaron.Zang@Sun.COM 	}
2547688SAaron.Zang@Sun.COM 
2557688SAaron.Zang@Sun.COM 	mutex_enter(&sdv->sdev_lookup_lock);
2567688SAaron.Zang@Sun.COM 	SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP);
2577688SAaron.Zang@Sun.COM 	mutex_exit(&sdv->sdev_lookup_lock);
2587688SAaron.Zang@Sun.COM 
2597688SAaron.Zang@Sun.COM 	if (type & SDEV_VATTR) {
26011279SJerry.Gilliam@Sun.COM 		*vap = devvt_vattr;
2617688SAaron.Zang@Sun.COM 		vap->va_rdev = makedevice(maj, min);
2627688SAaron.Zang@Sun.COM 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
2637688SAaron.Zang@Sun.COM 		    NULL, cred, SDEV_READY);
2647688SAaron.Zang@Sun.COM 	} else if (type & SDEV_VLINK) {
2657688SAaron.Zang@Sun.COM 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
2667688SAaron.Zang@Sun.COM 
2677688SAaron.Zang@Sun.COM 		(void) vt_getactive(link, MAXPATHLEN);
26811279SJerry.Gilliam@Sun.COM 		*vap = sdev_vattr_lnk;
2697688SAaron.Zang@Sun.COM 		vap->va_size = strlen(link);
2707688SAaron.Zang@Sun.COM 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
2717688SAaron.Zang@Sun.COM 		    (void *)link, cred, SDEV_READY);
2727688SAaron.Zang@Sun.COM 
2737688SAaron.Zang@Sun.COM 		kmem_free(link, MAXPATHLEN);
2747688SAaron.Zang@Sun.COM 	}
2757688SAaron.Zang@Sun.COM 
2767688SAaron.Zang@Sun.COM 	mutex_enter(&sdv->sdev_lookup_lock);
2777688SAaron.Zang@Sun.COM 	SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP);
2787688SAaron.Zang@Sun.COM 	mutex_exit(&sdv->sdev_lookup_lock);
2797688SAaron.Zang@Sun.COM 
2807688SAaron.Zang@Sun.COM }
2817688SAaron.Zang@Sun.COM 
2827688SAaron.Zang@Sun.COM static void
devvt_rebuild_stale_link(struct sdev_node * ddv,struct sdev_node * dv)283*12717SJerry.Gilliam@Sun.COM devvt_rebuild_stale_link(struct sdev_node *ddv, struct sdev_node *dv)
284*12717SJerry.Gilliam@Sun.COM {
285*12717SJerry.Gilliam@Sun.COM 	char *link;
286*12717SJerry.Gilliam@Sun.COM 
287*12717SJerry.Gilliam@Sun.COM 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
288*12717SJerry.Gilliam@Sun.COM 
289*12717SJerry.Gilliam@Sun.COM 	ASSERT((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == 0) ||
290*12717SJerry.Gilliam@Sun.COM 	    (strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == 0));
291*12717SJerry.Gilliam@Sun.COM 
292*12717SJerry.Gilliam@Sun.COM 	link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
293*12717SJerry.Gilliam@Sun.COM 	if (strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == 0) {
294*12717SJerry.Gilliam@Sun.COM 		(void) vt_getactive(link, MAXPATHLEN);
295*12717SJerry.Gilliam@Sun.COM 	} else if (strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == 0) {
296*12717SJerry.Gilliam@Sun.COM 		(void) vt_getconsuser(link, MAXPATHLEN);
297*12717SJerry.Gilliam@Sun.COM 	}
298*12717SJerry.Gilliam@Sun.COM 
299*12717SJerry.Gilliam@Sun.COM 	if (strcmp(link, dv->sdev_symlink) != 0) {
300*12717SJerry.Gilliam@Sun.COM 		strfree(dv->sdev_symlink);
301*12717SJerry.Gilliam@Sun.COM 		dv->sdev_symlink = strdup(link);
302*12717SJerry.Gilliam@Sun.COM 		dv->sdev_attr->va_size = strlen(link);
303*12717SJerry.Gilliam@Sun.COM 	}
304*12717SJerry.Gilliam@Sun.COM 	kmem_free(link, MAXPATHLEN);
305*12717SJerry.Gilliam@Sun.COM }
306*12717SJerry.Gilliam@Sun.COM 
307*12717SJerry.Gilliam@Sun.COM /*
308*12717SJerry.Gilliam@Sun.COM  * First step in refreshing directory contents.
309*12717SJerry.Gilliam@Sun.COM  * Remove each invalid entry and rebuild the link
310*12717SJerry.Gilliam@Sun.COM  * reference for each stale entry.
311*12717SJerry.Gilliam@Sun.COM  */
312*12717SJerry.Gilliam@Sun.COM static void
devvt_prunedir(struct sdev_node * ddv)3137688SAaron.Zang@Sun.COM devvt_prunedir(struct sdev_node *ddv)
3147688SAaron.Zang@Sun.COM {
3157688SAaron.Zang@Sun.COM 	struct vnode *vp;
3167688SAaron.Zang@Sun.COM 	struct sdev_node *dv, *next = NULL;
3177688SAaron.Zang@Sun.COM 	int (*vtor)(struct sdev_node *) = NULL;
3187688SAaron.Zang@Sun.COM 
3197688SAaron.Zang@Sun.COM 	ASSERT(ddv->sdev_flags & SDEV_VTOR);
3207688SAaron.Zang@Sun.COM 
3217688SAaron.Zang@Sun.COM 	vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
3227688SAaron.Zang@Sun.COM 	ASSERT(vtor);
3237688SAaron.Zang@Sun.COM 
3247688SAaron.Zang@Sun.COM 	for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
3257688SAaron.Zang@Sun.COM 		next = SDEV_NEXT_ENTRY(ddv, dv);
3267688SAaron.Zang@Sun.COM 
3277688SAaron.Zang@Sun.COM 		switch (vtor(dv)) {
3287688SAaron.Zang@Sun.COM 		case SDEV_VTOR_VALID:
329*12717SJerry.Gilliam@Sun.COM 			break;
3307688SAaron.Zang@Sun.COM 		case SDEV_VTOR_SKIP:
331*12717SJerry.Gilliam@Sun.COM 			break;
3327688SAaron.Zang@Sun.COM 		case SDEV_VTOR_INVALID:
333*12717SJerry.Gilliam@Sun.COM 			vp = SDEVTOV(dv);
334*12717SJerry.Gilliam@Sun.COM 			if (vp->v_count != 0)
335*12717SJerry.Gilliam@Sun.COM 				break;
336*12717SJerry.Gilliam@Sun.COM 			/* remove the cached node */
337*12717SJerry.Gilliam@Sun.COM 			SDEV_HOLD(dv);
338*12717SJerry.Gilliam@Sun.COM 			(void) sdev_cache_update(ddv, &dv,
339*12717SJerry.Gilliam@Sun.COM 			    dv->sdev_name, SDEV_CACHE_DELETE);
340*12717SJerry.Gilliam@Sun.COM 			break;
3418023SPhil.Kirk@Sun.COM 		case SDEV_VTOR_STALE:
342*12717SJerry.Gilliam@Sun.COM 			devvt_rebuild_stale_link(ddv, dv);
3437688SAaron.Zang@Sun.COM 			break;
3447688SAaron.Zang@Sun.COM 		}
3457688SAaron.Zang@Sun.COM 	}
3467688SAaron.Zang@Sun.COM }
3477688SAaron.Zang@Sun.COM 
3487688SAaron.Zang@Sun.COM static void
devvt_cleandir(struct vnode * dvp,struct cred * cred)3497688SAaron.Zang@Sun.COM devvt_cleandir(struct vnode *dvp, struct cred *cred)
3507688SAaron.Zang@Sun.COM {
3517688SAaron.Zang@Sun.COM 	struct sdev_node *sdvp = VTOSDEV(dvp);
3527688SAaron.Zang@Sun.COM 	struct sdev_node *dv, *next = NULL;
3537688SAaron.Zang@Sun.COM 	int min, cnt;
35412195SAaron.Zang@Sun.COM 	char found = 0;
3557688SAaron.Zang@Sun.COM 
3567688SAaron.Zang@Sun.COM 	mutex_enter(&vc_lock);
3577688SAaron.Zang@Sun.COM 	cnt = VC_INSTANCES_COUNT;
3587688SAaron.Zang@Sun.COM 	mutex_exit(&vc_lock);
3597688SAaron.Zang@Sun.COM 
3607688SAaron.Zang@Sun.COM /* We have to fool warlock this way, otherwise it will complain */
3617688SAaron.Zang@Sun.COM #ifndef	__lock_lint
3627688SAaron.Zang@Sun.COM 	if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) {
3637688SAaron.Zang@Sun.COM 		rw_exit(&sdvp->sdev_contents);
3647688SAaron.Zang@Sun.COM 		rw_enter(&sdvp->sdev_contents, RW_WRITER);
3657688SAaron.Zang@Sun.COM 	}
3667688SAaron.Zang@Sun.COM #else
3677688SAaron.Zang@Sun.COM 	rw_enter(&sdvp->sdev_contents, RW_WRITER);
3687688SAaron.Zang@Sun.COM #endif
3697688SAaron.Zang@Sun.COM 
370*12717SJerry.Gilliam@Sun.COM 	/* 1.  prune invalid nodes and rebuild stale symlinks */
371*12717SJerry.Gilliam@Sun.COM 	devvt_prunedir(sdvp);
372*12717SJerry.Gilliam@Sun.COM 
373*12717SJerry.Gilliam@Sun.COM 	/* 2. create missing nodes */
3747688SAaron.Zang@Sun.COM 	for (min = 0; min < cnt; min++) {
3757688SAaron.Zang@Sun.COM 		char nm[16];
3767688SAaron.Zang@Sun.COM 
3777688SAaron.Zang@Sun.COM 		if (vt_minor_valid(min) == B_FALSE)
3787688SAaron.Zang@Sun.COM 			continue;
3797688SAaron.Zang@Sun.COM 
3807688SAaron.Zang@Sun.COM 		(void) snprintf(nm, sizeof (nm), "%d", min);
3817688SAaron.Zang@Sun.COM 		found = 0;
3827688SAaron.Zang@Sun.COM 		for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
3837688SAaron.Zang@Sun.COM 			next = SDEV_NEXT_ENTRY(sdvp, dv);
3847688SAaron.Zang@Sun.COM 
3857688SAaron.Zang@Sun.COM 			/* skip stale nodes */
3867688SAaron.Zang@Sun.COM 			if (dv->sdev_flags & SDEV_STALE)
3877688SAaron.Zang@Sun.COM 				continue;
388*12717SJerry.Gilliam@Sun.COM 			/* validate only ready nodes */
3897688SAaron.Zang@Sun.COM 			if (dv->sdev_state != SDEV_READY)
3907688SAaron.Zang@Sun.COM 				continue;
3917688SAaron.Zang@Sun.COM 			if (strcmp(nm, dv->sdev_name) == 0) {
3927688SAaron.Zang@Sun.COM 				found = 1;
3937688SAaron.Zang@Sun.COM 				break;
3947688SAaron.Zang@Sun.COM 			}
3957688SAaron.Zang@Sun.COM 		}
3967688SAaron.Zang@Sun.COM 		if (!found) {
3977688SAaron.Zang@Sun.COM 			devvt_create_snode(sdvp, nm, cred, SDEV_VATTR);
3987688SAaron.Zang@Sun.COM 		}
3997688SAaron.Zang@Sun.COM 	}
4007688SAaron.Zang@Sun.COM 
401*12717SJerry.Gilliam@Sun.COM 	/* 3. create active link node and console user link node */
4027688SAaron.Zang@Sun.COM 	found = 0;
4037688SAaron.Zang@Sun.COM 	for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
4047688SAaron.Zang@Sun.COM 		next = SDEV_NEXT_ENTRY(sdvp, dv);
4057688SAaron.Zang@Sun.COM 
4067688SAaron.Zang@Sun.COM 		/* skip stale nodes */
4077688SAaron.Zang@Sun.COM 		if (dv->sdev_flags & SDEV_STALE)
4087688SAaron.Zang@Sun.COM 			continue;
409*12717SJerry.Gilliam@Sun.COM 		/* validate only ready nodes */
4107688SAaron.Zang@Sun.COM 		if (dv->sdev_state != SDEV_READY)
4117688SAaron.Zang@Sun.COM 			continue;
41212195SAaron.Zang@Sun.COM 		if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL))
41312195SAaron.Zang@Sun.COM 			found |= 0x01;
41412195SAaron.Zang@Sun.COM 		if ((strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == NULL))
41512195SAaron.Zang@Sun.COM 			found |= 0x02;
41612195SAaron.Zang@Sun.COM 
41712195SAaron.Zang@Sun.COM 		if ((found & 0x01) && (found & 0x02))
4187688SAaron.Zang@Sun.COM 			break;
4197688SAaron.Zang@Sun.COM 	}
42012195SAaron.Zang@Sun.COM 	if (!(found & 0x01))
4217688SAaron.Zang@Sun.COM 		devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK);
42212195SAaron.Zang@Sun.COM 	if (!(found & 0x02))
42312195SAaron.Zang@Sun.COM 		devvt_create_snode(sdvp, DEVVT_CONSUSER_NAME, cred, SDEV_VLINK);
42412195SAaron.Zang@Sun.COM 
4257688SAaron.Zang@Sun.COM #ifndef	__lock_lint
4267688SAaron.Zang@Sun.COM 	rw_downgrade(&sdvp->sdev_contents);
4277688SAaron.Zang@Sun.COM #else
4287688SAaron.Zang@Sun.COM 	rw_exit(&sdvp->sdev_contents);
4297688SAaron.Zang@Sun.COM #endif
4307688SAaron.Zang@Sun.COM }
4317688SAaron.Zang@Sun.COM 
4327688SAaron.Zang@Sun.COM /*ARGSUSED4*/
4337688SAaron.Zang@Sun.COM static int
devvt_readdir(struct vnode * dvp,struct uio * uiop,struct cred * cred,int * eofp,caller_context_t * ct,int flags)4347688SAaron.Zang@Sun.COM devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
4357688SAaron.Zang@Sun.COM     int *eofp, caller_context_t *ct, int flags)
4367688SAaron.Zang@Sun.COM {
4377688SAaron.Zang@Sun.COM 	if (uiop->uio_offset == 0) {
4387688SAaron.Zang@Sun.COM 		devvt_cleandir(dvp, cred);
4397688SAaron.Zang@Sun.COM 	}
4407688SAaron.Zang@Sun.COM 
4417688SAaron.Zang@Sun.COM 	return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
4427688SAaron.Zang@Sun.COM }
4437688SAaron.Zang@Sun.COM 
4447688SAaron.Zang@Sun.COM /*
4457688SAaron.Zang@Sun.COM  * We allow create to find existing nodes
4467688SAaron.Zang@Sun.COM  *	- if the node doesn't exist - EROFS
4477688SAaron.Zang@Sun.COM  *	- creating an existing dir read-only succeeds, otherwise EISDIR
4487688SAaron.Zang@Sun.COM  *	- exclusive creates fail - EEXIST
4497688SAaron.Zang@Sun.COM  */
4507688SAaron.Zang@Sun.COM /*ARGSUSED2*/
4517688SAaron.Zang@Sun.COM static int
devvt_create(struct vnode * dvp,char * nm,struct vattr * vap,vcexcl_t excl,int mode,struct vnode ** vpp,struct cred * cred,int flag,caller_context_t * ct,vsecattr_t * vsecp)4527688SAaron.Zang@Sun.COM devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
4537688SAaron.Zang@Sun.COM     int mode, struct vnode **vpp, struct cred *cred, int flag,
4547688SAaron.Zang@Sun.COM     caller_context_t *ct, vsecattr_t *vsecp)
4557688SAaron.Zang@Sun.COM {
4567688SAaron.Zang@Sun.COM 	int error;
4577688SAaron.Zang@Sun.COM 	struct vnode *vp;
4587688SAaron.Zang@Sun.COM 
4597688SAaron.Zang@Sun.COM 	*vpp = NULL;
4607688SAaron.Zang@Sun.COM 
4617688SAaron.Zang@Sun.COM 	if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
4627688SAaron.Zang@Sun.COM 	    NULL)) != 0) {
4637688SAaron.Zang@Sun.COM 		if (error == ENOENT)
4647688SAaron.Zang@Sun.COM 			error = EROFS;
4657688SAaron.Zang@Sun.COM 		return (error);
4667688SAaron.Zang@Sun.COM 	}
4677688SAaron.Zang@Sun.COM 
4687688SAaron.Zang@Sun.COM 	if (excl == EXCL)
4697688SAaron.Zang@Sun.COM 		error = EEXIST;
4707688SAaron.Zang@Sun.COM 	else if (vp->v_type == VDIR && (mode & VWRITE))
4717688SAaron.Zang@Sun.COM 		error = EISDIR;
4727688SAaron.Zang@Sun.COM 	else
4737688SAaron.Zang@Sun.COM 		error = VOP_ACCESS(vp, mode, 0, cred, ct);
4747688SAaron.Zang@Sun.COM 
4757688SAaron.Zang@Sun.COM 	if (error) {
4767688SAaron.Zang@Sun.COM 		VN_RELE(vp);
4777688SAaron.Zang@Sun.COM 	} else
4787688SAaron.Zang@Sun.COM 		*vpp = vp;
4797688SAaron.Zang@Sun.COM 
4807688SAaron.Zang@Sun.COM 	return (error);
4817688SAaron.Zang@Sun.COM }
4827688SAaron.Zang@Sun.COM 
4837688SAaron.Zang@Sun.COM const fs_operation_def_t devvt_vnodeops_tbl[] = {
4847688SAaron.Zang@Sun.COM 	VOPNAME_READDIR,	{ .vop_readdir = devvt_readdir },
4857688SAaron.Zang@Sun.COM 	VOPNAME_LOOKUP,		{ .vop_lookup = devvt_lookup },
4867688SAaron.Zang@Sun.COM 	VOPNAME_CREATE,		{ .vop_create = devvt_create },
4877688SAaron.Zang@Sun.COM 	VOPNAME_REMOVE,		{ .error = fs_nosys },
4887688SAaron.Zang@Sun.COM 	VOPNAME_MKDIR,		{ .error = fs_nosys },
4897688SAaron.Zang@Sun.COM 	VOPNAME_RMDIR,		{ .error = fs_nosys },
4907688SAaron.Zang@Sun.COM 	VOPNAME_SYMLINK,	{ .error = fs_nosys },
4917688SAaron.Zang@Sun.COM 	VOPNAME_SETSECATTR,	{ .error = fs_nosys },
4927688SAaron.Zang@Sun.COM 	NULL,			NULL
4937688SAaron.Zang@Sun.COM };
494