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