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