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