xref: /onnv-gate/usr/src/uts/common/fs/dev/sdev_ipnetops.c (revision 8023:faf256d5c16c)
1*8023SPhil.Kirk@Sun.COM /*
2*8023SPhil.Kirk@Sun.COM  * CDDL HEADER START
3*8023SPhil.Kirk@Sun.COM  *
4*8023SPhil.Kirk@Sun.COM  * The contents of this file are subject to the terms of the
5*8023SPhil.Kirk@Sun.COM  * Common Development and Distribution License (the "License").
6*8023SPhil.Kirk@Sun.COM  * You may not use this file except in compliance with the License.
7*8023SPhil.Kirk@Sun.COM  *
8*8023SPhil.Kirk@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8023SPhil.Kirk@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*8023SPhil.Kirk@Sun.COM  * See the License for the specific language governing permissions
11*8023SPhil.Kirk@Sun.COM  * and limitations under the License.
12*8023SPhil.Kirk@Sun.COM  *
13*8023SPhil.Kirk@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*8023SPhil.Kirk@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8023SPhil.Kirk@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*8023SPhil.Kirk@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*8023SPhil.Kirk@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*8023SPhil.Kirk@Sun.COM  *
19*8023SPhil.Kirk@Sun.COM  * CDDL HEADER END
20*8023SPhil.Kirk@Sun.COM  */
21*8023SPhil.Kirk@Sun.COM /*
22*8023SPhil.Kirk@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*8023SPhil.Kirk@Sun.COM  * Use is subject to license terms.
24*8023SPhil.Kirk@Sun.COM  */
25*8023SPhil.Kirk@Sun.COM 
26*8023SPhil.Kirk@Sun.COM /*
27*8023SPhil.Kirk@Sun.COM  * vnode ops for the /dev/ipnet directory
28*8023SPhil.Kirk@Sun.COM  *	The lookup is based on the ipnetif nodes held
29*8023SPhil.Kirk@Sun.COM  *	in the ipnet module. We also override readdir
30*8023SPhil.Kirk@Sun.COM  *	in order to delete ipnet nodes no longer in use.
31*8023SPhil.Kirk@Sun.COM  */
32*8023SPhil.Kirk@Sun.COM 
33*8023SPhil.Kirk@Sun.COM #include <sys/types.h>
34*8023SPhil.Kirk@Sun.COM #include <sys/param.h>
35*8023SPhil.Kirk@Sun.COM #include <sys/sysmacros.h>
36*8023SPhil.Kirk@Sun.COM #include <sys/sunndi.h>
37*8023SPhil.Kirk@Sun.COM #include <fs/fs_subr.h>
38*8023SPhil.Kirk@Sun.COM #include <sys/fs/dv_node.h>
39*8023SPhil.Kirk@Sun.COM #include <sys/fs/sdev_impl.h>
40*8023SPhil.Kirk@Sun.COM #include <sys/policy.h>
41*8023SPhil.Kirk@Sun.COM #include <inet/ipnet.h>
42*8023SPhil.Kirk@Sun.COM #include <sys/zone.h>
43*8023SPhil.Kirk@Sun.COM 
44*8023SPhil.Kirk@Sun.COM struct vnodeops		*devipnet_vnodeops;
45*8023SPhil.Kirk@Sun.COM 
46*8023SPhil.Kirk@Sun.COM static void
devipnet_fill_vattr(struct vattr * vap,dev_t dev)47*8023SPhil.Kirk@Sun.COM devipnet_fill_vattr(struct vattr *vap, dev_t dev)
48*8023SPhil.Kirk@Sun.COM {
49*8023SPhil.Kirk@Sun.COM 	timestruc_t now;
50*8023SPhil.Kirk@Sun.COM 
51*8023SPhil.Kirk@Sun.COM 	*vap = sdev_vattr_chr;
52*8023SPhil.Kirk@Sun.COM 	vap->va_rdev = dev;
53*8023SPhil.Kirk@Sun.COM 	vap->va_mode |= 0666;
54*8023SPhil.Kirk@Sun.COM 
55*8023SPhil.Kirk@Sun.COM 	gethrestime(&now);
56*8023SPhil.Kirk@Sun.COM 	vap->va_atime = now;
57*8023SPhil.Kirk@Sun.COM 	vap->va_mtime = now;
58*8023SPhil.Kirk@Sun.COM 	vap->va_ctime = now;
59*8023SPhil.Kirk@Sun.COM }
60*8023SPhil.Kirk@Sun.COM 
61*8023SPhil.Kirk@Sun.COM /*
62*8023SPhil.Kirk@Sun.COM  * Check if an ipnet sdev_node is still valid.
63*8023SPhil.Kirk@Sun.COM  */
64*8023SPhil.Kirk@Sun.COM int
devipnet_validate(struct sdev_node * dv)65*8023SPhil.Kirk@Sun.COM devipnet_validate(struct sdev_node *dv)
66*8023SPhil.Kirk@Sun.COM {
67*8023SPhil.Kirk@Sun.COM 	dev_t	dev;
68*8023SPhil.Kirk@Sun.COM 
69*8023SPhil.Kirk@Sun.COM 	dev = ipnet_if_getdev(dv->sdev_name, getzoneid());
70*8023SPhil.Kirk@Sun.COM 	if (dev == (dev_t)-1)
71*8023SPhil.Kirk@Sun.COM 		return (SDEV_VTOR_INVALID);
72*8023SPhil.Kirk@Sun.COM 	if (getminor(SDEVTOV(dv)->v_rdev) != getminor(dev))
73*8023SPhil.Kirk@Sun.COM 		return (SDEV_VTOR_STALE);
74*8023SPhil.Kirk@Sun.COM 	return (SDEV_VTOR_VALID);
75*8023SPhil.Kirk@Sun.COM }
76*8023SPhil.Kirk@Sun.COM 
77*8023SPhil.Kirk@Sun.COM /*
78*8023SPhil.Kirk@Sun.COM  * This callback is invoked from devname_lookup_func() to create
79*8023SPhil.Kirk@Sun.COM  * an ipnet entry when the node is not found in the cache.
80*8023SPhil.Kirk@Sun.COM  */
81*8023SPhil.Kirk@Sun.COM /*ARGSUSED*/
82*8023SPhil.Kirk@Sun.COM static int
devipnet_create_rvp(struct sdev_node * ddv,char * nm,void ** arg,cred_t * cred,void * whatever,char * whichever)83*8023SPhil.Kirk@Sun.COM devipnet_create_rvp(struct sdev_node *ddv, char *nm,
84*8023SPhil.Kirk@Sun.COM     void **arg, cred_t *cred, void *whatever, char *whichever)
85*8023SPhil.Kirk@Sun.COM {
86*8023SPhil.Kirk@Sun.COM 	dev_t		dev;
87*8023SPhil.Kirk@Sun.COM 	struct vattr	*vap = (struct vattr *)arg;
88*8023SPhil.Kirk@Sun.COM 	int		err = 0;
89*8023SPhil.Kirk@Sun.COM 
90*8023SPhil.Kirk@Sun.COM 	if ((dev = ipnet_if_getdev(nm, getzoneid())) == (dev_t)-1)
91*8023SPhil.Kirk@Sun.COM 		err = ENOENT;
92*8023SPhil.Kirk@Sun.COM 	else
93*8023SPhil.Kirk@Sun.COM 		devipnet_fill_vattr(vap, dev);
94*8023SPhil.Kirk@Sun.COM 
95*8023SPhil.Kirk@Sun.COM 	return (err);
96*8023SPhil.Kirk@Sun.COM }
97*8023SPhil.Kirk@Sun.COM 
98*8023SPhil.Kirk@Sun.COM /*
99*8023SPhil.Kirk@Sun.COM  * Lookup for /dev/ipnet directory
100*8023SPhil.Kirk@Sun.COM  *	If the entry does not exist, the devipnet_create_rvp() callback
101*8023SPhil.Kirk@Sun.COM  *	is invoked to create it. Nodes do not persist across reboot.
102*8023SPhil.Kirk@Sun.COM  */
103*8023SPhil.Kirk@Sun.COM /*ARGSUSED3*/
104*8023SPhil.Kirk@Sun.COM static int
devipnet_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)105*8023SPhil.Kirk@Sun.COM devipnet_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
106*8023SPhil.Kirk@Sun.COM     struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
107*8023SPhil.Kirk@Sun.COM     caller_context_t *ct, int *direntflags, pathname_t *realpnp)
108*8023SPhil.Kirk@Sun.COM {
109*8023SPhil.Kirk@Sun.COM 	struct sdev_node *sdvp = VTOSDEV(dvp);
110*8023SPhil.Kirk@Sun.COM 	struct sdev_node *dv;
111*8023SPhil.Kirk@Sun.COM 	struct vnode *rvp = NULL;
112*8023SPhil.Kirk@Sun.COM 	int error;
113*8023SPhil.Kirk@Sun.COM 
114*8023SPhil.Kirk@Sun.COM 	error = devname_lookup_func(sdvp, nm, vpp, cred, devipnet_create_rvp,
115*8023SPhil.Kirk@Sun.COM 	    SDEV_VATTR);
116*8023SPhil.Kirk@Sun.COM 
117*8023SPhil.Kirk@Sun.COM 	if (error == 0) {
118*8023SPhil.Kirk@Sun.COM 		switch ((*vpp)->v_type) {
119*8023SPhil.Kirk@Sun.COM 		case VCHR:
120*8023SPhil.Kirk@Sun.COM 			dv = VTOSDEV(VTOS(*vpp)->s_realvp);
121*8023SPhil.Kirk@Sun.COM 			ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
122*8023SPhil.Kirk@Sun.COM 			break;
123*8023SPhil.Kirk@Sun.COM 		case VDIR:
124*8023SPhil.Kirk@Sun.COM 			dv = VTOSDEV(*vpp);
125*8023SPhil.Kirk@Sun.COM 			break;
126*8023SPhil.Kirk@Sun.COM 		default:
127*8023SPhil.Kirk@Sun.COM 			cmn_err(CE_PANIC, "devipnet_lookup: Unsupported node "
128*8023SPhil.Kirk@Sun.COM 			    "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
129*8023SPhil.Kirk@Sun.COM 			break;
130*8023SPhil.Kirk@Sun.COM 		}
131*8023SPhil.Kirk@Sun.COM 		ASSERT(SDEV_HELD(dv));
132*8023SPhil.Kirk@Sun.COM 	}
133*8023SPhil.Kirk@Sun.COM 
134*8023SPhil.Kirk@Sun.COM 	return (error);
135*8023SPhil.Kirk@Sun.COM }
136*8023SPhil.Kirk@Sun.COM 
137*8023SPhil.Kirk@Sun.COM static void
devipnet_filldir_entry(const char * name,void * arg,dev_t dev)138*8023SPhil.Kirk@Sun.COM devipnet_filldir_entry(const char *name, void *arg, dev_t dev)
139*8023SPhil.Kirk@Sun.COM {
140*8023SPhil.Kirk@Sun.COM 	struct sdev_node *ddv = arg;
141*8023SPhil.Kirk@Sun.COM 	struct vattr vattr;
142*8023SPhil.Kirk@Sun.COM 	struct sdev_node *dv;
143*8023SPhil.Kirk@Sun.COM 
144*8023SPhil.Kirk@Sun.COM 	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
145*8023SPhil.Kirk@Sun.COM 
146*8023SPhil.Kirk@Sun.COM 	if ((dv = sdev_cache_lookup(ddv, (char *)name)) == NULL) {
147*8023SPhil.Kirk@Sun.COM 		devipnet_fill_vattr(&vattr, dev);
148*8023SPhil.Kirk@Sun.COM 		if (sdev_mknode(ddv, (char *)name, &dv, &vattr, NULL, NULL,
149*8023SPhil.Kirk@Sun.COM 		    kcred, SDEV_READY) != 0)
150*8023SPhil.Kirk@Sun.COM 			return;
151*8023SPhil.Kirk@Sun.COM 	}
152*8023SPhil.Kirk@Sun.COM 	SDEV_SIMPLE_RELE(dv);
153*8023SPhil.Kirk@Sun.COM }
154*8023SPhil.Kirk@Sun.COM 
155*8023SPhil.Kirk@Sun.COM static void
devipnet_filldir(struct sdev_node * ddv)156*8023SPhil.Kirk@Sun.COM devipnet_filldir(struct sdev_node *ddv)
157*8023SPhil.Kirk@Sun.COM {
158*8023SPhil.Kirk@Sun.COM 	sdev_node_t	*dv, *next;
159*8023SPhil.Kirk@Sun.COM 
160*8023SPhil.Kirk@Sun.COM 	ASSERT(RW_READ_HELD(&ddv->sdev_contents));
161*8023SPhil.Kirk@Sun.COM 	if (rw_tryupgrade(&ddv->sdev_contents) == NULL) {
162*8023SPhil.Kirk@Sun.COM 		rw_exit(&ddv->sdev_contents);
163*8023SPhil.Kirk@Sun.COM 		rw_enter(&ddv->sdev_contents, RW_WRITER);
164*8023SPhil.Kirk@Sun.COM 	}
165*8023SPhil.Kirk@Sun.COM 
166*8023SPhil.Kirk@Sun.COM 	for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
167*8023SPhil.Kirk@Sun.COM 		next = SDEV_NEXT_ENTRY(ddv, dv);
168*8023SPhil.Kirk@Sun.COM 
169*8023SPhil.Kirk@Sun.COM 		/* validate and prune only ready nodes */
170*8023SPhil.Kirk@Sun.COM 		if (dv->sdev_state != SDEV_READY)
171*8023SPhil.Kirk@Sun.COM 			continue;
172*8023SPhil.Kirk@Sun.COM 		switch (devipnet_validate(dv)) {
173*8023SPhil.Kirk@Sun.COM 		case SDEV_VTOR_VALID:
174*8023SPhil.Kirk@Sun.COM 		case SDEV_VTOR_SKIP:
175*8023SPhil.Kirk@Sun.COM 			continue;
176*8023SPhil.Kirk@Sun.COM 		case SDEV_VTOR_INVALID:
177*8023SPhil.Kirk@Sun.COM 		case SDEV_VTOR_STALE:
178*8023SPhil.Kirk@Sun.COM 			sdcmn_err12(("devipnet_filldir: destroy invalid "
179*8023SPhil.Kirk@Sun.COM 			    "node: %s(%p)\n", dv->sdev_name, (void *)dv));
180*8023SPhil.Kirk@Sun.COM 			break;
181*8023SPhil.Kirk@Sun.COM 		}
182*8023SPhil.Kirk@Sun.COM 
183*8023SPhil.Kirk@Sun.COM 		if (SDEVTOV(dv)->v_count > 0)
184*8023SPhil.Kirk@Sun.COM 			continue;
185*8023SPhil.Kirk@Sun.COM 		SDEV_HOLD(dv);
186*8023SPhil.Kirk@Sun.COM 		/* remove the cache node */
187*8023SPhil.Kirk@Sun.COM 		(void) sdev_cache_update(ddv, &dv, dv->sdev_name,
188*8023SPhil.Kirk@Sun.COM 		    SDEV_CACHE_DELETE);
189*8023SPhil.Kirk@Sun.COM 	}
190*8023SPhil.Kirk@Sun.COM 
191*8023SPhil.Kirk@Sun.COM 	ipnet_walk_if(devipnet_filldir_entry, ddv, getzoneid());
192*8023SPhil.Kirk@Sun.COM 
193*8023SPhil.Kirk@Sun.COM 	rw_downgrade(&ddv->sdev_contents);
194*8023SPhil.Kirk@Sun.COM }
195*8023SPhil.Kirk@Sun.COM 
196*8023SPhil.Kirk@Sun.COM /*
197*8023SPhil.Kirk@Sun.COM  * Display all instantiated ipnet device nodes.
198*8023SPhil.Kirk@Sun.COM  */
199*8023SPhil.Kirk@Sun.COM /* ARGSUSED */
200*8023SPhil.Kirk@Sun.COM static int
devipnet_readdir(struct vnode * dvp,struct uio * uiop,struct cred * cred,int * eofp,caller_context_t * ct,int flags)201*8023SPhil.Kirk@Sun.COM devipnet_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
202*8023SPhil.Kirk@Sun.COM     int *eofp, caller_context_t *ct, int flags)
203*8023SPhil.Kirk@Sun.COM {
204*8023SPhil.Kirk@Sun.COM 	struct sdev_node *sdvp = VTOSDEV(dvp);
205*8023SPhil.Kirk@Sun.COM 
206*8023SPhil.Kirk@Sun.COM 	if (uiop->uio_offset == 0)
207*8023SPhil.Kirk@Sun.COM 		devipnet_filldir(sdvp);
208*8023SPhil.Kirk@Sun.COM 
209*8023SPhil.Kirk@Sun.COM 	return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
210*8023SPhil.Kirk@Sun.COM }
211*8023SPhil.Kirk@Sun.COM 
212*8023SPhil.Kirk@Sun.COM /*
213*8023SPhil.Kirk@Sun.COM  * We override lookup and readdir to build entries based on the
214*8023SPhil.Kirk@Sun.COM  * in kernel ipnet table.
215*8023SPhil.Kirk@Sun.COM  */
216*8023SPhil.Kirk@Sun.COM const fs_operation_def_t devipnet_vnodeops_tbl[] = {
217*8023SPhil.Kirk@Sun.COM 	VOPNAME_READDIR,	{ .vop_readdir = devipnet_readdir },
218*8023SPhil.Kirk@Sun.COM 	VOPNAME_LOOKUP,		{ .vop_lookup = devipnet_lookup },
219*8023SPhil.Kirk@Sun.COM 	VOPNAME_CREATE,		{ .error = fs_nosys },
220*8023SPhil.Kirk@Sun.COM 	VOPNAME_REMOVE,		{ .error = fs_nosys },
221*8023SPhil.Kirk@Sun.COM 	VOPNAME_MKDIR,		{ .error = fs_nosys },
222*8023SPhil.Kirk@Sun.COM 	VOPNAME_RMDIR,		{ .error = fs_nosys },
223*8023SPhil.Kirk@Sun.COM 	VOPNAME_SYMLINK,	{ .error = fs_nosys },
224*8023SPhil.Kirk@Sun.COM 	VOPNAME_SETSECATTR,	{ .error = fs_nosys },
225*8023SPhil.Kirk@Sun.COM 	NULL,			NULL
226*8023SPhil.Kirk@Sun.COM };
227