137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*49232Smckusick * @(#)vfs_subr.c 7.54 (Berkeley) 05/06/91 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1437488Smckusick #include "param.h" 1548024Smckusick #include "proc.h" 1637488Smckusick #include "mount.h" 1737488Smckusick #include "time.h" 1837488Smckusick #include "vnode.h" 1940652Smckusick #include "specdev.h" 2038265Smckusick #include "namei.h" 2138265Smckusick #include "ucred.h" 22*49232Smckusick #include "buf.h" 2337488Smckusick #include "errno.h" 2439433Smckusick #include "malloc.h" 2537488Smckusick 2637488Smckusick /* 2737488Smckusick * Remove a mount point from the list of mounted filesystems. 2837488Smckusick * Unmount of the root is illegal. 2937488Smckusick */ 3037488Smckusick void 3137488Smckusick vfs_remove(mp) 3237488Smckusick register struct mount *mp; 3337488Smckusick { 3437488Smckusick 3537488Smckusick if (mp == rootfs) 3637488Smckusick panic("vfs_remove: unmounting root"); 3741400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 3841400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 3941400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 4037488Smckusick vfs_unlock(mp); 4137488Smckusick } 4237488Smckusick 4337488Smckusick /* 4437488Smckusick * Lock a filesystem. 4537488Smckusick * Used to prevent access to it while mounting and unmounting. 4637488Smckusick */ 4737488Smckusick vfs_lock(mp) 4837488Smckusick register struct mount *mp; 4937488Smckusick { 5037488Smckusick 5141400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 5241400Smckusick mp->mnt_flag |= MNT_MWAIT; 5339045Smckusick sleep((caddr_t)mp, PVFS); 5439045Smckusick } 5541400Smckusick mp->mnt_flag |= MNT_MLOCK; 5637488Smckusick return (0); 5737488Smckusick } 5837488Smckusick 5937488Smckusick /* 6037488Smckusick * Unlock a locked filesystem. 6137488Smckusick * Panic if filesystem is not locked. 6237488Smckusick */ 6337488Smckusick void 6437488Smckusick vfs_unlock(mp) 6537488Smckusick register struct mount *mp; 6637488Smckusick { 6737488Smckusick 6841400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 6941300Smckusick panic("vfs_unlock: not locked"); 7041400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 7141400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 7241400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 7337488Smckusick wakeup((caddr_t)mp); 7437488Smckusick } 7537488Smckusick } 7637488Smckusick 7737488Smckusick /* 7841300Smckusick * Mark a mount point as busy. 7941300Smckusick * Used to synchronize access and to delay unmounting. 8041300Smckusick */ 8141300Smckusick vfs_busy(mp) 8241300Smckusick register struct mount *mp; 8341300Smckusick { 8441300Smckusick 8541400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 8641400Smckusick mp->mnt_flag |= MNT_MPWANT; 8741400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 8841300Smckusick } 8941419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 9041419Smckusick return (1); 9141400Smckusick mp->mnt_flag |= MNT_MPBUSY; 9241300Smckusick return (0); 9341300Smckusick } 9441300Smckusick 9541300Smckusick /* 9641300Smckusick * Free a busy filesystem. 9741300Smckusick * Panic if filesystem is not busy. 9841300Smckusick */ 9941300Smckusick vfs_unbusy(mp) 10041300Smckusick register struct mount *mp; 10141300Smckusick { 10241300Smckusick 10341400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 10441300Smckusick panic("vfs_unbusy: not busy"); 10541400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 10641400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 10741400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 10841400Smckusick wakeup((caddr_t)&mp->mnt_flag); 10941300Smckusick } 11041300Smckusick } 11141300Smckusick 11241300Smckusick /* 11337488Smckusick * Lookup a mount point by filesystem identifier. 11437488Smckusick */ 11537488Smckusick struct mount * 11637488Smckusick getvfs(fsid) 11737488Smckusick fsid_t *fsid; 11837488Smckusick { 11937488Smckusick register struct mount *mp; 12037488Smckusick 12138288Smckusick mp = rootfs; 12238288Smckusick do { 12341400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 12441400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 12538288Smckusick return (mp); 12637488Smckusick } 12741400Smckusick mp = mp->mnt_next; 12838288Smckusick } while (mp != rootfs); 12938288Smckusick return ((struct mount *)0); 13037488Smckusick } 13137488Smckusick 13237488Smckusick /* 13337488Smckusick * Set vnode attributes to VNOVAL 13437488Smckusick */ 13537488Smckusick void vattr_null(vap) 13637488Smckusick register struct vattr *vap; 13737488Smckusick { 13837488Smckusick 13937488Smckusick vap->va_type = VNON; 14037488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 14137488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 14240643Smckusick vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 14340643Smckusick vap->va_bytes = vap->va_bytes_rsv = 14437488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 14537488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 14638258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 14738258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 14837488Smckusick } 14938265Smckusick 15038265Smckusick /* 15138265Smckusick * Initialize a nameidata structure 15238265Smckusick */ 15338265Smckusick ndinit(ndp) 15438265Smckusick register struct nameidata *ndp; 15538265Smckusick { 15638265Smckusick 15738265Smckusick bzero((caddr_t)ndp, sizeof(struct nameidata)); 15838265Smckusick ndp->ni_iov = &ndp->ni_nd.nd_iovec; 15938265Smckusick ndp->ni_iovcnt = 1; 16038265Smckusick ndp->ni_base = (caddr_t)&ndp->ni_dent; 16138265Smckusick ndp->ni_rw = UIO_WRITE; 16239736Smckusick ndp->ni_uioseg = UIO_SYSSPACE; 16338265Smckusick } 16438265Smckusick 16538265Smckusick /* 16638265Smckusick * Duplicate a nameidata structure 16738265Smckusick */ 16838265Smckusick nddup(ndp, newndp) 16938265Smckusick register struct nameidata *ndp, *newndp; 17038265Smckusick { 17138265Smckusick 17238265Smckusick ndinit(newndp); 17338265Smckusick newndp->ni_cred = ndp->ni_cred; 17438265Smckusick crhold(newndp->ni_cred); 17538265Smckusick } 17638265Smckusick 17738265Smckusick /* 17838265Smckusick * Release a nameidata structure 17938265Smckusick */ 18038265Smckusick ndrele(ndp) 18138265Smckusick register struct nameidata *ndp; 18238265Smckusick { 18338265Smckusick 18438265Smckusick crfree(ndp->ni_cred); 18538265Smckusick } 18639397Smckusick 18739397Smckusick /* 18839397Smckusick * Routines having to do with the management of the vnode table. 18939397Smckusick */ 19039397Smckusick struct vnode *vfreeh, **vfreet; 19139447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 19239635Smckusick extern void vclean(); 19340883Smckusick long numvnodes; 19441363Smckusick struct vattr va_null; 19539397Smckusick 19639397Smckusick /* 19739433Smckusick * Initialize the vnode structures and initialize each file system type. 19839397Smckusick */ 19939433Smckusick vfsinit() 20039397Smckusick { 20139433Smckusick struct vfsops **vfsp; 20239397Smckusick 20339433Smckusick /* 20439433Smckusick * Initialize the vnode name cache 20539433Smckusick */ 20639433Smckusick nchinit(); 20739433Smckusick /* 20839433Smckusick * Initialize each file system type. 20939433Smckusick */ 21041363Smckusick vattr_null(&va_null); 21139433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 21239433Smckusick if (*vfsp == NULL) 21339433Smckusick continue; 21439433Smckusick (*(*vfsp)->vfs_init)(); 21539433Smckusick } 21639397Smckusick } 21739397Smckusick 21839397Smckusick /* 21939397Smckusick * Return the next vnode from the free list. 22039397Smckusick */ 22139397Smckusick getnewvnode(tag, mp, vops, vpp) 22239397Smckusick enum vtagtype tag; 22339397Smckusick struct mount *mp; 22439397Smckusick struct vnodeops *vops; 22539397Smckusick struct vnode **vpp; 22639397Smckusick { 22739397Smckusick register struct vnode *vp, *vq; 22839397Smckusick 22940883Smckusick if (numvnodes < desiredvnodes) { 23045118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 23145118Smckusick M_VNODE, M_WAITOK); 23240883Smckusick bzero((char *)vp, sizeof *vp); 23340883Smckusick numvnodes++; 23440883Smckusick } else { 23540883Smckusick if ((vp = vfreeh) == NULL) { 23640883Smckusick tablefull("vnode"); 23740883Smckusick *vpp = 0; 23840883Smckusick return (ENFILE); 23940883Smckusick } 24040883Smckusick if (vp->v_usecount) 24140883Smckusick panic("free vnode isn't"); 24240883Smckusick if (vq = vp->v_freef) 24340883Smckusick vq->v_freeb = &vfreeh; 24440883Smckusick else 24540883Smckusick vfreet = &vfreeh; 24640883Smckusick vfreeh = vq; 24740883Smckusick vp->v_freef = NULL; 24840883Smckusick vp->v_freeb = NULL; 24940883Smckusick if (vp->v_type != VBAD) 25040883Smckusick vgone(vp); 25140883Smckusick vp->v_flag = 0; 25240883Smckusick vp->v_lastr = 0; 25340883Smckusick vp->v_socket = 0; 25439397Smckusick } 25539512Smckusick vp->v_type = VNON; 25639397Smckusick cache_purge(vp); 25739397Smckusick vp->v_tag = tag; 25839433Smckusick vp->v_op = vops; 25939397Smckusick insmntque(vp, mp); 26039397Smckusick VREF(vp); 26139397Smckusick *vpp = vp; 26239397Smckusick return (0); 26339397Smckusick } 26439397Smckusick 26539397Smckusick /* 26639397Smckusick * Move a vnode from one mount queue to another. 26739397Smckusick */ 26839397Smckusick insmntque(vp, mp) 26939397Smckusick register struct vnode *vp; 27039397Smckusick register struct mount *mp; 27139397Smckusick { 27239397Smckusick struct vnode *vq; 27339397Smckusick 27439397Smckusick /* 27539397Smckusick * Delete from old mount point vnode list, if on one. 27639397Smckusick */ 27739397Smckusick if (vp->v_mountb) { 27839397Smckusick if (vq = vp->v_mountf) 27939397Smckusick vq->v_mountb = vp->v_mountb; 28039397Smckusick *vp->v_mountb = vq; 28139397Smckusick } 28239397Smckusick /* 28339397Smckusick * Insert into list of vnodes for the new mount point, if available. 28439397Smckusick */ 28539621Smckusick vp->v_mount = mp; 28639397Smckusick if (mp == NULL) { 28739397Smckusick vp->v_mountf = NULL; 28839397Smckusick vp->v_mountb = NULL; 28939397Smckusick return; 29039397Smckusick } 29141400Smckusick if (mp->mnt_mounth) { 29241400Smckusick vp->v_mountf = mp->mnt_mounth; 29341400Smckusick vp->v_mountb = &mp->mnt_mounth; 29441400Smckusick mp->mnt_mounth->v_mountb = &vp->v_mountf; 29541400Smckusick mp->mnt_mounth = vp; 29639397Smckusick } else { 29741400Smckusick mp->mnt_mounth = vp; 29841400Smckusick vp->v_mountb = &mp->mnt_mounth; 29939397Smckusick vp->v_mountf = NULL; 30039397Smckusick } 30139397Smckusick } 30239397Smckusick 30339397Smckusick /* 304*49232Smckusick * Make sure all write-behind blocks associated 305*49232Smckusick * with mount point are flushed out (from sync). 306*49232Smckusick */ 307*49232Smckusick mntflushbuf(mountp, flags) 308*49232Smckusick struct mount *mountp; 309*49232Smckusick int flags; 310*49232Smckusick { 311*49232Smckusick register struct vnode *vp; 312*49232Smckusick 313*49232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 314*49232Smckusick panic("mntflushbuf: not busy"); 315*49232Smckusick loop: 316*49232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 317*49232Smckusick if (VOP_ISLOCKED(vp)) 318*49232Smckusick continue; 319*49232Smckusick if (vget(vp)) 320*49232Smckusick goto loop; 321*49232Smckusick vflushbuf(vp, flags); 322*49232Smckusick vput(vp); 323*49232Smckusick if (vp->v_mount != mountp) 324*49232Smckusick goto loop; 325*49232Smckusick } 326*49232Smckusick } 327*49232Smckusick 328*49232Smckusick /* 329*49232Smckusick * Flush all dirty buffers associated with a vnode. 330*49232Smckusick */ 331*49232Smckusick vflushbuf(vp, flags) 332*49232Smckusick register struct vnode *vp; 333*49232Smckusick int flags; 334*49232Smckusick { 335*49232Smckusick register struct buf *bp; 336*49232Smckusick struct buf *nbp; 337*49232Smckusick int s; 338*49232Smckusick 339*49232Smckusick loop: 340*49232Smckusick s = splbio(); 341*49232Smckusick for (bp = vp->v_dirtyblkhd; bp; bp = nbp) { 342*49232Smckusick nbp = bp->b_blockf; 343*49232Smckusick if ((bp->b_flags & B_BUSY)) 344*49232Smckusick continue; 345*49232Smckusick if ((bp->b_flags & B_DELWRI) == 0) 346*49232Smckusick panic("vflushbuf: not dirty"); 347*49232Smckusick bremfree(bp); 348*49232Smckusick bp->b_flags |= B_BUSY; 349*49232Smckusick splx(s); 350*49232Smckusick /* 351*49232Smckusick * Wait for I/O associated with indirect blocks to complete, 352*49232Smckusick * since there is no way to quickly wait for them below. 353*49232Smckusick * NB: This is really specific to ufs, but is done here 354*49232Smckusick * as it is easier and quicker. 355*49232Smckusick */ 356*49232Smckusick if (bp->b_vp == vp || (flags & B_SYNC) == 0) { 357*49232Smckusick (void) bawrite(bp); 358*49232Smckusick s = splbio(); 359*49232Smckusick } else { 360*49232Smckusick (void) bwrite(bp); 361*49232Smckusick goto loop; 362*49232Smckusick } 363*49232Smckusick } 364*49232Smckusick splx(s); 365*49232Smckusick if ((flags & B_SYNC) == 0) 366*49232Smckusick return; 367*49232Smckusick s = splbio(); 368*49232Smckusick while (vp->v_numoutput) { 369*49232Smckusick vp->v_flag |= VBWAIT; 370*49232Smckusick sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); 371*49232Smckusick } 372*49232Smckusick splx(s); 373*49232Smckusick if (vp->v_dirtyblkhd) { 374*49232Smckusick vprint("vflushbuf: dirty", vp); 375*49232Smckusick goto loop; 376*49232Smckusick } 377*49232Smckusick } 378*49232Smckusick 379*49232Smckusick /* 380*49232Smckusick * Update outstanding I/O count and do wakeup if requested. 381*49232Smckusick */ 382*49232Smckusick vwakeup(bp) 383*49232Smckusick register struct buf *bp; 384*49232Smckusick { 385*49232Smckusick register struct vnode *vp; 386*49232Smckusick 387*49232Smckusick bp->b_dirtyoff = bp->b_dirtyend = 0; 388*49232Smckusick if (vp = bp->b_vp) { 389*49232Smckusick vp->v_numoutput--; 390*49232Smckusick if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { 391*49232Smckusick if (vp->v_numoutput < 0) 392*49232Smckusick panic("vwakeup: neg numoutput"); 393*49232Smckusick vp->v_flag &= ~VBWAIT; 394*49232Smckusick wakeup((caddr_t)&vp->v_numoutput); 395*49232Smckusick } 396*49232Smckusick } 397*49232Smckusick } 398*49232Smckusick 399*49232Smckusick /* 400*49232Smckusick * Invalidate in core blocks belonging to closed or umounted filesystem 401*49232Smckusick * 402*49232Smckusick * Go through the list of vnodes associated with the file system; 403*49232Smckusick * for each vnode invalidate any buffers that it holds. Normally 404*49232Smckusick * this routine is preceeded by a bflush call, so that on a quiescent 405*49232Smckusick * filesystem there will be no dirty buffers when we are done. Binval 406*49232Smckusick * returns the count of dirty buffers when it is finished. 407*49232Smckusick */ 408*49232Smckusick mntinvalbuf(mountp) 409*49232Smckusick struct mount *mountp; 410*49232Smckusick { 411*49232Smckusick register struct vnode *vp; 412*49232Smckusick int dirty = 0; 413*49232Smckusick 414*49232Smckusick if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 415*49232Smckusick panic("mntinvalbuf: not busy"); 416*49232Smckusick loop: 417*49232Smckusick for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 418*49232Smckusick if (vget(vp)) 419*49232Smckusick goto loop; 420*49232Smckusick dirty += vinvalbuf(vp, 1); 421*49232Smckusick vput(vp); 422*49232Smckusick if (vp->v_mount != mountp) 423*49232Smckusick goto loop; 424*49232Smckusick } 425*49232Smckusick return (dirty); 426*49232Smckusick } 427*49232Smckusick 428*49232Smckusick /* 429*49232Smckusick * Flush out and invalidate all buffers associated with a vnode. 430*49232Smckusick * Called with the underlying object locked. 431*49232Smckusick */ 432*49232Smckusick vinvalbuf(vp, save) 433*49232Smckusick register struct vnode *vp; 434*49232Smckusick int save; 435*49232Smckusick { 436*49232Smckusick register struct buf *bp; 437*49232Smckusick struct buf *nbp, *blist; 438*49232Smckusick int s, dirty = 0; 439*49232Smckusick 440*49232Smckusick for (;;) { 441*49232Smckusick if (blist = vp->v_dirtyblkhd) 442*49232Smckusick /* void */; 443*49232Smckusick else if (blist = vp->v_cleanblkhd) 444*49232Smckusick /* void */; 445*49232Smckusick else 446*49232Smckusick break; 447*49232Smckusick for (bp = blist; bp; bp = nbp) { 448*49232Smckusick nbp = bp->b_blockf; 449*49232Smckusick s = splbio(); 450*49232Smckusick if (bp->b_flags & B_BUSY) { 451*49232Smckusick bp->b_flags |= B_WANTED; 452*49232Smckusick sleep((caddr_t)bp, PRIBIO + 1); 453*49232Smckusick splx(s); 454*49232Smckusick break; 455*49232Smckusick } 456*49232Smckusick bremfree(bp); 457*49232Smckusick bp->b_flags |= B_BUSY; 458*49232Smckusick splx(s); 459*49232Smckusick if (save && (bp->b_flags & B_DELWRI)) { 460*49232Smckusick dirty++; 461*49232Smckusick (void) bwrite(bp); 462*49232Smckusick break; 463*49232Smckusick } 464*49232Smckusick if (bp->b_vp != vp) 465*49232Smckusick reassignbuf(bp, bp->b_vp); 466*49232Smckusick else 467*49232Smckusick bp->b_flags |= B_INVAL; 468*49232Smckusick brelse(bp); 469*49232Smckusick } 470*49232Smckusick } 471*49232Smckusick if (vp->v_dirtyblkhd || vp->v_cleanblkhd) 472*49232Smckusick panic("vinvalbuf: flush failed"); 473*49232Smckusick return (dirty); 474*49232Smckusick } 475*49232Smckusick 476*49232Smckusick /* 477*49232Smckusick * Associate a buffer with a vnode. 478*49232Smckusick */ 479*49232Smckusick bgetvp(vp, bp) 480*49232Smckusick register struct vnode *vp; 481*49232Smckusick register struct buf *bp; 482*49232Smckusick { 483*49232Smckusick 484*49232Smckusick if (bp->b_vp) 485*49232Smckusick panic("bgetvp: not free"); 486*49232Smckusick VHOLD(vp); 487*49232Smckusick bp->b_vp = vp; 488*49232Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) 489*49232Smckusick bp->b_dev = vp->v_rdev; 490*49232Smckusick else 491*49232Smckusick bp->b_dev = NODEV; 492*49232Smckusick /* 493*49232Smckusick * Insert onto list for new vnode. 494*49232Smckusick */ 495*49232Smckusick if (vp->v_cleanblkhd) { 496*49232Smckusick bp->b_blockf = vp->v_cleanblkhd; 497*49232Smckusick bp->b_blockb = &vp->v_cleanblkhd; 498*49232Smckusick vp->v_cleanblkhd->b_blockb = &bp->b_blockf; 499*49232Smckusick vp->v_cleanblkhd = bp; 500*49232Smckusick } else { 501*49232Smckusick vp->v_cleanblkhd = bp; 502*49232Smckusick bp->b_blockb = &vp->v_cleanblkhd; 503*49232Smckusick bp->b_blockf = NULL; 504*49232Smckusick } 505*49232Smckusick } 506*49232Smckusick 507*49232Smckusick /* 508*49232Smckusick * Disassociate a buffer from a vnode. 509*49232Smckusick */ 510*49232Smckusick brelvp(bp) 511*49232Smckusick register struct buf *bp; 512*49232Smckusick { 513*49232Smckusick struct buf *bq; 514*49232Smckusick struct vnode *vp; 515*49232Smckusick 516*49232Smckusick if (bp->b_vp == (struct vnode *) 0) 517*49232Smckusick panic("brelvp: NULL"); 518*49232Smckusick /* 519*49232Smckusick * Delete from old vnode list, if on one. 520*49232Smckusick */ 521*49232Smckusick if (bp->b_blockb) { 522*49232Smckusick if (bq = bp->b_blockf) 523*49232Smckusick bq->b_blockb = bp->b_blockb; 524*49232Smckusick *bp->b_blockb = bq; 525*49232Smckusick bp->b_blockf = NULL; 526*49232Smckusick bp->b_blockb = NULL; 527*49232Smckusick } 528*49232Smckusick vp = bp->b_vp; 529*49232Smckusick bp->b_vp = (struct vnode *) 0; 530*49232Smckusick HOLDRELE(vp); 531*49232Smckusick } 532*49232Smckusick 533*49232Smckusick /* 534*49232Smckusick * Reassign a buffer from one vnode to another. 535*49232Smckusick * Used to assign file specific control information 536*49232Smckusick * (indirect blocks) to the vnode to which they belong. 537*49232Smckusick */ 538*49232Smckusick reassignbuf(bp, newvp) 539*49232Smckusick register struct buf *bp; 540*49232Smckusick register struct vnode *newvp; 541*49232Smckusick { 542*49232Smckusick register struct buf *bq, **listheadp; 543*49232Smckusick 544*49232Smckusick if (newvp == NULL) 545*49232Smckusick panic("reassignbuf: NULL"); 546*49232Smckusick /* 547*49232Smckusick * Delete from old vnode list, if on one. 548*49232Smckusick */ 549*49232Smckusick if (bp->b_blockb) { 550*49232Smckusick if (bq = bp->b_blockf) 551*49232Smckusick bq->b_blockb = bp->b_blockb; 552*49232Smckusick *bp->b_blockb = bq; 553*49232Smckusick } 554*49232Smckusick /* 555*49232Smckusick * If dirty, put on list of dirty buffers; 556*49232Smckusick * otherwise insert onto list of clean buffers. 557*49232Smckusick */ 558*49232Smckusick if (bp->b_flags & B_DELWRI) 559*49232Smckusick listheadp = &newvp->v_dirtyblkhd; 560*49232Smckusick else 561*49232Smckusick listheadp = &newvp->v_cleanblkhd; 562*49232Smckusick if (*listheadp) { 563*49232Smckusick bp->b_blockf = *listheadp; 564*49232Smckusick bp->b_blockb = listheadp; 565*49232Smckusick bp->b_blockf->b_blockb = &bp->b_blockf; 566*49232Smckusick *listheadp = bp; 567*49232Smckusick } else { 568*49232Smckusick *listheadp = bp; 569*49232Smckusick bp->b_blockb = listheadp; 570*49232Smckusick bp->b_blockf = NULL; 571*49232Smckusick } 572*49232Smckusick } 573*49232Smckusick 574*49232Smckusick /* 57539433Smckusick * Create a vnode for a block device. 57639433Smckusick * Used for root filesystem, argdev, and swap areas. 57739433Smckusick * Also used for memory file system special devices. 57839397Smckusick */ 57939433Smckusick bdevvp(dev, vpp) 58039433Smckusick dev_t dev; 58139433Smckusick struct vnode **vpp; 58239433Smckusick { 58339433Smckusick register struct vnode *vp; 58439433Smckusick struct vnode *nvp; 58539433Smckusick int error; 58639433Smckusick 58746989Smckusick if (dev == NODEV) 58846989Smckusick return (0); 58939447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 59039433Smckusick if (error) { 59139433Smckusick *vpp = 0; 59239433Smckusick return (error); 59339433Smckusick } 59439433Smckusick vp = nvp; 59539433Smckusick vp->v_type = VBLK; 59639615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 59739433Smckusick vput(vp); 59839433Smckusick vp = nvp; 59939433Smckusick } 60039433Smckusick *vpp = vp; 60139433Smckusick return (0); 60239433Smckusick } 60339433Smckusick 60439433Smckusick /* 60539433Smckusick * Check to see if the new vnode represents a special device 60639433Smckusick * for which we already have a vnode (either because of 60739433Smckusick * bdevvp() or because of a different vnode representing 60839433Smckusick * the same block device). If such an alias exists, deallocate 60939509Smckusick * the existing contents and return the aliased vnode. The 61039433Smckusick * caller is responsible for filling it with its new contents. 61139433Smckusick */ 61239433Smckusick struct vnode * 61339615Smckusick checkalias(nvp, nvp_rdev, mp) 61439433Smckusick register struct vnode *nvp; 61539615Smckusick dev_t nvp_rdev; 61639433Smckusick struct mount *mp; 61739433Smckusick { 61839433Smckusick register struct vnode *vp; 61939615Smckusick struct vnode **vpp; 62039433Smckusick 62139433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 62241400Smckusick return (NULLVP); 62339615Smckusick 62439615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 62539433Smckusick loop: 62639615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 62739615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 62839433Smckusick continue; 62939615Smckusick /* 63039615Smckusick * Alias, but not in use, so flush it out. 63139615Smckusick */ 63239809Smckusick if (vp->v_usecount == 0) { 63339615Smckusick vgone(vp); 63439615Smckusick goto loop; 63539615Smckusick } 63639633Smckusick if (vget(vp)) 63739633Smckusick goto loop; 63839433Smckusick break; 63939433Smckusick } 64039615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 64139615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 64239615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 64339615Smckusick nvp->v_rdev = nvp_rdev; 64439809Smckusick nvp->v_hashchain = vpp; 64539615Smckusick nvp->v_specnext = *vpp; 64642152Smckusick nvp->v_specflags = 0; 64739615Smckusick *vpp = nvp; 64840640Smckusick if (vp != NULL) { 64940640Smckusick nvp->v_flag |= VALIASED; 65040640Smckusick vp->v_flag |= VALIASED; 65140640Smckusick vput(vp); 65240640Smckusick } 65341400Smckusick return (NULLVP); 65439433Smckusick } 65539484Smckusick VOP_UNLOCK(vp); 65639484Smckusick vclean(vp, 0); 65739433Smckusick vp->v_op = nvp->v_op; 65839433Smckusick vp->v_tag = nvp->v_tag; 65939433Smckusick nvp->v_type = VNON; 66039433Smckusick insmntque(vp, mp); 66139433Smckusick return (vp); 66239433Smckusick } 66339433Smckusick 66439433Smckusick /* 66539433Smckusick * Grab a particular vnode from the free list, increment its 66639433Smckusick * reference count and lock it. The vnode lock bit is set the 66739433Smckusick * vnode is being eliminated in vgone. The process is awakened 66839433Smckusick * when the transition is completed, and an error returned to 66939433Smckusick * indicate that the vnode is no longer usable (possibly having 67039433Smckusick * been changed to a new file system type). 67139433Smckusick */ 67239397Smckusick vget(vp) 67339397Smckusick register struct vnode *vp; 67439397Smckusick { 67539397Smckusick register struct vnode *vq; 67639397Smckusick 67739433Smckusick if (vp->v_flag & VXLOCK) { 67839433Smckusick vp->v_flag |= VXWANT; 67939433Smckusick sleep((caddr_t)vp, PINOD); 68039433Smckusick return (1); 68139433Smckusick } 68239809Smckusick if (vp->v_usecount == 0) { 68339433Smckusick if (vq = vp->v_freef) 68439433Smckusick vq->v_freeb = vp->v_freeb; 68539433Smckusick else 68639433Smckusick vfreet = vp->v_freeb; 68739433Smckusick *vp->v_freeb = vq; 68839433Smckusick vp->v_freef = NULL; 68939433Smckusick vp->v_freeb = NULL; 69039433Smckusick } 69139397Smckusick VREF(vp); 69239433Smckusick VOP_LOCK(vp); 69339433Smckusick return (0); 69439397Smckusick } 69539397Smckusick 69639397Smckusick /* 69739397Smckusick * Vnode reference, just increment the count 69839397Smckusick */ 69939397Smckusick void vref(vp) 70039397Smckusick struct vnode *vp; 70139397Smckusick { 70239397Smckusick 70339809Smckusick vp->v_usecount++; 70439397Smckusick } 70539397Smckusick 70639397Smckusick /* 70739397Smckusick * vput(), just unlock and vrele() 70839397Smckusick */ 70939397Smckusick void vput(vp) 71039397Smckusick register struct vnode *vp; 71139397Smckusick { 71239397Smckusick VOP_UNLOCK(vp); 71339397Smckusick vrele(vp); 71439397Smckusick } 71539397Smckusick 71639397Smckusick /* 71739397Smckusick * Vnode release. 71839397Smckusick * If count drops to zero, call inactive routine and return to freelist. 71939397Smckusick */ 72039397Smckusick void vrele(vp) 72139397Smckusick register struct vnode *vp; 72239397Smckusick { 72348024Smckusick struct proc *p = curproc; /* XXX */ 72439397Smckusick 72539397Smckusick if (vp == NULL) 72639433Smckusick panic("vrele: null vp"); 72739809Smckusick vp->v_usecount--; 72839809Smckusick if (vp->v_usecount < 0) 72939667Smckusick vprint("vrele: bad ref count", vp); 73039809Smckusick if (vp->v_usecount > 0) 73139397Smckusick return; 73241400Smckusick if (vfreeh == NULLVP) { 73339397Smckusick /* 73439397Smckusick * insert into empty list 73539397Smckusick */ 73639397Smckusick vfreeh = vp; 73739397Smckusick vp->v_freeb = &vfreeh; 73839397Smckusick } else { 73939397Smckusick /* 74039397Smckusick * insert at tail of list 74139397Smckusick */ 74239397Smckusick *vfreet = vp; 74339397Smckusick vp->v_freeb = vfreet; 74439397Smckusick } 74539433Smckusick vp->v_freef = NULL; 74639433Smckusick vfreet = &vp->v_freef; 74748024Smckusick VOP_INACTIVE(vp, p); 74839397Smckusick } 74939433Smckusick 75039433Smckusick /* 75139809Smckusick * Page or buffer structure gets a reference. 75239809Smckusick */ 75339809Smckusick vhold(vp) 75439809Smckusick register struct vnode *vp; 75539809Smckusick { 75639809Smckusick 75739809Smckusick vp->v_holdcnt++; 75839809Smckusick } 75939809Smckusick 76039809Smckusick /* 76139809Smckusick * Page or buffer structure frees a reference. 76239809Smckusick */ 76339809Smckusick holdrele(vp) 76439809Smckusick register struct vnode *vp; 76539809Smckusick { 76639809Smckusick 76739809Smckusick if (vp->v_holdcnt <= 0) 76839809Smckusick panic("holdrele: holdcnt"); 76939809Smckusick vp->v_holdcnt--; 77039809Smckusick } 77139809Smckusick 77239809Smckusick /* 77339509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 77439509Smckusick * 77539509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 77639509Smckusick * return error if any are found (nb: this is a user error, not a 77739509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 77839509Smckusick * that are found. 77939509Smckusick */ 78039509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 78139509Smckusick 78239509Smckusick vflush(mp, skipvp, flags) 78339509Smckusick struct mount *mp; 78439509Smckusick struct vnode *skipvp; 78539509Smckusick int flags; 78639509Smckusick { 78739509Smckusick register struct vnode *vp, *nvp; 78839509Smckusick int busy = 0; 78939509Smckusick 79041400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 79141300Smckusick panic("vflush: not busy"); 79241421Smckusick loop: 79341400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 79441421Smckusick if (vp->v_mount != mp) 79541421Smckusick goto loop; 79639509Smckusick nvp = vp->v_mountf; 79739509Smckusick /* 79839509Smckusick * Skip over a selected vnode. 79939509Smckusick */ 80039509Smckusick if (vp == skipvp) 80139509Smckusick continue; 80239509Smckusick /* 80341300Smckusick * Skip over a vnodes marked VSYSTEM. 80441300Smckusick */ 80541300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 80641300Smckusick continue; 80741300Smckusick /* 80839809Smckusick * With v_usecount == 0, all we need to do is clear 80939509Smckusick * out the vnode data structures and we are done. 81039509Smckusick */ 81139809Smckusick if (vp->v_usecount == 0) { 81239509Smckusick vgone(vp); 81339509Smckusick continue; 81439509Smckusick } 81539509Smckusick /* 81639509Smckusick * For block or character devices, revert to an 81739509Smckusick * anonymous device. For all other files, just kill them. 81839509Smckusick */ 81941300Smckusick if (flags & FORCECLOSE) { 82039509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 82139509Smckusick vgone(vp); 82239509Smckusick } else { 82339509Smckusick vclean(vp, 0); 82439509Smckusick vp->v_op = &spec_vnodeops; 82539509Smckusick insmntque(vp, (struct mount *)0); 82639509Smckusick } 82739509Smckusick continue; 82839509Smckusick } 82939509Smckusick if (busyprt) 83039667Smckusick vprint("vflush: busy vnode", vp); 83139509Smckusick busy++; 83239509Smckusick } 83339509Smckusick if (busy) 83439509Smckusick return (EBUSY); 83539509Smckusick return (0); 83639509Smckusick } 83739509Smckusick 83839509Smckusick /* 83939433Smckusick * Disassociate the underlying file system from a vnode. 84039433Smckusick */ 84141300Smckusick void vclean(vp, flags) 84239433Smckusick register struct vnode *vp; 84345118Smckusick int flags; 84439433Smckusick { 84539433Smckusick struct vnodeops *origops; 84639484Smckusick int active; 84748024Smckusick struct proc *p = curproc; /* XXX */ 84839433Smckusick 84939484Smckusick /* 85039484Smckusick * Check to see if the vnode is in use. 85139667Smckusick * If so we have to reference it before we clean it out 85239667Smckusick * so that its count cannot fall to zero and generate a 85339667Smckusick * race against ourselves to recycle it. 85439484Smckusick */ 85539809Smckusick if (active = vp->v_usecount) 85639484Smckusick VREF(vp); 85739484Smckusick /* 85839484Smckusick * Prevent the vnode from being recycled or 85939484Smckusick * brought into use while we clean it out. 86039484Smckusick */ 86139667Smckusick if (vp->v_flag & VXLOCK) 86239667Smckusick panic("vclean: deadlock"); 86339433Smckusick vp->v_flag |= VXLOCK; 86439433Smckusick /* 86539667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 86639667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 86739667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 86839667Smckusick * For active vnodes, it ensures that no other activity can 86939667Smckusick * occur while the buffer list is being cleaned out. 87039667Smckusick */ 87139667Smckusick VOP_LOCK(vp); 87241300Smckusick if (flags & DOCLOSE) 87339667Smckusick vinvalbuf(vp, 1); 87439667Smckusick /* 87539433Smckusick * Prevent any further operations on the vnode from 87639433Smckusick * being passed through to the old file system. 87739433Smckusick */ 87839433Smckusick origops = vp->v_op; 87939433Smckusick vp->v_op = &dead_vnodeops; 88039433Smckusick vp->v_tag = VT_NON; 88139433Smckusick /* 88239484Smckusick * If purging an active vnode, it must be unlocked, closed, 88339484Smckusick * and deactivated before being reclaimed. 88439433Smckusick */ 88539667Smckusick (*(origops->vn_unlock))(vp); 88639484Smckusick if (active) { 88741300Smckusick if (flags & DOCLOSE) 88848354Smckusick (*(origops->vn_close))(vp, IO_NDELAY, NOCRED, p); 88948024Smckusick (*(origops->vn_inactive))(vp, p); 89039433Smckusick } 89139433Smckusick /* 89239433Smckusick * Reclaim the vnode. 89339433Smckusick */ 89439433Smckusick if ((*(origops->vn_reclaim))(vp)) 89539433Smckusick panic("vclean: cannot reclaim"); 89639484Smckusick if (active) 89739484Smckusick vrele(vp); 89839433Smckusick /* 89939433Smckusick * Done with purge, notify sleepers in vget of the grim news. 90039433Smckusick */ 90139433Smckusick vp->v_flag &= ~VXLOCK; 90239433Smckusick if (vp->v_flag & VXWANT) { 90339433Smckusick vp->v_flag &= ~VXWANT; 90439433Smckusick wakeup((caddr_t)vp); 90539433Smckusick } 90639433Smckusick } 90739433Smckusick 90839433Smckusick /* 90939633Smckusick * Eliminate all activity associated with the requested vnode 91039633Smckusick * and with all vnodes aliased to the requested vnode. 91139633Smckusick */ 91239633Smckusick void vgoneall(vp) 91339633Smckusick register struct vnode *vp; 91439633Smckusick { 91539809Smckusick register struct vnode *vq; 91639633Smckusick 91740665Smckusick if (vp->v_flag & VALIASED) { 91840665Smckusick /* 91940665Smckusick * If a vgone (or vclean) is already in progress, 92040665Smckusick * wait until it is done and return. 92140665Smckusick */ 92240665Smckusick if (vp->v_flag & VXLOCK) { 92340665Smckusick vp->v_flag |= VXWANT; 92440665Smckusick sleep((caddr_t)vp, PINOD); 92540665Smckusick return; 92639633Smckusick } 92740665Smckusick /* 92840665Smckusick * Ensure that vp will not be vgone'd while we 92940665Smckusick * are eliminating its aliases. 93040665Smckusick */ 93140665Smckusick vp->v_flag |= VXLOCK; 93240665Smckusick while (vp->v_flag & VALIASED) { 93340665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 93440665Smckusick if (vq->v_rdev != vp->v_rdev || 93540665Smckusick vq->v_type != vp->v_type || vp == vq) 93640665Smckusick continue; 93740665Smckusick vgone(vq); 93840665Smckusick break; 93940665Smckusick } 94040665Smckusick } 94140665Smckusick /* 94240665Smckusick * Remove the lock so that vgone below will 94340665Smckusick * really eliminate the vnode after which time 94440665Smckusick * vgone will awaken any sleepers. 94540665Smckusick */ 94640665Smckusick vp->v_flag &= ~VXLOCK; 94739633Smckusick } 94839633Smckusick vgone(vp); 94939633Smckusick } 95039633Smckusick 95139633Smckusick /* 95239433Smckusick * Eliminate all activity associated with a vnode 95339433Smckusick * in preparation for reuse. 95439433Smckusick */ 95539433Smckusick void vgone(vp) 95639433Smckusick register struct vnode *vp; 95739433Smckusick { 95839809Smckusick register struct vnode *vq; 95939615Smckusick struct vnode *vx; 96039615Smckusick long count; 96139433Smckusick 96239433Smckusick /* 96340548Smckusick * If a vgone (or vclean) is already in progress, 96440548Smckusick * wait until it is done and return. 96540548Smckusick */ 96640548Smckusick if (vp->v_flag & VXLOCK) { 96740548Smckusick vp->v_flag |= VXWANT; 96840548Smckusick sleep((caddr_t)vp, PINOD); 96940548Smckusick return; 97040548Smckusick } 97140548Smckusick /* 97239433Smckusick * Clean out the filesystem specific data. 97339433Smckusick */ 97441300Smckusick vclean(vp, DOCLOSE); 97539433Smckusick /* 97639433Smckusick * Delete from old mount point vnode list, if on one. 97739433Smckusick */ 97839433Smckusick if (vp->v_mountb) { 97939433Smckusick if (vq = vp->v_mountf) 98039433Smckusick vq->v_mountb = vp->v_mountb; 98139433Smckusick *vp->v_mountb = vq; 98239433Smckusick vp->v_mountf = NULL; 98339433Smckusick vp->v_mountb = NULL; 98439433Smckusick } 98539433Smckusick /* 98639433Smckusick * If special device, remove it from special device alias list. 98739433Smckusick */ 98839433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 98939809Smckusick if (*vp->v_hashchain == vp) { 99039809Smckusick *vp->v_hashchain = vp->v_specnext; 99139433Smckusick } else { 99239809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 99339615Smckusick if (vq->v_specnext != vp) 99439433Smckusick continue; 99539615Smckusick vq->v_specnext = vp->v_specnext; 99639433Smckusick break; 99739433Smckusick } 99839615Smckusick if (vq == NULL) 99939433Smckusick panic("missing bdev"); 100039433Smckusick } 100139615Smckusick if (vp->v_flag & VALIASED) { 100239809Smckusick count = 0; 100339809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 100440108Smckusick if (vq->v_rdev != vp->v_rdev || 100540108Smckusick vq->v_type != vp->v_type) 100639615Smckusick continue; 100739615Smckusick count++; 100839615Smckusick vx = vq; 100939615Smckusick } 101039615Smckusick if (count == 0) 101139615Smckusick panic("missing alias"); 101239615Smckusick if (count == 1) 101339615Smckusick vx->v_flag &= ~VALIASED; 101439615Smckusick vp->v_flag &= ~VALIASED; 101539615Smckusick } 101639615Smckusick FREE(vp->v_specinfo, M_VNODE); 101739615Smckusick vp->v_specinfo = NULL; 101839433Smckusick } 101939433Smckusick /* 102039433Smckusick * If it is on the freelist, move it to the head of the list. 102139433Smckusick */ 102239433Smckusick if (vp->v_freeb) { 102339433Smckusick if (vq = vp->v_freef) 102439433Smckusick vq->v_freeb = vp->v_freeb; 102539433Smckusick else 102639433Smckusick vfreet = vp->v_freeb; 102739433Smckusick *vp->v_freeb = vq; 102839433Smckusick vp->v_freef = vfreeh; 102939433Smckusick vp->v_freeb = &vfreeh; 103039433Smckusick vfreeh->v_freeb = &vp->v_freef; 103139433Smckusick vfreeh = vp; 103239433Smckusick } 103339484Smckusick vp->v_type = VBAD; 103439433Smckusick } 103539633Smckusick 103639633Smckusick /* 103739821Smckusick * Lookup a vnode by device number. 103839821Smckusick */ 103939821Smckusick vfinddev(dev, type, vpp) 104039821Smckusick dev_t dev; 104139821Smckusick enum vtype type; 104239821Smckusick struct vnode **vpp; 104339821Smckusick { 104439821Smckusick register struct vnode *vp; 104539821Smckusick 104639821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 104739821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 104839821Smckusick continue; 104939821Smckusick *vpp = vp; 105039821Smckusick return (0); 105139821Smckusick } 105239821Smckusick return (1); 105339821Smckusick } 105439821Smckusick 105539821Smckusick /* 105639633Smckusick * Calculate the total number of references to a special device. 105739633Smckusick */ 105839633Smckusick vcount(vp) 105939633Smckusick register struct vnode *vp; 106039633Smckusick { 106139809Smckusick register struct vnode *vq; 106239633Smckusick int count; 106339633Smckusick 106439633Smckusick if ((vp->v_flag & VALIASED) == 0) 106539809Smckusick return (vp->v_usecount); 106639633Smckusick loop: 106739809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 106840108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 106939633Smckusick continue; 107039633Smckusick /* 107139633Smckusick * Alias, but not in use, so flush it out. 107239633Smckusick */ 107339809Smckusick if (vq->v_usecount == 0) { 107439633Smckusick vgone(vq); 107539633Smckusick goto loop; 107639633Smckusick } 107739809Smckusick count += vq->v_usecount; 107839633Smckusick } 107939633Smckusick return (count); 108039633Smckusick } 108139667Smckusick 108239667Smckusick /* 108339667Smckusick * Print out a description of a vnode. 108439667Smckusick */ 108539667Smckusick static char *typename[] = 108640286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 108739667Smckusick 108839667Smckusick vprint(label, vp) 108939667Smckusick char *label; 109039667Smckusick register struct vnode *vp; 109139667Smckusick { 109239913Smckusick char buf[64]; 109339667Smckusick 109439667Smckusick if (label != NULL) 109539667Smckusick printf("%s: ", label); 109639913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 109739809Smckusick vp->v_usecount, vp->v_holdcnt); 109839913Smckusick buf[0] = '\0'; 109939913Smckusick if (vp->v_flag & VROOT) 110039913Smckusick strcat(buf, "|VROOT"); 110139913Smckusick if (vp->v_flag & VTEXT) 110239913Smckusick strcat(buf, "|VTEXT"); 110341300Smckusick if (vp->v_flag & VSYSTEM) 110441300Smckusick strcat(buf, "|VSYSTEM"); 110541300Smckusick if (vp->v_flag & VXLOCK) 110641300Smckusick strcat(buf, "|VXLOCK"); 110741300Smckusick if (vp->v_flag & VXWANT) 110841300Smckusick strcat(buf, "|VXWANT"); 110941300Smckusick if (vp->v_flag & VBWAIT) 111041300Smckusick strcat(buf, "|VBWAIT"); 111139913Smckusick if (vp->v_flag & VALIASED) 111239913Smckusick strcat(buf, "|VALIASED"); 111339913Smckusick if (buf[0] != '\0') 111439913Smckusick printf(" flags (%s)", &buf[1]); 111539913Smckusick printf("\n\t"); 111639667Smckusick VOP_PRINT(vp); 111739667Smckusick } 111841110Smarc 111941110Smarc int kinfo_vdebug = 1; 112041110Smarc int kinfo_vgetfailed; 112141110Smarc #define KINFO_VNODESLOP 10 112241110Smarc /* 112341110Smarc * Dump vnode list (via kinfo). 112441110Smarc * Copyout address of vnode followed by vnode. 112541110Smarc */ 112645118Smckusick /* ARGSUSED */ 112741110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 112845118Smckusick int op; 112941110Smarc char *where; 113045118Smckusick int *acopysize, arg, *aneeded; 113141110Smarc { 113241110Smarc register struct mount *mp = rootfs; 113341300Smckusick struct mount *omp; 113441110Smarc struct vnode *vp; 113541110Smarc register char *bp = where, *savebp; 113641110Smarc char *ewhere = where + *acopysize; 113741110Smarc int error; 113841110Smarc 113941110Smarc #define VPTRSZ sizeof (struct vnode *) 114041110Smarc #define VNODESZ sizeof (struct vnode) 114141110Smarc if (where == NULL) { 114241110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 114341110Smarc return (0); 114441110Smarc } 114541110Smarc 114641110Smarc do { 114741300Smckusick if (vfs_busy(mp)) { 114841400Smckusick mp = mp->mnt_next; 114941300Smckusick continue; 115041300Smckusick } 115141110Smarc savebp = bp; 115241110Smarc again: 115341421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 115441422Smckusick /* 115541422Smckusick * Check that the vp is still associated with 115641422Smckusick * this filesystem. RACE: could have been 115741422Smckusick * recycled onto the same filesystem. 115841422Smckusick */ 115941421Smckusick if (vp->v_mount != mp) { 116041421Smckusick if (kinfo_vdebug) 116141421Smckusick printf("kinfo: vp changed\n"); 116241421Smckusick bp = savebp; 116341421Smckusick goto again; 116441421Smckusick } 116541110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 116641110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 116741110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 116841422Smckusick VNODESZ)))) 116941110Smarc return (error); 117041110Smarc bp += VPTRSZ + VNODESZ; 117141110Smarc } 117241300Smckusick omp = mp; 117341400Smckusick mp = mp->mnt_next; 117441300Smckusick vfs_unbusy(omp); 117541110Smarc } while (mp != rootfs); 117641110Smarc 117741110Smarc *aneeded = bp - where; 117841110Smarc if (bp > ewhere) 117941110Smarc *acopysize = ewhere - where; 118041110Smarc else 118141110Smarc *acopysize = bp - where; 118241110Smarc return (0); 118341110Smarc } 1184