lint
[unix-history] / usr / src / sys / kern / vfs_subr.c
CommitLineData
3c4390e8
KM
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
dbf0c423 5 * %sccs.include.redist.c%
3c4390e8 6 *
451df175 7 * @(#)vfs_subr.c 7.71 (Berkeley) %G%
3c4390e8
KM
8 */
9
10/*
11 * External virtual filesystem routines
12 */
13
cb796a23
KB
14#include <sys/param.h>
15#include <sys/proc.h>
16#include <sys/mount.h>
17#include <sys/time.h>
18#include <sys/vnode.h>
807cc430 19#include <sys/stat.h>
cb796a23
KB
20#include <sys/specdev.h>
21#include <sys/namei.h>
22#include <sys/ucred.h>
23#include <sys/buf.h>
24#include <sys/errno.h>
25#include <sys/malloc.h>
3c4390e8 26
807cc430
KM
27enum vtype iftovt_tab[16] = {
28 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
29 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
30};
31int vttoif_tab[9] = {
32 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,
33 S_IFSOCK, S_IFIFO, S_IFMT,
34};
35
3c4390e8
KM
36/*
37 * Remove a mount point from the list of mounted filesystems.
38 * Unmount of the root is illegal.
39 */
40void
41vfs_remove(mp)
42 register struct mount *mp;
43{
44
45 if (mp == rootfs)
46 panic("vfs_remove: unmounting root");
54fb9dc2
KM
47 mp->mnt_prev->mnt_next = mp->mnt_next;
48 mp->mnt_next->mnt_prev = mp->mnt_prev;
49 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
3c4390e8
KM
50 vfs_unlock(mp);
51}
52
53/*
54 * Lock a filesystem.
55 * Used to prevent access to it while mounting and unmounting.
56 */
57vfs_lock(mp)
58 register struct mount *mp;
59{
60
54fb9dc2
KM
61 while(mp->mnt_flag & MNT_MLOCK) {
62 mp->mnt_flag |= MNT_MWAIT;
594501df
KM
63 sleep((caddr_t)mp, PVFS);
64 }
54fb9dc2 65 mp->mnt_flag |= MNT_MLOCK;
3c4390e8
KM
66 return (0);
67}
68
69/*
70 * Unlock a locked filesystem.
71 * Panic if filesystem is not locked.
72 */
73void
74vfs_unlock(mp)
75 register struct mount *mp;
76{
77
54fb9dc2 78 if ((mp->mnt_flag & MNT_MLOCK) == 0)
36ef03ec 79 panic("vfs_unlock: not locked");
54fb9dc2
KM
80 mp->mnt_flag &= ~MNT_MLOCK;
81 if (mp->mnt_flag & MNT_MWAIT) {
82 mp->mnt_flag &= ~MNT_MWAIT;
3c4390e8
KM
83 wakeup((caddr_t)mp);
84 }
85}
86
36ef03ec
KM
87/*
88 * Mark a mount point as busy.
89 * Used to synchronize access and to delay unmounting.
90 */
91vfs_busy(mp)
92 register struct mount *mp;
93{
94
54fb9dc2
KM
95 while(mp->mnt_flag & MNT_MPBUSY) {
96 mp->mnt_flag |= MNT_MPWANT;
97 sleep((caddr_t)&mp->mnt_flag, PVFS);
36ef03ec 98 }
d8b63609
KM
99 if (mp->mnt_flag & MNT_UNMOUNT)
100 return (1);
54fb9dc2 101 mp->mnt_flag |= MNT_MPBUSY;
36ef03ec
KM
102 return (0);
103}
104
105/*
106 * Free a busy filesystem.
107 * Panic if filesystem is not busy.
108 */
36ef03ec
KM
109vfs_unbusy(mp)
110 register struct mount *mp;
111{
112
54fb9dc2 113 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
36ef03ec 114 panic("vfs_unbusy: not busy");
54fb9dc2
KM
115 mp->mnt_flag &= ~MNT_MPBUSY;
116 if (mp->mnt_flag & MNT_MPWANT) {
117 mp->mnt_flag &= ~MNT_MPWANT;
118 wakeup((caddr_t)&mp->mnt_flag);
36ef03ec
KM
119 }
120}
121
3c4390e8
KM
122/*
123 * Lookup a mount point by filesystem identifier.
124 */
125struct mount *
126getvfs(fsid)
127 fsid_t *fsid;
128{
129 register struct mount *mp;
130
d713f801
KM
131 mp = rootfs;
132 do {
54fb9dc2
KM
133 if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&
134 mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) {
d713f801 135 return (mp);
3c4390e8 136 }
54fb9dc2 137 mp = mp->mnt_next;
d713f801
KM
138 } while (mp != rootfs);
139 return ((struct mount *)0);
3c4390e8
KM
140}
141
142/*
143 * Set vnode attributes to VNOVAL
144 */
145void vattr_null(vap)
146 register struct vattr *vap;
147{
148
149 vap->va_type = VNON;
83504fd5
KM
150 vap->va_size = vap->va_bytes = VNOVAL;
151#ifdef _NOQUAD
152 vap->va_size_rsv = vap->va_bytes_rsv = VNOVAL;
153#endif
3c4390e8 154 vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
83504fd5
KM
155 vap->va_fsid = vap->va_fileid =
156 vap->va_blocksize = vap->va_rdev =
3c4390e8
KM
157 vap->va_atime.tv_sec = vap->va_atime.tv_usec =
158 vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
8cf4d4fb
KM
159 vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
160 vap->va_flags = vap->va_gen = VNOVAL;
3c4390e8 161}
c60798ca 162
36d09cb1
KM
163/*
164 * Routines having to do with the management of the vnode table.
165 */
166struct vnode *vfreeh, **vfreet;
4ef5d036 167extern struct vnodeops dead_vnodeops, spec_vnodeops;
32339c94 168extern void vclean();
1a80f56e 169long numvnodes;
d3664d8f 170struct vattr va_null;
c0de8792 171
36d09cb1 172/*
ef24f6dd 173 * Initialize the vnode structures and initialize each file system type.
36d09cb1 174 */
ef24f6dd 175vfsinit()
36d09cb1 176{
ef24f6dd 177 struct vfsops **vfsp;
36d09cb1 178
ef24f6dd
KM
179 /*
180 * Initialize the vnode name cache
181 */
182 nchinit();
183 /*
184 * Initialize each file system type.
185 */
d3664d8f 186 vattr_null(&va_null);
ef24f6dd
KM
187 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
188 if (*vfsp == NULL)
189 continue;
190 (*(*vfsp)->vfs_init)();
191 }
36d09cb1
KM
192}
193
194/*
195 * Return the next vnode from the free list.
196 */
197getnewvnode(tag, mp, vops, vpp)
198 enum vtagtype tag;
199 struct mount *mp;
200 struct vnodeops *vops;
201 struct vnode **vpp;
202{
203 register struct vnode *vp, *vq;
204
1a80f56e 205 if (numvnodes < desiredvnodes) {
aacc1bff
KM
206 vp = (struct vnode *)malloc((u_long)sizeof *vp,
207 M_VNODE, M_WAITOK);
1a80f56e
KM
208 bzero((char *)vp, sizeof *vp);
209 numvnodes++;
210 } else {
211 if ((vp = vfreeh) == NULL) {
212 tablefull("vnode");
213 *vpp = 0;
214 return (ENFILE);
215 }
216 if (vp->v_usecount)
217 panic("free vnode isn't");
218 if (vq = vp->v_freef)
219 vq->v_freeb = &vfreeh;
220 else
221 vfreet = &vfreeh;
222 vfreeh = vq;
223 vp->v_freef = NULL;
224 vp->v_freeb = NULL;
39b99eb6 225 vp->v_lease = NULL;
1a80f56e
KM
226 if (vp->v_type != VBAD)
227 vgone(vp);
2345b093
KM
228 if (vp->v_data)
229 panic("cleaned vnode isn't");
1a80f56e 230 vp->v_flag = 0;
1a80f56e
KM
231 vp->v_lastr = 0;
232 vp->v_socket = 0;
36d09cb1 233 }
b027498b 234 vp->v_type = VNON;
36d09cb1
KM
235 cache_purge(vp);
236 vp->v_tag = tag;
ef24f6dd 237 vp->v_op = vops;
36d09cb1
KM
238 insmntque(vp, mp);
239 VREF(vp);
240 *vpp = vp;
241 return (0);
242}
243
244/*
245 * Move a vnode from one mount queue to another.
246 */
247insmntque(vp, mp)
248 register struct vnode *vp;
249 register struct mount *mp;
250{
8136adfc 251 register struct vnode *vq;
36d09cb1
KM
252
253 /*
254 * Delete from old mount point vnode list, if on one.
255 */
256 if (vp->v_mountb) {
257 if (vq = vp->v_mountf)
258 vq->v_mountb = vp->v_mountb;
259 *vp->v_mountb = vq;
260 }
261 /*
262 * Insert into list of vnodes for the new mount point, if available.
263 */
a45ff315 264 vp->v_mount = mp;
36d09cb1
KM
265 if (mp == NULL) {
266 vp->v_mountf = NULL;
267 vp->v_mountb = NULL;
268 return;
269 }
8136adfc
KM
270 if (vq = mp->mnt_mounth)
271 vq->v_mountb = &vp->v_mountf;
272 vp->v_mountf = vq;
273 vp->v_mountb = &mp->mnt_mounth;
274 mp->mnt_mounth = vp;
36d09cb1
KM
275}
276
76429560
KM
277/*
278 * Make sure all write-behind blocks associated
279 * with mount point are flushed out (from sync).
280 */
281mntflushbuf(mountp, flags)
282 struct mount *mountp;
283 int flags;
284{
285 register struct vnode *vp;
286
287 if ((mountp->mnt_flag & MNT_MPBUSY) == 0)
288 panic("mntflushbuf: not busy");
289loop:
290 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) {
291 if (VOP_ISLOCKED(vp))
292 continue;
293 if (vget(vp))
294 goto loop;
295 vflushbuf(vp, flags);
296 vput(vp);
297 if (vp->v_mount != mountp)
298 goto loop;
299 }
300}
301
302/*
303 * Flush all dirty buffers associated with a vnode.
304 */
305vflushbuf(vp, flags)
306 register struct vnode *vp;
307 int flags;
308{
309 register struct buf *bp;
310 struct buf *nbp;
311 int s;
312
313loop:
314 s = splbio();
315 for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
316 nbp = bp->b_blockf;
317 if ((bp->b_flags & B_BUSY))
318 continue;
319 if ((bp->b_flags & B_DELWRI) == 0)
320 panic("vflushbuf: not dirty");
321 bremfree(bp);
322 bp->b_flags |= B_BUSY;
323 splx(s);
324 /*
325 * Wait for I/O associated with indirect blocks to complete,
326 * since there is no way to quickly wait for them below.
327 * NB: This is really specific to ufs, but is done here
328 * as it is easier and quicker.
329 */
77dc8a8c 330 if (bp->b_vp == vp || (flags & B_SYNC) == 0)
76429560 331 (void) bawrite(bp);
77dc8a8c 332 else
76429560 333 (void) bwrite(bp);
77dc8a8c 334 goto loop;
76429560
KM
335 }
336 splx(s);
337 if ((flags & B_SYNC) == 0)
338 return;
339 s = splbio();
340 while (vp->v_numoutput) {
341 vp->v_flag |= VBWAIT;
342 sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
343 }
344 splx(s);
345 if (vp->v_dirtyblkhd) {
346 vprint("vflushbuf: dirty", vp);
347 goto loop;
348 }
349}
350
351/*
352 * Update outstanding I/O count and do wakeup if requested.
353 */
354vwakeup(bp)
355 register struct buf *bp;
356{
357 register struct vnode *vp;
358
359 bp->b_dirtyoff = bp->b_dirtyend = 0;
360 if (vp = bp->b_vp) {
361 vp->v_numoutput--;
362 if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
363 if (vp->v_numoutput < 0)
364 panic("vwakeup: neg numoutput");
365 vp->v_flag &= ~VBWAIT;
366 wakeup((caddr_t)&vp->v_numoutput);
367 }
368 }
369}
370
371/*
372 * Invalidate in core blocks belonging to closed or umounted filesystem
373 *
374 * Go through the list of vnodes associated with the file system;
375 * for each vnode invalidate any buffers that it holds. Normally
376 * this routine is preceeded by a bflush call, so that on a quiescent
377 * filesystem there will be no dirty buffers when we are done. Binval
378 * returns the count of dirty buffers when it is finished.
379 */
380mntinvalbuf(mountp)
381 struct mount *mountp;
382{
383 register struct vnode *vp;
384 int dirty = 0;
385
386 if ((mountp->mnt_flag & MNT_MPBUSY) == 0)
387 panic("mntinvalbuf: not busy");
388loop:
389 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) {
390 if (vget(vp))
391 goto loop;
392 dirty += vinvalbuf(vp, 1);
393 vput(vp);
394 if (vp->v_mount != mountp)
395 goto loop;
396 }
397 return (dirty);
398}
399
400/*
401 * Flush out and invalidate all buffers associated with a vnode.
402 * Called with the underlying object locked.
403 */
404vinvalbuf(vp, save)
405 register struct vnode *vp;
406 int save;
407{
408 register struct buf *bp;
409 struct buf *nbp, *blist;
410 int s, dirty = 0;
411
412 for (;;) {
413 if (blist = vp->v_dirtyblkhd)
414 /* void */;
415 else if (blist = vp->v_cleanblkhd)
416 /* void */;
417 else
418 break;
419 for (bp = blist; bp; bp = nbp) {
420 nbp = bp->b_blockf;
421 s = splbio();
422 if (bp->b_flags & B_BUSY) {
423 bp->b_flags |= B_WANTED;
424 sleep((caddr_t)bp, PRIBIO + 1);
425 splx(s);
426 break;
427 }
428 bremfree(bp);
429 bp->b_flags |= B_BUSY;
430 splx(s);
431 if (save && (bp->b_flags & B_DELWRI)) {
24e9a81d
KM
432 dirty++;
433 (void) VOP_BWRITE(bp);
76429560
KM
434 break;
435 }
436 if (bp->b_vp != vp)
437 reassignbuf(bp, bp->b_vp);
438 else
439 bp->b_flags |= B_INVAL;
440 brelse(bp);
441 }
442 }
443 if (vp->v_dirtyblkhd || vp->v_cleanblkhd)
444 panic("vinvalbuf: flush failed");
445 return (dirty);
446}
447
448/*
449 * Associate a buffer with a vnode.
450 */
451bgetvp(vp, bp)
452 register struct vnode *vp;
453 register struct buf *bp;
454{
8136adfc
KM
455 register struct vnode *vq;
456 register struct buf *bq;
76429560
KM
457
458 if (bp->b_vp)
459 panic("bgetvp: not free");
460 VHOLD(vp);
461 bp->b_vp = vp;
462 if (vp->v_type == VBLK || vp->v_type == VCHR)
463 bp->b_dev = vp->v_rdev;
464 else
465 bp->b_dev = NODEV;
466 /*
467 * Insert onto list for new vnode.
468 */
8136adfc
KM
469 if (bq = vp->v_cleanblkhd)
470 bq->b_blockb = &bp->b_blockf;
471 bp->b_blockf = bq;
472 bp->b_blockb = &vp->v_cleanblkhd;
473 vp->v_cleanblkhd = bp;
76429560
KM
474}
475
476/*
477 * Disassociate a buffer from a vnode.
478 */
479brelvp(bp)
480 register struct buf *bp;
481{
482 struct buf *bq;
483 struct vnode *vp;
484
485 if (bp->b_vp == (struct vnode *) 0)
486 panic("brelvp: NULL");
487 /*
488 * Delete from old vnode list, if on one.
489 */
490 if (bp->b_blockb) {
491 if (bq = bp->b_blockf)
492 bq->b_blockb = bp->b_blockb;
493 *bp->b_blockb = bq;
494 bp->b_blockf = NULL;
495 bp->b_blockb = NULL;
496 }
497 vp = bp->b_vp;
498 bp->b_vp = (struct vnode *) 0;
499 HOLDRELE(vp);
500}
501
502/*
503 * Reassign a buffer from one vnode to another.
504 * Used to assign file specific control information
505 * (indirect blocks) to the vnode to which they belong.
506 */
507reassignbuf(bp, newvp)
508 register struct buf *bp;
509 register struct vnode *newvp;
510{
511 register struct buf *bq, **listheadp;
512
e5c3f16e
KM
513 if (newvp == NULL) {
514 printf("reassignbuf: NULL");
515 return;
516 }
76429560
KM
517 /*
518 * Delete from old vnode list, if on one.
519 */
520 if (bp->b_blockb) {
521 if (bq = bp->b_blockf)
522 bq->b_blockb = bp->b_blockb;
523 *bp->b_blockb = bq;
524 }
525 /*
526 * If dirty, put on list of dirty buffers;
527 * otherwise insert onto list of clean buffers.
528 */
529 if (bp->b_flags & B_DELWRI)
530 listheadp = &newvp->v_dirtyblkhd;
531 else
532 listheadp = &newvp->v_cleanblkhd;
8136adfc
KM
533 if (bq = *listheadp)
534 bq->b_blockb = &bp->b_blockf;
535 bp->b_blockf = bq;
536 bp->b_blockb = listheadp;
537 *listheadp = bp;
76429560
KM
538}
539
36d09cb1 540/*
ef24f6dd
KM
541 * Create a vnode for a block device.
542 * Used for root filesystem, argdev, and swap areas.
543 * Also used for memory file system special devices.
544 */
545bdevvp(dev, vpp)
546 dev_t dev;
547 struct vnode **vpp;
548{
ef24f6dd
KM
549 register struct vnode *vp;
550 struct vnode *nvp;
551 int error;
552
1c89915d
KM
553 if (dev == NODEV)
554 return (0);
4ef5d036 555 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
ef24f6dd
KM
556 if (error) {
557 *vpp = 0;
558 return (error);
559 }
560 vp = nvp;
561 vp->v_type = VBLK;
c0de8792 562 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
ef24f6dd
KM
563 vput(vp);
564 vp = nvp;
565 }
566 *vpp = vp;
567 return (0);
568}
569
570/*
571 * Check to see if the new vnode represents a special device
572 * for which we already have a vnode (either because of
573 * bdevvp() or because of a different vnode representing
574 * the same block device). If such an alias exists, deallocate
f0556f86 575 * the existing contents and return the aliased vnode. The
ef24f6dd
KM
576 * caller is responsible for filling it with its new contents.
577 */
578struct vnode *
c0de8792 579checkalias(nvp, nvp_rdev, mp)
ef24f6dd 580 register struct vnode *nvp;
c0de8792 581 dev_t nvp_rdev;
ef24f6dd
KM
582 struct mount *mp;
583{
584 register struct vnode *vp;
c0de8792 585 struct vnode **vpp;
ef24f6dd
KM
586
587 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
54fb9dc2 588 return (NULLVP);
c0de8792
KM
589
590 vpp = &speclisth[SPECHASH(nvp_rdev)];
ef24f6dd 591loop:
c0de8792
KM
592 for (vp = *vpp; vp; vp = vp->v_specnext) {
593 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
ef24f6dd 594 continue;
c0de8792
KM
595 /*
596 * Alias, but not in use, so flush it out.
597 */
7f7b7d89 598 if (vp->v_usecount == 0) {
c0de8792
KM
599 vgone(vp);
600 goto loop;
601 }
ef62830d
KM
602 if (vget(vp))
603 goto loop;
ef24f6dd
KM
604 break;
605 }
c0de8792 606 if (vp == NULL || vp->v_tag != VT_NON) {
c0de8792
KM
607 MALLOC(nvp->v_specinfo, struct specinfo *,
608 sizeof(struct specinfo), M_VNODE, M_WAITOK);
609 nvp->v_rdev = nvp_rdev;
7f7b7d89 610 nvp->v_hashchain = vpp;
c0de8792 611 nvp->v_specnext = *vpp;
2c957a90 612 nvp->v_specflags = 0;
c0de8792 613 *vpp = nvp;
40452d5e
KM
614 if (vp != NULL) {
615 nvp->v_flag |= VALIASED;
616 vp->v_flag |= VALIASED;
617 vput(vp);
618 }
54fb9dc2 619 return (NULLVP);
ef24f6dd 620 }
2bae1875
KM
621 VOP_UNLOCK(vp);
622 vclean(vp, 0);
ef24f6dd
KM
623 vp->v_op = nvp->v_op;
624 vp->v_tag = nvp->v_tag;
625 nvp->v_type = VNON;
626 insmntque(vp, mp);
627 return (vp);
628}
629
630/*
631 * Grab a particular vnode from the free list, increment its
632 * reference count and lock it. The vnode lock bit is set the
633 * vnode is being eliminated in vgone. The process is awakened
634 * when the transition is completed, and an error returned to
635 * indicate that the vnode is no longer usable (possibly having
636 * been changed to a new file system type).
36d09cb1
KM
637 */
638vget(vp)
639 register struct vnode *vp;
640{
641 register struct vnode *vq;
642
ef24f6dd
KM
643 if (vp->v_flag & VXLOCK) {
644 vp->v_flag |= VXWANT;
645 sleep((caddr_t)vp, PINOD);
646 return (1);
647 }
7f7b7d89 648 if (vp->v_usecount == 0) {
ef24f6dd
KM
649 if (vq = vp->v_freef)
650 vq->v_freeb = vp->v_freeb;
651 else
652 vfreet = vp->v_freeb;
653 *vp->v_freeb = vq;
654 vp->v_freef = NULL;
655 vp->v_freeb = NULL;
656 }
36d09cb1 657 VREF(vp);
ef24f6dd
KM
658 VOP_LOCK(vp);
659 return (0);
36d09cb1
KM
660}
661
d32390ea
KM
662int bug_refs = 0;
663
36d09cb1
KM
664/*
665 * Vnode reference, just increment the count
666 */
667void vref(vp)
668 struct vnode *vp;
669{
670
7f7b7d89 671 vp->v_usecount++;
d32390ea
KM
672 if (vp->v_type != VBLK && curproc)
673 curproc->p_spare[0]++;
674 if (bug_refs)
675 vprint("vref: ");
36d09cb1
KM
676}
677
678/*
679 * vput(), just unlock and vrele()
680 */
681void vput(vp)
682 register struct vnode *vp;
683{
4d1ee2eb 684
36d09cb1
KM
685 VOP_UNLOCK(vp);
686 vrele(vp);
687}
688
689/*
690 * Vnode release.
691 * If count drops to zero, call inactive routine and return to freelist.
692 */
693void vrele(vp)
694 register struct vnode *vp;
695{
c099667a 696 struct proc *p = curproc; /* XXX */
36d09cb1 697
65c3b3a8 698#ifdef DIAGNOSTIC
36d09cb1 699 if (vp == NULL)
ef24f6dd 700 panic("vrele: null vp");
65c3b3a8 701#endif
7f7b7d89 702 vp->v_usecount--;
d32390ea
KM
703 if (vp->v_type != VBLK && curproc)
704 curproc->p_spare[0]--;
705 if (bug_refs)
706 vprint("vref: ");
7f7b7d89 707 if (vp->v_usecount > 0)
36d09cb1 708 return;
65c3b3a8
KM
709#ifdef DIAGNOSTIC
710 if (vp->v_usecount != 0 || vp->v_writecount != 0) {
711 vprint("vrele: bad ref count", vp);
712 panic("vrele: ref cnt");
713 }
714#endif
54fb9dc2 715 if (vfreeh == NULLVP) {
36d09cb1
KM
716 /*
717 * insert into empty list
718 */
719 vfreeh = vp;
720 vp->v_freeb = &vfreeh;
36d09cb1
KM
721 } else {
722 /*
723 * insert at tail of list
724 */
725 *vfreet = vp;
726 vp->v_freeb = vfreet;
36d09cb1 727 }
ef24f6dd
KM
728 vp->v_freef = NULL;
729 vfreet = &vp->v_freef;
c099667a 730 VOP_INACTIVE(vp, p);
ef24f6dd
KM
731}
732
7f7b7d89
KM
733/*
734 * Page or buffer structure gets a reference.
735 */
451df175 736void vhold(vp)
7f7b7d89
KM
737 register struct vnode *vp;
738{
739
740 vp->v_holdcnt++;
741}
742
743/*
744 * Page or buffer structure frees a reference.
745 */
451df175 746void holdrele(vp)
7f7b7d89
KM
747 register struct vnode *vp;
748{
749
750 if (vp->v_holdcnt <= 0)
751 panic("holdrele: holdcnt");
752 vp->v_holdcnt--;
753}
754
f0556f86
KM
755/*
756 * Remove any vnodes in the vnode table belonging to mount point mp.
757 *
758 * If MNT_NOFORCE is specified, there should not be any active ones,
759 * return error if any are found (nb: this is a user error, not a
760 * system error). If MNT_FORCE is specified, detach any active vnodes
761 * that are found.
762 */
763int busyprt = 0; /* patch to print out busy vnodes */
764
765vflush(mp, skipvp, flags)
766 struct mount *mp;
767 struct vnode *skipvp;
768 int flags;
769{
770 register struct vnode *vp, *nvp;
771 int busy = 0;
772
54fb9dc2 773 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
36ef03ec 774 panic("vflush: not busy");
4597dd33 775loop:
54fb9dc2 776 for (vp = mp->mnt_mounth; vp; vp = nvp) {
4597dd33
KM
777 if (vp->v_mount != mp)
778 goto loop;
f0556f86
KM
779 nvp = vp->v_mountf;
780 /*
781 * Skip over a selected vnode.
f0556f86
KM
782 */
783 if (vp == skipvp)
784 continue;
36ef03ec
KM
785 /*
786 * Skip over a vnodes marked VSYSTEM.
787 */
788 if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
789 continue;
f0556f86 790 /*
7f7b7d89 791 * With v_usecount == 0, all we need to do is clear
f0556f86
KM
792 * out the vnode data structures and we are done.
793 */
7f7b7d89 794 if (vp->v_usecount == 0) {
f0556f86
KM
795 vgone(vp);
796 continue;
797 }
798 /*
799 * For block or character devices, revert to an
800 * anonymous device. For all other files, just kill them.
801 */
36ef03ec 802 if (flags & FORCECLOSE) {
f0556f86
KM
803 if (vp->v_type != VBLK && vp->v_type != VCHR) {
804 vgone(vp);
805 } else {
806 vclean(vp, 0);
807 vp->v_op = &spec_vnodeops;
808 insmntque(vp, (struct mount *)0);
809 }
810 continue;
811 }
812 if (busyprt)
0bf84b18 813 vprint("vflush: busy vnode", vp);
f0556f86
KM
814 busy++;
815 }
816 if (busy)
817 return (EBUSY);
818 return (0);
819}
820
ef24f6dd
KM
821/*
822 * Disassociate the underlying file system from a vnode.
ef24f6dd 823 */
36ef03ec 824void vclean(vp, flags)
ef24f6dd 825 register struct vnode *vp;
aacc1bff 826 int flags;
ef24f6dd
KM
827{
828 struct vnodeops *origops;
2bae1875 829 int active;
c099667a 830 struct proc *p = curproc; /* XXX */
ef24f6dd 831
2bae1875
KM
832 /*
833 * Check to see if the vnode is in use.
0bf84b18
KM
834 * If so we have to reference it before we clean it out
835 * so that its count cannot fall to zero and generate a
836 * race against ourselves to recycle it.
2bae1875 837 */
7f7b7d89 838 if (active = vp->v_usecount)
2bae1875 839 VREF(vp);
2bae1875
KM
840 /*
841 * Prevent the vnode from being recycled or
842 * brought into use while we clean it out.
843 */
0bf84b18
KM
844 if (vp->v_flag & VXLOCK)
845 panic("vclean: deadlock");
ef24f6dd 846 vp->v_flag |= VXLOCK;
0bf84b18
KM
847 /*
848 * Even if the count is zero, the VOP_INACTIVE routine may still
849 * have the object locked while it cleans it out. The VOP_LOCK
850 * ensures that the VOP_INACTIVE routine is done with its work.
851 * For active vnodes, it ensures that no other activity can
852 * occur while the buffer list is being cleaned out.
853 */
854 VOP_LOCK(vp);
36ef03ec 855 if (flags & DOCLOSE)
0bf84b18 856 vinvalbuf(vp, 1);
ef24f6dd
KM
857 /*
858 * Prevent any further operations on the vnode from
859 * being passed through to the old file system.
860 */
861 origops = vp->v_op;
862 vp->v_op = &dead_vnodeops;
863 vp->v_tag = VT_NON;
864 /*
2bae1875
KM
865 * If purging an active vnode, it must be unlocked, closed,
866 * and deactivated before being reclaimed.
ef24f6dd 867 */
20454d5a 868 (*(origops->vop_unlock))(vp);
2bae1875 869 if (active) {
36ef03ec 870 if (flags & DOCLOSE)
20454d5a
KM
871 (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p);
872 (*(origops->vop_inactive))(vp, p);
ef24f6dd
KM
873 }
874 /*
875 * Reclaim the vnode.
876 */
20454d5a 877 if ((*(origops->vop_reclaim))(vp))
ef24f6dd 878 panic("vclean: cannot reclaim");
2bae1875
KM
879 if (active)
880 vrele(vp);
ef24f6dd
KM
881 /*
882 * Done with purge, notify sleepers in vget of the grim news.
883 */
884 vp->v_flag &= ~VXLOCK;
885 if (vp->v_flag & VXWANT) {
886 vp->v_flag &= ~VXWANT;
887 wakeup((caddr_t)vp);
888 }
889}
890
ef62830d
KM
891/*
892 * Eliminate all activity associated with the requested vnode
893 * and with all vnodes aliased to the requested vnode.
894 */
895void vgoneall(vp)
896 register struct vnode *vp;
897{
7f7b7d89 898 register struct vnode *vq;
ef62830d 899
7a7b3a95
KM
900 if (vp->v_flag & VALIASED) {
901 /*
902 * If a vgone (or vclean) is already in progress,
903 * wait until it is done and return.
904 */
905 if (vp->v_flag & VXLOCK) {
906 vp->v_flag |= VXWANT;
907 sleep((caddr_t)vp, PINOD);
908 return;
909 }
910 /*
911 * Ensure that vp will not be vgone'd while we
912 * are eliminating its aliases.
913 */
914 vp->v_flag |= VXLOCK;
915 while (vp->v_flag & VALIASED) {
916 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
917 if (vq->v_rdev != vp->v_rdev ||
918 vq->v_type != vp->v_type || vp == vq)
919 continue;
920 vgone(vq);
921 break;
922 }
ef62830d 923 }
7a7b3a95
KM
924 /*
925 * Remove the lock so that vgone below will
926 * really eliminate the vnode after which time
927 * vgone will awaken any sleepers.
928 */
929 vp->v_flag &= ~VXLOCK;
ef62830d
KM
930 }
931 vgone(vp);
932}
933
ef24f6dd
KM
934/*
935 * Eliminate all activity associated with a vnode
936 * in preparation for reuse.
937 */
938void vgone(vp)
939 register struct vnode *vp;
940{
7f7b7d89 941 register struct vnode *vq;
c0de8792 942 struct vnode *vx;
ef24f6dd 943
4f55e3ec
KM
944 /*
945 * If a vgone (or vclean) is already in progress,
946 * wait until it is done and return.
947 */
948 if (vp->v_flag & VXLOCK) {
949 vp->v_flag |= VXWANT;
950 sleep((caddr_t)vp, PINOD);
951 return;
952 }
ef24f6dd
KM
953 /*
954 * Clean out the filesystem specific data.
955 */
36ef03ec 956 vclean(vp, DOCLOSE);
ef24f6dd
KM
957 /*
958 * Delete from old mount point vnode list, if on one.
959 */
960 if (vp->v_mountb) {
961 if (vq = vp->v_mountf)
962 vq->v_mountb = vp->v_mountb;
963 *vp->v_mountb = vq;
964 vp->v_mountf = NULL;
965 vp->v_mountb = NULL;
d10e9258 966 vp->v_mount = NULL;
ef24f6dd
KM
967 }
968 /*
969 * If special device, remove it from special device alias list.
970 */
971 if (vp->v_type == VBLK || vp->v_type == VCHR) {
7f7b7d89
KM
972 if (*vp->v_hashchain == vp) {
973 *vp->v_hashchain = vp->v_specnext;
ef24f6dd 974 } else {
7f7b7d89 975 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
c0de8792 976 if (vq->v_specnext != vp)
ef24f6dd 977 continue;
c0de8792 978 vq->v_specnext = vp->v_specnext;
ef24f6dd
KM
979 break;
980 }
c0de8792 981 if (vq == NULL)
ef24f6dd
KM
982 panic("missing bdev");
983 }
c0de8792 984 if (vp->v_flag & VALIASED) {
4d1ee2eb 985 vx = NULL;
7f7b7d89 986 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c
KM
987 if (vq->v_rdev != vp->v_rdev ||
988 vq->v_type != vp->v_type)
c0de8792 989 continue;
4d1ee2eb
CT
990 if (vx)
991 break;
c0de8792
KM
992 vx = vq;
993 }
4d1ee2eb 994 if (vx == NULL)
c0de8792 995 panic("missing alias");
4d1ee2eb 996 if (vq == NULL)
c0de8792
KM
997 vx->v_flag &= ~VALIASED;
998 vp->v_flag &= ~VALIASED;
999 }
1000 FREE(vp->v_specinfo, M_VNODE);
1001 vp->v_specinfo = NULL;
ef24f6dd
KM
1002 }
1003 /*
1004 * If it is on the freelist, move it to the head of the list.
1005 */
1006 if (vp->v_freeb) {
1007 if (vq = vp->v_freef)
1008 vq->v_freeb = vp->v_freeb;
1009 else
1010 vfreet = vp->v_freeb;
1011 *vp->v_freeb = vq;
1012 vp->v_freef = vfreeh;
1013 vp->v_freeb = &vfreeh;
1014 vfreeh->v_freeb = &vp->v_freef;
1015 vfreeh = vp;
1016 }
2bae1875 1017 vp->v_type = VBAD;
36d09cb1 1018}
ef62830d 1019
2bcd6066
KM
1020/*
1021 * Lookup a vnode by device number.
1022 */
1023vfinddev(dev, type, vpp)
1024 dev_t dev;
1025 enum vtype type;
1026 struct vnode **vpp;
1027{
1028 register struct vnode *vp;
1029
1030 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
1031 if (dev != vp->v_rdev || type != vp->v_type)
1032 continue;
1033 *vpp = vp;
1034 return (0);
1035 }
1036 return (1);
1037}
1038
ef62830d
KM
1039/*
1040 * Calculate the total number of references to a special device.
1041 */
1042vcount(vp)
1043 register struct vnode *vp;
1044{
7f7b7d89 1045 register struct vnode *vq;
ef62830d
KM
1046 int count;
1047
1048 if ((vp->v_flag & VALIASED) == 0)
7f7b7d89 1049 return (vp->v_usecount);
ef62830d 1050loop:
7f7b7d89 1051 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c 1052 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
ef62830d
KM
1053 continue;
1054 /*
1055 * Alias, but not in use, so flush it out.
1056 */
7f7b7d89 1057 if (vq->v_usecount == 0) {
ef62830d
KM
1058 vgone(vq);
1059 goto loop;
1060 }
7f7b7d89 1061 count += vq->v_usecount;
ef62830d
KM
1062 }
1063 return (count);
1064}
0bf84b18
KM
1065
1066/*
1067 * Print out a description of a vnode.
1068 */
1069static char *typename[] =
61f846a8 1070 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
0bf84b18
KM
1071
1072vprint(label, vp)
1073 char *label;
1074 register struct vnode *vp;
1075{
f2f730c6 1076 char buf[64];
0bf84b18
KM
1077
1078 if (label != NULL)
1079 printf("%s: ", label);
65c3b3a8
KM
1080 printf("type %s, usecount %d, writecount %d, refcount %d,",
1081 typename[vp->v_type], vp->v_usecount, vp->v_writecount,
1082 vp->v_holdcnt);
f2f730c6
KM
1083 buf[0] = '\0';
1084 if (vp->v_flag & VROOT)
1085 strcat(buf, "|VROOT");
1086 if (vp->v_flag & VTEXT)
1087 strcat(buf, "|VTEXT");
36ef03ec
KM
1088 if (vp->v_flag & VSYSTEM)
1089 strcat(buf, "|VSYSTEM");
36ef03ec
KM
1090 if (vp->v_flag & VXLOCK)
1091 strcat(buf, "|VXLOCK");
1092 if (vp->v_flag & VXWANT)
1093 strcat(buf, "|VXWANT");
f2f730c6
KM
1094 if (vp->v_flag & VBWAIT)
1095 strcat(buf, "|VBWAIT");
36ef03ec
KM
1096 if (vp->v_flag & VALIASED)
1097 strcat(buf, "|VALIASED");
f2f730c6
KM
1098 if (buf[0] != '\0')
1099 printf(" flags (%s)", &buf[1]);
1100 printf("\n\t");
0bf84b18
KM
1101 VOP_PRINT(vp);
1102}
985cbdd5 1103
34c62e18
KM
1104#ifdef DEBUG
1105/*
1106 * List all of the locked vnodes in the system.
1107 * Called when debugging the kernel.
1108 */
1109printlockedvnodes()
1110{
1111 register struct mount *mp;
1112 register struct vnode *vp;
1113
1114 printf("Locked vnodes\n");
1115 mp = rootfs;
1116 do {
1117 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf)
1118 if (VOP_ISLOCKED(vp))
1119 vprint((char *)0, vp);
1120 mp = mp->mnt_next;
1121 } while (mp != rootfs);
1122}
1123#endif
1124
985cbdd5
MT
1125int kinfo_vdebug = 1;
1126int kinfo_vgetfailed;
1127#define KINFO_VNODESLOP 10
1128/*
1129 * Dump vnode list (via kinfo).
1130 * Copyout address of vnode followed by vnode.
1131 */
aacc1bff 1132/* ARGSUSED */
985cbdd5 1133kinfo_vnode(op, where, acopysize, arg, aneeded)
aacc1bff 1134 int op;
985cbdd5 1135 char *where;
aacc1bff 1136 int *acopysize, arg, *aneeded;
985cbdd5
MT
1137{
1138 register struct mount *mp = rootfs;
36ef03ec 1139 struct mount *omp;
985cbdd5 1140 struct vnode *vp;
985cbdd5
MT
1141 register char *bp = where, *savebp;
1142 char *ewhere = where + *acopysize;
1143 int error;
1144
1145#define VPTRSZ sizeof (struct vnode *)
1146#define VNODESZ sizeof (struct vnode)
1147 if (where == NULL) {
1148 *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
1149 return (0);
1150 }
1151
985cbdd5 1152 do {
36ef03ec 1153 if (vfs_busy(mp)) {
54fb9dc2 1154 mp = mp->mnt_next;
36ef03ec
KM
1155 continue;
1156 }
985cbdd5
MT
1157 savebp = bp;
1158again:
4597dd33 1159 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
41185b3b
KM
1160 /*
1161 * Check that the vp is still associated with
1162 * this filesystem. RACE: could have been
1163 * recycled onto the same filesystem.
1164 */
4597dd33
KM
1165 if (vp->v_mount != mp) {
1166 if (kinfo_vdebug)
1167 printf("kinfo: vp changed\n");
1168 bp = savebp;
1169 goto again;
1170 }
985cbdd5
MT
1171 if ((bp + VPTRSZ + VNODESZ <= ewhere) &&
1172 ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
1173 (error = copyout((caddr_t)vp, bp + VPTRSZ,
41185b3b 1174 VNODESZ))))
985cbdd5 1175 return (error);
985cbdd5 1176 bp += VPTRSZ + VNODESZ;
985cbdd5 1177 }
36ef03ec 1178 omp = mp;
54fb9dc2 1179 mp = mp->mnt_next;
36ef03ec 1180 vfs_unbusy(omp);
985cbdd5
MT
1181 } while (mp != rootfs);
1182
1183 *aneeded = bp - where;
1184 if (bp > ewhere)
1185 *acopysize = ewhere - where;
1186 else
1187 *acopysize = bp - where;
1188 return (0);
1189}