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