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