eliminate reallocbuf; merge in ufs_machdep.c
[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 *
dbf0c423 7 * @(#)vfs_subr.c 7.47 (Berkeley) %G%
3c4390e8
KM
8 */
9
10/*
11 * External virtual filesystem routines
12 */
13
14#include "param.h"
15#include "mount.h"
16#include "time.h"
17#include "vnode.h"
0f93ba7b 18#include "specdev.h"
c60798ca
KM
19#include "namei.h"
20#include "ucred.h"
3c4390e8 21#include "errno.h"
ef24f6dd 22#include "malloc.h"
3c4390e8 23
3c4390e8
KM
24/*
25 * Remove a mount point from the list of mounted filesystems.
26 * Unmount of the root is illegal.
27 */
28void
29vfs_remove(mp)
30 register struct mount *mp;
31{
32
33 if (mp == rootfs)
34 panic("vfs_remove: unmounting root");
54fb9dc2
KM
35 mp->mnt_prev->mnt_next = mp->mnt_next;
36 mp->mnt_next->mnt_prev = mp->mnt_prev;
37 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
3c4390e8
KM
38 vfs_unlock(mp);
39}
40
41/*
42 * Lock a filesystem.
43 * Used to prevent access to it while mounting and unmounting.
44 */
45vfs_lock(mp)
46 register struct mount *mp;
47{
48
54fb9dc2
KM
49 while(mp->mnt_flag & MNT_MLOCK) {
50 mp->mnt_flag |= MNT_MWAIT;
594501df
KM
51 sleep((caddr_t)mp, PVFS);
52 }
54fb9dc2 53 mp->mnt_flag |= MNT_MLOCK;
3c4390e8
KM
54 return (0);
55}
56
57/*
58 * Unlock a locked filesystem.
59 * Panic if filesystem is not locked.
60 */
61void
62vfs_unlock(mp)
63 register struct mount *mp;
64{
65
54fb9dc2 66 if ((mp->mnt_flag & MNT_MLOCK) == 0)
36ef03ec 67 panic("vfs_unlock: not locked");
54fb9dc2
KM
68 mp->mnt_flag &= ~MNT_MLOCK;
69 if (mp->mnt_flag & MNT_MWAIT) {
70 mp->mnt_flag &= ~MNT_MWAIT;
3c4390e8
KM
71 wakeup((caddr_t)mp);
72 }
73}
74
36ef03ec
KM
75/*
76 * Mark a mount point as busy.
77 * Used to synchronize access and to delay unmounting.
78 */
79vfs_busy(mp)
80 register struct mount *mp;
81{
82
54fb9dc2
KM
83 while(mp->mnt_flag & MNT_MPBUSY) {
84 mp->mnt_flag |= MNT_MPWANT;
85 sleep((caddr_t)&mp->mnt_flag, PVFS);
36ef03ec 86 }
d8b63609
KM
87 if (mp->mnt_flag & MNT_UNMOUNT)
88 return (1);
54fb9dc2 89 mp->mnt_flag |= MNT_MPBUSY;
36ef03ec
KM
90 return (0);
91}
92
93/*
94 * Free a busy filesystem.
95 * Panic if filesystem is not busy.
96 */
97void
98vfs_unbusy(mp)
99 register struct mount *mp;
100{
101
54fb9dc2 102 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
36ef03ec 103 panic("vfs_unbusy: not busy");
54fb9dc2
KM
104 mp->mnt_flag &= ~MNT_MPBUSY;
105 if (mp->mnt_flag & MNT_MPWANT) {
106 mp->mnt_flag &= ~MNT_MPWANT;
107 wakeup((caddr_t)&mp->mnt_flag);
36ef03ec
KM
108 }
109}
110
3c4390e8
KM
111/*
112 * Lookup a mount point by filesystem identifier.
113 */
114struct mount *
115getvfs(fsid)
116 fsid_t *fsid;
117{
118 register struct mount *mp;
119
d713f801
KM
120 mp = rootfs;
121 do {
54fb9dc2
KM
122 if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&
123 mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) {
d713f801 124 return (mp);
3c4390e8 125 }
54fb9dc2 126 mp = mp->mnt_next;
d713f801
KM
127 } while (mp != rootfs);
128 return ((struct mount *)0);
3c4390e8
KM
129}
130
131/*
132 * Set vnode attributes to VNOVAL
133 */
134void vattr_null(vap)
135 register struct vattr *vap;
136{
137
138 vap->va_type = VNON;
139 vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
140 vap->va_fsid = vap->va_fileid = vap->va_size =
8fae943a
KM
141 vap->va_size_rsv = vap->va_blocksize = vap->va_rdev =
142 vap->va_bytes = vap->va_bytes_rsv =
3c4390e8
KM
143 vap->va_atime.tv_sec = vap->va_atime.tv_usec =
144 vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
8cf4d4fb
KM
145 vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
146 vap->va_flags = vap->va_gen = VNOVAL;
3c4390e8 147}
c60798ca
KM
148
149/*
150 * Initialize a nameidata structure
151 */
152ndinit(ndp)
153 register struct nameidata *ndp;
154{
155
156 bzero((caddr_t)ndp, sizeof(struct nameidata));
157 ndp->ni_iov = &ndp->ni_nd.nd_iovec;
158 ndp->ni_iovcnt = 1;
159 ndp->ni_base = (caddr_t)&ndp->ni_dent;
160 ndp->ni_rw = UIO_WRITE;
4dbe3531 161 ndp->ni_uioseg = UIO_SYSSPACE;
c60798ca
KM
162}
163
164/*
165 * Duplicate a nameidata structure
166 */
167nddup(ndp, newndp)
168 register struct nameidata *ndp, *newndp;
169{
170
171 ndinit(newndp);
172 newndp->ni_cdir = ndp->ni_cdir;
8fe1c702 173 VREF(newndp->ni_cdir);
c60798ca
KM
174 newndp->ni_rdir = ndp->ni_rdir;
175 if (newndp->ni_rdir)
8fe1c702 176 VREF(newndp->ni_rdir);
c60798ca
KM
177 newndp->ni_cred = ndp->ni_cred;
178 crhold(newndp->ni_cred);
179}
180
181/*
182 * Release a nameidata structure
183 */
184ndrele(ndp)
185 register struct nameidata *ndp;
186{
187
188 vrele(ndp->ni_cdir);
189 if (ndp->ni_rdir)
190 vrele(ndp->ni_rdir);
191 crfree(ndp->ni_cred);
192}
36d09cb1
KM
193
194/*
195 * Routines having to do with the management of the vnode table.
196 */
197struct vnode *vfreeh, **vfreet;
4ef5d036 198extern struct vnodeops dead_vnodeops, spec_vnodeops;
32339c94 199extern void vclean();
1a80f56e 200long numvnodes;
d3664d8f 201struct vattr va_null;
c0de8792 202
36d09cb1 203/*
ef24f6dd 204 * Initialize the vnode structures and initialize each file system type.
36d09cb1 205 */
ef24f6dd 206vfsinit()
36d09cb1 207{
ef24f6dd 208 struct vfsops **vfsp;
36d09cb1 209
ef24f6dd
KM
210 /*
211 * Initialize the vnode name cache
212 */
213 nchinit();
214 /*
215 * Initialize each file system type.
216 */
d3664d8f 217 vattr_null(&va_null);
ef24f6dd
KM
218 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
219 if (*vfsp == NULL)
220 continue;
221 (*(*vfsp)->vfs_init)();
222 }
36d09cb1
KM
223}
224
225/*
226 * Return the next vnode from the free list.
227 */
228getnewvnode(tag, mp, vops, vpp)
229 enum vtagtype tag;
230 struct mount *mp;
231 struct vnodeops *vops;
232 struct vnode **vpp;
233{
234 register struct vnode *vp, *vq;
235
1a80f56e
KM
236 if (numvnodes < desiredvnodes) {
237 vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK);
238 bzero((char *)vp, sizeof *vp);
239 numvnodes++;
240 } else {
241 if ((vp = vfreeh) == NULL) {
242 tablefull("vnode");
243 *vpp = 0;
244 return (ENFILE);
245 }
246 if (vp->v_usecount)
247 panic("free vnode isn't");
248 if (vq = vp->v_freef)
249 vq->v_freeb = &vfreeh;
250 else
251 vfreet = &vfreeh;
252 vfreeh = vq;
253 vp->v_freef = NULL;
254 vp->v_freeb = NULL;
255 if (vp->v_type != VBAD)
256 vgone(vp);
257 vp->v_flag = 0;
258 vp->v_shlockc = 0;
259 vp->v_exlockc = 0;
260 vp->v_lastr = 0;
261 vp->v_socket = 0;
36d09cb1 262 }
b027498b 263 vp->v_type = VNON;
36d09cb1
KM
264 cache_purge(vp);
265 vp->v_tag = tag;
ef24f6dd 266 vp->v_op = vops;
36d09cb1
KM
267 insmntque(vp, mp);
268 VREF(vp);
269 *vpp = vp;
270 return (0);
271}
272
273/*
274 * Move a vnode from one mount queue to another.
275 */
276insmntque(vp, mp)
277 register struct vnode *vp;
278 register struct mount *mp;
279{
280 struct vnode *vq;
281
282 /*
283 * Delete from old mount point vnode list, if on one.
284 */
285 if (vp->v_mountb) {
286 if (vq = vp->v_mountf)
287 vq->v_mountb = vp->v_mountb;
288 *vp->v_mountb = vq;
289 }
290 /*
291 * Insert into list of vnodes for the new mount point, if available.
292 */
a45ff315 293 vp->v_mount = mp;
36d09cb1
KM
294 if (mp == NULL) {
295 vp->v_mountf = NULL;
296 vp->v_mountb = NULL;
297 return;
298 }
54fb9dc2
KM
299 if (mp->mnt_mounth) {
300 vp->v_mountf = mp->mnt_mounth;
301 vp->v_mountb = &mp->mnt_mounth;
302 mp->mnt_mounth->v_mountb = &vp->v_mountf;
303 mp->mnt_mounth = vp;
36d09cb1 304 } else {
54fb9dc2
KM
305 mp->mnt_mounth = vp;
306 vp->v_mountb = &mp->mnt_mounth;
36d09cb1
KM
307 vp->v_mountf = NULL;
308 }
309}
310
311/*
ef24f6dd
KM
312 * Create a vnode for a block device.
313 * Used for root filesystem, argdev, and swap areas.
314 * Also used for memory file system special devices.
315 */
316bdevvp(dev, vpp)
317 dev_t dev;
318 struct vnode **vpp;
319{
ef24f6dd
KM
320 register struct vnode *vp;
321 struct vnode *nvp;
322 int error;
323
4ef5d036 324 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
ef24f6dd
KM
325 if (error) {
326 *vpp = 0;
327 return (error);
328 }
329 vp = nvp;
330 vp->v_type = VBLK;
c0de8792 331 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
ef24f6dd
KM
332 vput(vp);
333 vp = nvp;
334 }
335 *vpp = vp;
336 return (0);
337}
338
339/*
340 * Check to see if the new vnode represents a special device
341 * for which we already have a vnode (either because of
342 * bdevvp() or because of a different vnode representing
343 * the same block device). If such an alias exists, deallocate
f0556f86 344 * the existing contents and return the aliased vnode. The
ef24f6dd
KM
345 * caller is responsible for filling it with its new contents.
346 */
347struct vnode *
c0de8792 348checkalias(nvp, nvp_rdev, mp)
ef24f6dd 349 register struct vnode *nvp;
c0de8792 350 dev_t nvp_rdev;
ef24f6dd
KM
351 struct mount *mp;
352{
353 register struct vnode *vp;
c0de8792 354 struct vnode **vpp;
ef24f6dd
KM
355
356 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
54fb9dc2 357 return (NULLVP);
c0de8792
KM
358
359 vpp = &speclisth[SPECHASH(nvp_rdev)];
ef24f6dd 360loop:
c0de8792
KM
361 for (vp = *vpp; vp; vp = vp->v_specnext) {
362 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
ef24f6dd 363 continue;
c0de8792
KM
364 /*
365 * Alias, but not in use, so flush it out.
366 */
7f7b7d89 367 if (vp->v_usecount == 0) {
c0de8792
KM
368 vgone(vp);
369 goto loop;
370 }
ef62830d
KM
371 if (vget(vp))
372 goto loop;
ef24f6dd
KM
373 break;
374 }
c0de8792 375 if (vp == NULL || vp->v_tag != VT_NON) {
c0de8792
KM
376 MALLOC(nvp->v_specinfo, struct specinfo *,
377 sizeof(struct specinfo), M_VNODE, M_WAITOK);
378 nvp->v_rdev = nvp_rdev;
7f7b7d89 379 nvp->v_hashchain = vpp;
c0de8792 380 nvp->v_specnext = *vpp;
2c957a90 381 nvp->v_specflags = 0;
c0de8792 382 *vpp = nvp;
40452d5e
KM
383 if (vp != NULL) {
384 nvp->v_flag |= VALIASED;
385 vp->v_flag |= VALIASED;
386 vput(vp);
387 }
54fb9dc2 388 return (NULLVP);
ef24f6dd 389 }
2bae1875
KM
390 VOP_UNLOCK(vp);
391 vclean(vp, 0);
ef24f6dd
KM
392 vp->v_op = nvp->v_op;
393 vp->v_tag = nvp->v_tag;
394 nvp->v_type = VNON;
395 insmntque(vp, mp);
396 return (vp);
397}
398
399/*
400 * Grab a particular vnode from the free list, increment its
401 * reference count and lock it. The vnode lock bit is set the
402 * vnode is being eliminated in vgone. The process is awakened
403 * when the transition is completed, and an error returned to
404 * indicate that the vnode is no longer usable (possibly having
405 * been changed to a new file system type).
36d09cb1
KM
406 */
407vget(vp)
408 register struct vnode *vp;
409{
410 register struct vnode *vq;
411
ef24f6dd
KM
412 if (vp->v_flag & VXLOCK) {
413 vp->v_flag |= VXWANT;
414 sleep((caddr_t)vp, PINOD);
415 return (1);
416 }
7f7b7d89 417 if (vp->v_usecount == 0) {
ef24f6dd
KM
418 if (vq = vp->v_freef)
419 vq->v_freeb = vp->v_freeb;
420 else
421 vfreet = vp->v_freeb;
422 *vp->v_freeb = vq;
423 vp->v_freef = NULL;
424 vp->v_freeb = NULL;
425 }
36d09cb1 426 VREF(vp);
ef24f6dd
KM
427 VOP_LOCK(vp);
428 return (0);
36d09cb1
KM
429}
430
431/*
432 * Vnode reference, just increment the count
433 */
434void vref(vp)
435 struct vnode *vp;
436{
437
7f7b7d89 438 vp->v_usecount++;
36d09cb1
KM
439}
440
441/*
442 * vput(), just unlock and vrele()
443 */
444void vput(vp)
445 register struct vnode *vp;
446{
447 VOP_UNLOCK(vp);
448 vrele(vp);
449}
450
451/*
452 * Vnode release.
453 * If count drops to zero, call inactive routine and return to freelist.
454 */
455void vrele(vp)
456 register struct vnode *vp;
457{
458
459 if (vp == NULL)
ef24f6dd 460 panic("vrele: null vp");
7f7b7d89
KM
461 vp->v_usecount--;
462 if (vp->v_usecount < 0)
0bf84b18 463 vprint("vrele: bad ref count", vp);
7f7b7d89 464 if (vp->v_usecount > 0)
36d09cb1 465 return;
54fb9dc2 466 if (vfreeh == NULLVP) {
36d09cb1
KM
467 /*
468 * insert into empty list
469 */
470 vfreeh = vp;
471 vp->v_freeb = &vfreeh;
36d09cb1
KM
472 } else {
473 /*
474 * insert at tail of list
475 */
476 *vfreet = vp;
477 vp->v_freeb = vfreet;
36d09cb1 478 }
ef24f6dd
KM
479 vp->v_freef = NULL;
480 vfreet = &vp->v_freef;
481 VOP_INACTIVE(vp);
482}
483
7f7b7d89
KM
484/*
485 * Page or buffer structure gets a reference.
486 */
487vhold(vp)
488 register struct vnode *vp;
489{
490
491 vp->v_holdcnt++;
492}
493
494/*
495 * Page or buffer structure frees a reference.
496 */
497holdrele(vp)
498 register struct vnode *vp;
499{
500
501 if (vp->v_holdcnt <= 0)
502 panic("holdrele: holdcnt");
503 vp->v_holdcnt--;
504}
505
f0556f86
KM
506/*
507 * Remove any vnodes in the vnode table belonging to mount point mp.
508 *
509 * If MNT_NOFORCE is specified, there should not be any active ones,
510 * return error if any are found (nb: this is a user error, not a
511 * system error). If MNT_FORCE is specified, detach any active vnodes
512 * that are found.
513 */
514int busyprt = 0; /* patch to print out busy vnodes */
515
516vflush(mp, skipvp, flags)
517 struct mount *mp;
518 struct vnode *skipvp;
519 int flags;
520{
521 register struct vnode *vp, *nvp;
522 int busy = 0;
523
54fb9dc2 524 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
36ef03ec 525 panic("vflush: not busy");
4597dd33 526loop:
54fb9dc2 527 for (vp = mp->mnt_mounth; vp; vp = nvp) {
4597dd33
KM
528 if (vp->v_mount != mp)
529 goto loop;
f0556f86
KM
530 nvp = vp->v_mountf;
531 /*
532 * Skip over a selected vnode.
f0556f86
KM
533 */
534 if (vp == skipvp)
535 continue;
36ef03ec
KM
536 /*
537 * Skip over a vnodes marked VSYSTEM.
538 */
539 if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
540 continue;
f0556f86 541 /*
7f7b7d89 542 * With v_usecount == 0, all we need to do is clear
f0556f86
KM
543 * out the vnode data structures and we are done.
544 */
7f7b7d89 545 if (vp->v_usecount == 0) {
f0556f86
KM
546 vgone(vp);
547 continue;
548 }
549 /*
550 * For block or character devices, revert to an
551 * anonymous device. For all other files, just kill them.
552 */
36ef03ec 553 if (flags & FORCECLOSE) {
f0556f86
KM
554 if (vp->v_type != VBLK && vp->v_type != VCHR) {
555 vgone(vp);
556 } else {
557 vclean(vp, 0);
558 vp->v_op = &spec_vnodeops;
559 insmntque(vp, (struct mount *)0);
560 }
561 continue;
562 }
563 if (busyprt)
0bf84b18 564 vprint("vflush: busy vnode", vp);
f0556f86
KM
565 busy++;
566 }
567 if (busy)
568 return (EBUSY);
569 return (0);
570}
571
ef24f6dd
KM
572/*
573 * Disassociate the underlying file system from a vnode.
ef24f6dd 574 */
36ef03ec 575void vclean(vp, flags)
ef24f6dd 576 register struct vnode *vp;
36ef03ec 577 long flags;
ef24f6dd
KM
578{
579 struct vnodeops *origops;
2bae1875 580 int active;
ef24f6dd 581
2bae1875
KM
582 /*
583 * Check to see if the vnode is in use.
0bf84b18
KM
584 * If so we have to reference it before we clean it out
585 * so that its count cannot fall to zero and generate a
586 * race against ourselves to recycle it.
2bae1875 587 */
7f7b7d89 588 if (active = vp->v_usecount)
2bae1875 589 VREF(vp);
2bae1875
KM
590 /*
591 * Prevent the vnode from being recycled or
592 * brought into use while we clean it out.
593 */
0bf84b18
KM
594 if (vp->v_flag & VXLOCK)
595 panic("vclean: deadlock");
ef24f6dd 596 vp->v_flag |= VXLOCK;
0bf84b18
KM
597 /*
598 * Even if the count is zero, the VOP_INACTIVE routine may still
599 * have the object locked while it cleans it out. The VOP_LOCK
600 * ensures that the VOP_INACTIVE routine is done with its work.
601 * For active vnodes, it ensures that no other activity can
602 * occur while the buffer list is being cleaned out.
603 */
604 VOP_LOCK(vp);
36ef03ec 605 if (flags & DOCLOSE)
0bf84b18 606 vinvalbuf(vp, 1);
ef24f6dd
KM
607 /*
608 * Prevent any further operations on the vnode from
609 * being passed through to the old file system.
610 */
611 origops = vp->v_op;
612 vp->v_op = &dead_vnodeops;
613 vp->v_tag = VT_NON;
614 /*
2bae1875
KM
615 * If purging an active vnode, it must be unlocked, closed,
616 * and deactivated before being reclaimed.
ef24f6dd 617 */
0bf84b18 618 (*(origops->vn_unlock))(vp);
2bae1875 619 if (active) {
36ef03ec 620 if (flags & DOCLOSE)
2bae1875 621 (*(origops->vn_close))(vp, 0, NOCRED);
ef24f6dd
KM
622 (*(origops->vn_inactive))(vp);
623 }
624 /*
625 * Reclaim the vnode.
626 */
627 if ((*(origops->vn_reclaim))(vp))
628 panic("vclean: cannot reclaim");
2bae1875
KM
629 if (active)
630 vrele(vp);
ef24f6dd
KM
631 /*
632 * Done with purge, notify sleepers in vget of the grim news.
633 */
634 vp->v_flag &= ~VXLOCK;
635 if (vp->v_flag & VXWANT) {
636 vp->v_flag &= ~VXWANT;
637 wakeup((caddr_t)vp);
638 }
639}
640
ef62830d
KM
641/*
642 * Eliminate all activity associated with the requested vnode
643 * and with all vnodes aliased to the requested vnode.
644 */
645void vgoneall(vp)
646 register struct vnode *vp;
647{
7f7b7d89 648 register struct vnode *vq;
ef62830d 649
7a7b3a95
KM
650 if (vp->v_flag & VALIASED) {
651 /*
652 * If a vgone (or vclean) is already in progress,
653 * wait until it is done and return.
654 */
655 if (vp->v_flag & VXLOCK) {
656 vp->v_flag |= VXWANT;
657 sleep((caddr_t)vp, PINOD);
658 return;
659 }
660 /*
661 * Ensure that vp will not be vgone'd while we
662 * are eliminating its aliases.
663 */
664 vp->v_flag |= VXLOCK;
665 while (vp->v_flag & VALIASED) {
666 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
667 if (vq->v_rdev != vp->v_rdev ||
668 vq->v_type != vp->v_type || vp == vq)
669 continue;
670 vgone(vq);
671 break;
672 }
ef62830d 673 }
7a7b3a95
KM
674 /*
675 * Remove the lock so that vgone below will
676 * really eliminate the vnode after which time
677 * vgone will awaken any sleepers.
678 */
679 vp->v_flag &= ~VXLOCK;
ef62830d
KM
680 }
681 vgone(vp);
682}
683
ef24f6dd
KM
684/*
685 * Eliminate all activity associated with a vnode
686 * in preparation for reuse.
687 */
688void vgone(vp)
689 register struct vnode *vp;
690{
7f7b7d89 691 register struct vnode *vq;
c0de8792
KM
692 struct vnode *vx;
693 long count;
ef24f6dd 694
4f55e3ec
KM
695 /*
696 * If a vgone (or vclean) is already in progress,
697 * wait until it is done and return.
698 */
699 if (vp->v_flag & VXLOCK) {
700 vp->v_flag |= VXWANT;
701 sleep((caddr_t)vp, PINOD);
702 return;
703 }
ef24f6dd
KM
704 /*
705 * Clean out the filesystem specific data.
706 */
36ef03ec 707 vclean(vp, DOCLOSE);
ef24f6dd
KM
708 /*
709 * Delete from old mount point vnode list, if on one.
710 */
711 if (vp->v_mountb) {
712 if (vq = vp->v_mountf)
713 vq->v_mountb = vp->v_mountb;
714 *vp->v_mountb = vq;
715 vp->v_mountf = NULL;
716 vp->v_mountb = NULL;
717 }
718 /*
719 * If special device, remove it from special device alias list.
720 */
721 if (vp->v_type == VBLK || vp->v_type == VCHR) {
7f7b7d89
KM
722 if (*vp->v_hashchain == vp) {
723 *vp->v_hashchain = vp->v_specnext;
ef24f6dd 724 } else {
7f7b7d89 725 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
c0de8792 726 if (vq->v_specnext != vp)
ef24f6dd 727 continue;
c0de8792 728 vq->v_specnext = vp->v_specnext;
ef24f6dd
KM
729 break;
730 }
c0de8792 731 if (vq == NULL)
ef24f6dd
KM
732 panic("missing bdev");
733 }
c0de8792 734 if (vp->v_flag & VALIASED) {
7f7b7d89
KM
735 count = 0;
736 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c
KM
737 if (vq->v_rdev != vp->v_rdev ||
738 vq->v_type != vp->v_type)
c0de8792
KM
739 continue;
740 count++;
741 vx = vq;
742 }
743 if (count == 0)
744 panic("missing alias");
745 if (count == 1)
746 vx->v_flag &= ~VALIASED;
747 vp->v_flag &= ~VALIASED;
748 }
749 FREE(vp->v_specinfo, M_VNODE);
750 vp->v_specinfo = NULL;
ef24f6dd
KM
751 }
752 /*
753 * If it is on the freelist, move it to the head of the list.
754 */
755 if (vp->v_freeb) {
756 if (vq = vp->v_freef)
757 vq->v_freeb = vp->v_freeb;
758 else
759 vfreet = vp->v_freeb;
760 *vp->v_freeb = vq;
761 vp->v_freef = vfreeh;
762 vp->v_freeb = &vfreeh;
763 vfreeh->v_freeb = &vp->v_freef;
764 vfreeh = vp;
765 }
2bae1875 766 vp->v_type = VBAD;
36d09cb1 767}
ef62830d 768
2bcd6066
KM
769/*
770 * Lookup a vnode by device number.
771 */
772vfinddev(dev, type, vpp)
773 dev_t dev;
774 enum vtype type;
775 struct vnode **vpp;
776{
777 register struct vnode *vp;
778
779 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
780 if (dev != vp->v_rdev || type != vp->v_type)
781 continue;
782 *vpp = vp;
783 return (0);
784 }
785 return (1);
786}
787
ef62830d
KM
788/*
789 * Calculate the total number of references to a special device.
790 */
791vcount(vp)
792 register struct vnode *vp;
793{
7f7b7d89 794 register struct vnode *vq;
ef62830d
KM
795 int count;
796
797 if ((vp->v_flag & VALIASED) == 0)
7f7b7d89 798 return (vp->v_usecount);
ef62830d 799loop:
7f7b7d89 800 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c 801 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
ef62830d
KM
802 continue;
803 /*
804 * Alias, but not in use, so flush it out.
805 */
7f7b7d89 806 if (vq->v_usecount == 0) {
ef62830d
KM
807 vgone(vq);
808 goto loop;
809 }
7f7b7d89 810 count += vq->v_usecount;
ef62830d
KM
811 }
812 return (count);
813}
0bf84b18
KM
814
815/*
816 * Print out a description of a vnode.
817 */
818static char *typename[] =
61f846a8 819 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
0bf84b18
KM
820
821vprint(label, vp)
822 char *label;
823 register struct vnode *vp;
824{
f2f730c6 825 char buf[64];
0bf84b18
KM
826
827 if (label != NULL)
828 printf("%s: ", label);
f2f730c6 829 printf("type %s, usecount %d, refcount %d,", typename[vp->v_type],
7f7b7d89 830 vp->v_usecount, vp->v_holdcnt);
f2f730c6
KM
831 buf[0] = '\0';
832 if (vp->v_flag & VROOT)
833 strcat(buf, "|VROOT");
834 if (vp->v_flag & VTEXT)
835 strcat(buf, "|VTEXT");
36ef03ec
KM
836 if (vp->v_flag & VSYSTEM)
837 strcat(buf, "|VSYSTEM");
f2f730c6
KM
838 if (vp->v_flag & VEXLOCK)
839 strcat(buf, "|VEXLOCK");
840 if (vp->v_flag & VSHLOCK)
841 strcat(buf, "|VSHLOCK");
842 if (vp->v_flag & VLWAIT)
843 strcat(buf, "|VLWAIT");
36ef03ec
KM
844 if (vp->v_flag & VXLOCK)
845 strcat(buf, "|VXLOCK");
846 if (vp->v_flag & VXWANT)
847 strcat(buf, "|VXWANT");
f2f730c6
KM
848 if (vp->v_flag & VBWAIT)
849 strcat(buf, "|VBWAIT");
36ef03ec
KM
850 if (vp->v_flag & VALIASED)
851 strcat(buf, "|VALIASED");
f2f730c6
KM
852 if (buf[0] != '\0')
853 printf(" flags (%s)", &buf[1]);
854 printf("\n\t");
0bf84b18
KM
855 VOP_PRINT(vp);
856}
985cbdd5
MT
857
858int kinfo_vdebug = 1;
859int kinfo_vgetfailed;
860#define KINFO_VNODESLOP 10
861/*
862 * Dump vnode list (via kinfo).
863 * Copyout address of vnode followed by vnode.
864 */
865kinfo_vnode(op, where, acopysize, arg, aneeded)
866 char *where;
867 int *acopysize, *aneeded;
868{
869 register struct mount *mp = rootfs;
36ef03ec 870 struct mount *omp;
985cbdd5
MT
871 struct vnode *vp;
872 register needed = 0;
873 register char *bp = where, *savebp;
874 char *ewhere = where + *acopysize;
875 int error;
876
877#define VPTRSZ sizeof (struct vnode *)
878#define VNODESZ sizeof (struct vnode)
879 if (where == NULL) {
880 *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
881 return (0);
882 }
883
985cbdd5 884 do {
36ef03ec 885 if (vfs_busy(mp)) {
54fb9dc2 886 mp = mp->mnt_next;
36ef03ec
KM
887 continue;
888 }
985cbdd5
MT
889 savebp = bp;
890again:
4597dd33 891 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
41185b3b
KM
892 /*
893 * Check that the vp is still associated with
894 * this filesystem. RACE: could have been
895 * recycled onto the same filesystem.
896 */
4597dd33
KM
897 if (vp->v_mount != mp) {
898 if (kinfo_vdebug)
899 printf("kinfo: vp changed\n");
900 bp = savebp;
901 goto again;
902 }
985cbdd5
MT
903 if ((bp + VPTRSZ + VNODESZ <= ewhere) &&
904 ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
905 (error = copyout((caddr_t)vp, bp + VPTRSZ,
41185b3b 906 VNODESZ))))
985cbdd5 907 return (error);
985cbdd5 908 bp += VPTRSZ + VNODESZ;
985cbdd5 909 }
36ef03ec 910 omp = mp;
54fb9dc2 911 mp = mp->mnt_next;
36ef03ec 912 vfs_unbusy(omp);
985cbdd5
MT
913 } while (mp != rootfs);
914
915 *aneeded = bp - where;
916 if (bp > ewhere)
917 *acopysize = ewhere - where;
918 else
919 *acopysize = bp - where;
920 return (0);
921}