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