137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 5*44458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*44458Sbostic * @(#)vfs_subr.c 7.47 (Berkeley) 06/28/90 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1437488Smckusick #include "param.h" 1537488Smckusick #include "mount.h" 1637488Smckusick #include "time.h" 1737488Smckusick #include "vnode.h" 1840652Smckusick #include "specdev.h" 1938265Smckusick #include "namei.h" 2038265Smckusick #include "ucred.h" 2137488Smckusick #include "errno.h" 2239433Smckusick #include "malloc.h" 2337488Smckusick 2437488Smckusick /* 2537488Smckusick * Remove a mount point from the list of mounted filesystems. 2637488Smckusick * Unmount of the root is illegal. 2737488Smckusick */ 2837488Smckusick void 2937488Smckusick vfs_remove(mp) 3037488Smckusick register struct mount *mp; 3137488Smckusick { 3237488Smckusick 3337488Smckusick if (mp == rootfs) 3437488Smckusick panic("vfs_remove: unmounting root"); 3541400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 3641400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 3741400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 3837488Smckusick vfs_unlock(mp); 3937488Smckusick } 4037488Smckusick 4137488Smckusick /* 4237488Smckusick * Lock a filesystem. 4337488Smckusick * Used to prevent access to it while mounting and unmounting. 4437488Smckusick */ 4537488Smckusick vfs_lock(mp) 4637488Smckusick register struct mount *mp; 4737488Smckusick { 4837488Smckusick 4941400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 5041400Smckusick mp->mnt_flag |= MNT_MWAIT; 5139045Smckusick sleep((caddr_t)mp, PVFS); 5239045Smckusick } 5341400Smckusick mp->mnt_flag |= MNT_MLOCK; 5437488Smckusick return (0); 5537488Smckusick } 5637488Smckusick 5737488Smckusick /* 5837488Smckusick * Unlock a locked filesystem. 5937488Smckusick * Panic if filesystem is not locked. 6037488Smckusick */ 6137488Smckusick void 6237488Smckusick vfs_unlock(mp) 6337488Smckusick register struct mount *mp; 6437488Smckusick { 6537488Smckusick 6641400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 6741300Smckusick panic("vfs_unlock: not locked"); 6841400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 6941400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 7041400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 7137488Smckusick wakeup((caddr_t)mp); 7237488Smckusick } 7337488Smckusick } 7437488Smckusick 7537488Smckusick /* 7641300Smckusick * Mark a mount point as busy. 7741300Smckusick * Used to synchronize access and to delay unmounting. 7841300Smckusick */ 7941300Smckusick vfs_busy(mp) 8041300Smckusick register struct mount *mp; 8141300Smckusick { 8241300Smckusick 8341400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 8441400Smckusick mp->mnt_flag |= MNT_MPWANT; 8541400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 8641300Smckusick } 8741419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 8841419Smckusick return (1); 8941400Smckusick mp->mnt_flag |= MNT_MPBUSY; 9041300Smckusick return (0); 9141300Smckusick } 9241300Smckusick 9341300Smckusick /* 9441300Smckusick * Free a busy filesystem. 9541300Smckusick * Panic if filesystem is not busy. 9641300Smckusick */ 9741300Smckusick void 9841300Smckusick vfs_unbusy(mp) 9941300Smckusick register struct mount *mp; 10041300Smckusick { 10141300Smckusick 10241400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 10341300Smckusick panic("vfs_unbusy: not busy"); 10441400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 10541400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 10641400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 10741400Smckusick wakeup((caddr_t)&mp->mnt_flag); 10841300Smckusick } 10941300Smckusick } 11041300Smckusick 11141300Smckusick /* 11237488Smckusick * Lookup a mount point by filesystem identifier. 11337488Smckusick */ 11437488Smckusick struct mount * 11537488Smckusick getvfs(fsid) 11637488Smckusick fsid_t *fsid; 11737488Smckusick { 11837488Smckusick register struct mount *mp; 11937488Smckusick 12038288Smckusick mp = rootfs; 12138288Smckusick do { 12241400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 12341400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 12438288Smckusick return (mp); 12537488Smckusick } 12641400Smckusick mp = mp->mnt_next; 12738288Smckusick } while (mp != rootfs); 12838288Smckusick return ((struct mount *)0); 12937488Smckusick } 13037488Smckusick 13137488Smckusick /* 13237488Smckusick * Set vnode attributes to VNOVAL 13337488Smckusick */ 13437488Smckusick void vattr_null(vap) 13537488Smckusick register struct vattr *vap; 13637488Smckusick { 13737488Smckusick 13837488Smckusick vap->va_type = VNON; 13937488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 14037488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 14140643Smckusick vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 14240643Smckusick vap->va_bytes = vap->va_bytes_rsv = 14337488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 14437488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 14538258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 14638258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 14737488Smckusick } 14838265Smckusick 14938265Smckusick /* 15038265Smckusick * Initialize a nameidata structure 15138265Smckusick */ 15238265Smckusick ndinit(ndp) 15338265Smckusick register struct nameidata *ndp; 15438265Smckusick { 15538265Smckusick 15638265Smckusick bzero((caddr_t)ndp, sizeof(struct nameidata)); 15738265Smckusick ndp->ni_iov = &ndp->ni_nd.nd_iovec; 15838265Smckusick ndp->ni_iovcnt = 1; 15938265Smckusick ndp->ni_base = (caddr_t)&ndp->ni_dent; 16038265Smckusick ndp->ni_rw = UIO_WRITE; 16139736Smckusick ndp->ni_uioseg = UIO_SYSSPACE; 16238265Smckusick } 16338265Smckusick 16438265Smckusick /* 16538265Smckusick * Duplicate a nameidata structure 16638265Smckusick */ 16738265Smckusick nddup(ndp, newndp) 16838265Smckusick register struct nameidata *ndp, *newndp; 16938265Smckusick { 17038265Smckusick 17138265Smckusick ndinit(newndp); 17238265Smckusick newndp->ni_cdir = ndp->ni_cdir; 17338348Smckusick VREF(newndp->ni_cdir); 17438265Smckusick newndp->ni_rdir = ndp->ni_rdir; 17538265Smckusick if (newndp->ni_rdir) 17638348Smckusick VREF(newndp->ni_rdir); 17738265Smckusick newndp->ni_cred = ndp->ni_cred; 17838265Smckusick crhold(newndp->ni_cred); 17938265Smckusick } 18038265Smckusick 18138265Smckusick /* 18238265Smckusick * Release a nameidata structure 18338265Smckusick */ 18438265Smckusick ndrele(ndp) 18538265Smckusick register struct nameidata *ndp; 18638265Smckusick { 18738265Smckusick 18838265Smckusick vrele(ndp->ni_cdir); 18938265Smckusick if (ndp->ni_rdir) 19038265Smckusick vrele(ndp->ni_rdir); 19138265Smckusick crfree(ndp->ni_cred); 19238265Smckusick } 19339397Smckusick 19439397Smckusick /* 19539397Smckusick * Routines having to do with the management of the vnode table. 19639397Smckusick */ 19739397Smckusick struct vnode *vfreeh, **vfreet; 19839447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 19939635Smckusick extern void vclean(); 20040883Smckusick long numvnodes; 20141363Smckusick struct vattr va_null; 20239397Smckusick 20339397Smckusick /* 20439433Smckusick * Initialize the vnode structures and initialize each file system type. 20539397Smckusick */ 20639433Smckusick vfsinit() 20739397Smckusick { 20839433Smckusick struct vfsops **vfsp; 20939397Smckusick 21039433Smckusick /* 21139433Smckusick * Initialize the vnode name cache 21239433Smckusick */ 21339433Smckusick nchinit(); 21439433Smckusick /* 21539433Smckusick * Initialize each file system type. 21639433Smckusick */ 21741363Smckusick vattr_null(&va_null); 21839433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 21939433Smckusick if (*vfsp == NULL) 22039433Smckusick continue; 22139433Smckusick (*(*vfsp)->vfs_init)(); 22239433Smckusick } 22339397Smckusick } 22439397Smckusick 22539397Smckusick /* 22639397Smckusick * Return the next vnode from the free list. 22739397Smckusick */ 22839397Smckusick getnewvnode(tag, mp, vops, vpp) 22939397Smckusick enum vtagtype tag; 23039397Smckusick struct mount *mp; 23139397Smckusick struct vnodeops *vops; 23239397Smckusick struct vnode **vpp; 23339397Smckusick { 23439397Smckusick register struct vnode *vp, *vq; 23539397Smckusick 23640883Smckusick if (numvnodes < desiredvnodes) { 23740883Smckusick vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK); 23840883Smckusick bzero((char *)vp, sizeof *vp); 23940883Smckusick numvnodes++; 24040883Smckusick } else { 24140883Smckusick if ((vp = vfreeh) == NULL) { 24240883Smckusick tablefull("vnode"); 24340883Smckusick *vpp = 0; 24440883Smckusick return (ENFILE); 24540883Smckusick } 24640883Smckusick if (vp->v_usecount) 24740883Smckusick panic("free vnode isn't"); 24840883Smckusick if (vq = vp->v_freef) 24940883Smckusick vq->v_freeb = &vfreeh; 25040883Smckusick else 25140883Smckusick vfreet = &vfreeh; 25240883Smckusick vfreeh = vq; 25340883Smckusick vp->v_freef = NULL; 25440883Smckusick vp->v_freeb = NULL; 25540883Smckusick if (vp->v_type != VBAD) 25640883Smckusick vgone(vp); 25740883Smckusick vp->v_flag = 0; 25840883Smckusick vp->v_shlockc = 0; 25940883Smckusick vp->v_exlockc = 0; 26040883Smckusick vp->v_lastr = 0; 26140883Smckusick vp->v_socket = 0; 26239397Smckusick } 26339512Smckusick vp->v_type = VNON; 26439397Smckusick cache_purge(vp); 26539397Smckusick vp->v_tag = tag; 26639433Smckusick vp->v_op = vops; 26739397Smckusick insmntque(vp, mp); 26839397Smckusick VREF(vp); 26939397Smckusick *vpp = vp; 27039397Smckusick return (0); 27139397Smckusick } 27239397Smckusick 27339397Smckusick /* 27439397Smckusick * Move a vnode from one mount queue to another. 27539397Smckusick */ 27639397Smckusick insmntque(vp, mp) 27739397Smckusick register struct vnode *vp; 27839397Smckusick register struct mount *mp; 27939397Smckusick { 28039397Smckusick struct vnode *vq; 28139397Smckusick 28239397Smckusick /* 28339397Smckusick * Delete from old mount point vnode list, if on one. 28439397Smckusick */ 28539397Smckusick if (vp->v_mountb) { 28639397Smckusick if (vq = vp->v_mountf) 28739397Smckusick vq->v_mountb = vp->v_mountb; 28839397Smckusick *vp->v_mountb = vq; 28939397Smckusick } 29039397Smckusick /* 29139397Smckusick * Insert into list of vnodes for the new mount point, if available. 29239397Smckusick */ 29339621Smckusick vp->v_mount = mp; 29439397Smckusick if (mp == NULL) { 29539397Smckusick vp->v_mountf = NULL; 29639397Smckusick vp->v_mountb = NULL; 29739397Smckusick return; 29839397Smckusick } 29941400Smckusick if (mp->mnt_mounth) { 30041400Smckusick vp->v_mountf = mp->mnt_mounth; 30141400Smckusick vp->v_mountb = &mp->mnt_mounth; 30241400Smckusick mp->mnt_mounth->v_mountb = &vp->v_mountf; 30341400Smckusick mp->mnt_mounth = vp; 30439397Smckusick } else { 30541400Smckusick mp->mnt_mounth = vp; 30641400Smckusick vp->v_mountb = &mp->mnt_mounth; 30739397Smckusick vp->v_mountf = NULL; 30839397Smckusick } 30939397Smckusick } 31039397Smckusick 31139397Smckusick /* 31239433Smckusick * Create a vnode for a block device. 31339433Smckusick * Used for root filesystem, argdev, and swap areas. 31439433Smckusick * Also used for memory file system special devices. 31539397Smckusick */ 31639433Smckusick bdevvp(dev, vpp) 31739433Smckusick dev_t dev; 31839433Smckusick struct vnode **vpp; 31939433Smckusick { 32039433Smckusick register struct vnode *vp; 32139433Smckusick struct vnode *nvp; 32239433Smckusick int error; 32339433Smckusick 32439447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 32539433Smckusick if (error) { 32639433Smckusick *vpp = 0; 32739433Smckusick return (error); 32839433Smckusick } 32939433Smckusick vp = nvp; 33039433Smckusick vp->v_type = VBLK; 33139615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 33239433Smckusick vput(vp); 33339433Smckusick vp = nvp; 33439433Smckusick } 33539433Smckusick *vpp = vp; 33639433Smckusick return (0); 33739433Smckusick } 33839433Smckusick 33939433Smckusick /* 34039433Smckusick * Check to see if the new vnode represents a special device 34139433Smckusick * for which we already have a vnode (either because of 34239433Smckusick * bdevvp() or because of a different vnode representing 34339433Smckusick * the same block device). If such an alias exists, deallocate 34439509Smckusick * the existing contents and return the aliased vnode. The 34539433Smckusick * caller is responsible for filling it with its new contents. 34639433Smckusick */ 34739433Smckusick struct vnode * 34839615Smckusick checkalias(nvp, nvp_rdev, mp) 34939433Smckusick register struct vnode *nvp; 35039615Smckusick dev_t nvp_rdev; 35139433Smckusick struct mount *mp; 35239433Smckusick { 35339433Smckusick register struct vnode *vp; 35439615Smckusick struct vnode **vpp; 35539433Smckusick 35639433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 35741400Smckusick return (NULLVP); 35839615Smckusick 35939615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 36039433Smckusick loop: 36139615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 36239615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 36339433Smckusick continue; 36439615Smckusick /* 36539615Smckusick * Alias, but not in use, so flush it out. 36639615Smckusick */ 36739809Smckusick if (vp->v_usecount == 0) { 36839615Smckusick vgone(vp); 36939615Smckusick goto loop; 37039615Smckusick } 37139633Smckusick if (vget(vp)) 37239633Smckusick goto loop; 37339433Smckusick break; 37439433Smckusick } 37539615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 37639615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 37739615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 37839615Smckusick nvp->v_rdev = nvp_rdev; 37939809Smckusick nvp->v_hashchain = vpp; 38039615Smckusick nvp->v_specnext = *vpp; 38142152Smckusick nvp->v_specflags = 0; 38239615Smckusick *vpp = nvp; 38340640Smckusick if (vp != NULL) { 38440640Smckusick nvp->v_flag |= VALIASED; 38540640Smckusick vp->v_flag |= VALIASED; 38640640Smckusick vput(vp); 38740640Smckusick } 38841400Smckusick return (NULLVP); 38939433Smckusick } 39039484Smckusick VOP_UNLOCK(vp); 39139484Smckusick vclean(vp, 0); 39239433Smckusick vp->v_op = nvp->v_op; 39339433Smckusick vp->v_tag = nvp->v_tag; 39439433Smckusick nvp->v_type = VNON; 39539433Smckusick insmntque(vp, mp); 39639433Smckusick return (vp); 39739433Smckusick } 39839433Smckusick 39939433Smckusick /* 40039433Smckusick * Grab a particular vnode from the free list, increment its 40139433Smckusick * reference count and lock it. The vnode lock bit is set the 40239433Smckusick * vnode is being eliminated in vgone. The process is awakened 40339433Smckusick * when the transition is completed, and an error returned to 40439433Smckusick * indicate that the vnode is no longer usable (possibly having 40539433Smckusick * been changed to a new file system type). 40639433Smckusick */ 40739397Smckusick vget(vp) 40839397Smckusick register struct vnode *vp; 40939397Smckusick { 41039397Smckusick register struct vnode *vq; 41139397Smckusick 41239433Smckusick if (vp->v_flag & VXLOCK) { 41339433Smckusick vp->v_flag |= VXWANT; 41439433Smckusick sleep((caddr_t)vp, PINOD); 41539433Smckusick return (1); 41639433Smckusick } 41739809Smckusick if (vp->v_usecount == 0) { 41839433Smckusick if (vq = vp->v_freef) 41939433Smckusick vq->v_freeb = vp->v_freeb; 42039433Smckusick else 42139433Smckusick vfreet = vp->v_freeb; 42239433Smckusick *vp->v_freeb = vq; 42339433Smckusick vp->v_freef = NULL; 42439433Smckusick vp->v_freeb = NULL; 42539433Smckusick } 42639397Smckusick VREF(vp); 42739433Smckusick VOP_LOCK(vp); 42839433Smckusick return (0); 42939397Smckusick } 43039397Smckusick 43139397Smckusick /* 43239397Smckusick * Vnode reference, just increment the count 43339397Smckusick */ 43439397Smckusick void vref(vp) 43539397Smckusick struct vnode *vp; 43639397Smckusick { 43739397Smckusick 43839809Smckusick vp->v_usecount++; 43939397Smckusick } 44039397Smckusick 44139397Smckusick /* 44239397Smckusick * vput(), just unlock and vrele() 44339397Smckusick */ 44439397Smckusick void vput(vp) 44539397Smckusick register struct vnode *vp; 44639397Smckusick { 44739397Smckusick VOP_UNLOCK(vp); 44839397Smckusick vrele(vp); 44939397Smckusick } 45039397Smckusick 45139397Smckusick /* 45239397Smckusick * Vnode release. 45339397Smckusick * If count drops to zero, call inactive routine and return to freelist. 45439397Smckusick */ 45539397Smckusick void vrele(vp) 45639397Smckusick register struct vnode *vp; 45739397Smckusick { 45839397Smckusick 45939397Smckusick if (vp == NULL) 46039433Smckusick panic("vrele: null vp"); 46139809Smckusick vp->v_usecount--; 46239809Smckusick if (vp->v_usecount < 0) 46339667Smckusick vprint("vrele: bad ref count", vp); 46439809Smckusick if (vp->v_usecount > 0) 46539397Smckusick return; 46641400Smckusick if (vfreeh == NULLVP) { 46739397Smckusick /* 46839397Smckusick * insert into empty list 46939397Smckusick */ 47039397Smckusick vfreeh = vp; 47139397Smckusick vp->v_freeb = &vfreeh; 47239397Smckusick } else { 47339397Smckusick /* 47439397Smckusick * insert at tail of list 47539397Smckusick */ 47639397Smckusick *vfreet = vp; 47739397Smckusick vp->v_freeb = vfreet; 47839397Smckusick } 47939433Smckusick vp->v_freef = NULL; 48039433Smckusick vfreet = &vp->v_freef; 48139433Smckusick VOP_INACTIVE(vp); 48239397Smckusick } 48339433Smckusick 48439433Smckusick /* 48539809Smckusick * Page or buffer structure gets a reference. 48639809Smckusick */ 48739809Smckusick vhold(vp) 48839809Smckusick register struct vnode *vp; 48939809Smckusick { 49039809Smckusick 49139809Smckusick vp->v_holdcnt++; 49239809Smckusick } 49339809Smckusick 49439809Smckusick /* 49539809Smckusick * Page or buffer structure frees a reference. 49639809Smckusick */ 49739809Smckusick holdrele(vp) 49839809Smckusick register struct vnode *vp; 49939809Smckusick { 50039809Smckusick 50139809Smckusick if (vp->v_holdcnt <= 0) 50239809Smckusick panic("holdrele: holdcnt"); 50339809Smckusick vp->v_holdcnt--; 50439809Smckusick } 50539809Smckusick 50639809Smckusick /* 50739509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 50839509Smckusick * 50939509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 51039509Smckusick * return error if any are found (nb: this is a user error, not a 51139509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 51239509Smckusick * that are found. 51339509Smckusick */ 51439509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 51539509Smckusick 51639509Smckusick vflush(mp, skipvp, flags) 51739509Smckusick struct mount *mp; 51839509Smckusick struct vnode *skipvp; 51939509Smckusick int flags; 52039509Smckusick { 52139509Smckusick register struct vnode *vp, *nvp; 52239509Smckusick int busy = 0; 52339509Smckusick 52441400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 52541300Smckusick panic("vflush: not busy"); 52641421Smckusick loop: 52741400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 52841421Smckusick if (vp->v_mount != mp) 52941421Smckusick goto loop; 53039509Smckusick nvp = vp->v_mountf; 53139509Smckusick /* 53239509Smckusick * Skip over a selected vnode. 53339509Smckusick */ 53439509Smckusick if (vp == skipvp) 53539509Smckusick continue; 53639509Smckusick /* 53741300Smckusick * Skip over a vnodes marked VSYSTEM. 53841300Smckusick */ 53941300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 54041300Smckusick continue; 54141300Smckusick /* 54239809Smckusick * With v_usecount == 0, all we need to do is clear 54339509Smckusick * out the vnode data structures and we are done. 54439509Smckusick */ 54539809Smckusick if (vp->v_usecount == 0) { 54639509Smckusick vgone(vp); 54739509Smckusick continue; 54839509Smckusick } 54939509Smckusick /* 55039509Smckusick * For block or character devices, revert to an 55139509Smckusick * anonymous device. For all other files, just kill them. 55239509Smckusick */ 55341300Smckusick if (flags & FORCECLOSE) { 55439509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 55539509Smckusick vgone(vp); 55639509Smckusick } else { 55739509Smckusick vclean(vp, 0); 55839509Smckusick vp->v_op = &spec_vnodeops; 55939509Smckusick insmntque(vp, (struct mount *)0); 56039509Smckusick } 56139509Smckusick continue; 56239509Smckusick } 56339509Smckusick if (busyprt) 56439667Smckusick vprint("vflush: busy vnode", vp); 56539509Smckusick busy++; 56639509Smckusick } 56739509Smckusick if (busy) 56839509Smckusick return (EBUSY); 56939509Smckusick return (0); 57039509Smckusick } 57139509Smckusick 57239509Smckusick /* 57339433Smckusick * Disassociate the underlying file system from a vnode. 57439433Smckusick */ 57541300Smckusick void vclean(vp, flags) 57639433Smckusick register struct vnode *vp; 57741300Smckusick long flags; 57839433Smckusick { 57939433Smckusick struct vnodeops *origops; 58039484Smckusick int active; 58139433Smckusick 58239484Smckusick /* 58339484Smckusick * Check to see if the vnode is in use. 58439667Smckusick * If so we have to reference it before we clean it out 58539667Smckusick * so that its count cannot fall to zero and generate a 58639667Smckusick * race against ourselves to recycle it. 58739484Smckusick */ 58839809Smckusick if (active = vp->v_usecount) 58939484Smckusick VREF(vp); 59039484Smckusick /* 59139484Smckusick * Prevent the vnode from being recycled or 59239484Smckusick * brought into use while we clean it out. 59339484Smckusick */ 59439667Smckusick if (vp->v_flag & VXLOCK) 59539667Smckusick panic("vclean: deadlock"); 59639433Smckusick vp->v_flag |= VXLOCK; 59739433Smckusick /* 59839667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 59939667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 60039667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 60139667Smckusick * For active vnodes, it ensures that no other activity can 60239667Smckusick * occur while the buffer list is being cleaned out. 60339667Smckusick */ 60439667Smckusick VOP_LOCK(vp); 60541300Smckusick if (flags & DOCLOSE) 60639667Smckusick vinvalbuf(vp, 1); 60739667Smckusick /* 60839433Smckusick * Prevent any further operations on the vnode from 60939433Smckusick * being passed through to the old file system. 61039433Smckusick */ 61139433Smckusick origops = vp->v_op; 61239433Smckusick vp->v_op = &dead_vnodeops; 61339433Smckusick vp->v_tag = VT_NON; 61439433Smckusick /* 61539484Smckusick * If purging an active vnode, it must be unlocked, closed, 61639484Smckusick * and deactivated before being reclaimed. 61739433Smckusick */ 61839667Smckusick (*(origops->vn_unlock))(vp); 61939484Smckusick if (active) { 62041300Smckusick if (flags & DOCLOSE) 62139484Smckusick (*(origops->vn_close))(vp, 0, NOCRED); 62239433Smckusick (*(origops->vn_inactive))(vp); 62339433Smckusick } 62439433Smckusick /* 62539433Smckusick * Reclaim the vnode. 62639433Smckusick */ 62739433Smckusick if ((*(origops->vn_reclaim))(vp)) 62839433Smckusick panic("vclean: cannot reclaim"); 62939484Smckusick if (active) 63039484Smckusick vrele(vp); 63139433Smckusick /* 63239433Smckusick * Done with purge, notify sleepers in vget of the grim news. 63339433Smckusick */ 63439433Smckusick vp->v_flag &= ~VXLOCK; 63539433Smckusick if (vp->v_flag & VXWANT) { 63639433Smckusick vp->v_flag &= ~VXWANT; 63739433Smckusick wakeup((caddr_t)vp); 63839433Smckusick } 63939433Smckusick } 64039433Smckusick 64139433Smckusick /* 64239633Smckusick * Eliminate all activity associated with the requested vnode 64339633Smckusick * and with all vnodes aliased to the requested vnode. 64439633Smckusick */ 64539633Smckusick void vgoneall(vp) 64639633Smckusick register struct vnode *vp; 64739633Smckusick { 64839809Smckusick register struct vnode *vq; 64939633Smckusick 65040665Smckusick if (vp->v_flag & VALIASED) { 65140665Smckusick /* 65240665Smckusick * If a vgone (or vclean) is already in progress, 65340665Smckusick * wait until it is done and return. 65440665Smckusick */ 65540665Smckusick if (vp->v_flag & VXLOCK) { 65640665Smckusick vp->v_flag |= VXWANT; 65740665Smckusick sleep((caddr_t)vp, PINOD); 65840665Smckusick return; 65939633Smckusick } 66040665Smckusick /* 66140665Smckusick * Ensure that vp will not be vgone'd while we 66240665Smckusick * are eliminating its aliases. 66340665Smckusick */ 66440665Smckusick vp->v_flag |= VXLOCK; 66540665Smckusick while (vp->v_flag & VALIASED) { 66640665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 66740665Smckusick if (vq->v_rdev != vp->v_rdev || 66840665Smckusick vq->v_type != vp->v_type || vp == vq) 66940665Smckusick continue; 67040665Smckusick vgone(vq); 67140665Smckusick break; 67240665Smckusick } 67340665Smckusick } 67440665Smckusick /* 67540665Smckusick * Remove the lock so that vgone below will 67640665Smckusick * really eliminate the vnode after which time 67740665Smckusick * vgone will awaken any sleepers. 67840665Smckusick */ 67940665Smckusick vp->v_flag &= ~VXLOCK; 68039633Smckusick } 68139633Smckusick vgone(vp); 68239633Smckusick } 68339633Smckusick 68439633Smckusick /* 68539433Smckusick * Eliminate all activity associated with a vnode 68639433Smckusick * in preparation for reuse. 68739433Smckusick */ 68839433Smckusick void vgone(vp) 68939433Smckusick register struct vnode *vp; 69039433Smckusick { 69139809Smckusick register struct vnode *vq; 69239615Smckusick struct vnode *vx; 69339615Smckusick long count; 69439433Smckusick 69539433Smckusick /* 69640548Smckusick * If a vgone (or vclean) is already in progress, 69740548Smckusick * wait until it is done and return. 69840548Smckusick */ 69940548Smckusick if (vp->v_flag & VXLOCK) { 70040548Smckusick vp->v_flag |= VXWANT; 70140548Smckusick sleep((caddr_t)vp, PINOD); 70240548Smckusick return; 70340548Smckusick } 70440548Smckusick /* 70539433Smckusick * Clean out the filesystem specific data. 70639433Smckusick */ 70741300Smckusick vclean(vp, DOCLOSE); 70839433Smckusick /* 70939433Smckusick * Delete from old mount point vnode list, if on one. 71039433Smckusick */ 71139433Smckusick if (vp->v_mountb) { 71239433Smckusick if (vq = vp->v_mountf) 71339433Smckusick vq->v_mountb = vp->v_mountb; 71439433Smckusick *vp->v_mountb = vq; 71539433Smckusick vp->v_mountf = NULL; 71639433Smckusick vp->v_mountb = NULL; 71739433Smckusick } 71839433Smckusick /* 71939433Smckusick * If special device, remove it from special device alias list. 72039433Smckusick */ 72139433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 72239809Smckusick if (*vp->v_hashchain == vp) { 72339809Smckusick *vp->v_hashchain = vp->v_specnext; 72439433Smckusick } else { 72539809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 72639615Smckusick if (vq->v_specnext != vp) 72739433Smckusick continue; 72839615Smckusick vq->v_specnext = vp->v_specnext; 72939433Smckusick break; 73039433Smckusick } 73139615Smckusick if (vq == NULL) 73239433Smckusick panic("missing bdev"); 73339433Smckusick } 73439615Smckusick if (vp->v_flag & VALIASED) { 73539809Smckusick count = 0; 73639809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 73740108Smckusick if (vq->v_rdev != vp->v_rdev || 73840108Smckusick vq->v_type != vp->v_type) 73939615Smckusick continue; 74039615Smckusick count++; 74139615Smckusick vx = vq; 74239615Smckusick } 74339615Smckusick if (count == 0) 74439615Smckusick panic("missing alias"); 74539615Smckusick if (count == 1) 74639615Smckusick vx->v_flag &= ~VALIASED; 74739615Smckusick vp->v_flag &= ~VALIASED; 74839615Smckusick } 74939615Smckusick FREE(vp->v_specinfo, M_VNODE); 75039615Smckusick vp->v_specinfo = NULL; 75139433Smckusick } 75239433Smckusick /* 75339433Smckusick * If it is on the freelist, move it to the head of the list. 75439433Smckusick */ 75539433Smckusick if (vp->v_freeb) { 75639433Smckusick if (vq = vp->v_freef) 75739433Smckusick vq->v_freeb = vp->v_freeb; 75839433Smckusick else 75939433Smckusick vfreet = vp->v_freeb; 76039433Smckusick *vp->v_freeb = vq; 76139433Smckusick vp->v_freef = vfreeh; 76239433Smckusick vp->v_freeb = &vfreeh; 76339433Smckusick vfreeh->v_freeb = &vp->v_freef; 76439433Smckusick vfreeh = vp; 76539433Smckusick } 76639484Smckusick vp->v_type = VBAD; 76739433Smckusick } 76839633Smckusick 76939633Smckusick /* 77039821Smckusick * Lookup a vnode by device number. 77139821Smckusick */ 77239821Smckusick vfinddev(dev, type, vpp) 77339821Smckusick dev_t dev; 77439821Smckusick enum vtype type; 77539821Smckusick struct vnode **vpp; 77639821Smckusick { 77739821Smckusick register struct vnode *vp; 77839821Smckusick 77939821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 78039821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 78139821Smckusick continue; 78239821Smckusick *vpp = vp; 78339821Smckusick return (0); 78439821Smckusick } 78539821Smckusick return (1); 78639821Smckusick } 78739821Smckusick 78839821Smckusick /* 78939633Smckusick * Calculate the total number of references to a special device. 79039633Smckusick */ 79139633Smckusick vcount(vp) 79239633Smckusick register struct vnode *vp; 79339633Smckusick { 79439809Smckusick register struct vnode *vq; 79539633Smckusick int count; 79639633Smckusick 79739633Smckusick if ((vp->v_flag & VALIASED) == 0) 79839809Smckusick return (vp->v_usecount); 79939633Smckusick loop: 80039809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 80140108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 80239633Smckusick continue; 80339633Smckusick /* 80439633Smckusick * Alias, but not in use, so flush it out. 80539633Smckusick */ 80639809Smckusick if (vq->v_usecount == 0) { 80739633Smckusick vgone(vq); 80839633Smckusick goto loop; 80939633Smckusick } 81039809Smckusick count += vq->v_usecount; 81139633Smckusick } 81239633Smckusick return (count); 81339633Smckusick } 81439667Smckusick 81539667Smckusick /* 81639667Smckusick * Print out a description of a vnode. 81739667Smckusick */ 81839667Smckusick static char *typename[] = 81940286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 82039667Smckusick 82139667Smckusick vprint(label, vp) 82239667Smckusick char *label; 82339667Smckusick register struct vnode *vp; 82439667Smckusick { 82539913Smckusick char buf[64]; 82639667Smckusick 82739667Smckusick if (label != NULL) 82839667Smckusick printf("%s: ", label); 82939913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 83039809Smckusick vp->v_usecount, vp->v_holdcnt); 83139913Smckusick buf[0] = '\0'; 83239913Smckusick if (vp->v_flag & VROOT) 83339913Smckusick strcat(buf, "|VROOT"); 83439913Smckusick if (vp->v_flag & VTEXT) 83539913Smckusick strcat(buf, "|VTEXT"); 83641300Smckusick if (vp->v_flag & VSYSTEM) 83741300Smckusick strcat(buf, "|VSYSTEM"); 83839913Smckusick if (vp->v_flag & VEXLOCK) 83939913Smckusick strcat(buf, "|VEXLOCK"); 84039913Smckusick if (vp->v_flag & VSHLOCK) 84139913Smckusick strcat(buf, "|VSHLOCK"); 84239913Smckusick if (vp->v_flag & VLWAIT) 84339913Smckusick strcat(buf, "|VLWAIT"); 84441300Smckusick if (vp->v_flag & VXLOCK) 84541300Smckusick strcat(buf, "|VXLOCK"); 84641300Smckusick if (vp->v_flag & VXWANT) 84741300Smckusick strcat(buf, "|VXWANT"); 84841300Smckusick if (vp->v_flag & VBWAIT) 84941300Smckusick strcat(buf, "|VBWAIT"); 85039913Smckusick if (vp->v_flag & VALIASED) 85139913Smckusick strcat(buf, "|VALIASED"); 85239913Smckusick if (buf[0] != '\0') 85339913Smckusick printf(" flags (%s)", &buf[1]); 85439913Smckusick printf("\n\t"); 85539667Smckusick VOP_PRINT(vp); 85639667Smckusick } 85741110Smarc 85841110Smarc int kinfo_vdebug = 1; 85941110Smarc int kinfo_vgetfailed; 86041110Smarc #define KINFO_VNODESLOP 10 86141110Smarc /* 86241110Smarc * Dump vnode list (via kinfo). 86341110Smarc * Copyout address of vnode followed by vnode. 86441110Smarc */ 86541110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 86641110Smarc char *where; 86741110Smarc int *acopysize, *aneeded; 86841110Smarc { 86941110Smarc register struct mount *mp = rootfs; 87041300Smckusick struct mount *omp; 87141110Smarc struct vnode *vp; 87241110Smarc register needed = 0; 87341110Smarc register char *bp = where, *savebp; 87441110Smarc char *ewhere = where + *acopysize; 87541110Smarc int error; 87641110Smarc 87741110Smarc #define VPTRSZ sizeof (struct vnode *) 87841110Smarc #define VNODESZ sizeof (struct vnode) 87941110Smarc if (where == NULL) { 88041110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 88141110Smarc return (0); 88241110Smarc } 88341110Smarc 88441110Smarc do { 88541300Smckusick if (vfs_busy(mp)) { 88641400Smckusick mp = mp->mnt_next; 88741300Smckusick continue; 88841300Smckusick } 88941110Smarc savebp = bp; 89041110Smarc again: 89141421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 89241422Smckusick /* 89341422Smckusick * Check that the vp is still associated with 89441422Smckusick * this filesystem. RACE: could have been 89541422Smckusick * recycled onto the same filesystem. 89641422Smckusick */ 89741421Smckusick if (vp->v_mount != mp) { 89841421Smckusick if (kinfo_vdebug) 89941421Smckusick printf("kinfo: vp changed\n"); 90041421Smckusick bp = savebp; 90141421Smckusick goto again; 90241421Smckusick } 90341110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 90441110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 90541110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 90641422Smckusick VNODESZ)))) 90741110Smarc return (error); 90841110Smarc bp += VPTRSZ + VNODESZ; 90941110Smarc } 91041300Smckusick omp = mp; 91141400Smckusick mp = mp->mnt_next; 91241300Smckusick vfs_unbusy(omp); 91341110Smarc } while (mp != rootfs); 91441110Smarc 91541110Smarc *aneeded = bp - where; 91641110Smarc if (bp > ewhere) 91741110Smarc *acopysize = ewhere - where; 91841110Smarc else 91941110Smarc *acopysize = bp - where; 92041110Smarc return (0); 92141110Smarc } 922