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