137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 537488Smckusick * Redistribution and use in source and binary forms are permitted 637488Smckusick * provided that the above copyright notice and this paragraph are 737488Smckusick * duplicated in all such forms and that any documentation, 837488Smckusick * advertising materials, and other materials related to such 937488Smckusick * distribution and use acknowledge that the software was developed 1037488Smckusick * by the University of California, Berkeley. The name of the 1137488Smckusick * University may not be used to endorse or promote products derived 1237488Smckusick * from this software without specific prior written permission. 1337488Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437488Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537488Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637488Smckusick * 17*41300Smckusick * @(#)vfs_subr.c 7.40 (Berkeley) 05/02/90 1837488Smckusick */ 1937488Smckusick 2037488Smckusick /* 2137488Smckusick * External virtual filesystem routines 2237488Smckusick */ 2337488Smckusick 2437488Smckusick #include "param.h" 2537488Smckusick #include "mount.h" 2637488Smckusick #include "time.h" 2737488Smckusick #include "vnode.h" 2840652Smckusick #include "specdev.h" 2938265Smckusick #include "namei.h" 3038265Smckusick #include "ucred.h" 3137488Smckusick #include "errno.h" 3239433Smckusick #include "malloc.h" 3337488Smckusick 3437488Smckusick /* 3537488Smckusick * Remove a mount point from the list of mounted filesystems. 3637488Smckusick * Unmount of the root is illegal. 3737488Smckusick */ 3837488Smckusick void 3937488Smckusick vfs_remove(mp) 4037488Smckusick register struct mount *mp; 4137488Smckusick { 4237488Smckusick 4337488Smckusick if (mp == rootfs) 4437488Smckusick panic("vfs_remove: unmounting root"); 4537488Smckusick mp->m_prev->m_next = mp->m_next; 4637488Smckusick mp->m_next->m_prev = mp->m_prev; 4737488Smckusick mp->m_vnodecovered->v_mountedhere = (struct mount *)0; 4837488Smckusick vfs_unlock(mp); 4937488Smckusick } 5037488Smckusick 5137488Smckusick /* 5237488Smckusick * Lock a filesystem. 5337488Smckusick * Used to prevent access to it while mounting and unmounting. 5437488Smckusick */ 5537488Smckusick vfs_lock(mp) 5637488Smckusick register struct mount *mp; 5737488Smckusick { 5837488Smckusick 5939045Smckusick while(mp->m_flag & M_MLOCK) { 6039045Smckusick mp->m_flag |= M_MWAIT; 6139045Smckusick sleep((caddr_t)mp, PVFS); 6239045Smckusick } 6337488Smckusick mp->m_flag |= M_MLOCK; 6437488Smckusick return (0); 6537488Smckusick } 6637488Smckusick 6737488Smckusick /* 6837488Smckusick * Unlock a locked filesystem. 6937488Smckusick * Panic if filesystem is not locked. 7037488Smckusick */ 7137488Smckusick void 7237488Smckusick vfs_unlock(mp) 7337488Smckusick register struct mount *mp; 7437488Smckusick { 7537488Smckusick 7637488Smckusick if ((mp->m_flag & M_MLOCK) == 0) 77*41300Smckusick panic("vfs_unlock: not locked"); 7837488Smckusick mp->m_flag &= ~M_MLOCK; 7937488Smckusick if (mp->m_flag & M_MWAIT) { 8037488Smckusick mp->m_flag &= ~M_MWAIT; 8137488Smckusick wakeup((caddr_t)mp); 8237488Smckusick } 8337488Smckusick } 8437488Smckusick 8537488Smckusick /* 86*41300Smckusick * Mark a mount point as busy. 87*41300Smckusick * Used to synchronize access and to delay unmounting. 88*41300Smckusick */ 89*41300Smckusick vfs_busy(mp) 90*41300Smckusick register struct mount *mp; 91*41300Smckusick { 92*41300Smckusick 93*41300Smckusick if (mp->m_flag & M_UNMOUNT) 94*41300Smckusick return (1); 95*41300Smckusick while(mp->m_flag & M_MPBUSY) { 96*41300Smckusick mp->m_flag |= M_MPWANT; 97*41300Smckusick sleep((caddr_t)&mp->m_flag, PVFS); 98*41300Smckusick } 99*41300Smckusick mp->m_flag |= M_MPBUSY; 100*41300Smckusick return (0); 101*41300Smckusick } 102*41300Smckusick 103*41300Smckusick /* 104*41300Smckusick * Free a busy filesystem. 105*41300Smckusick * Panic if filesystem is not busy. 106*41300Smckusick */ 107*41300Smckusick void 108*41300Smckusick vfs_unbusy(mp) 109*41300Smckusick register struct mount *mp; 110*41300Smckusick { 111*41300Smckusick 112*41300Smckusick if ((mp->m_flag & M_MPBUSY) == 0) 113*41300Smckusick panic("vfs_unbusy: not busy"); 114*41300Smckusick mp->m_flag &= ~M_MPBUSY; 115*41300Smckusick if (mp->m_flag & M_MPWANT) { 116*41300Smckusick mp->m_flag &= ~M_MPWANT; 117*41300Smckusick wakeup((caddr_t)&mp->m_flag); 118*41300Smckusick } 119*41300Smckusick } 120*41300Smckusick 121*41300Smckusick /* 12237488Smckusick * Lookup a mount point by filesystem identifier. 12337488Smckusick */ 12437488Smckusick struct mount * 12537488Smckusick getvfs(fsid) 12637488Smckusick fsid_t *fsid; 12737488Smckusick { 12837488Smckusick register struct mount *mp; 12937488Smckusick 13038288Smckusick mp = rootfs; 13138288Smckusick do { 13240342Smckusick if (mp->m_stat.f_fsid.val[0] == fsid->val[0] && 13340342Smckusick mp->m_stat.f_fsid.val[1] == fsid->val[1]) { 13438288Smckusick return (mp); 13537488Smckusick } 13638288Smckusick mp = mp->m_next; 13738288Smckusick } while (mp != rootfs); 13838288Smckusick return ((struct mount *)0); 13937488Smckusick } 14037488Smckusick 14137488Smckusick /* 14237488Smckusick * Set vnode attributes to VNOVAL 14337488Smckusick */ 14437488Smckusick void vattr_null(vap) 14537488Smckusick register struct vattr *vap; 14637488Smckusick { 14737488Smckusick 14837488Smckusick vap->va_type = VNON; 14937488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 15037488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 15140643Smckusick vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 15240643Smckusick vap->va_bytes = vap->va_bytes_rsv = 15337488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 15437488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 15538258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 15638258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 15737488Smckusick } 15838265Smckusick 15938265Smckusick /* 16038265Smckusick * Initialize a nameidata structure 16138265Smckusick */ 16238265Smckusick ndinit(ndp) 16338265Smckusick register struct nameidata *ndp; 16438265Smckusick { 16538265Smckusick 16638265Smckusick bzero((caddr_t)ndp, sizeof(struct nameidata)); 16738265Smckusick ndp->ni_iov = &ndp->ni_nd.nd_iovec; 16838265Smckusick ndp->ni_iovcnt = 1; 16938265Smckusick ndp->ni_base = (caddr_t)&ndp->ni_dent; 17038265Smckusick ndp->ni_rw = UIO_WRITE; 17139736Smckusick ndp->ni_uioseg = UIO_SYSSPACE; 17238265Smckusick } 17338265Smckusick 17438265Smckusick /* 17538265Smckusick * Duplicate a nameidata structure 17638265Smckusick */ 17738265Smckusick nddup(ndp, newndp) 17838265Smckusick register struct nameidata *ndp, *newndp; 17938265Smckusick { 18038265Smckusick 18138265Smckusick ndinit(newndp); 18238265Smckusick newndp->ni_cdir = ndp->ni_cdir; 18338348Smckusick VREF(newndp->ni_cdir); 18438265Smckusick newndp->ni_rdir = ndp->ni_rdir; 18538265Smckusick if (newndp->ni_rdir) 18638348Smckusick VREF(newndp->ni_rdir); 18738265Smckusick newndp->ni_cred = ndp->ni_cred; 18838265Smckusick crhold(newndp->ni_cred); 18938265Smckusick } 19038265Smckusick 19138265Smckusick /* 19238265Smckusick * Release a nameidata structure 19338265Smckusick */ 19438265Smckusick ndrele(ndp) 19538265Smckusick register struct nameidata *ndp; 19638265Smckusick { 19738265Smckusick 19838265Smckusick vrele(ndp->ni_cdir); 19938265Smckusick if (ndp->ni_rdir) 20038265Smckusick vrele(ndp->ni_rdir); 20138265Smckusick crfree(ndp->ni_cred); 20238265Smckusick } 20339397Smckusick 20439397Smckusick /* 20539397Smckusick * Routines having to do with the management of the vnode table. 20639397Smckusick */ 20739397Smckusick struct vnode *vfreeh, **vfreet; 20839447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 20939635Smckusick extern void vclean(); 21040883Smckusick long numvnodes; 21139397Smckusick 21239397Smckusick /* 21339433Smckusick * Initialize the vnode structures and initialize each file system type. 21439397Smckusick */ 21539433Smckusick vfsinit() 21639397Smckusick { 21739433Smckusick struct vfsops **vfsp; 21839397Smckusick 21939433Smckusick /* 22039433Smckusick * Initialize the vnode name cache 22139433Smckusick */ 22239433Smckusick nchinit(); 22339433Smckusick /* 22439433Smckusick * Initialize each file system type. 22539433Smckusick */ 22639433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 22739433Smckusick if (*vfsp == NULL) 22839433Smckusick continue; 22939433Smckusick (*(*vfsp)->vfs_init)(); 23039433Smckusick } 23139397Smckusick } 23239397Smckusick 23339397Smckusick /* 23439397Smckusick * Return the next vnode from the free list. 23539397Smckusick */ 23639397Smckusick getnewvnode(tag, mp, vops, vpp) 23739397Smckusick enum vtagtype tag; 23839397Smckusick struct mount *mp; 23939397Smckusick struct vnodeops *vops; 24039397Smckusick struct vnode **vpp; 24139397Smckusick { 24239397Smckusick register struct vnode *vp, *vq; 24339397Smckusick 24440883Smckusick if (numvnodes < desiredvnodes) { 24540883Smckusick vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK); 24640883Smckusick bzero((char *)vp, sizeof *vp); 24740883Smckusick numvnodes++; 24840883Smckusick } else { 24940883Smckusick if ((vp = vfreeh) == NULL) { 25040883Smckusick tablefull("vnode"); 25140883Smckusick *vpp = 0; 25240883Smckusick return (ENFILE); 25340883Smckusick } 25440883Smckusick if (vp->v_usecount) 25540883Smckusick panic("free vnode isn't"); 25640883Smckusick if (vq = vp->v_freef) 25740883Smckusick vq->v_freeb = &vfreeh; 25840883Smckusick else 25940883Smckusick vfreet = &vfreeh; 26040883Smckusick vfreeh = vq; 26140883Smckusick vp->v_freef = NULL; 26240883Smckusick vp->v_freeb = NULL; 26340883Smckusick if (vp->v_type != VBAD) 26440883Smckusick vgone(vp); 26540883Smckusick vp->v_flag = 0; 26640883Smckusick vp->v_shlockc = 0; 26740883Smckusick vp->v_exlockc = 0; 26840883Smckusick vp->v_lastr = 0; 26940883Smckusick vp->v_socket = 0; 27039397Smckusick } 27139512Smckusick vp->v_type = VNON; 27239397Smckusick cache_purge(vp); 27339397Smckusick vp->v_tag = tag; 27439433Smckusick vp->v_op = vops; 27539397Smckusick insmntque(vp, mp); 27639397Smckusick VREF(vp); 27739397Smckusick *vpp = vp; 27839397Smckusick return (0); 27939397Smckusick } 28039397Smckusick 28139397Smckusick /* 28239397Smckusick * Move a vnode from one mount queue to another. 28339397Smckusick */ 28439397Smckusick insmntque(vp, mp) 28539397Smckusick register struct vnode *vp; 28639397Smckusick register struct mount *mp; 28739397Smckusick { 28839397Smckusick struct vnode *vq; 28939397Smckusick 29039397Smckusick /* 29139397Smckusick * Delete from old mount point vnode list, if on one. 29239397Smckusick */ 29339397Smckusick if (vp->v_mountb) { 29439397Smckusick if (vq = vp->v_mountf) 29539397Smckusick vq->v_mountb = vp->v_mountb; 29639397Smckusick *vp->v_mountb = vq; 29739397Smckusick } 29839397Smckusick /* 29939397Smckusick * Insert into list of vnodes for the new mount point, if available. 30039397Smckusick */ 30139621Smckusick vp->v_mount = mp; 30239397Smckusick if (mp == NULL) { 30339397Smckusick vp->v_mountf = NULL; 30439397Smckusick vp->v_mountb = NULL; 30539397Smckusick return; 30639397Smckusick } 30739397Smckusick if (mp->m_mounth) { 30839397Smckusick vp->v_mountf = mp->m_mounth; 30939397Smckusick vp->v_mountb = &mp->m_mounth; 31039397Smckusick mp->m_mounth->v_mountb = &vp->v_mountf; 31139397Smckusick mp->m_mounth = vp; 31239397Smckusick } else { 31339397Smckusick mp->m_mounth = vp; 31439397Smckusick vp->v_mountb = &mp->m_mounth; 31539397Smckusick vp->v_mountf = NULL; 31639397Smckusick } 31739397Smckusick } 31839397Smckusick 31939397Smckusick /* 32039433Smckusick * Create a vnode for a block device. 32139433Smckusick * Used for root filesystem, argdev, and swap areas. 32239433Smckusick * Also used for memory file system special devices. 32339397Smckusick */ 32439433Smckusick bdevvp(dev, vpp) 32539433Smckusick dev_t dev; 32639433Smckusick struct vnode **vpp; 32739433Smckusick { 32839433Smckusick register struct vnode *vp; 32939433Smckusick struct vnode *nvp; 33039433Smckusick int error; 33139433Smckusick 33239447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 33339433Smckusick if (error) { 33439433Smckusick *vpp = 0; 33539433Smckusick return (error); 33639433Smckusick } 33739433Smckusick vp = nvp; 33839433Smckusick vp->v_type = VBLK; 33939615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 34039433Smckusick vput(vp); 34139433Smckusick vp = nvp; 34239433Smckusick } 34339433Smckusick *vpp = vp; 34439433Smckusick return (0); 34539433Smckusick } 34639433Smckusick 34739433Smckusick /* 34839433Smckusick * Check to see if the new vnode represents a special device 34939433Smckusick * for which we already have a vnode (either because of 35039433Smckusick * bdevvp() or because of a different vnode representing 35139433Smckusick * the same block device). If such an alias exists, deallocate 35239509Smckusick * the existing contents and return the aliased vnode. The 35339433Smckusick * caller is responsible for filling it with its new contents. 35439433Smckusick */ 35539433Smckusick struct vnode * 35639615Smckusick checkalias(nvp, nvp_rdev, mp) 35739433Smckusick register struct vnode *nvp; 35839615Smckusick dev_t nvp_rdev; 35939433Smckusick struct mount *mp; 36039433Smckusick { 36139433Smckusick register struct vnode *vp; 36239615Smckusick struct vnode **vpp; 36339433Smckusick 36439433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 36539433Smckusick return ((struct vnode *)0); 36639615Smckusick 36739615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 36839433Smckusick loop: 36939615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 37039615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 37139433Smckusick continue; 37239615Smckusick /* 37339615Smckusick * Alias, but not in use, so flush it out. 37439615Smckusick */ 37539809Smckusick if (vp->v_usecount == 0) { 37639615Smckusick vgone(vp); 37739615Smckusick goto loop; 37839615Smckusick } 37939633Smckusick if (vget(vp)) 38039633Smckusick goto loop; 38139433Smckusick break; 38239433Smckusick } 38339615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 38439615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 38539615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 38639615Smckusick nvp->v_rdev = nvp_rdev; 38739809Smckusick nvp->v_hashchain = vpp; 38839615Smckusick nvp->v_specnext = *vpp; 38939615Smckusick *vpp = nvp; 39040640Smckusick if (vp != NULL) { 39140640Smckusick nvp->v_flag |= VALIASED; 39240640Smckusick vp->v_flag |= VALIASED; 39340640Smckusick vput(vp); 39440640Smckusick } 39539433Smckusick return ((struct vnode *)0); 39639433Smckusick } 39739484Smckusick VOP_UNLOCK(vp); 39839484Smckusick vclean(vp, 0); 39939433Smckusick vp->v_op = nvp->v_op; 40039433Smckusick vp->v_tag = nvp->v_tag; 40139433Smckusick nvp->v_type = VNON; 40239433Smckusick insmntque(vp, mp); 40339433Smckusick return (vp); 40439433Smckusick } 40539433Smckusick 40639433Smckusick /* 40739433Smckusick * Grab a particular vnode from the free list, increment its 40839433Smckusick * reference count and lock it. The vnode lock bit is set the 40939433Smckusick * vnode is being eliminated in vgone. The process is awakened 41039433Smckusick * when the transition is completed, and an error returned to 41139433Smckusick * indicate that the vnode is no longer usable (possibly having 41239433Smckusick * been changed to a new file system type). 41339433Smckusick */ 41439397Smckusick vget(vp) 41539397Smckusick register struct vnode *vp; 41639397Smckusick { 41739397Smckusick register struct vnode *vq; 41839397Smckusick 41939433Smckusick if (vp->v_flag & VXLOCK) { 42039433Smckusick vp->v_flag |= VXWANT; 42139433Smckusick sleep((caddr_t)vp, PINOD); 42239433Smckusick return (1); 42339433Smckusick } 42439809Smckusick if (vp->v_usecount == 0) { 42539433Smckusick if (vq = vp->v_freef) 42639433Smckusick vq->v_freeb = vp->v_freeb; 42739433Smckusick else 42839433Smckusick vfreet = vp->v_freeb; 42939433Smckusick *vp->v_freeb = vq; 43039433Smckusick vp->v_freef = NULL; 43139433Smckusick vp->v_freeb = NULL; 43239433Smckusick } 43339397Smckusick VREF(vp); 43439433Smckusick VOP_LOCK(vp); 43539433Smckusick return (0); 43639397Smckusick } 43739397Smckusick 43839397Smckusick /* 43939397Smckusick * Vnode reference, just increment the count 44039397Smckusick */ 44139397Smckusick void vref(vp) 44239397Smckusick struct vnode *vp; 44339397Smckusick { 44439397Smckusick 44539809Smckusick vp->v_usecount++; 44639397Smckusick } 44739397Smckusick 44839397Smckusick /* 44939397Smckusick * vput(), just unlock and vrele() 45039397Smckusick */ 45139397Smckusick void vput(vp) 45239397Smckusick register struct vnode *vp; 45339397Smckusick { 45439397Smckusick VOP_UNLOCK(vp); 45539397Smckusick vrele(vp); 45639397Smckusick } 45739397Smckusick 45839397Smckusick /* 45939397Smckusick * Vnode release. 46039397Smckusick * If count drops to zero, call inactive routine and return to freelist. 46139397Smckusick */ 46239397Smckusick void vrele(vp) 46339397Smckusick register struct vnode *vp; 46439397Smckusick { 46539397Smckusick 46639397Smckusick if (vp == NULL) 46739433Smckusick panic("vrele: null vp"); 46839809Smckusick vp->v_usecount--; 46939809Smckusick if (vp->v_usecount < 0) 47039667Smckusick vprint("vrele: bad ref count", vp); 47139809Smckusick if (vp->v_usecount > 0) 47239397Smckusick return; 47339397Smckusick if (vfreeh == (struct vnode *)0) { 47439397Smckusick /* 47539397Smckusick * insert into empty list 47639397Smckusick */ 47739397Smckusick vfreeh = vp; 47839397Smckusick vp->v_freeb = &vfreeh; 47939397Smckusick } else { 48039397Smckusick /* 48139397Smckusick * insert at tail of list 48239397Smckusick */ 48339397Smckusick *vfreet = vp; 48439397Smckusick vp->v_freeb = vfreet; 48539397Smckusick } 48639433Smckusick vp->v_freef = NULL; 48739433Smckusick vfreet = &vp->v_freef; 48839433Smckusick VOP_INACTIVE(vp); 48939397Smckusick } 49039433Smckusick 49139433Smckusick /* 49239809Smckusick * Page or buffer structure gets a reference. 49339809Smckusick */ 49439809Smckusick vhold(vp) 49539809Smckusick register struct vnode *vp; 49639809Smckusick { 49739809Smckusick 49839809Smckusick vp->v_holdcnt++; 49939809Smckusick } 50039809Smckusick 50139809Smckusick /* 50239809Smckusick * Page or buffer structure frees a reference. 50339809Smckusick */ 50439809Smckusick holdrele(vp) 50539809Smckusick register struct vnode *vp; 50639809Smckusick { 50739809Smckusick 50839809Smckusick if (vp->v_holdcnt <= 0) 50939809Smckusick panic("holdrele: holdcnt"); 51039809Smckusick vp->v_holdcnt--; 51139809Smckusick } 51239809Smckusick 51339809Smckusick /* 51439509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 51539509Smckusick * 51639509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 51739509Smckusick * return error if any are found (nb: this is a user error, not a 51839509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 51939509Smckusick * that are found. 52039509Smckusick */ 52139509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 52239509Smckusick 52339509Smckusick vflush(mp, skipvp, flags) 52439509Smckusick struct mount *mp; 52539509Smckusick struct vnode *skipvp; 52639509Smckusick int flags; 52739509Smckusick { 52839509Smckusick register struct vnode *vp, *nvp; 52939509Smckusick int busy = 0; 53039509Smckusick 531*41300Smckusick if ((mp->m_flag & M_MPBUSY) == 0) 532*41300Smckusick panic("vflush: not busy"); 53339509Smckusick for (vp = mp->m_mounth; vp; vp = nvp) { 53439509Smckusick nvp = vp->v_mountf; 53539509Smckusick /* 53639509Smckusick * Skip over a selected vnode. 53739509Smckusick */ 53839509Smckusick if (vp == skipvp) 53939509Smckusick continue; 54039509Smckusick /* 541*41300Smckusick * Skip over a vnodes marked VSYSTEM. 542*41300Smckusick */ 543*41300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 544*41300Smckusick continue; 545*41300Smckusick /* 54639809Smckusick * With v_usecount == 0, all we need to do is clear 54739509Smckusick * out the vnode data structures and we are done. 54839509Smckusick */ 54939809Smckusick if (vp->v_usecount == 0) { 55039509Smckusick vgone(vp); 55139509Smckusick continue; 55239509Smckusick } 55339509Smckusick /* 55439509Smckusick * For block or character devices, revert to an 55539509Smckusick * anonymous device. For all other files, just kill them. 55639509Smckusick */ 557*41300Smckusick if (flags & FORCECLOSE) { 55839509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 55939509Smckusick vgone(vp); 56039509Smckusick } else { 56139509Smckusick vclean(vp, 0); 56239509Smckusick vp->v_op = &spec_vnodeops; 56339509Smckusick insmntque(vp, (struct mount *)0); 56439509Smckusick } 56539509Smckusick continue; 56639509Smckusick } 56739509Smckusick if (busyprt) 56839667Smckusick vprint("vflush: busy vnode", vp); 56939509Smckusick busy++; 57039509Smckusick } 57139509Smckusick if (busy) 57239509Smckusick return (EBUSY); 57339509Smckusick return (0); 57439509Smckusick } 57539509Smckusick 57639509Smckusick /* 57739433Smckusick * Disassociate the underlying file system from a vnode. 57839433Smckusick */ 579*41300Smckusick void vclean(vp, flags) 58039433Smckusick register struct vnode *vp; 581*41300Smckusick long flags; 58239433Smckusick { 58339433Smckusick struct vnodeops *origops; 58439484Smckusick int active; 58539433Smckusick 58639484Smckusick /* 58739484Smckusick * Check to see if the vnode is in use. 58839667Smckusick * If so we have to reference it before we clean it out 58939667Smckusick * so that its count cannot fall to zero and generate a 59039667Smckusick * race against ourselves to recycle it. 59139484Smckusick */ 59239809Smckusick if (active = vp->v_usecount) 59339484Smckusick VREF(vp); 59439484Smckusick /* 59539484Smckusick * Prevent the vnode from being recycled or 59639484Smckusick * brought into use while we clean it out. 59739484Smckusick */ 59839667Smckusick if (vp->v_flag & VXLOCK) 59939667Smckusick panic("vclean: deadlock"); 60039433Smckusick vp->v_flag |= VXLOCK; 60139433Smckusick /* 60239667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 60339667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 60439667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 60539667Smckusick * For active vnodes, it ensures that no other activity can 60639667Smckusick * occur while the buffer list is being cleaned out. 60739667Smckusick */ 60839667Smckusick VOP_LOCK(vp); 609*41300Smckusick if (flags & DOCLOSE) 61039667Smckusick vinvalbuf(vp, 1); 61139667Smckusick /* 61239433Smckusick * Prevent any further operations on the vnode from 61339433Smckusick * being passed through to the old file system. 61439433Smckusick */ 61539433Smckusick origops = vp->v_op; 61639433Smckusick vp->v_op = &dead_vnodeops; 61739433Smckusick vp->v_tag = VT_NON; 61839433Smckusick /* 61939484Smckusick * If purging an active vnode, it must be unlocked, closed, 62039484Smckusick * and deactivated before being reclaimed. 62139433Smckusick */ 62239667Smckusick (*(origops->vn_unlock))(vp); 62339484Smckusick if (active) { 624*41300Smckusick if (flags & DOCLOSE) 62539484Smckusick (*(origops->vn_close))(vp, 0, NOCRED); 62639433Smckusick (*(origops->vn_inactive))(vp); 62739433Smckusick } 62839433Smckusick /* 62939433Smckusick * Reclaim the vnode. 63039433Smckusick */ 63139433Smckusick if ((*(origops->vn_reclaim))(vp)) 63239433Smckusick panic("vclean: cannot reclaim"); 63339484Smckusick if (active) 63439484Smckusick vrele(vp); 63539433Smckusick /* 63639433Smckusick * Done with purge, notify sleepers in vget of the grim news. 63739433Smckusick */ 63839433Smckusick vp->v_flag &= ~VXLOCK; 63939433Smckusick if (vp->v_flag & VXWANT) { 64039433Smckusick vp->v_flag &= ~VXWANT; 64139433Smckusick wakeup((caddr_t)vp); 64239433Smckusick } 64339433Smckusick } 64439433Smckusick 64539433Smckusick /* 64639633Smckusick * Eliminate all activity associated with the requested vnode 64739633Smckusick * and with all vnodes aliased to the requested vnode. 64839633Smckusick */ 64939633Smckusick void vgoneall(vp) 65039633Smckusick register struct vnode *vp; 65139633Smckusick { 65239809Smckusick register struct vnode *vq; 65339633Smckusick 65440665Smckusick if (vp->v_flag & VALIASED) { 65540665Smckusick /* 65640665Smckusick * If a vgone (or vclean) is already in progress, 65740665Smckusick * wait until it is done and return. 65840665Smckusick */ 65940665Smckusick if (vp->v_flag & VXLOCK) { 66040665Smckusick vp->v_flag |= VXWANT; 66140665Smckusick sleep((caddr_t)vp, PINOD); 66240665Smckusick return; 66339633Smckusick } 66440665Smckusick /* 66540665Smckusick * Ensure that vp will not be vgone'd while we 66640665Smckusick * are eliminating its aliases. 66740665Smckusick */ 66840665Smckusick vp->v_flag |= VXLOCK; 66940665Smckusick while (vp->v_flag & VALIASED) { 67040665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 67140665Smckusick if (vq->v_rdev != vp->v_rdev || 67240665Smckusick vq->v_type != vp->v_type || vp == vq) 67340665Smckusick continue; 67440665Smckusick vgone(vq); 67540665Smckusick break; 67640665Smckusick } 67740665Smckusick } 67840665Smckusick /* 67940665Smckusick * Remove the lock so that vgone below will 68040665Smckusick * really eliminate the vnode after which time 68140665Smckusick * vgone will awaken any sleepers. 68240665Smckusick */ 68340665Smckusick vp->v_flag &= ~VXLOCK; 68439633Smckusick } 68539633Smckusick vgone(vp); 68639633Smckusick } 68739633Smckusick 68839633Smckusick /* 68939433Smckusick * Eliminate all activity associated with a vnode 69039433Smckusick * in preparation for reuse. 69139433Smckusick */ 69239433Smckusick void vgone(vp) 69339433Smckusick register struct vnode *vp; 69439433Smckusick { 69539809Smckusick register struct vnode *vq; 69639615Smckusick struct vnode *vx; 69739615Smckusick long count; 69839433Smckusick 69939433Smckusick /* 70040548Smckusick * If a vgone (or vclean) is already in progress, 70140548Smckusick * wait until it is done and return. 70240548Smckusick */ 70340548Smckusick if (vp->v_flag & VXLOCK) { 70440548Smckusick vp->v_flag |= VXWANT; 70540548Smckusick sleep((caddr_t)vp, PINOD); 70640548Smckusick return; 70740548Smckusick } 70840548Smckusick /* 70939433Smckusick * Clean out the filesystem specific data. 71039433Smckusick */ 711*41300Smckusick vclean(vp, DOCLOSE); 71239433Smckusick /* 71339433Smckusick * Delete from old mount point vnode list, if on one. 71439433Smckusick */ 71539433Smckusick if (vp->v_mountb) { 71639433Smckusick if (vq = vp->v_mountf) 71739433Smckusick vq->v_mountb = vp->v_mountb; 71839433Smckusick *vp->v_mountb = vq; 71939433Smckusick vp->v_mountf = NULL; 72039433Smckusick vp->v_mountb = NULL; 72139433Smckusick } 72239433Smckusick /* 72339433Smckusick * If special device, remove it from special device alias list. 72439433Smckusick */ 72539433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 72639809Smckusick if (*vp->v_hashchain == vp) { 72739809Smckusick *vp->v_hashchain = vp->v_specnext; 72839433Smckusick } else { 72939809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 73039615Smckusick if (vq->v_specnext != vp) 73139433Smckusick continue; 73239615Smckusick vq->v_specnext = vp->v_specnext; 73339433Smckusick break; 73439433Smckusick } 73539615Smckusick if (vq == NULL) 73639433Smckusick panic("missing bdev"); 73739433Smckusick } 73839615Smckusick if (vp->v_flag & VALIASED) { 73939809Smckusick count = 0; 74039809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 74140108Smckusick if (vq->v_rdev != vp->v_rdev || 74240108Smckusick vq->v_type != vp->v_type) 74339615Smckusick continue; 74439615Smckusick count++; 74539615Smckusick vx = vq; 74639615Smckusick } 74739615Smckusick if (count == 0) 74839615Smckusick panic("missing alias"); 74939615Smckusick if (count == 1) 75039615Smckusick vx->v_flag &= ~VALIASED; 75139615Smckusick vp->v_flag &= ~VALIASED; 75239615Smckusick } 75339615Smckusick FREE(vp->v_specinfo, M_VNODE); 75439615Smckusick vp->v_specinfo = NULL; 75539433Smckusick } 75639433Smckusick /* 75739433Smckusick * If it is on the freelist, move it to the head of the list. 75839433Smckusick */ 75939433Smckusick if (vp->v_freeb) { 76039433Smckusick if (vq = vp->v_freef) 76139433Smckusick vq->v_freeb = vp->v_freeb; 76239433Smckusick else 76339433Smckusick vfreet = vp->v_freeb; 76439433Smckusick *vp->v_freeb = vq; 76539433Smckusick vp->v_freef = vfreeh; 76639433Smckusick vp->v_freeb = &vfreeh; 76739433Smckusick vfreeh->v_freeb = &vp->v_freef; 76839433Smckusick vfreeh = vp; 76939433Smckusick } 77039484Smckusick vp->v_type = VBAD; 77139433Smckusick } 77239633Smckusick 77339633Smckusick /* 77439821Smckusick * Lookup a vnode by device number. 77539821Smckusick */ 77639821Smckusick vfinddev(dev, type, vpp) 77739821Smckusick dev_t dev; 77839821Smckusick enum vtype type; 77939821Smckusick struct vnode **vpp; 78039821Smckusick { 78139821Smckusick register struct vnode *vp; 78239821Smckusick 78339821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 78439821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 78539821Smckusick continue; 78639821Smckusick *vpp = vp; 78739821Smckusick return (0); 78839821Smckusick } 78939821Smckusick return (1); 79039821Smckusick } 79139821Smckusick 79239821Smckusick /* 79339633Smckusick * Calculate the total number of references to a special device. 79439633Smckusick */ 79539633Smckusick vcount(vp) 79639633Smckusick register struct vnode *vp; 79739633Smckusick { 79839809Smckusick register struct vnode *vq; 79939633Smckusick int count; 80039633Smckusick 80139633Smckusick if ((vp->v_flag & VALIASED) == 0) 80239809Smckusick return (vp->v_usecount); 80339633Smckusick loop: 80439809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 80540108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 80639633Smckusick continue; 80739633Smckusick /* 80839633Smckusick * Alias, but not in use, so flush it out. 80939633Smckusick */ 81039809Smckusick if (vq->v_usecount == 0) { 81139633Smckusick vgone(vq); 81239633Smckusick goto loop; 81339633Smckusick } 81439809Smckusick count += vq->v_usecount; 81539633Smckusick } 81639633Smckusick return (count); 81739633Smckusick } 81839667Smckusick 81939667Smckusick /* 82039667Smckusick * Print out a description of a vnode. 82139667Smckusick */ 82239667Smckusick static char *typename[] = 82340286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 82439667Smckusick 82539667Smckusick vprint(label, vp) 82639667Smckusick char *label; 82739667Smckusick register struct vnode *vp; 82839667Smckusick { 82939913Smckusick char buf[64]; 83039667Smckusick 83139667Smckusick if (label != NULL) 83239667Smckusick printf("%s: ", label); 83339913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 83439809Smckusick vp->v_usecount, vp->v_holdcnt); 83539913Smckusick buf[0] = '\0'; 83639913Smckusick if (vp->v_flag & VROOT) 83739913Smckusick strcat(buf, "|VROOT"); 83839913Smckusick if (vp->v_flag & VTEXT) 83939913Smckusick strcat(buf, "|VTEXT"); 840*41300Smckusick if (vp->v_flag & VSYSTEM) 841*41300Smckusick strcat(buf, "|VSYSTEM"); 84239913Smckusick if (vp->v_flag & VEXLOCK) 84339913Smckusick strcat(buf, "|VEXLOCK"); 84439913Smckusick if (vp->v_flag & VSHLOCK) 84539913Smckusick strcat(buf, "|VSHLOCK"); 84639913Smckusick if (vp->v_flag & VLWAIT) 84739913Smckusick strcat(buf, "|VLWAIT"); 848*41300Smckusick if (vp->v_flag & VXLOCK) 849*41300Smckusick strcat(buf, "|VXLOCK"); 850*41300Smckusick if (vp->v_flag & VXWANT) 851*41300Smckusick strcat(buf, "|VXWANT"); 852*41300Smckusick if (vp->v_flag & VBWAIT) 853*41300Smckusick strcat(buf, "|VBWAIT"); 85439913Smckusick if (vp->v_flag & VALIASED) 85539913Smckusick strcat(buf, "|VALIASED"); 85639913Smckusick if (buf[0] != '\0') 85739913Smckusick printf(" flags (%s)", &buf[1]); 85839913Smckusick printf("\n\t"); 85939667Smckusick VOP_PRINT(vp); 86039667Smckusick } 86141110Smarc 86241110Smarc int kinfo_vdebug = 1; 86341110Smarc int kinfo_vgetfailed; 86441110Smarc #define KINFO_VNODESLOP 10 86541110Smarc /* 86641110Smarc * Dump vnode list (via kinfo). 86741110Smarc * Copyout address of vnode followed by vnode. 86841110Smarc */ 86941110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 87041110Smarc char *where; 87141110Smarc int *acopysize, *aneeded; 87241110Smarc { 87341110Smarc register struct mount *mp = rootfs; 87441110Smarc register struct vnode *nextvp; 875*41300Smckusick struct mount *omp; 87641110Smarc struct vnode *vp; 87741110Smarc register needed = 0; 87841110Smarc register char *bp = where, *savebp; 87941110Smarc char *ewhere = where + *acopysize; 88041110Smarc int error; 88141110Smarc 88241110Smarc #define VPTRSZ sizeof (struct vnode *) 88341110Smarc #define VNODESZ sizeof (struct vnode) 88441110Smarc if (where == NULL) { 88541110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 88641110Smarc return (0); 88741110Smarc } 88841110Smarc 88941110Smarc #define RETRY bp = savebp ; goto again 89041110Smarc do { 891*41300Smckusick if (vfs_busy(mp)) { 892*41300Smckusick mp = mp->m_next; 893*41300Smckusick continue; 894*41300Smckusick } 89541110Smarc /* 89641110Smarc * A vget can fail if the vnode is being 89741110Smarc * recycled. In this (rare) case, we have to start 89841110Smarc * over with this filesystem. Also, have to 89941110Smarc * check that nextvp is still associated 90041110Smarc * with this filesystem. RACE: could have been 90141110Smarc * recycled onto same filesystem. 90241110Smarc */ 90341110Smarc savebp = bp; 90441110Smarc again: 90541110Smarc nextvp = mp->m_mounth; 90641110Smarc while (vp = nextvp) { 90741110Smarc if (vget(vp)) { 90841110Smarc if (kinfo_vdebug) 90941110Smarc printf("kinfo: vget failed\n"); 91041110Smarc kinfo_vgetfailed++; 91141110Smarc RETRY; 91241110Smarc } 91341110Smarc if (vp->v_mount != mp) { 91441110Smarc if (kinfo_vdebug) 91541110Smarc printf("kinfo: vp changed\n"); 91641110Smarc vput(vp); 91741110Smarc RETRY; 91841110Smarc } 91941110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 92041110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 92141110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 92241110Smarc VNODESZ)))) { 92341110Smarc vput(vp); 92441110Smarc return (error); 92541110Smarc } 92641110Smarc bp += VPTRSZ + VNODESZ; 92741110Smarc nextvp = vp->v_mountf; 92841110Smarc vput(vp); 92941110Smarc } 930*41300Smckusick omp = mp; 93141110Smarc mp = mp->m_next; 932*41300Smckusick vfs_unbusy(omp); 93341110Smarc } while (mp != rootfs); 93441110Smarc 93541110Smarc *aneeded = bp - where; 93641110Smarc if (bp > ewhere) 93741110Smarc *acopysize = ewhere - where; 93841110Smarc else 93941110Smarc *acopysize = bp - where; 94041110Smarc return (0); 94141110Smarc } 942