4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * vnode ops for the /dev/ipnet directory
28 * The lookup is based on the ipnetif nodes held
29 * in the ipnet module. We also override readdir
30 * in order to delete ipnet nodes no longer in use.
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/sysmacros.h>
36 #include <sys/sunndi.h>
37 #include <sys/fs_subr.h>
38 #include <sys/fs/dv_node.h>
39 #include <sys/fs/sdev_impl.h>
40 #include <sys/policy.h>
41 #include <inet/ipnet.h>
43 #include "sdev_vnops.h"
46 devipnet_fill_vattr(struct vattr
*vap
, dev_t dev
)
50 *vap
= sdev_vattr_chr
;
61 * Check if an ipnet sdev_node is still valid.
64 devipnet_validate(struct sdev_node
*dv
)
68 dev
= ipnet_if_getdev(dv
->sdev_name
, getzoneid());
70 return (SDEV_VTOR_INVALID
);
71 if (getminor(SDEVTOV(dv
)->v_rdev
) != getminor(dev
))
72 return (SDEV_VTOR_STALE
);
73 return (SDEV_VTOR_VALID
);
77 * This callback is invoked from devname_lookup_func() to create
78 * an ipnet entry when the node is not found in the cache.
82 devipnet_create_rvp(struct sdev_node
*ddv
, char *nm
,
83 void **arg
, cred_t
*cred
, void *whatever
, char *whichever
)
86 struct vattr
*vap
= (struct vattr
*)arg
;
89 if ((dev
= ipnet_if_getdev(nm
, getzoneid())) == (dev_t
)-1)
92 devipnet_fill_vattr(vap
, dev
);
98 * Lookup for /dev/ipnet directory
99 * If the entry does not exist, the devipnet_create_rvp() callback
100 * is invoked to create it. Nodes do not persist across reboot.
104 devipnet_lookup(struct vnode
*dvp
, char *nm
, struct vnode
**vpp
,
105 struct pathname
*pnp
, int flags
, struct vnode
*rdir
, struct cred
*cred
,
106 caller_context_t
*ct
, int *direntflags
, pathname_t
*realpnp
)
108 struct sdev_node
*sdvp
= VTOSDEV(dvp
);
109 struct sdev_node
*dv
;
110 struct vnode
*rvp
= NULL
;
113 error
= devname_lookup_func(sdvp
, nm
, vpp
, cred
, devipnet_create_rvp
,
117 switch ((*vpp
)->v_type
) {
119 dv
= VTOSDEV(VTOS(*vpp
)->s_realvp
);
120 ASSERT(fop_realvp(SDEVTOV(dv
), &rvp
, NULL
) == ENOSYS
);
126 cmn_err(CE_PANIC
, "devipnet_lookup: Unsupported node "
127 "type: %p: %d", (void *)(*vpp
), (*vpp
)->v_type
);
130 ASSERT(SDEV_HELD(dv
));
137 devipnet_filldir_entry(const char *name
, void *arg
, dev_t dev
)
139 struct sdev_node
*ddv
= arg
;
141 struct sdev_node
*dv
;
143 ASSERT(RW_WRITE_HELD(&ddv
->sdev_contents
));
145 if ((dv
= sdev_cache_lookup(ddv
, (char *)name
)) == NULL
) {
146 devipnet_fill_vattr(&vattr
, dev
);
147 if (sdev_mknode(ddv
, (char *)name
, &dv
, &vattr
, NULL
, NULL
,
148 kcred
, SDEV_READY
) != 0)
151 SDEV_SIMPLE_RELE(dv
);
155 devipnet_filldir(struct sdev_node
*ddv
)
157 sdev_node_t
*dv
, *next
;
159 ASSERT(RW_READ_HELD(&ddv
->sdev_contents
));
160 if (rw_tryupgrade(&ddv
->sdev_contents
) == 0) {
161 rw_exit(&ddv
->sdev_contents
);
162 rw_enter(&ddv
->sdev_contents
, RW_WRITER
);
164 * We've been made a zombie while we weren't looking. We'll bail
165 * if that's the case.
167 if (ddv
->sdev_state
== SDEV_ZOMBIE
) {
168 rw_exit(&ddv
->sdev_contents
);
173 for (dv
= SDEV_FIRST_ENTRY(ddv
); dv
; dv
= next
) {
174 next
= SDEV_NEXT_ENTRY(ddv
, dv
);
176 /* validate and prune only ready nodes */
177 if (dv
->sdev_state
!= SDEV_READY
)
179 switch (devipnet_validate(dv
)) {
180 case SDEV_VTOR_VALID
:
183 case SDEV_VTOR_INVALID
:
184 case SDEV_VTOR_STALE
:
185 sdcmn_err12(("devipnet_filldir: destroy invalid "
186 "node: %s(%p)\n", dv
->sdev_name
, (void *)dv
));
190 if (SDEVTOV(dv
)->v_count
> 0)
193 /* remove the cache node */
194 (void) sdev_cache_update(ddv
, &dv
, dv
->sdev_name
,
199 ipnet_walk_if(devipnet_filldir_entry
, ddv
, getzoneid());
201 rw_downgrade(&ddv
->sdev_contents
);
205 * Display all instantiated ipnet device nodes.
209 devipnet_readdir(struct vnode
*dvp
, struct uio
*uiop
, struct cred
*cred
,
210 int *eofp
, caller_context_t
*ct
, int flags
)
212 struct sdev_node
*sdvp
= VTOSDEV(dvp
);
214 if (uiop
->uio_offset
== 0)
215 devipnet_filldir(sdvp
);
217 return (devname_readdir_func(dvp
, uiop
, cred
, eofp
, 0));
221 * We override lookup and readdir to build entries based on the
222 * in kernel ipnet table.
224 const struct vnodeops devipnet_vnodeops
= {
225 .vop_open
= sdev_open
,
226 .vop_close
= sdev_close
,
227 .vop_read
= sdev_read
,
228 .vop_write
= sdev_write
,
229 .vop_ioctl
= sdev_ioctl
,
230 .vop_getattr
= sdev_getattr
,
231 .vop_setattr
= sdev_setattr
,
232 .vop_access
= sdev_access
,
233 .vop_rename
= sdev_rename
,
234 .vop_readlink
= sdev_readlink
,
235 .vop_inactive
= sdev_inactive
,
237 .vop_rwlock
= sdev_rwlock
,
238 .vop_rwunlock
= sdev_rwunlock
,
239 .vop_seek
= sdev_seek
,
240 .vop_frlock
= sdev_frlock
,
241 .vop_pathconf
= sdev_pathconf
,
242 .vop_getsecattr
= sdev_getsecattr
,
245 .vop_readdir
= devipnet_readdir
,
246 .vop_lookup
= devipnet_lookup
,
247 .vop_create
= fs_nosys
,
248 .vop_remove
= fs_nosys
,
249 .vop_mkdir
= fs_nosys
,
250 .vop_rmdir
= fs_nosys
,
251 .vop_symlink
= fs_nosys
,
252 .vop_setsecattr
= fs_nosys
,