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