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