xref: /onnv-gate/usr/src/uts/common/fs/dev/sdev_vtops.c (revision 7688:2757e6e1bb2a)
1*7688SAaron.Zang@Sun.COM /*
2*7688SAaron.Zang@Sun.COM  * CDDL HEADER START
3*7688SAaron.Zang@Sun.COM  *
4*7688SAaron.Zang@Sun.COM  * The contents of this file are subject to the terms of the
5*7688SAaron.Zang@Sun.COM  * Common Development and Distribution License (the "License").
6*7688SAaron.Zang@Sun.COM  * You may not use this file except in compliance with the License.
7*7688SAaron.Zang@Sun.COM  *
8*7688SAaron.Zang@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7688SAaron.Zang@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7688SAaron.Zang@Sun.COM  * See the License for the specific language governing permissions
11*7688SAaron.Zang@Sun.COM  * and limitations under the License.
12*7688SAaron.Zang@Sun.COM  *
13*7688SAaron.Zang@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7688SAaron.Zang@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7688SAaron.Zang@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7688SAaron.Zang@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7688SAaron.Zang@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7688SAaron.Zang@Sun.COM  *
19*7688SAaron.Zang@Sun.COM  * CDDL HEADER END
20*7688SAaron.Zang@Sun.COM  */
21*7688SAaron.Zang@Sun.COM /*
22*7688SAaron.Zang@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7688SAaron.Zang@Sun.COM  * Use is subject to license terms.
24*7688SAaron.Zang@Sun.COM  */
25*7688SAaron.Zang@Sun.COM 
26*7688SAaron.Zang@Sun.COM /*
27*7688SAaron.Zang@Sun.COM  * vnode ops for the /dev/vt directory
28*7688SAaron.Zang@Sun.COM  */
29*7688SAaron.Zang@Sun.COM 
30*7688SAaron.Zang@Sun.COM #include <sys/types.h>
31*7688SAaron.Zang@Sun.COM #include <sys/param.h>
32*7688SAaron.Zang@Sun.COM #include <sys/sysmacros.h>
33*7688SAaron.Zang@Sun.COM #include <sys/sunndi.h>
34*7688SAaron.Zang@Sun.COM #include <fs/fs_subr.h>
35*7688SAaron.Zang@Sun.COM #include <sys/fs/dv_node.h>
36*7688SAaron.Zang@Sun.COM #include <sys/fs/sdev_impl.h>
37*7688SAaron.Zang@Sun.COM #include <sys/policy.h>
38*7688SAaron.Zang@Sun.COM #include <sys/stat.h>
39*7688SAaron.Zang@Sun.COM #include <sys/vfs_opreg.h>
40*7688SAaron.Zang@Sun.COM #include <sys/tty.h>
41*7688SAaron.Zang@Sun.COM #include <sys/vt_impl.h>
42*7688SAaron.Zang@Sun.COM #include <sys/note.h>
43*7688SAaron.Zang@Sun.COM 
44*7688SAaron.Zang@Sun.COM /* warlock in this file only cares about variables shared by vt and devfs */
45*7688SAaron.Zang@Sun.COM _NOTE(SCHEME_PROTECTS_DATA("Do not care", sdev_node vattr vnode))
46*7688SAaron.Zang@Sun.COM 
47*7688SAaron.Zang@Sun.COM #define	DEVVT_UID_DEFAULT	SDEV_UID_DEFAULT
48*7688SAaron.Zang@Sun.COM #define	DEVVT_GID_DEFAULT	(0)
49*7688SAaron.Zang@Sun.COM #define	DEVVT_DEVMODE_DEFAULT	(0600)
50*7688SAaron.Zang@Sun.COM #define	DEVVT_ACTIVE_NAME	"active"
51*7688SAaron.Zang@Sun.COM 
52*7688SAaron.Zang@Sun.COM #define	isdigit(ch)	((ch) >= '0' && (ch) <= '9')
53*7688SAaron.Zang@Sun.COM 
54*7688SAaron.Zang@Sun.COM /* attributes for VT nodes */
55*7688SAaron.Zang@Sun.COM static vattr_t devvt_vattr = {
56*7688SAaron.Zang@Sun.COM 	AT_TYPE|AT_MODE|AT_UID|AT_GID,		/* va_mask */
57*7688SAaron.Zang@Sun.COM 	VCHR,					/* va_type */
58*7688SAaron.Zang@Sun.COM 	S_IFCHR | DEVVT_DEVMODE_DEFAULT,	/* va_mode */
59*7688SAaron.Zang@Sun.COM 	DEVVT_UID_DEFAULT,			/* va_uid */
60*7688SAaron.Zang@Sun.COM 	DEVVT_GID_DEFAULT,			/* va_gid */
61*7688SAaron.Zang@Sun.COM 	0					/* 0 hereafter */
62*7688SAaron.Zang@Sun.COM };
63*7688SAaron.Zang@Sun.COM 
64*7688SAaron.Zang@Sun.COM struct vnodeops		*devvt_vnodeops;
65*7688SAaron.Zang@Sun.COM 
66*7688SAaron.Zang@Sun.COM struct vnodeops *
67*7688SAaron.Zang@Sun.COM devvt_getvnodeops(void)
68*7688SAaron.Zang@Sun.COM {
69*7688SAaron.Zang@Sun.COM 	return (devvt_vnodeops);
70*7688SAaron.Zang@Sun.COM }
71*7688SAaron.Zang@Sun.COM 
72*7688SAaron.Zang@Sun.COM static int
73*7688SAaron.Zang@Sun.COM devvt_str2minor(const char *nm, minor_t *mp)
74*7688SAaron.Zang@Sun.COM {
75*7688SAaron.Zang@Sun.COM 	long uminor = 0;
76*7688SAaron.Zang@Sun.COM 	char *endptr = NULL;
77*7688SAaron.Zang@Sun.COM 
78*7688SAaron.Zang@Sun.COM 	if (nm == NULL || !isdigit(*nm))
79*7688SAaron.Zang@Sun.COM 		return (EINVAL);
80*7688SAaron.Zang@Sun.COM 
81*7688SAaron.Zang@Sun.COM 	*mp = 0;
82*7688SAaron.Zang@Sun.COM 	if (ddi_strtol(nm, &endptr, 10, &uminor) != 0 ||
83*7688SAaron.Zang@Sun.COM 	    *endptr != '\0' || uminor < 0) {
84*7688SAaron.Zang@Sun.COM 		return (EINVAL);
85*7688SAaron.Zang@Sun.COM 	}
86*7688SAaron.Zang@Sun.COM 
87*7688SAaron.Zang@Sun.COM 	*mp = (minor_t)uminor;
88*7688SAaron.Zang@Sun.COM 	return (0);
89*7688SAaron.Zang@Sun.COM }
90*7688SAaron.Zang@Sun.COM 
91*7688SAaron.Zang@Sun.COM /*ARGSUSED*/
92*7688SAaron.Zang@Sun.COM int
93*7688SAaron.Zang@Sun.COM devvt_validate(struct sdev_node *dv)
94*7688SAaron.Zang@Sun.COM {
95*7688SAaron.Zang@Sun.COM 	minor_t min;
96*7688SAaron.Zang@Sun.COM 	char *nm = dv->sdev_name;
97*7688SAaron.Zang@Sun.COM 
98*7688SAaron.Zang@Sun.COM 	ASSERT(!(dv->sdev_flags & SDEV_STALE));
99*7688SAaron.Zang@Sun.COM 	ASSERT(dv->sdev_state == SDEV_READY);
100*7688SAaron.Zang@Sun.COM 
101*7688SAaron.Zang@Sun.COM 	/* validate only READY nodes */
102*7688SAaron.Zang@Sun.COM 	if (dv->sdev_state != SDEV_READY) {
103*7688SAaron.Zang@Sun.COM 		sdcmn_err(("dev fs: skipping: node not ready %s(%p)",
104*7688SAaron.Zang@Sun.COM 		    nm, (void *)dv));
105*7688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_SKIP);
106*7688SAaron.Zang@Sun.COM 	}
107*7688SAaron.Zang@Sun.COM 
108*7688SAaron.Zang@Sun.COM 	if (vt_wc_attached() == (major_t)-1)
109*7688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
110*7688SAaron.Zang@Sun.COM 
111*7688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
112*7688SAaron.Zang@Sun.COM 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
113*7688SAaron.Zang@Sun.COM 
114*7688SAaron.Zang@Sun.COM 		(void) vt_getactive(link, MAXPATHLEN);
115*7688SAaron.Zang@Sun.COM 		if (strcmp(link, dv->sdev_symlink) != 0) {
116*7688SAaron.Zang@Sun.COM 			kmem_free(dv->sdev_symlink,
117*7688SAaron.Zang@Sun.COM 			    strlen(dv->sdev_symlink) + 1);
118*7688SAaron.Zang@Sun.COM 			dv->sdev_symlink = i_ddi_strdup(link, KM_SLEEP);
119*7688SAaron.Zang@Sun.COM 			dv->sdev_attr->va_size = strlen(link);
120*7688SAaron.Zang@Sun.COM 		}
121*7688SAaron.Zang@Sun.COM 		kmem_free(link, MAXPATHLEN);
122*7688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_VALID);
123*7688SAaron.Zang@Sun.COM 	} else if (devvt_str2minor(nm, &min) != 0) {
124*7688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
125*7688SAaron.Zang@Sun.COM 	}
126*7688SAaron.Zang@Sun.COM 
127*7688SAaron.Zang@Sun.COM 	if (vt_minor_valid(min) == B_FALSE)
128*7688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
129*7688SAaron.Zang@Sun.COM 
130*7688SAaron.Zang@Sun.COM 	return (SDEV_VTOR_VALID);
131*7688SAaron.Zang@Sun.COM }
132*7688SAaron.Zang@Sun.COM 
133*7688SAaron.Zang@Sun.COM /*
134*7688SAaron.Zang@Sun.COM  * This callback is invoked from devname_lookup_func() to create
135*7688SAaron.Zang@Sun.COM  * a entry when the node is not found in the cache.
136*7688SAaron.Zang@Sun.COM  */
137*7688SAaron.Zang@Sun.COM /*ARGSUSED*/
138*7688SAaron.Zang@Sun.COM static int
139*7688SAaron.Zang@Sun.COM devvt_create_rvp(struct sdev_node *ddv, char *nm,
140*7688SAaron.Zang@Sun.COM     void **arg, cred_t *cred, void *whatever, char *whichever)
141*7688SAaron.Zang@Sun.COM {
142*7688SAaron.Zang@Sun.COM 	minor_t min;
143*7688SAaron.Zang@Sun.COM 	major_t maj;
144*7688SAaron.Zang@Sun.COM 	struct vattr *vap = (struct vattr *)arg;
145*7688SAaron.Zang@Sun.COM 
146*7688SAaron.Zang@Sun.COM 	if ((maj = vt_wc_attached()) == (major_t)-1)
147*7688SAaron.Zang@Sun.COM 		return (SDEV_VTOR_INVALID);
148*7688SAaron.Zang@Sun.COM 
149*7688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
150*7688SAaron.Zang@Sun.COM 		(void) vt_getactive((char *)*arg, MAXPATHLEN);
151*7688SAaron.Zang@Sun.COM 		return (0);
152*7688SAaron.Zang@Sun.COM 	}
153*7688SAaron.Zang@Sun.COM 
154*7688SAaron.Zang@Sun.COM 	if (devvt_str2minor(nm, &min) != 0)
155*7688SAaron.Zang@Sun.COM 		return (-1);
156*7688SAaron.Zang@Sun.COM 
157*7688SAaron.Zang@Sun.COM 	if (vt_minor_valid(min) == B_FALSE)
158*7688SAaron.Zang@Sun.COM 		return (-1);
159*7688SAaron.Zang@Sun.COM 
160*7688SAaron.Zang@Sun.COM 	*vap = devvt_vattr;
161*7688SAaron.Zang@Sun.COM 	vap->va_rdev = makedevice(maj, min);
162*7688SAaron.Zang@Sun.COM 
163*7688SAaron.Zang@Sun.COM 	return (0);
164*7688SAaron.Zang@Sun.COM }
165*7688SAaron.Zang@Sun.COM 
166*7688SAaron.Zang@Sun.COM /*ARGSUSED3*/
167*7688SAaron.Zang@Sun.COM static int
168*7688SAaron.Zang@Sun.COM devvt_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
169*7688SAaron.Zang@Sun.COM     struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
170*7688SAaron.Zang@Sun.COM     caller_context_t *ct, int *direntflags, pathname_t *realpnp)
171*7688SAaron.Zang@Sun.COM {
172*7688SAaron.Zang@Sun.COM 	struct sdev_node *sdvp = VTOSDEV(dvp);
173*7688SAaron.Zang@Sun.COM 	struct sdev_node *dv;
174*7688SAaron.Zang@Sun.COM 	struct vnode *rvp = NULL;
175*7688SAaron.Zang@Sun.COM 	int type, error;
176*7688SAaron.Zang@Sun.COM 
177*7688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
178*7688SAaron.Zang@Sun.COM 		type = SDEV_VLINK;
179*7688SAaron.Zang@Sun.COM 	} else {
180*7688SAaron.Zang@Sun.COM 		type = SDEV_VATTR;
181*7688SAaron.Zang@Sun.COM 	}
182*7688SAaron.Zang@Sun.COM 
183*7688SAaron.Zang@Sun.COM /* Give warlock a more clear call graph */
184*7688SAaron.Zang@Sun.COM #ifndef __lock_lint
185*7688SAaron.Zang@Sun.COM 	error = devname_lookup_func(sdvp, nm, vpp, cred,
186*7688SAaron.Zang@Sun.COM 	    devvt_create_rvp, type);
187*7688SAaron.Zang@Sun.COM #else
188*7688SAaron.Zang@Sun.COM 	devvt_create_rvp(0, 0, 0, 0, 0, 0);
189*7688SAaron.Zang@Sun.COM #endif
190*7688SAaron.Zang@Sun.COM 
191*7688SAaron.Zang@Sun.COM 	if (error == 0) {
192*7688SAaron.Zang@Sun.COM 		switch ((*vpp)->v_type) {
193*7688SAaron.Zang@Sun.COM 		case VCHR:
194*7688SAaron.Zang@Sun.COM 			dv = VTOSDEV(VTOS(*vpp)->s_realvp);
195*7688SAaron.Zang@Sun.COM 			ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
196*7688SAaron.Zang@Sun.COM 			break;
197*7688SAaron.Zang@Sun.COM 		case VDIR:
198*7688SAaron.Zang@Sun.COM 		case VLNK:
199*7688SAaron.Zang@Sun.COM 			dv = VTOSDEV(*vpp);
200*7688SAaron.Zang@Sun.COM 			break;
201*7688SAaron.Zang@Sun.COM 		default:
202*7688SAaron.Zang@Sun.COM 			cmn_err(CE_PANIC, "devvt_lookup: Unsupported node "
203*7688SAaron.Zang@Sun.COM 			    "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
204*7688SAaron.Zang@Sun.COM 			break;
205*7688SAaron.Zang@Sun.COM 		}
206*7688SAaron.Zang@Sun.COM 		ASSERT(SDEV_HELD(dv));
207*7688SAaron.Zang@Sun.COM 	}
208*7688SAaron.Zang@Sun.COM 
209*7688SAaron.Zang@Sun.COM 	return (error);
210*7688SAaron.Zang@Sun.COM }
211*7688SAaron.Zang@Sun.COM 
212*7688SAaron.Zang@Sun.COM static void
213*7688SAaron.Zang@Sun.COM devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type)
214*7688SAaron.Zang@Sun.COM {
215*7688SAaron.Zang@Sun.COM 	int error;
216*7688SAaron.Zang@Sun.COM 	struct sdev_node *sdv = NULL;
217*7688SAaron.Zang@Sun.COM 	struct vattr *vap = NULL;
218*7688SAaron.Zang@Sun.COM 	major_t maj;
219*7688SAaron.Zang@Sun.COM 	minor_t min;
220*7688SAaron.Zang@Sun.COM 
221*7688SAaron.Zang@Sun.COM 	if ((maj = vt_wc_attached()) == (major_t)-1)
222*7688SAaron.Zang@Sun.COM 		return;
223*7688SAaron.Zang@Sun.COM 
224*7688SAaron.Zang@Sun.COM 	if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 &&
225*7688SAaron.Zang@Sun.COM 	    devvt_str2minor(nm, &min) != 0)
226*7688SAaron.Zang@Sun.COM 		return;
227*7688SAaron.Zang@Sun.COM 
228*7688SAaron.Zang@Sun.COM 	error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT);
229*7688SAaron.Zang@Sun.COM 	if (error || !sdv) {
230*7688SAaron.Zang@Sun.COM 		return;
231*7688SAaron.Zang@Sun.COM 	}
232*7688SAaron.Zang@Sun.COM 
233*7688SAaron.Zang@Sun.COM 	mutex_enter(&sdv->sdev_lookup_lock);
234*7688SAaron.Zang@Sun.COM 	SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP);
235*7688SAaron.Zang@Sun.COM 	mutex_exit(&sdv->sdev_lookup_lock);
236*7688SAaron.Zang@Sun.COM 
237*7688SAaron.Zang@Sun.COM 	if (type & SDEV_VATTR) {
238*7688SAaron.Zang@Sun.COM 		vap = &devvt_vattr;
239*7688SAaron.Zang@Sun.COM 		vap->va_rdev = makedevice(maj, min);
240*7688SAaron.Zang@Sun.COM 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
241*7688SAaron.Zang@Sun.COM 		    NULL, cred, SDEV_READY);
242*7688SAaron.Zang@Sun.COM 	} else if (type & SDEV_VLINK) {
243*7688SAaron.Zang@Sun.COM 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
244*7688SAaron.Zang@Sun.COM 
245*7688SAaron.Zang@Sun.COM 		(void) vt_getactive(link, MAXPATHLEN);
246*7688SAaron.Zang@Sun.COM 		vap = &sdev_vattr_lnk;
247*7688SAaron.Zang@Sun.COM 		vap->va_size = strlen(link);
248*7688SAaron.Zang@Sun.COM 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
249*7688SAaron.Zang@Sun.COM 		    (void *)link, cred, SDEV_READY);
250*7688SAaron.Zang@Sun.COM 
251*7688SAaron.Zang@Sun.COM 		kmem_free(link, MAXPATHLEN);
252*7688SAaron.Zang@Sun.COM 	}
253*7688SAaron.Zang@Sun.COM 
254*7688SAaron.Zang@Sun.COM 	mutex_enter(&sdv->sdev_lookup_lock);
255*7688SAaron.Zang@Sun.COM 	SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP);
256*7688SAaron.Zang@Sun.COM 	mutex_exit(&sdv->sdev_lookup_lock);
257*7688SAaron.Zang@Sun.COM 
258*7688SAaron.Zang@Sun.COM }
259*7688SAaron.Zang@Sun.COM 
260*7688SAaron.Zang@Sun.COM static void
261*7688SAaron.Zang@Sun.COM devvt_prunedir(struct sdev_node *ddv)
262*7688SAaron.Zang@Sun.COM {
263*7688SAaron.Zang@Sun.COM 	struct vnode *vp;
264*7688SAaron.Zang@Sun.COM 	struct sdev_node *dv, *next = NULL;
265*7688SAaron.Zang@Sun.COM 	int (*vtor)(struct sdev_node *) = NULL;
266*7688SAaron.Zang@Sun.COM 
267*7688SAaron.Zang@Sun.COM 	ASSERT(ddv->sdev_flags & SDEV_VTOR);
268*7688SAaron.Zang@Sun.COM 
269*7688SAaron.Zang@Sun.COM 	vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
270*7688SAaron.Zang@Sun.COM 	ASSERT(vtor);
271*7688SAaron.Zang@Sun.COM 
272*7688SAaron.Zang@Sun.COM 	for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
273*7688SAaron.Zang@Sun.COM 		next = SDEV_NEXT_ENTRY(ddv, dv);
274*7688SAaron.Zang@Sun.COM 
275*7688SAaron.Zang@Sun.COM 		/* skip stale nodes */
276*7688SAaron.Zang@Sun.COM 		if (dv->sdev_flags & SDEV_STALE)
277*7688SAaron.Zang@Sun.COM 			continue;
278*7688SAaron.Zang@Sun.COM 
279*7688SAaron.Zang@Sun.COM 		/* validate and prune only ready nodes */
280*7688SAaron.Zang@Sun.COM 		if (dv->sdev_state != SDEV_READY)
281*7688SAaron.Zang@Sun.COM 			continue;
282*7688SAaron.Zang@Sun.COM 
283*7688SAaron.Zang@Sun.COM 		switch (vtor(dv)) {
284*7688SAaron.Zang@Sun.COM 		case SDEV_VTOR_VALID:
285*7688SAaron.Zang@Sun.COM 		case SDEV_VTOR_SKIP:
286*7688SAaron.Zang@Sun.COM 			continue;
287*7688SAaron.Zang@Sun.COM 		case SDEV_VTOR_INVALID:
288*7688SAaron.Zang@Sun.COM 			sdcmn_err7(("destroy invalid "
289*7688SAaron.Zang@Sun.COM 			    "node: %s(%p)\n", dv->sdev_name, (void *)dv));
290*7688SAaron.Zang@Sun.COM 			break;
291*7688SAaron.Zang@Sun.COM 		}
292*7688SAaron.Zang@Sun.COM 		vp = SDEVTOV(dv);
293*7688SAaron.Zang@Sun.COM 		if (vp->v_count > 0)
294*7688SAaron.Zang@Sun.COM 			continue;
295*7688SAaron.Zang@Sun.COM 		SDEV_HOLD(dv);
296*7688SAaron.Zang@Sun.COM 		/* remove the cache node */
297*7688SAaron.Zang@Sun.COM 		(void) sdev_cache_update(ddv, &dv, dv->sdev_name,
298*7688SAaron.Zang@Sun.COM 		    SDEV_CACHE_DELETE);
299*7688SAaron.Zang@Sun.COM 	}
300*7688SAaron.Zang@Sun.COM }
301*7688SAaron.Zang@Sun.COM 
302*7688SAaron.Zang@Sun.COM static void
303*7688SAaron.Zang@Sun.COM devvt_cleandir(struct vnode *dvp, struct cred *cred)
304*7688SAaron.Zang@Sun.COM {
305*7688SAaron.Zang@Sun.COM 	struct sdev_node *sdvp = VTOSDEV(dvp);
306*7688SAaron.Zang@Sun.COM 	struct sdev_node *dv, *next = NULL;
307*7688SAaron.Zang@Sun.COM 	int min, cnt;
308*7688SAaron.Zang@Sun.COM 	int found = 0;
309*7688SAaron.Zang@Sun.COM 
310*7688SAaron.Zang@Sun.COM 	mutex_enter(&vc_lock);
311*7688SAaron.Zang@Sun.COM 	cnt = VC_INSTANCES_COUNT;
312*7688SAaron.Zang@Sun.COM 	mutex_exit(&vc_lock);
313*7688SAaron.Zang@Sun.COM 
314*7688SAaron.Zang@Sun.COM /* We have to fool warlock this way, otherwise it will complain */
315*7688SAaron.Zang@Sun.COM #ifndef	__lock_lint
316*7688SAaron.Zang@Sun.COM 	if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) {
317*7688SAaron.Zang@Sun.COM 		rw_exit(&sdvp->sdev_contents);
318*7688SAaron.Zang@Sun.COM 		rw_enter(&sdvp->sdev_contents, RW_WRITER);
319*7688SAaron.Zang@Sun.COM 	}
320*7688SAaron.Zang@Sun.COM #else
321*7688SAaron.Zang@Sun.COM 	rw_enter(&sdvp->sdev_contents, RW_WRITER);
322*7688SAaron.Zang@Sun.COM #endif
323*7688SAaron.Zang@Sun.COM 
324*7688SAaron.Zang@Sun.COM 	/* 1. create missed nodes */
325*7688SAaron.Zang@Sun.COM 	for (min = 0; min < cnt; min++) {
326*7688SAaron.Zang@Sun.COM 		char nm[16];
327*7688SAaron.Zang@Sun.COM 
328*7688SAaron.Zang@Sun.COM 		if (vt_minor_valid(min) == B_FALSE)
329*7688SAaron.Zang@Sun.COM 			continue;
330*7688SAaron.Zang@Sun.COM 
331*7688SAaron.Zang@Sun.COM 		(void) snprintf(nm, sizeof (nm), "%d", min);
332*7688SAaron.Zang@Sun.COM 		found = 0;
333*7688SAaron.Zang@Sun.COM 		for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
334*7688SAaron.Zang@Sun.COM 			next = SDEV_NEXT_ENTRY(sdvp, dv);
335*7688SAaron.Zang@Sun.COM 
336*7688SAaron.Zang@Sun.COM 			/* skip stale nodes */
337*7688SAaron.Zang@Sun.COM 			if (dv->sdev_flags & SDEV_STALE)
338*7688SAaron.Zang@Sun.COM 				continue;
339*7688SAaron.Zang@Sun.COM 			/* validate and prune only ready nodes */
340*7688SAaron.Zang@Sun.COM 			if (dv->sdev_state != SDEV_READY)
341*7688SAaron.Zang@Sun.COM 				continue;
342*7688SAaron.Zang@Sun.COM 			if (strcmp(nm, dv->sdev_name) == 0) {
343*7688SAaron.Zang@Sun.COM 				found = 1;
344*7688SAaron.Zang@Sun.COM 				break;
345*7688SAaron.Zang@Sun.COM 			}
346*7688SAaron.Zang@Sun.COM 		}
347*7688SAaron.Zang@Sun.COM 		if (!found) {
348*7688SAaron.Zang@Sun.COM 			devvt_create_snode(sdvp, nm, cred, SDEV_VATTR);
349*7688SAaron.Zang@Sun.COM 		}
350*7688SAaron.Zang@Sun.COM 	}
351*7688SAaron.Zang@Sun.COM 
352*7688SAaron.Zang@Sun.COM 	/* 2. create active link node */
353*7688SAaron.Zang@Sun.COM 	found = 0;
354*7688SAaron.Zang@Sun.COM 	for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
355*7688SAaron.Zang@Sun.COM 		next = SDEV_NEXT_ENTRY(sdvp, dv);
356*7688SAaron.Zang@Sun.COM 
357*7688SAaron.Zang@Sun.COM 		/* skip stale nodes */
358*7688SAaron.Zang@Sun.COM 		if (dv->sdev_flags & SDEV_STALE)
359*7688SAaron.Zang@Sun.COM 			continue;
360*7688SAaron.Zang@Sun.COM 		/* validate and prune only ready nodes */
361*7688SAaron.Zang@Sun.COM 		if (dv->sdev_state != SDEV_READY)
362*7688SAaron.Zang@Sun.COM 			continue;
363*7688SAaron.Zang@Sun.COM 		if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL)) {
364*7688SAaron.Zang@Sun.COM 			found = 1;
365*7688SAaron.Zang@Sun.COM 			break;
366*7688SAaron.Zang@Sun.COM 		}
367*7688SAaron.Zang@Sun.COM 	}
368*7688SAaron.Zang@Sun.COM 	if (!found)
369*7688SAaron.Zang@Sun.COM 		devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK);
370*7688SAaron.Zang@Sun.COM 
371*7688SAaron.Zang@Sun.COM 	/* 3. cleanup invalid nodes */
372*7688SAaron.Zang@Sun.COM 	devvt_prunedir(sdvp);
373*7688SAaron.Zang@Sun.COM 
374*7688SAaron.Zang@Sun.COM #ifndef	__lock_lint
375*7688SAaron.Zang@Sun.COM 	rw_downgrade(&sdvp->sdev_contents);
376*7688SAaron.Zang@Sun.COM #else
377*7688SAaron.Zang@Sun.COM 	rw_exit(&sdvp->sdev_contents);
378*7688SAaron.Zang@Sun.COM #endif
379*7688SAaron.Zang@Sun.COM }
380*7688SAaron.Zang@Sun.COM 
381*7688SAaron.Zang@Sun.COM /*ARGSUSED4*/
382*7688SAaron.Zang@Sun.COM static int
383*7688SAaron.Zang@Sun.COM devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
384*7688SAaron.Zang@Sun.COM     int *eofp, caller_context_t *ct, int flags)
385*7688SAaron.Zang@Sun.COM {
386*7688SAaron.Zang@Sun.COM 	if (uiop->uio_offset == 0) {
387*7688SAaron.Zang@Sun.COM 		devvt_cleandir(dvp, cred);
388*7688SAaron.Zang@Sun.COM 	}
389*7688SAaron.Zang@Sun.COM 
390*7688SAaron.Zang@Sun.COM 	return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
391*7688SAaron.Zang@Sun.COM }
392*7688SAaron.Zang@Sun.COM 
393*7688SAaron.Zang@Sun.COM /*
394*7688SAaron.Zang@Sun.COM  * We allow create to find existing nodes
395*7688SAaron.Zang@Sun.COM  *	- if the node doesn't exist - EROFS
396*7688SAaron.Zang@Sun.COM  *	- creating an existing dir read-only succeeds, otherwise EISDIR
397*7688SAaron.Zang@Sun.COM  *	- exclusive creates fail - EEXIST
398*7688SAaron.Zang@Sun.COM  */
399*7688SAaron.Zang@Sun.COM /*ARGSUSED2*/
400*7688SAaron.Zang@Sun.COM static int
401*7688SAaron.Zang@Sun.COM devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
402*7688SAaron.Zang@Sun.COM     int mode, struct vnode **vpp, struct cred *cred, int flag,
403*7688SAaron.Zang@Sun.COM     caller_context_t *ct, vsecattr_t *vsecp)
404*7688SAaron.Zang@Sun.COM {
405*7688SAaron.Zang@Sun.COM 	int error;
406*7688SAaron.Zang@Sun.COM 	struct vnode *vp;
407*7688SAaron.Zang@Sun.COM 
408*7688SAaron.Zang@Sun.COM 	*vpp = NULL;
409*7688SAaron.Zang@Sun.COM 
410*7688SAaron.Zang@Sun.COM 	if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
411*7688SAaron.Zang@Sun.COM 	    NULL)) != 0) {
412*7688SAaron.Zang@Sun.COM 		if (error == ENOENT)
413*7688SAaron.Zang@Sun.COM 			error = EROFS;
414*7688SAaron.Zang@Sun.COM 		return (error);
415*7688SAaron.Zang@Sun.COM 	}
416*7688SAaron.Zang@Sun.COM 
417*7688SAaron.Zang@Sun.COM 	if (excl == EXCL)
418*7688SAaron.Zang@Sun.COM 		error = EEXIST;
419*7688SAaron.Zang@Sun.COM 	else if (vp->v_type == VDIR && (mode & VWRITE))
420*7688SAaron.Zang@Sun.COM 		error = EISDIR;
421*7688SAaron.Zang@Sun.COM 	else
422*7688SAaron.Zang@Sun.COM 		error = VOP_ACCESS(vp, mode, 0, cred, ct);
423*7688SAaron.Zang@Sun.COM 
424*7688SAaron.Zang@Sun.COM 	if (error) {
425*7688SAaron.Zang@Sun.COM 		VN_RELE(vp);
426*7688SAaron.Zang@Sun.COM 	} else
427*7688SAaron.Zang@Sun.COM 		*vpp = vp;
428*7688SAaron.Zang@Sun.COM 
429*7688SAaron.Zang@Sun.COM 	return (error);
430*7688SAaron.Zang@Sun.COM }
431*7688SAaron.Zang@Sun.COM 
432*7688SAaron.Zang@Sun.COM const fs_operation_def_t devvt_vnodeops_tbl[] = {
433*7688SAaron.Zang@Sun.COM 	VOPNAME_READDIR,	{ .vop_readdir = devvt_readdir },
434*7688SAaron.Zang@Sun.COM 	VOPNAME_LOOKUP,		{ .vop_lookup = devvt_lookup },
435*7688SAaron.Zang@Sun.COM 	VOPNAME_CREATE,		{ .vop_create = devvt_create },
436*7688SAaron.Zang@Sun.COM 	VOPNAME_REMOVE,		{ .error = fs_nosys },
437*7688SAaron.Zang@Sun.COM 	VOPNAME_MKDIR,		{ .error = fs_nosys },
438*7688SAaron.Zang@Sun.COM 	VOPNAME_RMDIR,		{ .error = fs_nosys },
439*7688SAaron.Zang@Sun.COM 	VOPNAME_SYMLINK,	{ .error = fs_nosys },
440*7688SAaron.Zang@Sun.COM 	VOPNAME_SETSECATTR,	{ .error = fs_nosys },
441*7688SAaron.Zang@Sun.COM 	NULL,			NULL
442*7688SAaron.Zang@Sun.COM };
443