1 /* $NetBSD: kernfs_subr.c,v 1.19 2009/03/14 15:36:22 dsl Exp $ */
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
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
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
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
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 $");
79 #include "opt_ipsec.h"
82 #include <sys/param.h>
83 #include <sys/systm.h>
85 #include <sys/kernel.h>
87 #include <sys/vnode.h>
88 #include <sys/malloc.h>
91 #include <sys/filedesc.h>
92 #include <sys/mount.h>
94 #include <miscfs/kernfs/kernfs.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>
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
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
;
153 if ((*vpp
= kernfs_hashget(kfs_type
, mp
, kt
, value
)) != NULL
)
156 mutex_enter(&kfs_hashlock
);
157 if ((*vpp
= kernfs_hashget(kfs_type
, mp
, kt
, value
)) != NULL
) {
158 mutex_exit(&kfs_hashlock
);
162 if (kfs_type
== KFSdevice
) {
163 /* /kern/rootdev = look for device and obey */
164 /* /kern/rrootdev = look for device and obey */
170 panic("kernfs: kt == NULL for KFSdevice");
174 if (*dp
== NODEV
|| !vfinddev(*dp
, kt
->kt_vtype
, &fvp
)) {
175 mutex_exit(&kfs_hashlock
);
179 if (vget(fvp
, LK_EXCLUSIVE
))
182 mutex_exit(&kfs_hashlock
);
186 if ((error
= getnewvnode(VT_KERNFS
, mp
, kernfs_vnodeop_p
, &vp
)) != 0) {
188 mutex_exit(&kfs_hashlock
);
192 kfs
= malloc(sizeof(struct kernfs_node
), M_TEMP
, M_WAITOK
|M_ZERO
);
194 cookie
= &(VFSTOKERNFS(mp
)->fileno_cookie
);
196 TAILQ_FOREACH(kfsp
, &VFSTOKERNFS(mp
)->nodelist
, kfs_list
) {
197 if (kfsp
->kfs_cookie
== *cookie
) {
201 if (TAILQ_NEXT(kfsp
, kfs_list
)) {
202 if (kfsp
->kfs_cookie
< *cookie
&&
203 *cookie
< TAILQ_NEXT(kfsp
, kfs_list
)->kfs_cookie
)
205 if (kfsp
->kfs_cookie
+ 1 <
206 TAILQ_NEXT(kfsp
, kfs_list
)->kfs_cookie
) {
207 *cookie
= kfsp
->kfs_cookie
+ 1;
213 kfs
->kfs_cookie
= *cookie
;
216 TAILQ_INSERT_AFTER(&VFSTOKERNFS(mp
)->nodelist
, kfsp
, kfs
,
219 TAILQ_INSERT_TAIL(&VFSTOKERNFS(mp
)->nodelist
, kfs
, kfs_list
);
221 kfs
->kfs_type
= kfs_type
;
223 kfs
->kfs_fileno
= KERNFS_FILENO(kt
, kfs_type
, kfs
->kfs_cookie
);
224 kfs
->kfs_value
= value
;
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
;
233 uvm_vnp_setsize(vp
, 0);
234 mutex_exit(&kfs_hashlock
);
241 kernfs_freevp(struct vnode
*vp
)
243 struct kernfs_node
*kfs
= VTOKERN(vp
);
246 TAILQ_REMOVE(&VFSTOKERNFS(vp
->v_mount
)->nodelist
, kfs
, kfs_list
);
248 free(vp
->v_data
, M_TEMP
);
254 * Initialize kfsnode hash table.
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
);
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
;
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.
294 kernfs_hashdone(void)
297 hashdone(kfs_hashtbl
, HASH_LIST
, kfs_ihash
);
298 mutex_destroy(&kfs_hashlock
);
299 mutex_destroy(&kfs_ihash_lock
);
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
;
310 mutex_enter(&kfs_ihash_lock
);
311 ppp
= &kfs_hashtbl
[KFSVALUEHASH(value
)];
312 LIST_FOREACH(pp
, ppp
, kfs_hash
) {
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
))
323 mutex_exit(&kfs_ihash_lock
);
328 * Insert the kfsnode into the hash table and lock it.
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.
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
);
357 kernfs_revoke_sa(struct secasvar
*sav
)
359 struct kernfs_node
*kfs
, *pnext
;
361 struct kfs_hashhead
*ppp
;
364 if (key_setdumpsa_spi
== NULL
)
367 ppp
= &kfs_hashtbl
[KFSVALUEHASH(ntohl(sav
->spi
))];
368 for (kfs
= LIST_FIRST(ppp
); kfs
; kfs
= pnext
) {
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
);
375 VOP_REVOKE(vp
, REVOKEALL
);
384 kernfs_revoke_sp(struct secpolicy
*sp
)
386 struct kernfs_node
*kfs
, *pnext
;
388 struct kfs_hashhead
*ppp
;
390 ppp
= &kfs_hashtbl
[KFSVALUEHASH(sp
->id
)];
391 for (kfs
= LIST_FIRST(ppp
); kfs
; kfs
= pnext
) {
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
);