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*40643Smckusick * @(#)vfs_subr.c 7.34 (Berkeley) 03/27/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" 2838265Smckusick #include "namei.h" 2938265Smckusick #include "ucred.h" 3037488Smckusick #include "errno.h" 3139433Smckusick #include "malloc.h" 3237488Smckusick 3337488Smckusick /* 3440156Smckusick * Shorthand notation. 3540156Smckusick */ 3640156Smckusick #define v_hashchain v_specinfo->si_hashchain 3740156Smckusick #define v_specnext v_specinfo->si_specnext 3840156Smckusick 3940156Smckusick /* 4037488Smckusick * Remove a mount point from the list of mounted filesystems. 4137488Smckusick * Unmount of the root is illegal. 4237488Smckusick */ 4337488Smckusick void 4437488Smckusick vfs_remove(mp) 4537488Smckusick register struct mount *mp; 4637488Smckusick { 4737488Smckusick 4837488Smckusick if (mp == rootfs) 4937488Smckusick panic("vfs_remove: unmounting root"); 5037488Smckusick mp->m_prev->m_next = mp->m_next; 5137488Smckusick mp->m_next->m_prev = mp->m_prev; 5237488Smckusick mp->m_vnodecovered->v_mountedhere = (struct mount *)0; 5337488Smckusick vfs_unlock(mp); 5437488Smckusick } 5537488Smckusick 5637488Smckusick /* 5737488Smckusick * Lock a filesystem. 5837488Smckusick * Used to prevent access to it while mounting and unmounting. 5937488Smckusick */ 6037488Smckusick vfs_lock(mp) 6137488Smckusick register struct mount *mp; 6237488Smckusick { 6337488Smckusick 6439045Smckusick while(mp->m_flag & M_MLOCK) { 6539045Smckusick mp->m_flag |= M_MWAIT; 6639045Smckusick sleep((caddr_t)mp, PVFS); 6739045Smckusick } 6837488Smckusick mp->m_flag |= M_MLOCK; 6937488Smckusick return (0); 7037488Smckusick } 7137488Smckusick 7237488Smckusick /* 7337488Smckusick * Unlock a locked filesystem. 7437488Smckusick * Panic if filesystem is not locked. 7537488Smckusick */ 7637488Smckusick void 7737488Smckusick vfs_unlock(mp) 7837488Smckusick register struct mount *mp; 7937488Smckusick { 8037488Smckusick 8137488Smckusick if ((mp->m_flag & M_MLOCK) == 0) 8237488Smckusick panic("vfs_unlock: locked fs"); 8337488Smckusick mp->m_flag &= ~M_MLOCK; 8437488Smckusick if (mp->m_flag & M_MWAIT) { 8537488Smckusick mp->m_flag &= ~M_MWAIT; 8637488Smckusick wakeup((caddr_t)mp); 8737488Smckusick } 8837488Smckusick } 8937488Smckusick 9037488Smckusick /* 9137488Smckusick * Lookup a mount point by filesystem identifier. 9237488Smckusick */ 9337488Smckusick struct mount * 9437488Smckusick getvfs(fsid) 9537488Smckusick fsid_t *fsid; 9637488Smckusick { 9737488Smckusick register struct mount *mp; 9837488Smckusick 9938288Smckusick mp = rootfs; 10038288Smckusick do { 10140342Smckusick if (mp->m_stat.f_fsid.val[0] == fsid->val[0] && 10240342Smckusick mp->m_stat.f_fsid.val[1] == fsid->val[1]) { 10338288Smckusick return (mp); 10437488Smckusick } 10538288Smckusick mp = mp->m_next; 10638288Smckusick } while (mp != rootfs); 10738288Smckusick return ((struct mount *)0); 10837488Smckusick } 10937488Smckusick 11037488Smckusick /* 11137488Smckusick * Set vnode attributes to VNOVAL 11237488Smckusick */ 11337488Smckusick void vattr_null(vap) 11437488Smckusick register struct vattr *vap; 11537488Smckusick { 11637488Smckusick 11737488Smckusick vap->va_type = VNON; 11837488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 11937488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 120*40643Smckusick vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 121*40643Smckusick vap->va_bytes = vap->va_bytes_rsv = 12237488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 12337488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 12438258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 12538258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 12637488Smckusick } 12738265Smckusick 12838265Smckusick /* 12938265Smckusick * Initialize a nameidata structure 13038265Smckusick */ 13138265Smckusick ndinit(ndp) 13238265Smckusick register struct nameidata *ndp; 13338265Smckusick { 13438265Smckusick 13538265Smckusick bzero((caddr_t)ndp, sizeof(struct nameidata)); 13638265Smckusick ndp->ni_iov = &ndp->ni_nd.nd_iovec; 13738265Smckusick ndp->ni_iovcnt = 1; 13838265Smckusick ndp->ni_base = (caddr_t)&ndp->ni_dent; 13938265Smckusick ndp->ni_rw = UIO_WRITE; 14039736Smckusick ndp->ni_uioseg = UIO_SYSSPACE; 14138265Smckusick } 14238265Smckusick 14338265Smckusick /* 14438265Smckusick * Duplicate a nameidata structure 14538265Smckusick */ 14638265Smckusick nddup(ndp, newndp) 14738265Smckusick register struct nameidata *ndp, *newndp; 14838265Smckusick { 14938265Smckusick 15038265Smckusick ndinit(newndp); 15138265Smckusick newndp->ni_cdir = ndp->ni_cdir; 15238348Smckusick VREF(newndp->ni_cdir); 15338265Smckusick newndp->ni_rdir = ndp->ni_rdir; 15438265Smckusick if (newndp->ni_rdir) 15538348Smckusick VREF(newndp->ni_rdir); 15638265Smckusick newndp->ni_cred = ndp->ni_cred; 15738265Smckusick crhold(newndp->ni_cred); 15838265Smckusick } 15938265Smckusick 16038265Smckusick /* 16138265Smckusick * Release a nameidata structure 16238265Smckusick */ 16338265Smckusick ndrele(ndp) 16438265Smckusick register struct nameidata *ndp; 16538265Smckusick { 16638265Smckusick 16738265Smckusick vrele(ndp->ni_cdir); 16838265Smckusick if (ndp->ni_rdir) 16938265Smckusick vrele(ndp->ni_rdir); 17038265Smckusick crfree(ndp->ni_cred); 17138265Smckusick } 17239397Smckusick 17339397Smckusick /* 17439397Smckusick * Routines having to do with the management of the vnode table. 17539397Smckusick */ 17639397Smckusick struct vnode *vfreeh, **vfreet; 17739447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 17839635Smckusick extern void vclean(); 17939397Smckusick 18039615Smckusick #define SPECHSZ 64 18139615Smckusick #if ((SPECHSZ&(SPECHSZ-1)) == 0) 18239615Smckusick #define SPECHASH(rdev) (((rdev>>5)+(rdev))&(SPECHSZ-1)) 18339615Smckusick #else 18439615Smckusick #define SPECHASH(rdev) (((unsigned)((rdev>>5)+(rdev)))%SPECHSZ) 18539615Smckusick #endif 18639615Smckusick struct vnode *speclisth[SPECHSZ]; 18739615Smckusick 18839397Smckusick /* 18939433Smckusick * Initialize the vnode structures and initialize each file system type. 19039397Smckusick */ 19139433Smckusick vfsinit() 19239397Smckusick { 19339397Smckusick register struct vnode *vp = vnode; 19439433Smckusick struct vfsops **vfsp; 19539397Smckusick 19639433Smckusick /* 19739433Smckusick * Build vnode free list. 19839433Smckusick */ 19939397Smckusick vfreeh = vp; 20039397Smckusick vfreet = &vp->v_freef; 20139397Smckusick vp->v_freeb = &vfreeh; 20239397Smckusick vp->v_op = &dead_vnodeops; 20339945Smckusick vp->v_type = VBAD; 20439397Smckusick for (vp++; vp < vnodeNVNODE; vp++) { 20539397Smckusick *vfreet = vp; 20639397Smckusick vp->v_freeb = vfreet; 20739397Smckusick vfreet = &vp->v_freef; 20839397Smckusick vp->v_op = &dead_vnodeops; 20939945Smckusick vp->v_type = VBAD; 21039397Smckusick } 21139397Smckusick vp--; 21239397Smckusick vp->v_freef = NULL; 21339433Smckusick /* 21439433Smckusick * Initialize the vnode name cache 21539433Smckusick */ 21639433Smckusick nchinit(); 21739433Smckusick /* 21839433Smckusick * Initialize each file system type. 21939433Smckusick */ 22039433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 22139433Smckusick if (*vfsp == NULL) 22239433Smckusick continue; 22339433Smckusick (*(*vfsp)->vfs_init)(); 22439433Smckusick } 22539397Smckusick } 22639397Smckusick 22739397Smckusick /* 22839397Smckusick * Return the next vnode from the free list. 22939397Smckusick */ 23039397Smckusick getnewvnode(tag, mp, vops, vpp) 23139397Smckusick enum vtagtype tag; 23239397Smckusick struct mount *mp; 23339397Smckusick struct vnodeops *vops; 23439397Smckusick struct vnode **vpp; 23539397Smckusick { 23639397Smckusick register struct vnode *vp, *vq; 23739397Smckusick 23839397Smckusick if ((vp = vfreeh) == NULL) { 23939397Smckusick tablefull("vnode"); 24039397Smckusick *vpp = 0; 24139397Smckusick return (ENFILE); 24239397Smckusick } 24339809Smckusick if (vp->v_usecount) 24439397Smckusick panic("free vnode isn't"); 24539397Smckusick if (vq = vp->v_freef) 24639397Smckusick vq->v_freeb = &vfreeh; 24739397Smckusick vfreeh = vq; 24839397Smckusick vp->v_freef = NULL; 24939397Smckusick vp->v_freeb = NULL; 25039943Smckusick if (vp->v_type != VBAD) 25139433Smckusick vgone(vp); 25239512Smckusick vp->v_type = VNON; 25339397Smckusick vp->v_flag = 0; 25439397Smckusick vp->v_shlockc = 0; 25539397Smckusick vp->v_exlockc = 0; 25639809Smckusick vp->v_lastr = 0; 25739397Smckusick vp->v_socket = 0; 25839397Smckusick cache_purge(vp); 25939397Smckusick vp->v_tag = tag; 26039433Smckusick vp->v_op = vops; 26139397Smckusick insmntque(vp, mp); 26239397Smckusick VREF(vp); 26339397Smckusick *vpp = vp; 26439397Smckusick return (0); 26539397Smckusick } 26639397Smckusick 26739397Smckusick /* 26839397Smckusick * Move a vnode from one mount queue to another. 26939397Smckusick */ 27039397Smckusick insmntque(vp, mp) 27139397Smckusick register struct vnode *vp; 27239397Smckusick register struct mount *mp; 27339397Smckusick { 27439397Smckusick struct vnode *vq; 27539397Smckusick 27639397Smckusick /* 27739397Smckusick * Delete from old mount point vnode list, if on one. 27839397Smckusick */ 27939397Smckusick if (vp->v_mountb) { 28039397Smckusick if (vq = vp->v_mountf) 28139397Smckusick vq->v_mountb = vp->v_mountb; 28239397Smckusick *vp->v_mountb = vq; 28339397Smckusick } 28439397Smckusick /* 28539397Smckusick * Insert into list of vnodes for the new mount point, if available. 28639397Smckusick */ 28739621Smckusick vp->v_mount = mp; 28839397Smckusick if (mp == NULL) { 28939397Smckusick vp->v_mountf = NULL; 29039397Smckusick vp->v_mountb = NULL; 29139397Smckusick return; 29239397Smckusick } 29339397Smckusick if (mp->m_mounth) { 29439397Smckusick vp->v_mountf = mp->m_mounth; 29539397Smckusick vp->v_mountb = &mp->m_mounth; 29639397Smckusick mp->m_mounth->v_mountb = &vp->v_mountf; 29739397Smckusick mp->m_mounth = vp; 29839397Smckusick } else { 29939397Smckusick mp->m_mounth = vp; 30039397Smckusick vp->v_mountb = &mp->m_mounth; 30139397Smckusick vp->v_mountf = NULL; 30239397Smckusick } 30339397Smckusick } 30439397Smckusick 30539397Smckusick /* 30639433Smckusick * Create a vnode for a block device. 30739433Smckusick * Used for root filesystem, argdev, and swap areas. 30839433Smckusick * Also used for memory file system special devices. 30939397Smckusick */ 31039433Smckusick bdevvp(dev, vpp) 31139433Smckusick dev_t dev; 31239433Smckusick struct vnode **vpp; 31339433Smckusick { 31439433Smckusick register struct vnode *vp; 31539433Smckusick struct vnode *nvp; 31639433Smckusick int error; 31739433Smckusick 31839447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 31939433Smckusick if (error) { 32039433Smckusick *vpp = 0; 32139433Smckusick return (error); 32239433Smckusick } 32339433Smckusick vp = nvp; 32439433Smckusick vp->v_type = VBLK; 32539615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 32639433Smckusick vput(vp); 32739433Smckusick vp = nvp; 32839433Smckusick } 32939433Smckusick *vpp = vp; 33039433Smckusick return (0); 33139433Smckusick } 33239433Smckusick 33339433Smckusick /* 33439433Smckusick * Check to see if the new vnode represents a special device 33539433Smckusick * for which we already have a vnode (either because of 33639433Smckusick * bdevvp() or because of a different vnode representing 33739433Smckusick * the same block device). If such an alias exists, deallocate 33839509Smckusick * the existing contents and return the aliased vnode. The 33939433Smckusick * caller is responsible for filling it with its new contents. 34039433Smckusick */ 34139433Smckusick struct vnode * 34239615Smckusick checkalias(nvp, nvp_rdev, mp) 34339433Smckusick register struct vnode *nvp; 34439615Smckusick dev_t nvp_rdev; 34539433Smckusick struct mount *mp; 34639433Smckusick { 34739433Smckusick register struct vnode *vp; 34839615Smckusick struct vnode **vpp; 34939433Smckusick 35039433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 35139433Smckusick return ((struct vnode *)0); 35239615Smckusick 35339615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 35439433Smckusick loop: 35539615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 35639615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 35739433Smckusick continue; 35839615Smckusick /* 35939615Smckusick * Alias, but not in use, so flush it out. 36039615Smckusick */ 36139809Smckusick if (vp->v_usecount == 0) { 36239615Smckusick vgone(vp); 36339615Smckusick goto loop; 36439615Smckusick } 36539633Smckusick if (vget(vp)) 36639633Smckusick goto loop; 36739433Smckusick break; 36839433Smckusick } 36939615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 37039615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 37139615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 37239615Smckusick nvp->v_rdev = nvp_rdev; 37339809Smckusick nvp->v_hashchain = vpp; 37439615Smckusick nvp->v_specnext = *vpp; 37539615Smckusick *vpp = nvp; 37640640Smckusick if (vp != NULL) { 37740640Smckusick nvp->v_flag |= VALIASED; 37840640Smckusick vp->v_flag |= VALIASED; 37940640Smckusick vput(vp); 38040640Smckusick } 38139433Smckusick return ((struct vnode *)0); 38239433Smckusick } 38339484Smckusick VOP_UNLOCK(vp); 38439484Smckusick vclean(vp, 0); 38539433Smckusick vp->v_op = nvp->v_op; 38639433Smckusick vp->v_tag = nvp->v_tag; 38739433Smckusick nvp->v_type = VNON; 38839433Smckusick insmntque(vp, mp); 38939433Smckusick return (vp); 39039433Smckusick } 39139433Smckusick 39239433Smckusick /* 39339433Smckusick * Grab a particular vnode from the free list, increment its 39439433Smckusick * reference count and lock it. The vnode lock bit is set the 39539433Smckusick * vnode is being eliminated in vgone. The process is awakened 39639433Smckusick * when the transition is completed, and an error returned to 39739433Smckusick * indicate that the vnode is no longer usable (possibly having 39839433Smckusick * been changed to a new file system type). 39939433Smckusick */ 40039397Smckusick vget(vp) 40139397Smckusick register struct vnode *vp; 40239397Smckusick { 40339397Smckusick register struct vnode *vq; 40439397Smckusick 40539433Smckusick if (vp->v_flag & VXLOCK) { 40639433Smckusick vp->v_flag |= VXWANT; 40739433Smckusick sleep((caddr_t)vp, PINOD); 40839433Smckusick return (1); 40939433Smckusick } 41039809Smckusick if (vp->v_usecount == 0) { 41139433Smckusick if (vq = vp->v_freef) 41239433Smckusick vq->v_freeb = vp->v_freeb; 41339433Smckusick else 41439433Smckusick vfreet = vp->v_freeb; 41539433Smckusick *vp->v_freeb = vq; 41639433Smckusick vp->v_freef = NULL; 41739433Smckusick vp->v_freeb = NULL; 41839433Smckusick } 41939397Smckusick VREF(vp); 42039433Smckusick VOP_LOCK(vp); 42139433Smckusick return (0); 42239397Smckusick } 42339397Smckusick 42439397Smckusick /* 42539397Smckusick * Vnode reference, just increment the count 42639397Smckusick */ 42739397Smckusick void vref(vp) 42839397Smckusick struct vnode *vp; 42939397Smckusick { 43039397Smckusick 43139809Smckusick vp->v_usecount++; 43239397Smckusick } 43339397Smckusick 43439397Smckusick /* 43539397Smckusick * vput(), just unlock and vrele() 43639397Smckusick */ 43739397Smckusick void vput(vp) 43839397Smckusick register struct vnode *vp; 43939397Smckusick { 44039397Smckusick VOP_UNLOCK(vp); 44139397Smckusick vrele(vp); 44239397Smckusick } 44339397Smckusick 44439397Smckusick /* 44539397Smckusick * Vnode release. 44639397Smckusick * If count drops to zero, call inactive routine and return to freelist. 44739397Smckusick */ 44839397Smckusick void vrele(vp) 44939397Smckusick register struct vnode *vp; 45039397Smckusick { 45139397Smckusick 45239397Smckusick if (vp == NULL) 45339433Smckusick panic("vrele: null vp"); 45439809Smckusick vp->v_usecount--; 45539809Smckusick if (vp->v_usecount < 0) 45639667Smckusick vprint("vrele: bad ref count", vp); 45739809Smckusick if (vp->v_usecount > 0) 45839397Smckusick return; 45939397Smckusick if (vfreeh == (struct vnode *)0) { 46039397Smckusick /* 46139397Smckusick * insert into empty list 46239397Smckusick */ 46339397Smckusick vfreeh = vp; 46439397Smckusick vp->v_freeb = &vfreeh; 46539397Smckusick } else { 46639397Smckusick /* 46739397Smckusick * insert at tail of list 46839397Smckusick */ 46939397Smckusick *vfreet = vp; 47039397Smckusick vp->v_freeb = vfreet; 47139397Smckusick } 47239433Smckusick vp->v_freef = NULL; 47339433Smckusick vfreet = &vp->v_freef; 47439433Smckusick VOP_INACTIVE(vp); 47539397Smckusick } 47639433Smckusick 47739433Smckusick /* 47839809Smckusick * Page or buffer structure gets a reference. 47939809Smckusick */ 48039809Smckusick vhold(vp) 48139809Smckusick register struct vnode *vp; 48239809Smckusick { 48339809Smckusick 48439809Smckusick vp->v_holdcnt++; 48539809Smckusick } 48639809Smckusick 48739809Smckusick /* 48839809Smckusick * Page or buffer structure frees a reference. 48939809Smckusick */ 49039809Smckusick holdrele(vp) 49139809Smckusick register struct vnode *vp; 49239809Smckusick { 49339809Smckusick 49439809Smckusick if (vp->v_holdcnt <= 0) 49539809Smckusick panic("holdrele: holdcnt"); 49639809Smckusick vp->v_holdcnt--; 49739809Smckusick } 49839809Smckusick 49939809Smckusick /* 50039509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 50139509Smckusick * 50239509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 50339509Smckusick * return error if any are found (nb: this is a user error, not a 50439509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 50539509Smckusick * that are found. 50639509Smckusick */ 50739509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 50839509Smckusick 50939509Smckusick vflush(mp, skipvp, flags) 51039509Smckusick struct mount *mp; 51139509Smckusick struct vnode *skipvp; 51239509Smckusick int flags; 51339509Smckusick { 51439509Smckusick register struct vnode *vp, *nvp; 51539509Smckusick int busy = 0; 51639509Smckusick 51739509Smckusick for (vp = mp->m_mounth; vp; vp = nvp) { 51839509Smckusick nvp = vp->v_mountf; 51939509Smckusick /* 52039509Smckusick * Skip over a selected vnode. 52139509Smckusick * Used by ufs to skip over the quota structure inode. 52239509Smckusick */ 52339509Smckusick if (vp == skipvp) 52439509Smckusick continue; 52539509Smckusick /* 52639809Smckusick * With v_usecount == 0, all we need to do is clear 52739509Smckusick * out the vnode data structures and we are done. 52839509Smckusick */ 52939809Smckusick if (vp->v_usecount == 0) { 53039509Smckusick vgone(vp); 53139509Smckusick continue; 53239509Smckusick } 53339509Smckusick /* 53439509Smckusick * For block or character devices, revert to an 53539509Smckusick * anonymous device. For all other files, just kill them. 53639509Smckusick */ 53739509Smckusick if (flags & MNT_FORCE) { 53839509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 53939509Smckusick vgone(vp); 54039509Smckusick } else { 54139509Smckusick vclean(vp, 0); 54239509Smckusick vp->v_op = &spec_vnodeops; 54339509Smckusick insmntque(vp, (struct mount *)0); 54439509Smckusick } 54539509Smckusick continue; 54639509Smckusick } 54739509Smckusick if (busyprt) 54839667Smckusick vprint("vflush: busy vnode", vp); 54939509Smckusick busy++; 55039509Smckusick } 55139509Smckusick if (busy) 55239509Smckusick return (EBUSY); 55339509Smckusick return (0); 55439509Smckusick } 55539509Smckusick 55639509Smckusick /* 55739433Smckusick * Disassociate the underlying file system from a vnode. 55839433Smckusick */ 55939484Smckusick void vclean(vp, doclose) 56039433Smckusick register struct vnode *vp; 56139484Smckusick long doclose; 56239433Smckusick { 56339433Smckusick struct vnodeops *origops; 56439484Smckusick int active; 56539433Smckusick 56639484Smckusick /* 56739484Smckusick * Check to see if the vnode is in use. 56839667Smckusick * If so we have to reference it before we clean it out 56939667Smckusick * so that its count cannot fall to zero and generate a 57039667Smckusick * race against ourselves to recycle it. 57139484Smckusick */ 57239809Smckusick if (active = vp->v_usecount) 57339484Smckusick VREF(vp); 57439484Smckusick /* 57539484Smckusick * Prevent the vnode from being recycled or 57639484Smckusick * brought into use while we clean it out. 57739484Smckusick */ 57839667Smckusick if (vp->v_flag & VXLOCK) 57939667Smckusick panic("vclean: deadlock"); 58039433Smckusick vp->v_flag |= VXLOCK; 58139433Smckusick /* 58239667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 58339667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 58439667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 58539667Smckusick * For active vnodes, it ensures that no other activity can 58639667Smckusick * occur while the buffer list is being cleaned out. 58739667Smckusick */ 58839667Smckusick VOP_LOCK(vp); 58939667Smckusick if (doclose) 59039667Smckusick vinvalbuf(vp, 1); 59139667Smckusick /* 59239433Smckusick * Prevent any further operations on the vnode from 59339433Smckusick * being passed through to the old file system. 59439433Smckusick */ 59539433Smckusick origops = vp->v_op; 59639433Smckusick vp->v_op = &dead_vnodeops; 59739433Smckusick vp->v_tag = VT_NON; 59839433Smckusick /* 59939484Smckusick * If purging an active vnode, it must be unlocked, closed, 60039484Smckusick * and deactivated before being reclaimed. 60139433Smckusick */ 60239667Smckusick (*(origops->vn_unlock))(vp); 60339484Smckusick if (active) { 60439484Smckusick if (doclose) 60539484Smckusick (*(origops->vn_close))(vp, 0, NOCRED); 60639433Smckusick (*(origops->vn_inactive))(vp); 60739433Smckusick } 60839433Smckusick /* 60939433Smckusick * Reclaim the vnode. 61039433Smckusick */ 61139433Smckusick if ((*(origops->vn_reclaim))(vp)) 61239433Smckusick panic("vclean: cannot reclaim"); 61339484Smckusick if (active) 61439484Smckusick vrele(vp); 61539433Smckusick /* 61639433Smckusick * Done with purge, notify sleepers in vget of the grim news. 61739433Smckusick */ 61839433Smckusick vp->v_flag &= ~VXLOCK; 61939433Smckusick if (vp->v_flag & VXWANT) { 62039433Smckusick vp->v_flag &= ~VXWANT; 62139433Smckusick wakeup((caddr_t)vp); 62239433Smckusick } 62339433Smckusick } 62439433Smckusick 62539433Smckusick /* 62639633Smckusick * Eliminate all activity associated with the requested vnode 62739633Smckusick * and with all vnodes aliased to the requested vnode. 62839633Smckusick */ 62939633Smckusick void vgoneall(vp) 63039633Smckusick register struct vnode *vp; 63139633Smckusick { 63239809Smckusick register struct vnode *vq; 63339633Smckusick 63439809Smckusick while (vp->v_flag & VALIASED) { 63539809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 63640050Smckusick if (vq->v_rdev != vp->v_rdev || 63740050Smckusick vq->v_type != vp->v_type || vp == vq) 63839633Smckusick continue; 63939633Smckusick vgone(vq); 64039809Smckusick break; 64139633Smckusick } 64239633Smckusick } 64339633Smckusick vgone(vp); 64439633Smckusick } 64539633Smckusick 64639633Smckusick /* 64739433Smckusick * Eliminate all activity associated with a vnode 64839433Smckusick * in preparation for reuse. 64939433Smckusick */ 65039433Smckusick void vgone(vp) 65139433Smckusick register struct vnode *vp; 65239433Smckusick { 65339809Smckusick register struct vnode *vq; 65439615Smckusick struct vnode *vx; 65539615Smckusick long count; 65639433Smckusick 65739433Smckusick /* 65840548Smckusick * If a vgone (or vclean) is already in progress, 65940548Smckusick * wait until it is done and return. 66040548Smckusick */ 66140548Smckusick if (vp->v_flag & VXLOCK) { 66240548Smckusick vp->v_flag |= VXWANT; 66340548Smckusick sleep((caddr_t)vp, PINOD); 66440548Smckusick return; 66540548Smckusick } 66640548Smckusick /* 66739433Smckusick * Clean out the filesystem specific data. 66839433Smckusick */ 66939484Smckusick vclean(vp, 1); 67039433Smckusick /* 67139433Smckusick * Delete from old mount point vnode list, if on one. 67239433Smckusick */ 67339433Smckusick if (vp->v_mountb) { 67439433Smckusick if (vq = vp->v_mountf) 67539433Smckusick vq->v_mountb = vp->v_mountb; 67639433Smckusick *vp->v_mountb = vq; 67739433Smckusick vp->v_mountf = NULL; 67839433Smckusick vp->v_mountb = NULL; 67939433Smckusick } 68039433Smckusick /* 68139433Smckusick * If special device, remove it from special device alias list. 68239433Smckusick */ 68339433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 68439809Smckusick if (*vp->v_hashchain == vp) { 68539809Smckusick *vp->v_hashchain = vp->v_specnext; 68639433Smckusick } else { 68739809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 68839615Smckusick if (vq->v_specnext != vp) 68939433Smckusick continue; 69039615Smckusick vq->v_specnext = vp->v_specnext; 69139433Smckusick break; 69239433Smckusick } 69339615Smckusick if (vq == NULL) 69439433Smckusick panic("missing bdev"); 69539433Smckusick } 69639615Smckusick if (vp->v_flag & VALIASED) { 69739809Smckusick count = 0; 69839809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 69940108Smckusick if (vq->v_rdev != vp->v_rdev || 70040108Smckusick vq->v_type != vp->v_type) 70139615Smckusick continue; 70239615Smckusick count++; 70339615Smckusick vx = vq; 70439615Smckusick } 70539615Smckusick if (count == 0) 70639615Smckusick panic("missing alias"); 70739615Smckusick if (count == 1) 70839615Smckusick vx->v_flag &= ~VALIASED; 70939615Smckusick vp->v_flag &= ~VALIASED; 71039615Smckusick } 71139615Smckusick FREE(vp->v_specinfo, M_VNODE); 71239615Smckusick vp->v_specinfo = NULL; 71339433Smckusick } 71439433Smckusick /* 71539433Smckusick * If it is on the freelist, move it to the head of the list. 71639433Smckusick */ 71739433Smckusick if (vp->v_freeb) { 71839433Smckusick if (vq = vp->v_freef) 71939433Smckusick vq->v_freeb = vp->v_freeb; 72039433Smckusick else 72139433Smckusick vfreet = vp->v_freeb; 72239433Smckusick *vp->v_freeb = vq; 72339433Smckusick vp->v_freef = vfreeh; 72439433Smckusick vp->v_freeb = &vfreeh; 72539433Smckusick vfreeh->v_freeb = &vp->v_freef; 72639433Smckusick vfreeh = vp; 72739433Smckusick } 72839484Smckusick vp->v_type = VBAD; 72939433Smckusick } 73039633Smckusick 73139633Smckusick /* 73239821Smckusick * Lookup a vnode by device number. 73339821Smckusick */ 73439821Smckusick vfinddev(dev, type, vpp) 73539821Smckusick dev_t dev; 73639821Smckusick enum vtype type; 73739821Smckusick struct vnode **vpp; 73839821Smckusick { 73939821Smckusick register struct vnode *vp; 74039821Smckusick 74139821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 74239821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 74339821Smckusick continue; 74439821Smckusick *vpp = vp; 74539821Smckusick return (0); 74639821Smckusick } 74739821Smckusick return (1); 74839821Smckusick } 74939821Smckusick 75039821Smckusick /* 75139633Smckusick * Calculate the total number of references to a special device. 75239633Smckusick */ 75339633Smckusick vcount(vp) 75439633Smckusick register struct vnode *vp; 75539633Smckusick { 75639809Smckusick register struct vnode *vq; 75739633Smckusick int count; 75839633Smckusick 75939633Smckusick if ((vp->v_flag & VALIASED) == 0) 76039809Smckusick return (vp->v_usecount); 76139633Smckusick loop: 76239809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 76340108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 76439633Smckusick continue; 76539633Smckusick /* 76639633Smckusick * Alias, but not in use, so flush it out. 76739633Smckusick */ 76839809Smckusick if (vq->v_usecount == 0) { 76939633Smckusick vgone(vq); 77039633Smckusick goto loop; 77139633Smckusick } 77239809Smckusick count += vq->v_usecount; 77339633Smckusick } 77439633Smckusick return (count); 77539633Smckusick } 77639667Smckusick 77739667Smckusick /* 77839667Smckusick * Print out a description of a vnode. 77939667Smckusick */ 78039667Smckusick static char *typename[] = 78140286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 78239667Smckusick 78339667Smckusick vprint(label, vp) 78439667Smckusick char *label; 78539667Smckusick register struct vnode *vp; 78639667Smckusick { 78739913Smckusick char buf[64]; 78839667Smckusick 78939667Smckusick if (label != NULL) 79039667Smckusick printf("%s: ", label); 79139913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 79239809Smckusick vp->v_usecount, vp->v_holdcnt); 79339913Smckusick buf[0] = '\0'; 79439913Smckusick if (vp->v_flag & VROOT) 79539913Smckusick strcat(buf, "|VROOT"); 79639913Smckusick if (vp->v_flag & VTEXT) 79739913Smckusick strcat(buf, "|VTEXT"); 79839913Smckusick if (vp->v_flag & VXLOCK) 79939913Smckusick strcat(buf, "|VXLOCK"); 80039913Smckusick if (vp->v_flag & VXWANT) 80139913Smckusick strcat(buf, "|VXWANT"); 80239913Smckusick if (vp->v_flag & VEXLOCK) 80339913Smckusick strcat(buf, "|VEXLOCK"); 80439913Smckusick if (vp->v_flag & VSHLOCK) 80539913Smckusick strcat(buf, "|VSHLOCK"); 80639913Smckusick if (vp->v_flag & VLWAIT) 80739913Smckusick strcat(buf, "|VLWAIT"); 80839913Smckusick if (vp->v_flag & VALIASED) 80939913Smckusick strcat(buf, "|VALIASED"); 81039913Smckusick if (vp->v_flag & VBWAIT) 81139913Smckusick strcat(buf, "|VBWAIT"); 81239913Smckusick if (buf[0] != '\0') 81339913Smckusick printf(" flags (%s)", &buf[1]); 81439913Smckusick printf("\n\t"); 81539667Smckusick VOP_PRINT(vp); 81639667Smckusick } 817