Unleashed v1.4
[unleashed.git] / kernel / fs / dev / sdev_ipnetops.c
blob74f2624ed19c278e5acc7a332e374a34a18e6b74
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
42 #include <sys/zone.h>
43 #include "sdev_vnops.h"
45 static void
46 devipnet_fill_vattr(struct vattr *vap, dev_t dev)
48 timestruc_t now;
50 *vap = sdev_vattr_chr;
51 vap->va_rdev = dev;
52 vap->va_mode |= 0666;
54 gethrestime(&now);
55 vap->va_atime = now;
56 vap->va_mtime = now;
57 vap->va_ctime = now;
61 * Check if an ipnet sdev_node is still valid.
63 int
64 devipnet_validate(struct sdev_node *dv)
66 dev_t dev;
68 dev = ipnet_if_getdev(dv->sdev_name, getzoneid());
69 if (dev == (dev_t)-1)
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.
80 /*ARGSUSED*/
81 static int
82 devipnet_create_rvp(struct sdev_node *ddv, char *nm,
83 void **arg, cred_t *cred, void *whatever, char *whichever)
85 dev_t dev;
86 struct vattr *vap = (struct vattr *)arg;
87 int err = 0;
89 if ((dev = ipnet_if_getdev(nm, getzoneid())) == (dev_t)-1)
90 err = ENOENT;
91 else
92 devipnet_fill_vattr(vap, dev);
94 return (err);
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.
102 /*ARGSUSED3*/
103 static int
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;
111 int error;
113 error = devname_lookup_func(sdvp, nm, vpp, cred, devipnet_create_rvp,
114 SDEV_VATTR);
116 if (error == 0) {
117 switch ((*vpp)->v_type) {
118 case VCHR:
119 dv = VTOSDEV(VTOS(*vpp)->s_realvp);
120 ASSERT(fop_realvp(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
121 break;
122 case VDIR:
123 dv = VTOSDEV(*vpp);
124 break;
125 default:
126 cmn_err(CE_PANIC, "devipnet_lookup: Unsupported node "
127 "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
128 break;
130 ASSERT(SDEV_HELD(dv));
133 return (error);
136 static void
137 devipnet_filldir_entry(const char *name, void *arg, dev_t dev)
139 struct sdev_node *ddv = arg;
140 struct vattr vattr;
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)
149 return;
151 SDEV_SIMPLE_RELE(dv);
154 static void
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);
169 return;
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)
178 continue;
179 switch (devipnet_validate(dv)) {
180 case SDEV_VTOR_VALID:
181 case SDEV_VTOR_SKIP:
182 continue;
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));
187 break;
190 if (SDEVTOV(dv)->v_count > 0)
191 continue;
192 SDEV_HOLD(dv);
193 /* remove the cache node */
194 (void) sdev_cache_update(ddv, &dv, dv->sdev_name,
195 SDEV_CACHE_DELETE);
196 SDEV_RELE(dv);
199 ipnet_walk_if(devipnet_filldir_entry, ddv, getzoneid());
201 rw_downgrade(&ddv->sdev_contents);
205 * Display all instantiated ipnet device nodes.
207 /* ARGSUSED */
208 static int
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,
236 .vop_fid = sdev_fid,
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,
244 /* overrides */
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,