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