1 /* $NetBSD: kernfs_subr.c,v 1.7 2005/02/26 22:59:00 perry Exp $ */
2
3 /*
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Jan-Simon Pendry.
9 *
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.
21 *
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.
33 *
34 * @(#)kernfs_subr.c 8.6 (Berkeley) 5/14/95
35 */
36
37 /*
38 * Copyright (c) 1994 Christopher G. Demetriou. All rights reserved.
39 * Copyright (c) 1993 Jan-Simon Pendry
40 *
41 * This code is derived from software contributed to Berkeley by
42 * Jan-Simon Pendry.
43 *
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.
59 *
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.
71 *
72 * @(#)kernfs_subr.c 8.6 (Berkeley) 5/14/95
73 */
74
75 #include <sys/cdefs.h>
76 __KERNEL_RCSID(0, "$NetBSD: kernfs_subr.c,v 1.7 2005/02/26 22:59:00 perry Exp $");
77
78 #ifdef _KERNEL_OPT
79 #include "opt_ipsec.h"
80 #endif
81
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>
93
94 #include <miscfs/kernfs/kernfs.h>
95
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
104
105 void kernfs_hashins __P((struct kernfs_node *));
106 void kernfs_hashrem __P((struct kernfs_node *));
107 struct vnode *kernfs_hashget __P((kfstype, struct mount *,
108 const struct kern_target *, u_int32_t));
109
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)
113
114 static struct lock kfs_hashlock;
115 static struct simplelock kfs_hash_slock;
116
117 #define ISSET(t, f) ((t) & (f))
118
119 /*
120 * allocate a kfsnode/vnode pair. the vnode is
121 * referenced, and locked.
122 *
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.
127 *
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.
132 *
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.
139 *
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.
144 */
145 int
146 kernfs_allocvp(mp, vpp, kfs_type, kt, value)
147 struct mount *mp;
148 struct vnode **vpp;
149 kfstype kfs_type;
150 const struct kern_target *kt;
151 u_int32_t value;
152 {
153 struct kernfs_node *kfs = NULL, *kfsp;
154 struct vnode *vp = NULL;
155 int error;
156 long *cookie;
157
158 do {
159 if ((*vpp = kernfs_hashget(kfs_type, mp, kt, value)) != NULL)
160 return (0);
161 } while (lockmgr(&kfs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0));
162
163 if (kfs_type == KFSdevice) {
164 /* /kern/rootdev = look for device and obey */
165 /* /kern/rrootdev = look for device and obey */
166 dev_t *dp;
167 struct vnode *fvp;
168
169 #ifdef DIAGNOSTIC
170 if (!kt)
171 panic("kernfs: kt == NULL for KFSdevice");
172 #endif
173 dp = kt->kt_data;
174 loop:
175 if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) {
176 lockmgr(&kfs_hashlock, LK_RELEASE, NULL);
177 return (ENOENT);
178 }
179 vp = fvp;
180 if (vget(fvp, LK_EXCLUSIVE))
181 goto loop;
182 *vpp = vp;
183 lockmgr(&kfs_hashlock, LK_RELEASE, NULL);
184 return (0);
185 }
186
187 if ((error = getnewvnode(VT_KERNFS, mp, kernfs_vnodeop_p, &vp)) != 0) {
188 *vpp = NULL;
189 lockmgr(&kfs_hashlock, LK_RELEASE, NULL);
190 return (error);
191 }
192
193 MALLOC(kfs, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK);
194 memset(kfs, 0, sizeof(*kfs));
195 vp->v_data = kfs;
196 cookie = &(VFSTOKERNFS(mp)->fileno_cookie);
197 again:
198 TAILQ_FOREACH(kfsp, &VFSTOKERNFS(mp)->nodelist, kfs_list) {
199 if (kfsp->kfs_cookie == *cookie) {
200 (*cookie) ++;
201 goto again;
202 }
203 if (TAILQ_NEXT(kfsp, kfs_list)) {
204 if (kfsp->kfs_cookie < *cookie &&
205 *cookie < TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie)
206 break;
207 if (kfsp->kfs_cookie + 1 <
208 TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) {
209 *cookie = kfsp->kfs_cookie + 1;
210 break;
211 }
212 }
213 }
214
215 kfs->kfs_cookie = *cookie;
216
217 if (kfsp)
218 TAILQ_INSERT_AFTER(&VFSTOKERNFS(mp)->nodelist, kfsp, kfs,
219 kfs_list);
220 else
221 TAILQ_INSERT_TAIL(&VFSTOKERNFS(mp)->nodelist, kfs, kfs_list);
222
223 kfs->kfs_type = kfs_type;
224 kfs->kfs_vnode = vp;
225 kfs->kfs_fileno = KERNFS_FILENO(kt, kfs_type, kfs->kfs_cookie);
226 kfs->kfs_value = value;
227 kfs->kfs_kt = kt;
228 kfs->kfs_mode = kt->kt_mode;
229 vp->v_type = kt->kt_vtype;
230
231 if (kfs_type == KFSkern)
232 vp->v_flag = VROOT;
233
234 kernfs_hashins(kfs);
235 uvm_vnp_setsize(vp, 0);
236 lockmgr(&kfs_hashlock, LK_RELEASE, NULL);
237
238 *vpp = vp;
239 return (0);
240 }
241
242 int
243 kernfs_freevp(vp)
244 struct vnode *vp;
245 {
246 struct kernfs_node *kfs = VTOKERN(vp);
247
248 kernfs_hashrem(kfs);
249 TAILQ_REMOVE(&VFSTOKERNFS(vp->v_mount)->nodelist, kfs, kfs_list);
250
251 FREE(vp->v_data, M_TEMP);
252 vp->v_data = 0;
253 return (0);
254 }
255
256 /*
257 * Initialize kfsnode hash table.
258 */
259 void
260 kernfs_hashinit()
261 {
262
263 lockinit(&kfs_hashlock, PINOD, "kfs_hashlock", 0, 0);
264 kfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT,
265 M_WAITOK, &kfs_ihash);
266 simple_lock_init(&kfs_hash_slock);
267 }
268
269 void
270 kernfs_hashreinit()
271 {
272 struct kernfs_node *pp;
273 struct kfs_hashhead *oldhash, *hash;
274 u_long i, oldmask, mask, val;
275
276 hash = hashinit(desiredvnodes / 4, HASH_LIST, M_UFSMNT, M_WAITOK,
277 &mask);
278
279 simple_lock(&kfs_hash_slock);
280 oldhash = kfs_hashtbl;
281 oldmask = kfs_ihash;
282 kfs_hashtbl = hash;
283 kfs_ihash = mask;
284 for (i = 0; i <= oldmask; i++) {
285 while ((pp = LIST_FIRST(&oldhash[i])) != NULL) {
286 LIST_REMOVE(pp, kfs_hash);
287 val = KFSVALUEHASH(pp->kfs_value);
288 LIST_INSERT_HEAD(&hash[val], pp, kfs_hash);
289 }
290 }
291 simple_unlock(&kfs_hash_slock);
292 hashdone(oldhash, M_UFSMNT);
293 }
294
295 /*
296 * Free kfsnode hash table.
297 */
298 void
299 kernfs_hashdone()
300 {
301
302 hashdone(kfs_hashtbl, M_UFSMNT);
303 }
304
305 struct vnode *
306 kernfs_hashget(type, mp, kt, value)
307 kfstype type;
308 struct mount *mp;
309 const struct kern_target *kt;
310 u_int32_t value;
311 {
312 struct kfs_hashhead *ppp;
313 struct kernfs_node *pp;
314 struct vnode *vp;
315
316 loop:
317 simple_lock(&kfs_hash_slock);
318 ppp = &kfs_hashtbl[KFSVALUEHASH(value)];
319 LIST_FOREACH(pp, ppp, kfs_hash) {
320 vp = KERNFSTOV(pp);
321 if (pp->kfs_type == type && vp->v_mount == mp &&
322 pp->kfs_kt == kt && pp->kfs_value == value) {
323 simple_lock(&vp->v_interlock);
324 simple_unlock(&kfs_hash_slock);
325 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
326 goto loop;
327 return (vp);
328 }
329 }
330 simple_unlock(&kfs_hash_slock);
331 return (NULL);
332 }
333
334 /*
335 * Insert the kfsnode into the hash table and lock it.
336 */
337 void
338 kernfs_hashins(pp)
339 struct kernfs_node *pp;
340 {
341 struct kfs_hashhead *ppp;
342
343 /* lock the kfsnode, then put it on the appropriate hash list */
344 lockmgr(&pp->kfs_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0);
345
346 simple_lock(&kfs_hash_slock);
347 ppp = &kfs_hashtbl[KFSVALUEHASH(pp->kfs_value)];
348 LIST_INSERT_HEAD(ppp, pp, kfs_hash);
349 simple_unlock(&kfs_hash_slock);
350 }
351
352 /*
353 * Remove the kfsnode from the hash table.
354 */
355 void
356 kernfs_hashrem(pp)
357 struct kernfs_node *pp;
358 {
359 simple_lock(&kfs_hash_slock);
360 LIST_REMOVE(pp, kfs_hash);
361 simple_unlock(&kfs_hash_slock);
362 }
363
364 #ifdef IPSEC
365 void
366 kernfs_revoke_sa(sav)
367 struct secasvar *sav;
368 {
369 struct kernfs_node *kfs, *pnext;
370 struct vnode *vp;
371 struct kfs_hashhead *ppp;
372 struct mbuf *m;
373
374 ppp = &kfs_hashtbl[KFSVALUEHASH(ntohl(sav->spi))];
375 for (kfs = LIST_FIRST(ppp); kfs; kfs = pnext) {
376 vp = KERNFSTOV(kfs);
377 pnext = LIST_NEXT(kfs, kfs_hash);
378 if (vp->v_usecount > 0 && kfs->kfs_type == KFSipsecsa &&
379 kfs->kfs_value == ntohl(sav->spi)) {
380 m = key_setdumpsa_spi(sav->spi);
381 if (!m)
382 VOP_REVOKE(vp, REVOKEALL);
383 else
384 m_freem(m);
385 break;
386 }
387 }
388 }
389
390 void
391 kernfs_revoke_sp(sp)
392 struct secpolicy *sp;
393 {
394 struct kernfs_node *kfs, *pnext;
395 struct vnode *vp;
396 struct kfs_hashhead *ppp;
397
398 ppp = &kfs_hashtbl[KFSVALUEHASH(sp->id)];
399 for (kfs = LIST_FIRST(ppp); kfs; kfs = pnext) {
400 vp = KERNFSTOV(kfs);
401 pnext = LIST_NEXT(kfs, kfs_hash);
402 if (vp->v_usecount > 0 && kfs->kfs_type == KFSipsecsa &&
403 kfs->kfs_value == sp->id)
404 VOP_REVOKE(vp, REVOKEALL);
405 }
406 }
407 #endif
Cache object: 4ecf62f551af3404aee21b6c8446a683
|