ioctl cmd arg is u_long
[unix-history] / usr / src / sys / kern / vfs_subr.c
CommitLineData
3c4390e8 1/*
ec54f0cc
KB
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
adb35f79
KB
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
3c4390e8 9 *
dbf0c423 10 * %sccs.include.redist.c%
3c4390e8 11 *
9130defb 12 * @(#)vfs_subr.c 8.13 (Berkeley) %G%
3c4390e8
KM
13 */
14
15/*
16 * External virtual filesystem routines
17 */
18
cb796a23 19#include <sys/param.h>
917dc539 20#include <sys/systm.h>
cb796a23
KB
21#include <sys/proc.h>
22#include <sys/mount.h>
23#include <sys/time.h>
24#include <sys/vnode.h>
807cc430 25#include <sys/stat.h>
cb796a23
KB
26#include <sys/namei.h>
27#include <sys/ucred.h>
28#include <sys/buf.h>
29#include <sys/errno.h>
30#include <sys/malloc.h>
8981e258
MH
31#include <sys/domain.h>
32#include <sys/mbuf.h>
3c4390e8 33
bb4964fd
KM
34#include <vm/vm.h>
35#include <sys/sysctl.h>
36
021de758
JSP
37#include <miscfs/specfs/specdev.h>
38
807cc430
KM
39enum vtype iftovt_tab[16] = {
40 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
41 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
42};
43int vttoif_tab[9] = {
44 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,
45 S_IFSOCK, S_IFIFO, S_IFMT,
46};
47
e3249ec0
KM
48/*
49 * Insq/Remq for the vnode usage lists.
50 */
3fc2ac18
KM
51#define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs)
52#define bufremvn(bp) { \
53 LIST_REMOVE(bp, b_vnbufs); \
54 (bp)->b_vnbufs.le_next = NOLIST; \
55}
56
57TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */
58struct mntlist mountlist; /* mounted filesystem list */
e3249ec0 59
3c4390e8 60/*
3fc2ac18 61 * Initialize the vnode management data structures.
3c4390e8 62 */
3fc2ac18 63vntblinit()
3c4390e8
KM
64{
65
3fc2ac18
KM
66 TAILQ_INIT(&vnode_free_list);
67 TAILQ_INIT(&mountlist);
3c4390e8
KM
68}
69
70/*
71 * Lock a filesystem.
72 * Used to prevent access to it while mounting and unmounting.
73 */
74vfs_lock(mp)
75 register struct mount *mp;
76{
77
54fb9dc2
KM
78 while(mp->mnt_flag & MNT_MLOCK) {
79 mp->mnt_flag |= MNT_MWAIT;
594501df
KM
80 sleep((caddr_t)mp, PVFS);
81 }
54fb9dc2 82 mp->mnt_flag |= MNT_MLOCK;
3c4390e8
KM
83 return (0);
84}
85
86/*
87 * Unlock a locked filesystem.
88 * Panic if filesystem is not locked.
89 */
90void
91vfs_unlock(mp)
92 register struct mount *mp;
93{
94
54fb9dc2 95 if ((mp->mnt_flag & MNT_MLOCK) == 0)
36ef03ec 96 panic("vfs_unlock: not locked");
54fb9dc2
KM
97 mp->mnt_flag &= ~MNT_MLOCK;
98 if (mp->mnt_flag & MNT_MWAIT) {
99 mp->mnt_flag &= ~MNT_MWAIT;
3c4390e8
KM
100 wakeup((caddr_t)mp);
101 }
102}
103
36ef03ec
KM
104/*
105 * Mark a mount point as busy.
106 * Used to synchronize access and to delay unmounting.
107 */
108vfs_busy(mp)
109 register struct mount *mp;
110{
111
54fb9dc2
KM
112 while(mp->mnt_flag & MNT_MPBUSY) {
113 mp->mnt_flag |= MNT_MPWANT;
114 sleep((caddr_t)&mp->mnt_flag, PVFS);
36ef03ec 115 }
d8b63609
KM
116 if (mp->mnt_flag & MNT_UNMOUNT)
117 return (1);
54fb9dc2 118 mp->mnt_flag |= MNT_MPBUSY;
36ef03ec
KM
119 return (0);
120}
121
122/*
123 * Free a busy filesystem.
124 * Panic if filesystem is not busy.
125 */
36ef03ec
KM
126vfs_unbusy(mp)
127 register struct mount *mp;
128{
129
54fb9dc2 130 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
36ef03ec 131 panic("vfs_unbusy: not busy");
54fb9dc2
KM
132 mp->mnt_flag &= ~MNT_MPBUSY;
133 if (mp->mnt_flag & MNT_MPWANT) {
134 mp->mnt_flag &= ~MNT_MPWANT;
135 wakeup((caddr_t)&mp->mnt_flag);
36ef03ec
KM
136 }
137}
138
3c4390e8
KM
139/*
140 * Lookup a mount point by filesystem identifier.
141 */
142struct mount *
143getvfs(fsid)
144 fsid_t *fsid;
145{
146 register struct mount *mp;
147
3fc2ac18 148 for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) {
54fb9dc2 149 if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&
3fc2ac18 150 mp->mnt_stat.f_fsid.val[1] == fsid->val[1])
d713f801 151 return (mp);
3fc2ac18 152 }
d713f801 153 return ((struct mount *)0);
3c4390e8
KM
154}
155
917dc539
JSP
156/*
157 * Get a new unique fsid
158 */
159void
160getnewfsid(mp, mtype)
161 struct mount *mp;
162 int mtype;
163{
164static u_short xxxfs_mntid;
165
166 fsid_t tfsid;
167
1209b9a4 168 mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + mtype, 0);
917dc539
JSP
169 mp->mnt_stat.f_fsid.val[1] = mtype;
170 if (xxxfs_mntid == 0)
171 ++xxxfs_mntid;
1209b9a4 172 tfsid.val[0] = makedev(nblkdev + mtype, xxxfs_mntid);
917dc539 173 tfsid.val[1] = mtype;
3fc2ac18 174 if (mountlist.tqh_first != NULL) {
17fd1cc7
JSP
175 while (getvfs(&tfsid)) {
176 tfsid.val[0]++;
177 xxxfs_mntid++;
178 }
917dc539
JSP
179 }
180 mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
181}
182
3c4390e8
KM
183/*
184 * Set vnode attributes to VNOVAL
185 */
186void vattr_null(vap)
187 register struct vattr *vap;
188{
189
190 vap->va_type = VNON;
83504fd5 191 vap->va_size = vap->va_bytes = VNOVAL;
3c4390e8 192 vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
83504fd5
KM
193 vap->va_fsid = vap->va_fileid =
194 vap->va_blocksize = vap->va_rdev =
ecf75a7d
KM
195 vap->va_atime.ts_sec = vap->va_atime.ts_nsec =
196 vap->va_mtime.ts_sec = vap->va_mtime.ts_nsec =
197 vap->va_ctime.ts_sec = vap->va_ctime.ts_nsec =
8cf4d4fb 198 vap->va_flags = vap->va_gen = VNOVAL;
fcba749b 199 vap->va_vaflags = 0;
3c4390e8 200}
c60798ca 201
36d09cb1
KM
202/*
203 * Routines having to do with the management of the vnode table.
204 */
9342689a 205extern int (**dead_vnodeop_p)();
32339c94 206extern void vclean();
1a80f56e 207long numvnodes;
e781da98 208extern struct vattr va_null;
3e787e54
KM
209int newnodes = 0;
210int printcnt = 0;
36d09cb1
KM
211
212/*
213 * Return the next vnode from the free list.
214 */
215getnewvnode(tag, mp, vops, vpp)
216 enum vtagtype tag;
217 struct mount *mp;
cf74dd57 218 int (**vops)();
36d09cb1
KM
219 struct vnode **vpp;
220{
c768e50f 221 register struct vnode *vp;
1f9d2249 222 int s;
36d09cb1 223
3e787e54 224newnodes++;
3fc2ac18
KM
225 if ((vnode_free_list.tqh_first == NULL &&
226 numvnodes < 2 * desiredvnodes) ||
ecf75a7d 227 numvnodes < desiredvnodes) {
aacc1bff
KM
228 vp = (struct vnode *)malloc((u_long)sizeof *vp,
229 M_VNODE, M_WAITOK);
1a80f56e 230 bzero((char *)vp, sizeof *vp);
3e787e54
KM
231 vp->v_freelist.tqe_next = (struct vnode *)0xdeadf;
232 vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb;
233 vp->v_mntvnodes.le_next = (struct vnode *)0xdeadf;
234 vp->v_mntvnodes.le_prev = (struct vnode **)0xdeadb;
1a80f56e 235 numvnodes++;
3e787e54 236 vp->v_spare[0] = numvnodes;
1a80f56e 237 } else {
3fc2ac18 238 if ((vp = vnode_free_list.tqh_first) == NULL) {
1a80f56e
KM
239 tablefull("vnode");
240 *vpp = 0;
241 return (ENFILE);
242 }
243 if (vp->v_usecount)
244 panic("free vnode isn't");
3e787e54
KM
245 if (vp->v_freelist.tqe_next == (struct vnode *)0xdeadf ||
246 vp->v_freelist.tqe_prev == (struct vnode **)0xdeadb)
247 panic("getnewvnode: not on queue");
3fc2ac18 248 TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
3e787e54 249 vp->v_freelist.tqe_next = (struct vnode *)0xdeadf;
0bf9bb76
KM
250 /* see comment on why 0xdeadb is set at end of vgone (below) */
251 vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb;
39b99eb6 252 vp->v_lease = NULL;
1a80f56e
KM
253 if (vp->v_type != VBAD)
254 vgone(vp);
1f9d2249 255#ifdef DIAGNOSTIC
2345b093
KM
256 if (vp->v_data)
257 panic("cleaned vnode isn't");
1f9d2249
MS
258 s = splbio();
259 if (vp->v_numoutput)
260 panic("Clean vnode has pending I/O's");
261 splx(s);
262#endif
1a80f56e 263 vp->v_flag = 0;
1a80f56e 264 vp->v_lastr = 0;
2b5ada11
MH
265 vp->v_ralen = 0;
266 vp->v_maxra = 0;
1f9d2249
MS
267 vp->v_lastw = 0;
268 vp->v_lasta = 0;
269 vp->v_cstart = 0;
270 vp->v_clen = 0;
1a80f56e 271 vp->v_socket = 0;
36d09cb1 272 }
b027498b 273 vp->v_type = VNON;
36d09cb1
KM
274 cache_purge(vp);
275 vp->v_tag = tag;
ef24f6dd 276 vp->v_op = vops;
36d09cb1 277 insmntque(vp, mp);
36d09cb1 278 *vpp = vp;
0bf9bb76 279 vp->v_usecount = 1;
3fc2ac18 280 vp->v_data = 0;
3e787e54 281 if (printcnt-- > 0) vprint("getnewvnode got", vp);
36d09cb1
KM
282 return (0);
283}
8981e258 284
36d09cb1
KM
285/*
286 * Move a vnode from one mount queue to another.
287 */
288insmntque(vp, mp)
289 register struct vnode *vp;
290 register struct mount *mp;
291{
36d09cb1
KM
292
293 /*
294 * Delete from old mount point vnode list, if on one.
295 */
3e787e54
KM
296 if (vp->v_mount != NULL) {
297 if (vp->v_mntvnodes.le_next == (struct vnode *)0xdeadf ||
298 vp->v_mntvnodes.le_prev == (struct vnode **)0xdeadb)
299 panic("insmntque: not on queue");
3fc2ac18 300 LIST_REMOVE(vp, v_mntvnodes);
3e787e54
KM
301 vp->v_mntvnodes.le_next = (struct vnode *)0xdeadf;
302 vp->v_mntvnodes.le_prev = (struct vnode **)0xdeadb;
303 }
36d09cb1
KM
304 /*
305 * Insert into list of vnodes for the new mount point, if available.
306 */
3fc2ac18 307 if ((vp->v_mount = mp) == NULL)
36d09cb1 308 return;
3e787e54
KM
309 if (vp->v_mntvnodes.le_next != (struct vnode *)0xdeadf ||
310 vp->v_mntvnodes.le_prev != (struct vnode **)0xdeadb)
311 panic("insmntque: already on queue");
3fc2ac18 312 LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes);
36d09cb1
KM
313}
314
76429560
KM
315/*
316 * Update outstanding I/O count and do wakeup if requested.
317 */
318vwakeup(bp)
319 register struct buf *bp;
320{
321 register struct vnode *vp;
322
a9338fad 323 bp->b_flags &= ~B_WRITEINPROG;
76429560
KM
324 if (vp = bp->b_vp) {
325 vp->v_numoutput--;
1f9d2249
MS
326 if (vp->v_numoutput < 0)
327 panic("vwakeup: neg numoutput");
76429560
KM
328 if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
329 if (vp->v_numoutput < 0)
330 panic("vwakeup: neg numoutput");
331 vp->v_flag &= ~VBWAIT;
332 wakeup((caddr_t)&vp->v_numoutput);
333 }
334 }
335}
336
76429560
KM
337/*
338 * Flush out and invalidate all buffers associated with a vnode.
339 * Called with the underlying object locked.
340 */
d024c2ce 341int
c33e9e8b 342vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
76429560 343 register struct vnode *vp;
12079a9d 344 int flags;
d024c2ce
KM
345 struct ucred *cred;
346 struct proc *p;
c33e9e8b 347 int slpflag, slptimeo;
76429560
KM
348{
349 register struct buf *bp;
350 struct buf *nbp, *blist;
d024c2ce 351 int s, error;
76429560 352
12079a9d 353 if (flags & V_SAVE) {
d024c2ce
KM
354 if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p))
355 return (error);
3fc2ac18 356 if (vp->v_dirtyblkhd.lh_first != NULL)
d024c2ce
KM
357 panic("vinvalbuf: dirty bufs");
358 }
76429560 359 for (;;) {
3fc2ac18 360 if ((blist = vp->v_cleanblkhd.lh_first) && flags & V_SAVEMETA)
12079a9d 361 while (blist && blist->b_lblkno < 0)
3fc2ac18
KM
362 blist = blist->b_vnbufs.le_next;
363 if (!blist && (blist = vp->v_dirtyblkhd.lh_first) &&
e3249ec0 364 (flags & V_SAVEMETA))
12079a9d 365 while (blist && blist->b_lblkno < 0)
3fc2ac18 366 blist = blist->b_vnbufs.le_next;
12079a9d 367 if (!blist)
76429560 368 break;
12079a9d 369
76429560 370 for (bp = blist; bp; bp = nbp) {
3fc2ac18 371 nbp = bp->b_vnbufs.le_next;
12079a9d
MS
372 if (flags & V_SAVEMETA && bp->b_lblkno < 0)
373 continue;
76429560
KM
374 s = splbio();
375 if (bp->b_flags & B_BUSY) {
376 bp->b_flags |= B_WANTED;
c33e9e8b
KM
377 error = tsleep((caddr_t)bp,
378 slpflag | (PRIBIO + 1), "vinvalbuf",
379 slptimeo);
76429560 380 splx(s);
c33e9e8b
KM
381 if (error)
382 return (error);
76429560
KM
383 break;
384 }
385 bremfree(bp);
386 bp->b_flags |= B_BUSY;
387 splx(s);
c33e9e8b
KM
388 /*
389 * XXX Since there are no node locks for NFS, I believe
390 * there is a slight chance that a delayed write will
391 * occur while sleeping just above, so check for it.
392 */
393 if ((bp->b_flags & B_DELWRI) && (flags & V_SAVE)) {
394 (void) VOP_BWRITE(bp);
395 break;
396 }
12079a9d 397 bp->b_flags |= B_INVAL;
76429560
KM
398 brelse(bp);
399 }
400 }
e3249ec0 401 if (!(flags & V_SAVEMETA) &&
3fc2ac18 402 (vp->v_dirtyblkhd.lh_first || vp->v_cleanblkhd.lh_first))
76429560 403 panic("vinvalbuf: flush failed");
d024c2ce 404 return (0);
76429560
KM
405}
406
407/*
408 * Associate a buffer with a vnode.
409 */
410bgetvp(vp, bp)
411 register struct vnode *vp;
412 register struct buf *bp;
413{
414
415 if (bp->b_vp)
416 panic("bgetvp: not free");
417 VHOLD(vp);
418 bp->b_vp = vp;
419 if (vp->v_type == VBLK || vp->v_type == VCHR)
420 bp->b_dev = vp->v_rdev;
421 else
422 bp->b_dev = NODEV;
423 /*
424 * Insert onto list for new vnode.
425 */
e3249ec0 426 bufinsvn(bp, &vp->v_cleanblkhd);
76429560
KM
427}
428
429/*
430 * Disassociate a buffer from a vnode.
431 */
432brelvp(bp)
433 register struct buf *bp;
434{
76429560
KM
435 struct vnode *vp;
436
437 if (bp->b_vp == (struct vnode *) 0)
438 panic("brelvp: NULL");
439 /*
440 * Delete from old vnode list, if on one.
441 */
3fc2ac18 442 if (bp->b_vnbufs.le_next != NOLIST)
e3249ec0 443 bufremvn(bp);
76429560
KM
444 vp = bp->b_vp;
445 bp->b_vp = (struct vnode *) 0;
446 HOLDRELE(vp);
447}
448
449/*
450 * Reassign a buffer from one vnode to another.
451 * Used to assign file specific control information
452 * (indirect blocks) to the vnode to which they belong.
453 */
454reassignbuf(bp, newvp)
455 register struct buf *bp;
456 register struct vnode *newvp;
457{
3fc2ac18 458 register struct buflists *listheadp;
76429560 459
e5c3f16e
KM
460 if (newvp == NULL) {
461 printf("reassignbuf: NULL");
462 return;
463 }
76429560
KM
464 /*
465 * Delete from old vnode list, if on one.
466 */
3fc2ac18 467 if (bp->b_vnbufs.le_next != NOLIST)
e3249ec0 468 bufremvn(bp);
76429560
KM
469 /*
470 * If dirty, put on list of dirty buffers;
471 * otherwise insert onto list of clean buffers.
472 */
473 if (bp->b_flags & B_DELWRI)
474 listheadp = &newvp->v_dirtyblkhd;
475 else
476 listheadp = &newvp->v_cleanblkhd;
e3249ec0 477 bufinsvn(bp, listheadp);
76429560
KM
478}
479
36d09cb1 480/*
ef24f6dd
KM
481 * Create a vnode for a block device.
482 * Used for root filesystem, argdev, and swap areas.
483 * Also used for memory file system special devices.
484 */
485bdevvp(dev, vpp)
486 dev_t dev;
487 struct vnode **vpp;
488{
ef24f6dd
KM
489 register struct vnode *vp;
490 struct vnode *nvp;
491 int error;
492
1c89915d
KM
493 if (dev == NODEV)
494 return (0);
9342689a 495 error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp);
ef24f6dd
KM
496 if (error) {
497 *vpp = 0;
498 return (error);
499 }
500 vp = nvp;
501 vp->v_type = VBLK;
c0de8792 502 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
ef24f6dd
KM
503 vput(vp);
504 vp = nvp;
505 }
506 *vpp = vp;
507 return (0);
508}
509
510/*
511 * Check to see if the new vnode represents a special device
512 * for which we already have a vnode (either because of
513 * bdevvp() or because of a different vnode representing
514 * the same block device). If such an alias exists, deallocate
f0556f86 515 * the existing contents and return the aliased vnode. The
ef24f6dd
KM
516 * caller is responsible for filling it with its new contents.
517 */
518struct vnode *
c0de8792 519checkalias(nvp, nvp_rdev, mp)
ef24f6dd 520 register struct vnode *nvp;
c0de8792 521 dev_t nvp_rdev;
ef24f6dd
KM
522 struct mount *mp;
523{
524 register struct vnode *vp;
c0de8792 525 struct vnode **vpp;
ef24f6dd
KM
526
527 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
54fb9dc2 528 return (NULLVP);
c0de8792
KM
529
530 vpp = &speclisth[SPECHASH(nvp_rdev)];
ef24f6dd 531loop:
c0de8792
KM
532 for (vp = *vpp; vp; vp = vp->v_specnext) {
533 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
ef24f6dd 534 continue;
c0de8792
KM
535 /*
536 * Alias, but not in use, so flush it out.
537 */
7f7b7d89 538 if (vp->v_usecount == 0) {
c0de8792
KM
539 vgone(vp);
540 goto loop;
541 }
3fc2ac18 542 if (vget(vp, 1))
ef62830d 543 goto loop;
ef24f6dd
KM
544 break;
545 }
c0de8792 546 if (vp == NULL || vp->v_tag != VT_NON) {
c0de8792
KM
547 MALLOC(nvp->v_specinfo, struct specinfo *,
548 sizeof(struct specinfo), M_VNODE, M_WAITOK);
549 nvp->v_rdev = nvp_rdev;
7f7b7d89 550 nvp->v_hashchain = vpp;
c0de8792 551 nvp->v_specnext = *vpp;
2c957a90 552 nvp->v_specflags = 0;
c0de8792 553 *vpp = nvp;
40452d5e
KM
554 if (vp != NULL) {
555 nvp->v_flag |= VALIASED;
556 vp->v_flag |= VALIASED;
557 vput(vp);
558 }
54fb9dc2 559 return (NULLVP);
ef24f6dd 560 }
2bae1875
KM
561 VOP_UNLOCK(vp);
562 vclean(vp, 0);
ef24f6dd
KM
563 vp->v_op = nvp->v_op;
564 vp->v_tag = nvp->v_tag;
565 nvp->v_type = VNON;
566 insmntque(vp, mp);
567 return (vp);
568}
569
570/*
571 * Grab a particular vnode from the free list, increment its
572 * reference count and lock it. The vnode lock bit is set the
573 * vnode is being eliminated in vgone. The process is awakened
574 * when the transition is completed, and an error returned to
575 * indicate that the vnode is no longer usable (possibly having
576 * been changed to a new file system type).
36d09cb1 577 */
3fc2ac18 578vget(vp, lockflag)
36d09cb1 579 register struct vnode *vp;
3fc2ac18 580 int lockflag;
36d09cb1 581{
36d09cb1 582
9130defb
KM
583 /*
584 * If the vnode is in the process of being cleaned out for
585 * another use, we wait for the cleaning to finish and then
586 * return failure. Cleaning is determined either by checking
587 * that the VXLOCK flag is set, or that the use count is
588 * zero with the back pointer set to show that it has been
589 * removed from the free list by getnewvnode. The VXLOCK
590 * flag may not have been set yet because vclean is blocked in
591 * the VOP_LOCK call waiting for the VOP_INACTIVE to complete.
592 */
593 if ((vp->v_flag & VXLOCK) ||
594 (vp->v_usecount == 0 &&
595 vp->v_freelist.tqe_prev == (struct vnode **)0xdeadb)) {
ef24f6dd
KM
596 vp->v_flag |= VXWANT;
597 sleep((caddr_t)vp, PINOD);
598 return (1);
599 }
3e787e54
KM
600 if (vp->v_usecount == 0) {
601 if (vp->v_freelist.tqe_next == (struct vnode *)0xdeadf ||
602 vp->v_freelist.tqe_prev == (struct vnode **)0xdeadb)
603 panic("vget: not on queue");
3fc2ac18 604 TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
3e787e54
KM
605 vp->v_freelist.tqe_next = (struct vnode *)0xdeadf;
606 vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb;
607 }
ec04fc59 608 vp->v_usecount++;
3fc2ac18
KM
609 if (lockflag)
610 VOP_LOCK(vp);
3e787e54 611 if (printcnt-- > 0) vprint("vget got", vp);
ef24f6dd 612 return (0);
36d09cb1
KM
613}
614
d32390ea
KM
615int bug_refs = 0;
616
36d09cb1
KM
617/*
618 * Vnode reference, just increment the count
619 */
620void vref(vp)
621 struct vnode *vp;
622{
623
ec04fc59
KM
624 if (vp->v_usecount <= 0)
625 panic("vref used where vget required");
3e787e54
KM
626 if (vp->v_freelist.tqe_next != (struct vnode *)0xdeadf ||
627 vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb)
628 panic("vref: not free");
7f7b7d89 629 vp->v_usecount++;
3e787e54 630 if (printcnt-- > 0) vprint("vref get", vp);
d32390ea
KM
631 if (vp->v_type != VBLK && curproc)
632 curproc->p_spare[0]++;
633 if (bug_refs)
634 vprint("vref: ");
36d09cb1
KM
635}
636
637/*
638 * vput(), just unlock and vrele()
639 */
640void vput(vp)
641 register struct vnode *vp;
642{
4d1ee2eb 643
36d09cb1
KM
644 VOP_UNLOCK(vp);
645 vrele(vp);
646}
647
648/*
649 * Vnode release.
650 * If count drops to zero, call inactive routine and return to freelist.
651 */
652void vrele(vp)
653 register struct vnode *vp;
654{
655
65c3b3a8 656#ifdef DIAGNOSTIC
36d09cb1 657 if (vp == NULL)
ef24f6dd 658 panic("vrele: null vp");
65c3b3a8 659#endif
7f7b7d89 660 vp->v_usecount--;
3e787e54 661 if (printcnt-- > 0) vprint("vrele put", vp);
d32390ea
KM
662 if (vp->v_type != VBLK && curproc)
663 curproc->p_spare[0]--;
664 if (bug_refs)
665 vprint("vref: ");
7f7b7d89 666 if (vp->v_usecount > 0)
36d09cb1 667 return;
65c3b3a8
KM
668#ifdef DIAGNOSTIC
669 if (vp->v_usecount != 0 || vp->v_writecount != 0) {
670 vprint("vrele: bad ref count", vp);
671 panic("vrele: ref cnt");
672 }
673#endif
dc998e72
KM
674 /*
675 * insert at tail of LRU list
676 */
3e787e54
KM
677 if (vp->v_freelist.tqe_next != (struct vnode *)0xdeadf ||
678 vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb)
679 panic("vrele: not free");
3fc2ac18 680 TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
d024c2ce 681 VOP_INACTIVE(vp);
ef24f6dd
KM
682}
683
7f7b7d89
KM
684/*
685 * Page or buffer structure gets a reference.
686 */
451df175 687void vhold(vp)
7f7b7d89
KM
688 register struct vnode *vp;
689{
690
691 vp->v_holdcnt++;
692}
693
694/*
695 * Page or buffer structure frees a reference.
696 */
451df175 697void holdrele(vp)
7f7b7d89
KM
698 register struct vnode *vp;
699{
700
701 if (vp->v_holdcnt <= 0)
702 panic("holdrele: holdcnt");
703 vp->v_holdcnt--;
704}
705
f0556f86
KM
706/*
707 * Remove any vnodes in the vnode table belonging to mount point mp.
708 *
709 * If MNT_NOFORCE is specified, there should not be any active ones,
710 * return error if any are found (nb: this is a user error, not a
711 * system error). If MNT_FORCE is specified, detach any active vnodes
712 * that are found.
713 */
8981e258 714#ifdef DIAGNOSTIC
bb4964fd
KM
715int busyprt = 0; /* print out busy vnodes */
716struct ctldebug debug1 = { "busyprt", &busyprt };
8981e258 717#endif
f0556f86
KM
718
719vflush(mp, skipvp, flags)
720 struct mount *mp;
721 struct vnode *skipvp;
722 int flags;
723{
724 register struct vnode *vp, *nvp;
725 int busy = 0;
726
54fb9dc2 727 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
36ef03ec 728 panic("vflush: not busy");
4597dd33 729loop:
3fc2ac18 730 for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
4597dd33
KM
731 if (vp->v_mount != mp)
732 goto loop;
3fc2ac18 733 nvp = vp->v_mntvnodes.le_next;
f0556f86
KM
734 /*
735 * Skip over a selected vnode.
f0556f86
KM
736 */
737 if (vp == skipvp)
738 continue;
36ef03ec
KM
739 /*
740 * Skip over a vnodes marked VSYSTEM.
741 */
742 if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
743 continue;
da374605
KM
744 /*
745 * If WRITECLOSE is set, only flush out regular file
746 * vnodes open for writing.
747 */
748 if ((flags & WRITECLOSE) &&
749 (vp->v_writecount == 0 || vp->v_type != VREG))
750 continue;
f0556f86 751 /*
7f7b7d89 752 * With v_usecount == 0, all we need to do is clear
f0556f86
KM
753 * out the vnode data structures and we are done.
754 */
7f7b7d89 755 if (vp->v_usecount == 0) {
f0556f86
KM
756 vgone(vp);
757 continue;
758 }
759 /*
da374605 760 * If FORCECLOSE is set, forcibly close the vnode.
f0556f86
KM
761 * For block or character devices, revert to an
762 * anonymous device. For all other files, just kill them.
763 */
36ef03ec 764 if (flags & FORCECLOSE) {
f0556f86
KM
765 if (vp->v_type != VBLK && vp->v_type != VCHR) {
766 vgone(vp);
767 } else {
768 vclean(vp, 0);
9342689a 769 vp->v_op = spec_vnodeop_p;
f0556f86
KM
770 insmntque(vp, (struct mount *)0);
771 }
772 continue;
773 }
8981e258 774#ifdef DIAGNOSTIC
f0556f86 775 if (busyprt)
0bf84b18 776 vprint("vflush: busy vnode", vp);
8981e258 777#endif
f0556f86
KM
778 busy++;
779 }
780 if (busy)
781 return (EBUSY);
782 return (0);
783}
784
ef24f6dd
KM
785/*
786 * Disassociate the underlying file system from a vnode.
ef24f6dd 787 */
ecf75a7d
KM
788void
789vclean(vp, flags)
ef24f6dd 790 register struct vnode *vp;
aacc1bff 791 int flags;
ef24f6dd 792{
2bae1875 793 int active;
ef24f6dd 794
2bae1875
KM
795 /*
796 * Check to see if the vnode is in use.
0bf84b18
KM
797 * If so we have to reference it before we clean it out
798 * so that its count cannot fall to zero and generate a
799 * race against ourselves to recycle it.
2bae1875 800 */
7f7b7d89 801 if (active = vp->v_usecount)
2bae1875 802 VREF(vp);
669df1aa
KM
803 /*
804 * Even if the count is zero, the VOP_INACTIVE routine may still
805 * have the object locked while it cleans it out. The VOP_LOCK
806 * ensures that the VOP_INACTIVE routine is done with its work.
807 * For active vnodes, it ensures that no other activity can
808 * occur while the underlying object is being cleaned out.
809 */
810 VOP_LOCK(vp);
2bae1875
KM
811 /*
812 * Prevent the vnode from being recycled or
813 * brought into use while we clean it out.
814 */
0bf84b18
KM
815 if (vp->v_flag & VXLOCK)
816 panic("vclean: deadlock");
ef24f6dd 817 vp->v_flag |= VXLOCK;
0bf84b18 818 /*
669df1aa 819 * Clean out any buffers associated with the vnode.
0bf84b18 820 */
36ef03ec 821 if (flags & DOCLOSE)
c33e9e8b 822 vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0);
ef24f6dd 823 /*
669df1aa
KM
824 * Any other processes trying to obtain this lock must first
825 * wait for VXLOCK to clear, then call the new lock operation.
ef24f6dd 826 */
669df1aa 827 VOP_UNLOCK(vp);
ef24f6dd 828 /*
669df1aa
KM
829 * If purging an active vnode, it must be closed and
830 * deactivated before being reclaimed.
ef24f6dd 831 */
2bae1875 832 if (active) {
669df1aa
KM
833 if (flags & DOCLOSE)
834 VOP_CLOSE(vp, IO_NDELAY, NOCRED, NULL);
835 VOP_INACTIVE(vp);
ef24f6dd
KM
836 }
837 /*
838 * Reclaim the vnode.
839 */
669df1aa 840 if (VOP_RECLAIM(vp))
ef24f6dd 841 panic("vclean: cannot reclaim");
2bae1875
KM
842 if (active)
843 vrele(vp);
38c46eee 844
ef24f6dd 845 /*
669df1aa 846 * Done with purge, notify sleepers of the grim news.
ef24f6dd 847 */
669df1aa
KM
848 vp->v_op = dead_vnodeop_p;
849 vp->v_tag = VT_NON;
ef24f6dd
KM
850 vp->v_flag &= ~VXLOCK;
851 if (vp->v_flag & VXWANT) {
852 vp->v_flag &= ~VXWANT;
853 wakeup((caddr_t)vp);
854 }
855}
856
ef62830d
KM
857/*
858 * Eliminate all activity associated with the requested vnode
859 * and with all vnodes aliased to the requested vnode.
860 */
861void vgoneall(vp)
862 register struct vnode *vp;
863{
7f7b7d89 864 register struct vnode *vq;
ef62830d 865
7a7b3a95
KM
866 if (vp->v_flag & VALIASED) {
867 /*
868 * If a vgone (or vclean) is already in progress,
869 * wait until it is done and return.
870 */
871 if (vp->v_flag & VXLOCK) {
872 vp->v_flag |= VXWANT;
873 sleep((caddr_t)vp, PINOD);
874 return;
875 }
876 /*
877 * Ensure that vp will not be vgone'd while we
878 * are eliminating its aliases.
879 */
880 vp->v_flag |= VXLOCK;
881 while (vp->v_flag & VALIASED) {
882 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
883 if (vq->v_rdev != vp->v_rdev ||
884 vq->v_type != vp->v_type || vp == vq)
885 continue;
886 vgone(vq);
887 break;
888 }
ef62830d 889 }
7a7b3a95
KM
890 /*
891 * Remove the lock so that vgone below will
892 * really eliminate the vnode after which time
893 * vgone will awaken any sleepers.
894 */
895 vp->v_flag &= ~VXLOCK;
ef62830d
KM
896 }
897 vgone(vp);
898}
899
ef24f6dd
KM
900/*
901 * Eliminate all activity associated with a vnode
902 * in preparation for reuse.
903 */
904void vgone(vp)
905 register struct vnode *vp;
906{
7f7b7d89 907 register struct vnode *vq;
c0de8792 908 struct vnode *vx;
ef24f6dd 909
4f55e3ec
KM
910 /*
911 * If a vgone (or vclean) is already in progress,
912 * wait until it is done and return.
913 */
914 if (vp->v_flag & VXLOCK) {
915 vp->v_flag |= VXWANT;
916 sleep((caddr_t)vp, PINOD);
917 return;
918 }
ef24f6dd
KM
919 /*
920 * Clean out the filesystem specific data.
921 */
36ef03ec 922 vclean(vp, DOCLOSE);
ef24f6dd
KM
923 /*
924 * Delete from old mount point vnode list, if on one.
925 */
3fc2ac18 926 if (vp->v_mount != NULL) {
3e787e54
KM
927 if (vp->v_mntvnodes.le_next == (struct vnode *)0xdeadf ||
928 vp->v_mntvnodes.le_prev == (struct vnode **)0xdeadb)
929 panic("vgone: not on queue");
3fc2ac18 930 LIST_REMOVE(vp, v_mntvnodes);
3e787e54
KM
931 vp->v_mntvnodes.le_next = (struct vnode *)0xdeadf;
932 vp->v_mntvnodes.le_prev = (struct vnode **)0xdeadb;
d10e9258 933 vp->v_mount = NULL;
ef24f6dd
KM
934 }
935 /*
936 * If special device, remove it from special device alias list.
937 */
938 if (vp->v_type == VBLK || vp->v_type == VCHR) {
7f7b7d89
KM
939 if (*vp->v_hashchain == vp) {
940 *vp->v_hashchain = vp->v_specnext;
ef24f6dd 941 } else {
7f7b7d89 942 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
c0de8792 943 if (vq->v_specnext != vp)
ef24f6dd 944 continue;
c0de8792 945 vq->v_specnext = vp->v_specnext;
ef24f6dd
KM
946 break;
947 }
c0de8792 948 if (vq == NULL)
ef24f6dd
KM
949 panic("missing bdev");
950 }
c0de8792 951 if (vp->v_flag & VALIASED) {
4d1ee2eb 952 vx = NULL;
7f7b7d89 953 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c
KM
954 if (vq->v_rdev != vp->v_rdev ||
955 vq->v_type != vp->v_type)
c0de8792 956 continue;
4d1ee2eb
CT
957 if (vx)
958 break;
c0de8792
KM
959 vx = vq;
960 }
4d1ee2eb 961 if (vx == NULL)
c0de8792 962 panic("missing alias");
4d1ee2eb 963 if (vq == NULL)
c0de8792
KM
964 vx->v_flag &= ~VALIASED;
965 vp->v_flag &= ~VALIASED;
966 }
967 FREE(vp->v_specinfo, M_VNODE);
968 vp->v_specinfo = NULL;
ef24f6dd
KM
969 }
970 /*
3387ef89 971 * If it is on the freelist and not already at the head,
0bf9bb76
KM
972 * move it to the head of the list. The test of the back
973 * pointer and the reference count of zero is because
974 * it will be removed from the free list by getnewvnode,
975 * but will not have its reference count incremented until
976 * after calling vgone. If the reference count were
977 * incremented first, vgone would (incorrectly) try to
978 * close the previous instance of the underlying object.
979 * So, the back pointer is explicitly set to `0xdeadb' in
980 * getnewvnode after removing it from the freelist to ensure
981 * that we do not try to move it here.
ef24f6dd 982 */
0bf9bb76
KM
983 if (vp->v_usecount == 0 &&
984 vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb &&
985 vnode_free_list.tqh_first != vp) {
3e787e54
KM
986 if (vp->v_freelist.tqe_next == (struct vnode *)0xdeadf)
987 panic("vgone: use 0, not free");
3fc2ac18
KM
988 TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
989 TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
ef24f6dd 990 }
2bae1875 991 vp->v_type = VBAD;
36d09cb1 992}
ef62830d 993
2bcd6066
KM
994/*
995 * Lookup a vnode by device number.
996 */
997vfinddev(dev, type, vpp)
998 dev_t dev;
999 enum vtype type;
1000 struct vnode **vpp;
1001{
1002 register struct vnode *vp;
1003
1004 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
1005 if (dev != vp->v_rdev || type != vp->v_type)
1006 continue;
1007 *vpp = vp;
05378ee4 1008 return (1);
2bcd6066 1009 }
05378ee4 1010 return (0);
2bcd6066
KM
1011}
1012
ef62830d
KM
1013/*
1014 * Calculate the total number of references to a special device.
1015 */
1016vcount(vp)
1017 register struct vnode *vp;
1018{
1d2d7c6d 1019 register struct vnode *vq, *vnext;
ef62830d
KM
1020 int count;
1021
1d2d7c6d 1022loop:
ef62830d 1023 if ((vp->v_flag & VALIASED) == 0)
7f7b7d89 1024 return (vp->v_usecount);
1d2d7c6d
KM
1025 for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) {
1026 vnext = vq->v_specnext;
de81e10c 1027 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
ef62830d
KM
1028 continue;
1029 /*
1030 * Alias, but not in use, so flush it out.
1031 */
1d2d7c6d 1032 if (vq->v_usecount == 0 && vq != vp) {
ef62830d
KM
1033 vgone(vq);
1034 goto loop;
1035 }
7f7b7d89 1036 count += vq->v_usecount;
ef62830d
KM
1037 }
1038 return (count);
1039}
0bf84b18
KM
1040
1041/*
1042 * Print out a description of a vnode.
1043 */
1044static char *typename[] =
61f846a8 1045 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
0bf84b18
KM
1046
1047vprint(label, vp)
1048 char *label;
1049 register struct vnode *vp;
1050{
f2f730c6 1051 char buf[64];
0bf84b18
KM
1052
1053 if (label != NULL)
1054 printf("%s: ", label);
3e787e54 1055 printf("num %d ", vp->v_spare[0]);
65c3b3a8
KM
1056 printf("type %s, usecount %d, writecount %d, refcount %d,",
1057 typename[vp->v_type], vp->v_usecount, vp->v_writecount,
1058 vp->v_holdcnt);
f2f730c6
KM
1059 buf[0] = '\0';
1060 if (vp->v_flag & VROOT)
1061 strcat(buf, "|VROOT");
1062 if (vp->v_flag & VTEXT)
1063 strcat(buf, "|VTEXT");
36ef03ec
KM
1064 if (vp->v_flag & VSYSTEM)
1065 strcat(buf, "|VSYSTEM");
36ef03ec
KM
1066 if (vp->v_flag & VXLOCK)
1067 strcat(buf, "|VXLOCK");
1068 if (vp->v_flag & VXWANT)
1069 strcat(buf, "|VXWANT");
f2f730c6
KM
1070 if (vp->v_flag & VBWAIT)
1071 strcat(buf, "|VBWAIT");
36ef03ec
KM
1072 if (vp->v_flag & VALIASED)
1073 strcat(buf, "|VALIASED");
f2f730c6
KM
1074 if (buf[0] != '\0')
1075 printf(" flags (%s)", &buf[1]);
3fc2ac18
KM
1076 if (vp->v_data == NULL) {
1077 printf("\n");
1078 } else {
1079 printf("\n\t");
1080 VOP_PRINT(vp);
1081 }
0bf84b18 1082}
985cbdd5 1083
34c62e18
KM
1084#ifdef DEBUG
1085/*
1086 * List all of the locked vnodes in the system.
1087 * Called when debugging the kernel.
1088 */
1089printlockedvnodes()
1090{
1091 register struct mount *mp;
1092 register struct vnode *vp;
1093
1094 printf("Locked vnodes\n");
3fc2ac18
KM
1095 for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) {
1096 for (vp = mp->mnt_vnodelist.lh_first;
1097 vp != NULL;
1098 vp = vp->v_mntvnodes.le_next)
34c62e18
KM
1099 if (VOP_ISLOCKED(vp))
1100 vprint((char *)0, vp);
3fc2ac18 1101 }
34c62e18
KM
1102}
1103#endif
1104
985cbdd5
MT
1105int kinfo_vdebug = 1;
1106int kinfo_vgetfailed;
1107#define KINFO_VNODESLOP 10
1108/*
786fb484 1109 * Dump vnode list (via sysctl).
985cbdd5
MT
1110 * Copyout address of vnode followed by vnode.
1111 */
aacc1bff 1112/* ARGSUSED */
786fb484 1113sysctl_vnode(where, sizep)
985cbdd5 1114 char *where;
c1909da4 1115 size_t *sizep;
985cbdd5 1116{
3fc2ac18 1117 register struct mount *mp, *nmp;
985cbdd5 1118 struct vnode *vp;
985cbdd5 1119 register char *bp = where, *savebp;
5bf57294 1120 char *ewhere;
985cbdd5
MT
1121 int error;
1122
1123#define VPTRSZ sizeof (struct vnode *)
1124#define VNODESZ sizeof (struct vnode)
1125 if (where == NULL) {
786fb484 1126 *sizep = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
985cbdd5
MT
1127 return (0);
1128 }
786fb484 1129 ewhere = where + *sizep;
985cbdd5 1130
3fc2ac18
KM
1131 for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
1132 nmp = mp->mnt_list.tqe_next;
1133 if (vfs_busy(mp))
36ef03ec 1134 continue;
985cbdd5
MT
1135 savebp = bp;
1136again:
3fc2ac18
KM
1137 for (vp = mp->mnt_vnodelist.lh_first;
1138 vp != NULL;
1139 vp = vp->v_mntvnodes.le_next) {
41185b3b
KM
1140 /*
1141 * Check that the vp is still associated with
1142 * this filesystem. RACE: could have been
1143 * recycled onto the same filesystem.
1144 */
4597dd33
KM
1145 if (vp->v_mount != mp) {
1146 if (kinfo_vdebug)
1147 printf("kinfo: vp changed\n");
1148 bp = savebp;
1149 goto again;
1150 }
786fb484
KM
1151 if (bp + VPTRSZ + VNODESZ > ewhere) {
1152 *sizep = bp - where;
1153 return (ENOMEM);
1154 }
1155 if ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
1156 (error = copyout((caddr_t)vp, bp + VPTRSZ, VNODESZ)))
985cbdd5 1157 return (error);
985cbdd5 1158 bp += VPTRSZ + VNODESZ;
985cbdd5 1159 }
3fc2ac18
KM
1160 vfs_unbusy(mp);
1161 }
985cbdd5 1162
786fb484 1163 *sizep = bp - where;
985cbdd5
MT
1164 return (0);
1165}
8981e258
MH
1166
1167/*
1168 * Check to see if a filesystem is mounted on a block device.
1169 */
1170int
1171vfs_mountedon(vp)
1172 register struct vnode *vp;
1173{
1174 register struct vnode *vq;
1175
1176 if (vp->v_specflags & SI_MOUNTEDON)
1177 return (EBUSY);
1178 if (vp->v_flag & VALIASED) {
1179 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
1180 if (vq->v_rdev != vp->v_rdev ||
1181 vq->v_type != vp->v_type)
1182 continue;
1183 if (vq->v_specflags & SI_MOUNTEDON)
1184 return (EBUSY);
1185 }
1186 }
1187 return (0);
1188}
1189
1190/*
1191 * Build hash lists of net addresses and hang them off the mount point.
1192 * Called by ufs_mount() to set up the lists of export addresses.
1193 */
1194static int
1195vfs_hang_addrlist(mp, nep, argp)
1196 struct mount *mp;
1197 struct netexport *nep;
1198 struct export_args *argp;
1199{
1200 register struct netcred *np;
1201 register struct radix_node_head *rnh;
1202 register int i;
1203 struct radix_node *rn;
1204 struct sockaddr *saddr, *smask = 0;
1205 struct domain *dom;
1206 int error;
1207
1208 if (argp->ex_addrlen == 0) {
1209 if (mp->mnt_flag & MNT_DEFEXPORTED)
1210 return (EPERM);
1211 np = &nep->ne_defexported;
1212 np->netc_exflags = argp->ex_flags;
1213 np->netc_anon = argp->ex_anon;
1214 np->netc_anon.cr_ref = 1;
1215 mp->mnt_flag |= MNT_DEFEXPORTED;
1216 return (0);
1217 }
1218 i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen;
1219 np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK);
1220 bzero((caddr_t)np, i);
1221 saddr = (struct sockaddr *)(np + 1);
1222 if (error = copyin(argp->ex_addr, (caddr_t)saddr, argp->ex_addrlen))
1223 goto out;
1224 if (saddr->sa_len > argp->ex_addrlen)
1225 saddr->sa_len = argp->ex_addrlen;
1226 if (argp->ex_masklen) {
1227 smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen);
1228 error = copyin(argp->ex_addr, (caddr_t)smask, argp->ex_masklen);
1229 if (error)
1230 goto out;
1231 if (smask->sa_len > argp->ex_masklen)
1232 smask->sa_len = argp->ex_masklen;
1233 }
1234 i = saddr->sa_family;
1235 if ((rnh = nep->ne_rtable[i]) == 0) {
1236 /*
1237 * Seems silly to initialize every AF when most are not
1238 * used, do so on demand here
1239 */
1240 for (dom = domains; dom; dom = dom->dom_next)
1241 if (dom->dom_family == i && dom->dom_rtattach) {
1242 dom->dom_rtattach((void **)&nep->ne_rtable[i],
1243 dom->dom_rtoffset);
1244 break;
1245 }
1246 if ((rnh = nep->ne_rtable[i]) == 0) {
1247 error = ENOBUFS;
1248 goto out;
1249 }
1250 }
1251 rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh,
1252 np->netc_rnodes);
1253 if (rn == 0 || np != (struct netcred *)rn) { /* already exists */
1254 error = EPERM;
1255 goto out;
1256 }
1257 np->netc_exflags = argp->ex_flags;
1258 np->netc_anon = argp->ex_anon;
1259 np->netc_anon.cr_ref = 1;
1260 return (0);
1261out:
1262 free(np, M_NETADDR);
1263 return (error);
1264}
1265
1266/* ARGSUSED */
1267static int
1268vfs_free_netcred(rn, w)
1269 struct radix_node *rn;
1270 caddr_t w;
1271{
1272 register struct radix_node_head *rnh = (struct radix_node_head *)w;
1273
1274 (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
1275 free((caddr_t)rn, M_NETADDR);
1276 return (0);
1277}
1278
1279/*
1280 * Free the net address hash lists that are hanging off the mount points.
1281 */
1282static void
1283vfs_free_addrlist(nep)
1284 struct netexport *nep;
1285{
1286 register int i;
1287 register struct radix_node_head *rnh;
1288
1289 for (i = 0; i <= AF_MAX; i++)
1290 if (rnh = nep->ne_rtable[i]) {
1291 (*rnh->rnh_walktree)(rnh, vfs_free_netcred,
1292 (caddr_t)rnh);
1293 free((caddr_t)rnh, M_RTABLE);
1294 nep->ne_rtable[i] = 0;
1295 }
1296}
1297
1298int
1299vfs_export(mp, nep, argp)
1300 struct mount *mp;
1301 struct netexport *nep;
1302 struct export_args *argp;
1303{
1304 int error;
1305
1306 if (argp->ex_flags & MNT_DELEXPORT) {
1307 vfs_free_addrlist(nep);
1308 mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED);
1309 }
1310 if (argp->ex_flags & MNT_EXPORTED) {
1311 if (error = vfs_hang_addrlist(mp, nep, argp))
1312 return (error);
1313 mp->mnt_flag |= MNT_EXPORTED;
1314 }
1315 return (0);
1316}
1317
1318struct netcred *
1319vfs_export_lookup(mp, nep, nam)
1320 register struct mount *mp;
1321 struct netexport *nep;
1322 struct mbuf *nam;
1323{
1324 register struct netcred *np;
1325 register struct radix_node_head *rnh;
1326 struct sockaddr *saddr;
1327
1328 np = NULL;
1329 if (mp->mnt_flag & MNT_EXPORTED) {
1330 /*
1331 * Lookup in the export list first.
1332 */
1333 if (nam != NULL) {
1334 saddr = mtod(nam, struct sockaddr *);
1335 rnh = nep->ne_rtable[saddr->sa_family];
1336 if (rnh != NULL) {
1337 np = (struct netcred *)
1338 (*rnh->rnh_matchaddr)((caddr_t)saddr,
1339 rnh);
1340 if (np && np->netc_rnodes->rn_flags & RNF_ROOT)
1341 np = NULL;
1342 }
1343 }
1344 /*
1345 * If no address match, use the default if it exists.
1346 */
1347 if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED)
1348 np = &nep->ne_defexported;
1349 }
1350 return (np);
1351}