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*42152Smckusick * @(#)vfs_subr.c 7.46 (Berkeley) 05/16/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"); 4541400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 4641400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 4741400Smckusick mp->mnt_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 5941400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 6041400Smckusick mp->mnt_flag |= MNT_MWAIT; 6139045Smckusick sleep((caddr_t)mp, PVFS); 6239045Smckusick } 6341400Smckusick mp->mnt_flag |= MNT_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 7641400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 7741300Smckusick panic("vfs_unlock: not locked"); 7841400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 7941400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 8041400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 8137488Smckusick wakeup((caddr_t)mp); 8237488Smckusick } 8337488Smckusick } 8437488Smckusick 8537488Smckusick /* 8641300Smckusick * Mark a mount point as busy. 8741300Smckusick * Used to synchronize access and to delay unmounting. 8841300Smckusick */ 8941300Smckusick vfs_busy(mp) 9041300Smckusick register struct mount *mp; 9141300Smckusick { 9241300Smckusick 9341400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 9441400Smckusick mp->mnt_flag |= MNT_MPWANT; 9541400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 9641300Smckusick } 9741419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 9841419Smckusick return (1); 9941400Smckusick mp->mnt_flag |= MNT_MPBUSY; 10041300Smckusick return (0); 10141300Smckusick } 10241300Smckusick 10341300Smckusick /* 10441300Smckusick * Free a busy filesystem. 10541300Smckusick * Panic if filesystem is not busy. 10641300Smckusick */ 10741300Smckusick void 10841300Smckusick vfs_unbusy(mp) 10941300Smckusick register struct mount *mp; 11041300Smckusick { 11141300Smckusick 11241400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 11341300Smckusick panic("vfs_unbusy: not busy"); 11441400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 11541400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 11641400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 11741400Smckusick wakeup((caddr_t)&mp->mnt_flag); 11841300Smckusick } 11941300Smckusick } 12041300Smckusick 12141300Smckusick /* 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 { 13241400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 13341400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 13438288Smckusick return (mp); 13537488Smckusick } 13641400Smckusick mp = mp->mnt_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; 21141363Smckusick struct vattr va_null; 21239397Smckusick 21339397Smckusick /* 21439433Smckusick * Initialize the vnode structures and initialize each file system type. 21539397Smckusick */ 21639433Smckusick vfsinit() 21739397Smckusick { 21839433Smckusick struct vfsops **vfsp; 21939397Smckusick 22039433Smckusick /* 22139433Smckusick * Initialize the vnode name cache 22239433Smckusick */ 22339433Smckusick nchinit(); 22439433Smckusick /* 22539433Smckusick * Initialize each file system type. 22639433Smckusick */ 22741363Smckusick vattr_null(&va_null); 22839433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 22939433Smckusick if (*vfsp == NULL) 23039433Smckusick continue; 23139433Smckusick (*(*vfsp)->vfs_init)(); 23239433Smckusick } 23339397Smckusick } 23439397Smckusick 23539397Smckusick /* 23639397Smckusick * Return the next vnode from the free list. 23739397Smckusick */ 23839397Smckusick getnewvnode(tag, mp, vops, vpp) 23939397Smckusick enum vtagtype tag; 24039397Smckusick struct mount *mp; 24139397Smckusick struct vnodeops *vops; 24239397Smckusick struct vnode **vpp; 24339397Smckusick { 24439397Smckusick register struct vnode *vp, *vq; 24539397Smckusick 24640883Smckusick if (numvnodes < desiredvnodes) { 24740883Smckusick vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK); 24840883Smckusick bzero((char *)vp, sizeof *vp); 24940883Smckusick numvnodes++; 25040883Smckusick } else { 25140883Smckusick if ((vp = vfreeh) == NULL) { 25240883Smckusick tablefull("vnode"); 25340883Smckusick *vpp = 0; 25440883Smckusick return (ENFILE); 25540883Smckusick } 25640883Smckusick if (vp->v_usecount) 25740883Smckusick panic("free vnode isn't"); 25840883Smckusick if (vq = vp->v_freef) 25940883Smckusick vq->v_freeb = &vfreeh; 26040883Smckusick else 26140883Smckusick vfreet = &vfreeh; 26240883Smckusick vfreeh = vq; 26340883Smckusick vp->v_freef = NULL; 26440883Smckusick vp->v_freeb = NULL; 26540883Smckusick if (vp->v_type != VBAD) 26640883Smckusick vgone(vp); 26740883Smckusick vp->v_flag = 0; 26840883Smckusick vp->v_shlockc = 0; 26940883Smckusick vp->v_exlockc = 0; 27040883Smckusick vp->v_lastr = 0; 27140883Smckusick vp->v_socket = 0; 27239397Smckusick } 27339512Smckusick vp->v_type = VNON; 27439397Smckusick cache_purge(vp); 27539397Smckusick vp->v_tag = tag; 27639433Smckusick vp->v_op = vops; 27739397Smckusick insmntque(vp, mp); 27839397Smckusick VREF(vp); 27939397Smckusick *vpp = vp; 28039397Smckusick return (0); 28139397Smckusick } 28239397Smckusick 28339397Smckusick /* 28439397Smckusick * Move a vnode from one mount queue to another. 28539397Smckusick */ 28639397Smckusick insmntque(vp, mp) 28739397Smckusick register struct vnode *vp; 28839397Smckusick register struct mount *mp; 28939397Smckusick { 29039397Smckusick struct vnode *vq; 29139397Smckusick 29239397Smckusick /* 29339397Smckusick * Delete from old mount point vnode list, if on one. 29439397Smckusick */ 29539397Smckusick if (vp->v_mountb) { 29639397Smckusick if (vq = vp->v_mountf) 29739397Smckusick vq->v_mountb = vp->v_mountb; 29839397Smckusick *vp->v_mountb = vq; 29939397Smckusick } 30039397Smckusick /* 30139397Smckusick * Insert into list of vnodes for the new mount point, if available. 30239397Smckusick */ 30339621Smckusick vp->v_mount = mp; 30439397Smckusick if (mp == NULL) { 30539397Smckusick vp->v_mountf = NULL; 30639397Smckusick vp->v_mountb = NULL; 30739397Smckusick return; 30839397Smckusick } 30941400Smckusick if (mp->mnt_mounth) { 31041400Smckusick vp->v_mountf = mp->mnt_mounth; 31141400Smckusick vp->v_mountb = &mp->mnt_mounth; 31241400Smckusick mp->mnt_mounth->v_mountb = &vp->v_mountf; 31341400Smckusick mp->mnt_mounth = vp; 31439397Smckusick } else { 31541400Smckusick mp->mnt_mounth = vp; 31641400Smckusick vp->v_mountb = &mp->mnt_mounth; 31739397Smckusick vp->v_mountf = NULL; 31839397Smckusick } 31939397Smckusick } 32039397Smckusick 32139397Smckusick /* 32239433Smckusick * Create a vnode for a block device. 32339433Smckusick * Used for root filesystem, argdev, and swap areas. 32439433Smckusick * Also used for memory file system special devices. 32539397Smckusick */ 32639433Smckusick bdevvp(dev, vpp) 32739433Smckusick dev_t dev; 32839433Smckusick struct vnode **vpp; 32939433Smckusick { 33039433Smckusick register struct vnode *vp; 33139433Smckusick struct vnode *nvp; 33239433Smckusick int error; 33339433Smckusick 33439447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 33539433Smckusick if (error) { 33639433Smckusick *vpp = 0; 33739433Smckusick return (error); 33839433Smckusick } 33939433Smckusick vp = nvp; 34039433Smckusick vp->v_type = VBLK; 34139615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 34239433Smckusick vput(vp); 34339433Smckusick vp = nvp; 34439433Smckusick } 34539433Smckusick *vpp = vp; 34639433Smckusick return (0); 34739433Smckusick } 34839433Smckusick 34939433Smckusick /* 35039433Smckusick * Check to see if the new vnode represents a special device 35139433Smckusick * for which we already have a vnode (either because of 35239433Smckusick * bdevvp() or because of a different vnode representing 35339433Smckusick * the same block device). If such an alias exists, deallocate 35439509Smckusick * the existing contents and return the aliased vnode. The 35539433Smckusick * caller is responsible for filling it with its new contents. 35639433Smckusick */ 35739433Smckusick struct vnode * 35839615Smckusick checkalias(nvp, nvp_rdev, mp) 35939433Smckusick register struct vnode *nvp; 36039615Smckusick dev_t nvp_rdev; 36139433Smckusick struct mount *mp; 36239433Smckusick { 36339433Smckusick register struct vnode *vp; 36439615Smckusick struct vnode **vpp; 36539433Smckusick 36639433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 36741400Smckusick return (NULLVP); 36839615Smckusick 36939615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 37039433Smckusick loop: 37139615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 37239615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 37339433Smckusick continue; 37439615Smckusick /* 37539615Smckusick * Alias, but not in use, so flush it out. 37639615Smckusick */ 37739809Smckusick if (vp->v_usecount == 0) { 37839615Smckusick vgone(vp); 37939615Smckusick goto loop; 38039615Smckusick } 38139633Smckusick if (vget(vp)) 38239633Smckusick goto loop; 38339433Smckusick break; 38439433Smckusick } 38539615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 38639615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 38739615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 38839615Smckusick nvp->v_rdev = nvp_rdev; 38939809Smckusick nvp->v_hashchain = vpp; 39039615Smckusick nvp->v_specnext = *vpp; 391*42152Smckusick nvp->v_specflags = 0; 39239615Smckusick *vpp = nvp; 39340640Smckusick if (vp != NULL) { 39440640Smckusick nvp->v_flag |= VALIASED; 39540640Smckusick vp->v_flag |= VALIASED; 39640640Smckusick vput(vp); 39740640Smckusick } 39841400Smckusick return (NULLVP); 39939433Smckusick } 40039484Smckusick VOP_UNLOCK(vp); 40139484Smckusick vclean(vp, 0); 40239433Smckusick vp->v_op = nvp->v_op; 40339433Smckusick vp->v_tag = nvp->v_tag; 40439433Smckusick nvp->v_type = VNON; 40539433Smckusick insmntque(vp, mp); 40639433Smckusick return (vp); 40739433Smckusick } 40839433Smckusick 40939433Smckusick /* 41039433Smckusick * Grab a particular vnode from the free list, increment its 41139433Smckusick * reference count and lock it. The vnode lock bit is set the 41239433Smckusick * vnode is being eliminated in vgone. The process is awakened 41339433Smckusick * when the transition is completed, and an error returned to 41439433Smckusick * indicate that the vnode is no longer usable (possibly having 41539433Smckusick * been changed to a new file system type). 41639433Smckusick */ 41739397Smckusick vget(vp) 41839397Smckusick register struct vnode *vp; 41939397Smckusick { 42039397Smckusick register struct vnode *vq; 42139397Smckusick 42239433Smckusick if (vp->v_flag & VXLOCK) { 42339433Smckusick vp->v_flag |= VXWANT; 42439433Smckusick sleep((caddr_t)vp, PINOD); 42539433Smckusick return (1); 42639433Smckusick } 42739809Smckusick if (vp->v_usecount == 0) { 42839433Smckusick if (vq = vp->v_freef) 42939433Smckusick vq->v_freeb = vp->v_freeb; 43039433Smckusick else 43139433Smckusick vfreet = vp->v_freeb; 43239433Smckusick *vp->v_freeb = vq; 43339433Smckusick vp->v_freef = NULL; 43439433Smckusick vp->v_freeb = NULL; 43539433Smckusick } 43639397Smckusick VREF(vp); 43739433Smckusick VOP_LOCK(vp); 43839433Smckusick return (0); 43939397Smckusick } 44039397Smckusick 44139397Smckusick /* 44239397Smckusick * Vnode reference, just increment the count 44339397Smckusick */ 44439397Smckusick void vref(vp) 44539397Smckusick struct vnode *vp; 44639397Smckusick { 44739397Smckusick 44839809Smckusick vp->v_usecount++; 44939397Smckusick } 45039397Smckusick 45139397Smckusick /* 45239397Smckusick * vput(), just unlock and vrele() 45339397Smckusick */ 45439397Smckusick void vput(vp) 45539397Smckusick register struct vnode *vp; 45639397Smckusick { 45739397Smckusick VOP_UNLOCK(vp); 45839397Smckusick vrele(vp); 45939397Smckusick } 46039397Smckusick 46139397Smckusick /* 46239397Smckusick * Vnode release. 46339397Smckusick * If count drops to zero, call inactive routine and return to freelist. 46439397Smckusick */ 46539397Smckusick void vrele(vp) 46639397Smckusick register struct vnode *vp; 46739397Smckusick { 46839397Smckusick 46939397Smckusick if (vp == NULL) 47039433Smckusick panic("vrele: null vp"); 47139809Smckusick vp->v_usecount--; 47239809Smckusick if (vp->v_usecount < 0) 47339667Smckusick vprint("vrele: bad ref count", vp); 47439809Smckusick if (vp->v_usecount > 0) 47539397Smckusick return; 47641400Smckusick if (vfreeh == NULLVP) { 47739397Smckusick /* 47839397Smckusick * insert into empty list 47939397Smckusick */ 48039397Smckusick vfreeh = vp; 48139397Smckusick vp->v_freeb = &vfreeh; 48239397Smckusick } else { 48339397Smckusick /* 48439397Smckusick * insert at tail of list 48539397Smckusick */ 48639397Smckusick *vfreet = vp; 48739397Smckusick vp->v_freeb = vfreet; 48839397Smckusick } 48939433Smckusick vp->v_freef = NULL; 49039433Smckusick vfreet = &vp->v_freef; 49139433Smckusick VOP_INACTIVE(vp); 49239397Smckusick } 49339433Smckusick 49439433Smckusick /* 49539809Smckusick * Page or buffer structure gets a reference. 49639809Smckusick */ 49739809Smckusick vhold(vp) 49839809Smckusick register struct vnode *vp; 49939809Smckusick { 50039809Smckusick 50139809Smckusick vp->v_holdcnt++; 50239809Smckusick } 50339809Smckusick 50439809Smckusick /* 50539809Smckusick * Page or buffer structure frees a reference. 50639809Smckusick */ 50739809Smckusick holdrele(vp) 50839809Smckusick register struct vnode *vp; 50939809Smckusick { 51039809Smckusick 51139809Smckusick if (vp->v_holdcnt <= 0) 51239809Smckusick panic("holdrele: holdcnt"); 51339809Smckusick vp->v_holdcnt--; 51439809Smckusick } 51539809Smckusick 51639809Smckusick /* 51739509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 51839509Smckusick * 51939509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 52039509Smckusick * return error if any are found (nb: this is a user error, not a 52139509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 52239509Smckusick * that are found. 52339509Smckusick */ 52439509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 52539509Smckusick 52639509Smckusick vflush(mp, skipvp, flags) 52739509Smckusick struct mount *mp; 52839509Smckusick struct vnode *skipvp; 52939509Smckusick int flags; 53039509Smckusick { 53139509Smckusick register struct vnode *vp, *nvp; 53239509Smckusick int busy = 0; 53339509Smckusick 53441400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 53541300Smckusick panic("vflush: not busy"); 53641421Smckusick loop: 53741400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 53841421Smckusick if (vp->v_mount != mp) 53941421Smckusick goto loop; 54039509Smckusick nvp = vp->v_mountf; 54139509Smckusick /* 54239509Smckusick * Skip over a selected vnode. 54339509Smckusick */ 54439509Smckusick if (vp == skipvp) 54539509Smckusick continue; 54639509Smckusick /* 54741300Smckusick * Skip over a vnodes marked VSYSTEM. 54841300Smckusick */ 54941300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 55041300Smckusick continue; 55141300Smckusick /* 55239809Smckusick * With v_usecount == 0, all we need to do is clear 55339509Smckusick * out the vnode data structures and we are done. 55439509Smckusick */ 55539809Smckusick if (vp->v_usecount == 0) { 55639509Smckusick vgone(vp); 55739509Smckusick continue; 55839509Smckusick } 55939509Smckusick /* 56039509Smckusick * For block or character devices, revert to an 56139509Smckusick * anonymous device. For all other files, just kill them. 56239509Smckusick */ 56341300Smckusick if (flags & FORCECLOSE) { 56439509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 56539509Smckusick vgone(vp); 56639509Smckusick } else { 56739509Smckusick vclean(vp, 0); 56839509Smckusick vp->v_op = &spec_vnodeops; 56939509Smckusick insmntque(vp, (struct mount *)0); 57039509Smckusick } 57139509Smckusick continue; 57239509Smckusick } 57339509Smckusick if (busyprt) 57439667Smckusick vprint("vflush: busy vnode", vp); 57539509Smckusick busy++; 57639509Smckusick } 57739509Smckusick if (busy) 57839509Smckusick return (EBUSY); 57939509Smckusick return (0); 58039509Smckusick } 58139509Smckusick 58239509Smckusick /* 58339433Smckusick * Disassociate the underlying file system from a vnode. 58439433Smckusick */ 58541300Smckusick void vclean(vp, flags) 58639433Smckusick register struct vnode *vp; 58741300Smckusick long flags; 58839433Smckusick { 58939433Smckusick struct vnodeops *origops; 59039484Smckusick int active; 59139433Smckusick 59239484Smckusick /* 59339484Smckusick * Check to see if the vnode is in use. 59439667Smckusick * If so we have to reference it before we clean it out 59539667Smckusick * so that its count cannot fall to zero and generate a 59639667Smckusick * race against ourselves to recycle it. 59739484Smckusick */ 59839809Smckusick if (active = vp->v_usecount) 59939484Smckusick VREF(vp); 60039484Smckusick /* 60139484Smckusick * Prevent the vnode from being recycled or 60239484Smckusick * brought into use while we clean it out. 60339484Smckusick */ 60439667Smckusick if (vp->v_flag & VXLOCK) 60539667Smckusick panic("vclean: deadlock"); 60639433Smckusick vp->v_flag |= VXLOCK; 60739433Smckusick /* 60839667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 60939667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 61039667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 61139667Smckusick * For active vnodes, it ensures that no other activity can 61239667Smckusick * occur while the buffer list is being cleaned out. 61339667Smckusick */ 61439667Smckusick VOP_LOCK(vp); 61541300Smckusick if (flags & DOCLOSE) 61639667Smckusick vinvalbuf(vp, 1); 61739667Smckusick /* 61839433Smckusick * Prevent any further operations on the vnode from 61939433Smckusick * being passed through to the old file system. 62039433Smckusick */ 62139433Smckusick origops = vp->v_op; 62239433Smckusick vp->v_op = &dead_vnodeops; 62339433Smckusick vp->v_tag = VT_NON; 62439433Smckusick /* 62539484Smckusick * If purging an active vnode, it must be unlocked, closed, 62639484Smckusick * and deactivated before being reclaimed. 62739433Smckusick */ 62839667Smckusick (*(origops->vn_unlock))(vp); 62939484Smckusick if (active) { 63041300Smckusick if (flags & DOCLOSE) 63139484Smckusick (*(origops->vn_close))(vp, 0, NOCRED); 63239433Smckusick (*(origops->vn_inactive))(vp); 63339433Smckusick } 63439433Smckusick /* 63539433Smckusick * Reclaim the vnode. 63639433Smckusick */ 63739433Smckusick if ((*(origops->vn_reclaim))(vp)) 63839433Smckusick panic("vclean: cannot reclaim"); 63939484Smckusick if (active) 64039484Smckusick vrele(vp); 64139433Smckusick /* 64239433Smckusick * Done with purge, notify sleepers in vget of the grim news. 64339433Smckusick */ 64439433Smckusick vp->v_flag &= ~VXLOCK; 64539433Smckusick if (vp->v_flag & VXWANT) { 64639433Smckusick vp->v_flag &= ~VXWANT; 64739433Smckusick wakeup((caddr_t)vp); 64839433Smckusick } 64939433Smckusick } 65039433Smckusick 65139433Smckusick /* 65239633Smckusick * Eliminate all activity associated with the requested vnode 65339633Smckusick * and with all vnodes aliased to the requested vnode. 65439633Smckusick */ 65539633Smckusick void vgoneall(vp) 65639633Smckusick register struct vnode *vp; 65739633Smckusick { 65839809Smckusick register struct vnode *vq; 65939633Smckusick 66040665Smckusick if (vp->v_flag & VALIASED) { 66140665Smckusick /* 66240665Smckusick * If a vgone (or vclean) is already in progress, 66340665Smckusick * wait until it is done and return. 66440665Smckusick */ 66540665Smckusick if (vp->v_flag & VXLOCK) { 66640665Smckusick vp->v_flag |= VXWANT; 66740665Smckusick sleep((caddr_t)vp, PINOD); 66840665Smckusick return; 66939633Smckusick } 67040665Smckusick /* 67140665Smckusick * Ensure that vp will not be vgone'd while we 67240665Smckusick * are eliminating its aliases. 67340665Smckusick */ 67440665Smckusick vp->v_flag |= VXLOCK; 67540665Smckusick while (vp->v_flag & VALIASED) { 67640665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 67740665Smckusick if (vq->v_rdev != vp->v_rdev || 67840665Smckusick vq->v_type != vp->v_type || vp == vq) 67940665Smckusick continue; 68040665Smckusick vgone(vq); 68140665Smckusick break; 68240665Smckusick } 68340665Smckusick } 68440665Smckusick /* 68540665Smckusick * Remove the lock so that vgone below will 68640665Smckusick * really eliminate the vnode after which time 68740665Smckusick * vgone will awaken any sleepers. 68840665Smckusick */ 68940665Smckusick vp->v_flag &= ~VXLOCK; 69039633Smckusick } 69139633Smckusick vgone(vp); 69239633Smckusick } 69339633Smckusick 69439633Smckusick /* 69539433Smckusick * Eliminate all activity associated with a vnode 69639433Smckusick * in preparation for reuse. 69739433Smckusick */ 69839433Smckusick void vgone(vp) 69939433Smckusick register struct vnode *vp; 70039433Smckusick { 70139809Smckusick register struct vnode *vq; 70239615Smckusick struct vnode *vx; 70339615Smckusick long count; 70439433Smckusick 70539433Smckusick /* 70640548Smckusick * If a vgone (or vclean) is already in progress, 70740548Smckusick * wait until it is done and return. 70840548Smckusick */ 70940548Smckusick if (vp->v_flag & VXLOCK) { 71040548Smckusick vp->v_flag |= VXWANT; 71140548Smckusick sleep((caddr_t)vp, PINOD); 71240548Smckusick return; 71340548Smckusick } 71440548Smckusick /* 71539433Smckusick * Clean out the filesystem specific data. 71639433Smckusick */ 71741300Smckusick vclean(vp, DOCLOSE); 71839433Smckusick /* 71939433Smckusick * Delete from old mount point vnode list, if on one. 72039433Smckusick */ 72139433Smckusick if (vp->v_mountb) { 72239433Smckusick if (vq = vp->v_mountf) 72339433Smckusick vq->v_mountb = vp->v_mountb; 72439433Smckusick *vp->v_mountb = vq; 72539433Smckusick vp->v_mountf = NULL; 72639433Smckusick vp->v_mountb = NULL; 72739433Smckusick } 72839433Smckusick /* 72939433Smckusick * If special device, remove it from special device alias list. 73039433Smckusick */ 73139433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 73239809Smckusick if (*vp->v_hashchain == vp) { 73339809Smckusick *vp->v_hashchain = vp->v_specnext; 73439433Smckusick } else { 73539809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 73639615Smckusick if (vq->v_specnext != vp) 73739433Smckusick continue; 73839615Smckusick vq->v_specnext = vp->v_specnext; 73939433Smckusick break; 74039433Smckusick } 74139615Smckusick if (vq == NULL) 74239433Smckusick panic("missing bdev"); 74339433Smckusick } 74439615Smckusick if (vp->v_flag & VALIASED) { 74539809Smckusick count = 0; 74639809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 74740108Smckusick if (vq->v_rdev != vp->v_rdev || 74840108Smckusick vq->v_type != vp->v_type) 74939615Smckusick continue; 75039615Smckusick count++; 75139615Smckusick vx = vq; 75239615Smckusick } 75339615Smckusick if (count == 0) 75439615Smckusick panic("missing alias"); 75539615Smckusick if (count == 1) 75639615Smckusick vx->v_flag &= ~VALIASED; 75739615Smckusick vp->v_flag &= ~VALIASED; 75839615Smckusick } 75939615Smckusick FREE(vp->v_specinfo, M_VNODE); 76039615Smckusick vp->v_specinfo = NULL; 76139433Smckusick } 76239433Smckusick /* 76339433Smckusick * If it is on the freelist, move it to the head of the list. 76439433Smckusick */ 76539433Smckusick if (vp->v_freeb) { 76639433Smckusick if (vq = vp->v_freef) 76739433Smckusick vq->v_freeb = vp->v_freeb; 76839433Smckusick else 76939433Smckusick vfreet = vp->v_freeb; 77039433Smckusick *vp->v_freeb = vq; 77139433Smckusick vp->v_freef = vfreeh; 77239433Smckusick vp->v_freeb = &vfreeh; 77339433Smckusick vfreeh->v_freeb = &vp->v_freef; 77439433Smckusick vfreeh = vp; 77539433Smckusick } 77639484Smckusick vp->v_type = VBAD; 77739433Smckusick } 77839633Smckusick 77939633Smckusick /* 78039821Smckusick * Lookup a vnode by device number. 78139821Smckusick */ 78239821Smckusick vfinddev(dev, type, vpp) 78339821Smckusick dev_t dev; 78439821Smckusick enum vtype type; 78539821Smckusick struct vnode **vpp; 78639821Smckusick { 78739821Smckusick register struct vnode *vp; 78839821Smckusick 78939821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 79039821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 79139821Smckusick continue; 79239821Smckusick *vpp = vp; 79339821Smckusick return (0); 79439821Smckusick } 79539821Smckusick return (1); 79639821Smckusick } 79739821Smckusick 79839821Smckusick /* 79939633Smckusick * Calculate the total number of references to a special device. 80039633Smckusick */ 80139633Smckusick vcount(vp) 80239633Smckusick register struct vnode *vp; 80339633Smckusick { 80439809Smckusick register struct vnode *vq; 80539633Smckusick int count; 80639633Smckusick 80739633Smckusick if ((vp->v_flag & VALIASED) == 0) 80839809Smckusick return (vp->v_usecount); 80939633Smckusick loop: 81039809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 81140108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 81239633Smckusick continue; 81339633Smckusick /* 81439633Smckusick * Alias, but not in use, so flush it out. 81539633Smckusick */ 81639809Smckusick if (vq->v_usecount == 0) { 81739633Smckusick vgone(vq); 81839633Smckusick goto loop; 81939633Smckusick } 82039809Smckusick count += vq->v_usecount; 82139633Smckusick } 82239633Smckusick return (count); 82339633Smckusick } 82439667Smckusick 82539667Smckusick /* 82639667Smckusick * Print out a description of a vnode. 82739667Smckusick */ 82839667Smckusick static char *typename[] = 82940286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 83039667Smckusick 83139667Smckusick vprint(label, vp) 83239667Smckusick char *label; 83339667Smckusick register struct vnode *vp; 83439667Smckusick { 83539913Smckusick char buf[64]; 83639667Smckusick 83739667Smckusick if (label != NULL) 83839667Smckusick printf("%s: ", label); 83939913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 84039809Smckusick vp->v_usecount, vp->v_holdcnt); 84139913Smckusick buf[0] = '\0'; 84239913Smckusick if (vp->v_flag & VROOT) 84339913Smckusick strcat(buf, "|VROOT"); 84439913Smckusick if (vp->v_flag & VTEXT) 84539913Smckusick strcat(buf, "|VTEXT"); 84641300Smckusick if (vp->v_flag & VSYSTEM) 84741300Smckusick strcat(buf, "|VSYSTEM"); 84839913Smckusick if (vp->v_flag & VEXLOCK) 84939913Smckusick strcat(buf, "|VEXLOCK"); 85039913Smckusick if (vp->v_flag & VSHLOCK) 85139913Smckusick strcat(buf, "|VSHLOCK"); 85239913Smckusick if (vp->v_flag & VLWAIT) 85339913Smckusick strcat(buf, "|VLWAIT"); 85441300Smckusick if (vp->v_flag & VXLOCK) 85541300Smckusick strcat(buf, "|VXLOCK"); 85641300Smckusick if (vp->v_flag & VXWANT) 85741300Smckusick strcat(buf, "|VXWANT"); 85841300Smckusick if (vp->v_flag & VBWAIT) 85941300Smckusick strcat(buf, "|VBWAIT"); 86039913Smckusick if (vp->v_flag & VALIASED) 86139913Smckusick strcat(buf, "|VALIASED"); 86239913Smckusick if (buf[0] != '\0') 86339913Smckusick printf(" flags (%s)", &buf[1]); 86439913Smckusick printf("\n\t"); 86539667Smckusick VOP_PRINT(vp); 86639667Smckusick } 86741110Smarc 86841110Smarc int kinfo_vdebug = 1; 86941110Smarc int kinfo_vgetfailed; 87041110Smarc #define KINFO_VNODESLOP 10 87141110Smarc /* 87241110Smarc * Dump vnode list (via kinfo). 87341110Smarc * Copyout address of vnode followed by vnode. 87441110Smarc */ 87541110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 87641110Smarc char *where; 87741110Smarc int *acopysize, *aneeded; 87841110Smarc { 87941110Smarc register struct mount *mp = rootfs; 88041300Smckusick struct mount *omp; 88141110Smarc struct vnode *vp; 88241110Smarc register needed = 0; 88341110Smarc register char *bp = where, *savebp; 88441110Smarc char *ewhere = where + *acopysize; 88541110Smarc int error; 88641110Smarc 88741110Smarc #define VPTRSZ sizeof (struct vnode *) 88841110Smarc #define VNODESZ sizeof (struct vnode) 88941110Smarc if (where == NULL) { 89041110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 89141110Smarc return (0); 89241110Smarc } 89341110Smarc 89441110Smarc do { 89541300Smckusick if (vfs_busy(mp)) { 89641400Smckusick mp = mp->mnt_next; 89741300Smckusick continue; 89841300Smckusick } 89941110Smarc savebp = bp; 90041110Smarc again: 90141421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 90241422Smckusick /* 90341422Smckusick * Check that the vp is still associated with 90441422Smckusick * this filesystem. RACE: could have been 90541422Smckusick * recycled onto the same filesystem. 90641422Smckusick */ 90741421Smckusick if (vp->v_mount != mp) { 90841421Smckusick if (kinfo_vdebug) 90941421Smckusick printf("kinfo: vp changed\n"); 91041421Smckusick bp = savebp; 91141421Smckusick goto again; 91241421Smckusick } 91341110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 91441110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 91541110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 91641422Smckusick VNODESZ)))) 91741110Smarc return (error); 91841110Smarc bp += VPTRSZ + VNODESZ; 91941110Smarc } 92041300Smckusick omp = mp; 92141400Smckusick mp = mp->mnt_next; 92241300Smckusick vfs_unbusy(omp); 92341110Smarc } while (mp != rootfs); 92441110Smarc 92541110Smarc *aneeded = bp - where; 92641110Smarc if (bp > ewhere) 92741110Smarc *acopysize = ewhere - where; 92841110Smarc else 92941110Smarc *acopysize = bp - where; 93041110Smarc return (0); 93141110Smarc } 932