No empty .Rs/.Re
[netbsd-mini2440.git] / sys / miscfs / kernfs / kernfs_subr.c
blobc2191e1ebb7cedf16dbaeac6faaef480ab4bed38
1 /* $NetBSD: kernfs_subr.c,v 1.19 2009/03/14 15:36:22 dsl Exp $ */
3 /*
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Jan-Simon Pendry.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * @(#)kernfs_subr.c 8.6 (Berkeley) 5/14/95
38 * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved.
39 * Copyright (c) 1993 Jan-Simon Pendry
41 * This code is derived from software contributed to Berkeley by
42 * Jan-Simon Pendry.
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
72 * @(#)kernfs_subr.c 8.6 (Berkeley) 5/14/95
75 #include <sys/cdefs.h>
76 __KERNEL_RCSID(0, "$NetBSD: kernfs_subr.c,v 1.19 2009/03/14 15:36:22 dsl Exp $");
78 #ifdef _KERNEL_OPT
79 #include "opt_ipsec.h"
80 #endif
82 #include <sys/param.h>
83 #include <sys/systm.h>
84 #include <sys/time.h>
85 #include <sys/kernel.h>
86 #include <sys/proc.h>
87 #include <sys/vnode.h>
88 #include <sys/malloc.h>
89 #include <sys/stat.h>
90 #include <sys/file.h>
91 #include <sys/filedesc.h>
92 #include <sys/mount.h>
94 #include <miscfs/kernfs/kernfs.h>
96 #ifdef IPSEC
97 #include <sys/mbuf.h>
98 #include <net/route.h>
99 #include <netinet/in.h>
100 #include <netinet6/ipsec.h>
101 #include <netkey/keydb.h>
102 #include <netkey/key.h>
103 #endif
105 void kernfs_hashins(struct kernfs_node *);
106 void kernfs_hashrem(struct kernfs_node *);
107 struct vnode *kernfs_hashget(kfstype, struct mount *,
108 const struct kern_target *, u_int32_t);
110 static LIST_HEAD(kfs_hashhead, kernfs_node) *kfs_hashtbl;
111 static u_long kfs_ihash; /* size of hash table - 1 */
112 #define KFSVALUEHASH(v) ((v) & kfs_ihash)
114 static kmutex_t kfs_hashlock;
115 static kmutex_t kfs_ihash_lock;
117 #define ISSET(t, f) ((t) & (f))
120 * allocate a kfsnode/vnode pair. the vnode is
121 * referenced, and locked.
123 * the kfs_type, kfs_value and mount point uniquely
124 * identify a kfsnode. the mount point is needed
125 * because someone might mount this filesystem
126 * twice.
128 * all kfsnodes are maintained on a singly-linked
129 * list. new nodes are only allocated when they cannot
130 * be found on this list. entries on the list are
131 * removed when the vfs reclaim entry is called.
133 * a single lock is kept for the entire list. this is
134 * needed because the getnewvnode() function can block
135 * waiting for a vnode to become free, in which case there
136 * may be more than one process trying to get the same
137 * vnode. this lock is only taken if we are going to
138 * call getnewvnode, since the kernel itself is single-threaded.
140 * if an entry is found on the list, then call vget() to
141 * take a reference. this is done because there may be
142 * zero references to it and so it needs to removed from
143 * the vnode free list.
146 kernfs_allocvp(struct mount *mp, struct vnode **vpp, kfstype kfs_type, const struct kern_target *kt, u_int32_t value)
148 struct kernfs_node *kfs = NULL, *kfsp;
149 struct vnode *vp = NULL;
150 int error;
151 long *cookie;
153 if ((*vpp = kernfs_hashget(kfs_type, mp, kt, value)) != NULL)
154 return (0);
156 mutex_enter(&kfs_hashlock);
157 if ((*vpp = kernfs_hashget(kfs_type, mp, kt, value)) != NULL) {
158 mutex_exit(&kfs_hashlock);
159 return (0);
162 if (kfs_type == KFSdevice) {
163 /* /kern/rootdev = look for device and obey */
164 /* /kern/rrootdev = look for device and obey */
165 dev_t *dp;
166 struct vnode *fvp;
168 #ifdef DIAGNOSTIC
169 if (!kt)
170 panic("kernfs: kt == NULL for KFSdevice");
171 #endif
172 dp = kt->kt_data;
173 loop:
174 if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) {
175 mutex_exit(&kfs_hashlock);
176 return (ENOENT);
178 vp = fvp;
179 if (vget(fvp, LK_EXCLUSIVE))
180 goto loop;
181 *vpp = vp;
182 mutex_exit(&kfs_hashlock);
183 return (0);
186 if ((error = getnewvnode(VT_KERNFS, mp, kernfs_vnodeop_p, &vp)) != 0) {
187 *vpp = NULL;
188 mutex_exit(&kfs_hashlock);
189 return (error);
192 kfs = malloc(sizeof(struct kernfs_node), M_TEMP, M_WAITOK|M_ZERO);
193 vp->v_data = kfs;
194 cookie = &(VFSTOKERNFS(mp)->fileno_cookie);
195 again:
196 TAILQ_FOREACH(kfsp, &VFSTOKERNFS(mp)->nodelist, kfs_list) {
197 if (kfsp->kfs_cookie == *cookie) {
198 (*cookie) ++;
199 goto again;
201 if (TAILQ_NEXT(kfsp, kfs_list)) {
202 if (kfsp->kfs_cookie < *cookie &&
203 *cookie < TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie)
204 break;
205 if (kfsp->kfs_cookie + 1 <
206 TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) {
207 *cookie = kfsp->kfs_cookie + 1;
208 break;
213 kfs->kfs_cookie = *cookie;
215 if (kfsp)
216 TAILQ_INSERT_AFTER(&VFSTOKERNFS(mp)->nodelist, kfsp, kfs,
217 kfs_list);
218 else
219 TAILQ_INSERT_TAIL(&VFSTOKERNFS(mp)->nodelist, kfs, kfs_list);
221 kfs->kfs_type = kfs_type;
222 kfs->kfs_vnode = vp;
223 kfs->kfs_fileno = KERNFS_FILENO(kt, kfs_type, kfs->kfs_cookie);
224 kfs->kfs_value = value;
225 kfs->kfs_kt = kt;
226 kfs->kfs_mode = kt->kt_mode;
227 vp->v_type = kt->kt_vtype;
229 if (kfs_type == KFSkern)
230 vp->v_vflag = VV_ROOT;
232 kernfs_hashins(kfs);
233 uvm_vnp_setsize(vp, 0);
234 mutex_exit(&kfs_hashlock);
236 *vpp = vp;
237 return (0);
241 kernfs_freevp(struct vnode *vp)
243 struct kernfs_node *kfs = VTOKERN(vp);
245 kernfs_hashrem(kfs);
246 TAILQ_REMOVE(&VFSTOKERNFS(vp->v_mount)->nodelist, kfs, kfs_list);
248 free(vp->v_data, M_TEMP);
249 vp->v_data = 0;
250 return (0);
254 * Initialize kfsnode hash table.
256 void
257 kernfs_hashinit(void)
260 mutex_init(&kfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
261 mutex_init(&kfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE);
262 kfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, true, &kfs_ihash);
265 void
266 kernfs_hashreinit(void)
268 struct kernfs_node *pp;
269 struct kfs_hashhead *oldhash, *hash;
270 u_long i, oldmask, mask, val;
272 hash = hashinit(desiredvnodes / 4, HASH_LIST, true, &mask);
274 mutex_enter(&kfs_ihash_lock);
275 oldhash = kfs_hashtbl;
276 oldmask = kfs_ihash;
277 kfs_hashtbl = hash;
278 kfs_ihash = mask;
279 for (i = 0; i <= oldmask; i++) {
280 while ((pp = LIST_FIRST(&oldhash[i])) != NULL) {
281 LIST_REMOVE(pp, kfs_hash);
282 val = KFSVALUEHASH(pp->kfs_value);
283 LIST_INSERT_HEAD(&hash[val], pp, kfs_hash);
286 mutex_exit(&kfs_ihash_lock);
287 hashdone(oldhash, HASH_LIST, oldmask);
291 * Free kfsnode hash table.
293 void
294 kernfs_hashdone(void)
297 hashdone(kfs_hashtbl, HASH_LIST, kfs_ihash);
298 mutex_destroy(&kfs_hashlock);
299 mutex_destroy(&kfs_ihash_lock);
302 struct vnode *
303 kernfs_hashget(kfstype type, struct mount *mp, const struct kern_target *kt, u_int32_t value)
305 struct kfs_hashhead *ppp;
306 struct kernfs_node *pp;
307 struct vnode *vp;
309 loop:
310 mutex_enter(&kfs_ihash_lock);
311 ppp = &kfs_hashtbl[KFSVALUEHASH(value)];
312 LIST_FOREACH(pp, ppp, kfs_hash) {
313 vp = KERNFSTOV(pp);
314 if (pp->kfs_type == type && vp->v_mount == mp &&
315 pp->kfs_kt == kt && pp->kfs_value == value) {
316 mutex_enter(&vp->v_interlock);
317 mutex_exit(&kfs_ihash_lock);
318 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
319 goto loop;
320 return (vp);
323 mutex_exit(&kfs_ihash_lock);
324 return (NULL);
328 * Insert the kfsnode into the hash table and lock it.
330 void
331 kernfs_hashins(struct kernfs_node *pp)
333 struct kfs_hashhead *ppp;
335 /* lock the kfsnode, then put it on the appropriate hash list */
336 vlockmgr(&pp->kfs_vnode->v_lock, LK_EXCLUSIVE);
338 mutex_enter(&kfs_ihash_lock);
339 ppp = &kfs_hashtbl[KFSVALUEHASH(pp->kfs_value)];
340 LIST_INSERT_HEAD(ppp, pp, kfs_hash);
341 mutex_exit(&kfs_ihash_lock);
345 * Remove the kfsnode from the hash table.
347 void
348 kernfs_hashrem(struct kernfs_node *pp)
350 mutex_enter(&kfs_ihash_lock);
351 LIST_REMOVE(pp, kfs_hash);
352 mutex_exit(&kfs_ihash_lock);
355 #ifdef IPSEC
356 void
357 kernfs_revoke_sa(struct secasvar *sav)
359 struct kernfs_node *kfs, *pnext;
360 struct vnode *vp;
361 struct kfs_hashhead *ppp;
362 struct mbuf *m;
364 if (key_setdumpsa_spi == NULL)
365 return;
367 ppp = &kfs_hashtbl[KFSVALUEHASH(ntohl(sav->spi))];
368 for (kfs = LIST_FIRST(ppp); kfs; kfs = pnext) {
369 vp = KERNFSTOV(kfs);
370 pnext = LIST_NEXT(kfs, kfs_hash);
371 if (vp->v_usecount > 0 && kfs->kfs_type == KFSipsecsa &&
372 kfs->kfs_value == ntohl(sav->spi)) {
373 m = key_setdumpsa_spi(sav->spi);
374 if (!m)
375 VOP_REVOKE(vp, REVOKEALL);
376 else
377 m_freem(m);
378 break;
383 void
384 kernfs_revoke_sp(struct secpolicy *sp)
386 struct kernfs_node *kfs, *pnext;
387 struct vnode *vp;
388 struct kfs_hashhead *ppp;
390 ppp = &kfs_hashtbl[KFSVALUEHASH(sp->id)];
391 for (kfs = LIST_FIRST(ppp); kfs; kfs = pnext) {
392 vp = KERNFSTOV(kfs);
393 pnext = LIST_NEXT(kfs, kfs_hash);
394 if (vp->v_usecount > 0 && kfs->kfs_type == KFSipsecsa &&
395 kfs->kfs_value == sp->id)
396 VOP_REVOKE(vp, REVOKEALL);
399 #endif