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*41421Smckusick * @(#)vfs_subr.c 7.44 (Berkeley) 05/05/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; 39139615Smckusick *vpp = nvp; 39240640Smckusick if (vp != NULL) { 39340640Smckusick nvp->v_flag |= VALIASED; 39440640Smckusick vp->v_flag |= VALIASED; 39540640Smckusick vput(vp); 39640640Smckusick } 39741400Smckusick return (NULLVP); 39839433Smckusick } 39939484Smckusick VOP_UNLOCK(vp); 40039484Smckusick vclean(vp, 0); 40139433Smckusick vp->v_op = nvp->v_op; 40239433Smckusick vp->v_tag = nvp->v_tag; 40339433Smckusick nvp->v_type = VNON; 40439433Smckusick insmntque(vp, mp); 40539433Smckusick return (vp); 40639433Smckusick } 40739433Smckusick 40839433Smckusick /* 40939433Smckusick * Grab a particular vnode from the free list, increment its 41039433Smckusick * reference count and lock it. The vnode lock bit is set the 41139433Smckusick * vnode is being eliminated in vgone. The process is awakened 41239433Smckusick * when the transition is completed, and an error returned to 41339433Smckusick * indicate that the vnode is no longer usable (possibly having 41439433Smckusick * been changed to a new file system type). 41539433Smckusick */ 41639397Smckusick vget(vp) 41739397Smckusick register struct vnode *vp; 41839397Smckusick { 41939397Smckusick register struct vnode *vq; 42039397Smckusick 42139433Smckusick if (vp->v_flag & VXLOCK) { 42239433Smckusick vp->v_flag |= VXWANT; 42339433Smckusick sleep((caddr_t)vp, PINOD); 42439433Smckusick return (1); 42539433Smckusick } 42639809Smckusick if (vp->v_usecount == 0) { 42739433Smckusick if (vq = vp->v_freef) 42839433Smckusick vq->v_freeb = vp->v_freeb; 42939433Smckusick else 43039433Smckusick vfreet = vp->v_freeb; 43139433Smckusick *vp->v_freeb = vq; 43239433Smckusick vp->v_freef = NULL; 43339433Smckusick vp->v_freeb = NULL; 43439433Smckusick } 43539397Smckusick VREF(vp); 43639433Smckusick VOP_LOCK(vp); 43739433Smckusick return (0); 43839397Smckusick } 43939397Smckusick 44039397Smckusick /* 44139397Smckusick * Vnode reference, just increment the count 44239397Smckusick */ 44339397Smckusick void vref(vp) 44439397Smckusick struct vnode *vp; 44539397Smckusick { 44639397Smckusick 44739809Smckusick vp->v_usecount++; 44839397Smckusick } 44939397Smckusick 45039397Smckusick /* 45139397Smckusick * vput(), just unlock and vrele() 45239397Smckusick */ 45339397Smckusick void vput(vp) 45439397Smckusick register struct vnode *vp; 45539397Smckusick { 45639397Smckusick VOP_UNLOCK(vp); 45739397Smckusick vrele(vp); 45839397Smckusick } 45939397Smckusick 46039397Smckusick /* 46139397Smckusick * Vnode release. 46239397Smckusick * If count drops to zero, call inactive routine and return to freelist. 46339397Smckusick */ 46439397Smckusick void vrele(vp) 46539397Smckusick register struct vnode *vp; 46639397Smckusick { 46739397Smckusick 46839397Smckusick if (vp == NULL) 46939433Smckusick panic("vrele: null vp"); 47039809Smckusick vp->v_usecount--; 47139809Smckusick if (vp->v_usecount < 0) 47239667Smckusick vprint("vrele: bad ref count", vp); 47339809Smckusick if (vp->v_usecount > 0) 47439397Smckusick return; 47541400Smckusick if (vfreeh == NULLVP) { 47639397Smckusick /* 47739397Smckusick * insert into empty list 47839397Smckusick */ 47939397Smckusick vfreeh = vp; 48039397Smckusick vp->v_freeb = &vfreeh; 48139397Smckusick } else { 48239397Smckusick /* 48339397Smckusick * insert at tail of list 48439397Smckusick */ 48539397Smckusick *vfreet = vp; 48639397Smckusick vp->v_freeb = vfreet; 48739397Smckusick } 48839433Smckusick vp->v_freef = NULL; 48939433Smckusick vfreet = &vp->v_freef; 49039433Smckusick VOP_INACTIVE(vp); 49139397Smckusick } 49239433Smckusick 49339433Smckusick /* 49439809Smckusick * Page or buffer structure gets a reference. 49539809Smckusick */ 49639809Smckusick vhold(vp) 49739809Smckusick register struct vnode *vp; 49839809Smckusick { 49939809Smckusick 50039809Smckusick vp->v_holdcnt++; 50139809Smckusick } 50239809Smckusick 50339809Smckusick /* 50439809Smckusick * Page or buffer structure frees a reference. 50539809Smckusick */ 50639809Smckusick holdrele(vp) 50739809Smckusick register struct vnode *vp; 50839809Smckusick { 50939809Smckusick 51039809Smckusick if (vp->v_holdcnt <= 0) 51139809Smckusick panic("holdrele: holdcnt"); 51239809Smckusick vp->v_holdcnt--; 51339809Smckusick } 51439809Smckusick 51539809Smckusick /* 51639509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 51739509Smckusick * 51839509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 51939509Smckusick * return error if any are found (nb: this is a user error, not a 52039509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 52139509Smckusick * that are found. 52239509Smckusick */ 52339509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 52439509Smckusick 52539509Smckusick vflush(mp, skipvp, flags) 52639509Smckusick struct mount *mp; 52739509Smckusick struct vnode *skipvp; 52839509Smckusick int flags; 52939509Smckusick { 53039509Smckusick register struct vnode *vp, *nvp; 53139509Smckusick int busy = 0; 53239509Smckusick 53341400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 53441300Smckusick panic("vflush: not busy"); 535*41421Smckusick loop: 53641400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 537*41421Smckusick if (vp->v_mount != mp) 538*41421Smckusick goto loop; 53939509Smckusick nvp = vp->v_mountf; 54039509Smckusick /* 54139509Smckusick * Skip over a selected vnode. 54239509Smckusick */ 54339509Smckusick if (vp == skipvp) 54439509Smckusick continue; 54539509Smckusick /* 54641300Smckusick * Skip over a vnodes marked VSYSTEM. 54741300Smckusick */ 54841300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 54941300Smckusick continue; 55041300Smckusick /* 55139809Smckusick * With v_usecount == 0, all we need to do is clear 55239509Smckusick * out the vnode data structures and we are done. 55339509Smckusick */ 55439809Smckusick if (vp->v_usecount == 0) { 55539509Smckusick vgone(vp); 55639509Smckusick continue; 55739509Smckusick } 55839509Smckusick /* 55939509Smckusick * For block or character devices, revert to an 56039509Smckusick * anonymous device. For all other files, just kill them. 56139509Smckusick */ 56241300Smckusick if (flags & FORCECLOSE) { 56339509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 56439509Smckusick vgone(vp); 56539509Smckusick } else { 56639509Smckusick vclean(vp, 0); 56739509Smckusick vp->v_op = &spec_vnodeops; 56839509Smckusick insmntque(vp, (struct mount *)0); 56939509Smckusick } 57039509Smckusick continue; 57139509Smckusick } 57239509Smckusick if (busyprt) 57339667Smckusick vprint("vflush: busy vnode", vp); 57439509Smckusick busy++; 57539509Smckusick } 57639509Smckusick if (busy) 57739509Smckusick return (EBUSY); 57839509Smckusick return (0); 57939509Smckusick } 58039509Smckusick 58139509Smckusick /* 58239433Smckusick * Disassociate the underlying file system from a vnode. 58339433Smckusick */ 58441300Smckusick void vclean(vp, flags) 58539433Smckusick register struct vnode *vp; 58641300Smckusick long flags; 58739433Smckusick { 58839433Smckusick struct vnodeops *origops; 58939484Smckusick int active; 59039433Smckusick 59139484Smckusick /* 59239484Smckusick * Check to see if the vnode is in use. 59339667Smckusick * If so we have to reference it before we clean it out 59439667Smckusick * so that its count cannot fall to zero and generate a 59539667Smckusick * race against ourselves to recycle it. 59639484Smckusick */ 59739809Smckusick if (active = vp->v_usecount) 59839484Smckusick VREF(vp); 59939484Smckusick /* 60039484Smckusick * Prevent the vnode from being recycled or 60139484Smckusick * brought into use while we clean it out. 60239484Smckusick */ 60339667Smckusick if (vp->v_flag & VXLOCK) 60439667Smckusick panic("vclean: deadlock"); 60539433Smckusick vp->v_flag |= VXLOCK; 60639433Smckusick /* 60739667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 60839667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 60939667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 61039667Smckusick * For active vnodes, it ensures that no other activity can 61139667Smckusick * occur while the buffer list is being cleaned out. 61239667Smckusick */ 61339667Smckusick VOP_LOCK(vp); 61441300Smckusick if (flags & DOCLOSE) 61539667Smckusick vinvalbuf(vp, 1); 61639667Smckusick /* 61739433Smckusick * Prevent any further operations on the vnode from 61839433Smckusick * being passed through to the old file system. 61939433Smckusick */ 62039433Smckusick origops = vp->v_op; 62139433Smckusick vp->v_op = &dead_vnodeops; 62239433Smckusick vp->v_tag = VT_NON; 62339433Smckusick /* 62439484Smckusick * If purging an active vnode, it must be unlocked, closed, 62539484Smckusick * and deactivated before being reclaimed. 62639433Smckusick */ 62739667Smckusick (*(origops->vn_unlock))(vp); 62839484Smckusick if (active) { 62941300Smckusick if (flags & DOCLOSE) 63039484Smckusick (*(origops->vn_close))(vp, 0, NOCRED); 63139433Smckusick (*(origops->vn_inactive))(vp); 63239433Smckusick } 63339433Smckusick /* 63439433Smckusick * Reclaim the vnode. 63539433Smckusick */ 63639433Smckusick if ((*(origops->vn_reclaim))(vp)) 63739433Smckusick panic("vclean: cannot reclaim"); 63839484Smckusick if (active) 63939484Smckusick vrele(vp); 64039433Smckusick /* 64139433Smckusick * Done with purge, notify sleepers in vget of the grim news. 64239433Smckusick */ 64339433Smckusick vp->v_flag &= ~VXLOCK; 64439433Smckusick if (vp->v_flag & VXWANT) { 64539433Smckusick vp->v_flag &= ~VXWANT; 64639433Smckusick wakeup((caddr_t)vp); 64739433Smckusick } 64839433Smckusick } 64939433Smckusick 65039433Smckusick /* 65139633Smckusick * Eliminate all activity associated with the requested vnode 65239633Smckusick * and with all vnodes aliased to the requested vnode. 65339633Smckusick */ 65439633Smckusick void vgoneall(vp) 65539633Smckusick register struct vnode *vp; 65639633Smckusick { 65739809Smckusick register struct vnode *vq; 65839633Smckusick 65940665Smckusick if (vp->v_flag & VALIASED) { 66040665Smckusick /* 66140665Smckusick * If a vgone (or vclean) is already in progress, 66240665Smckusick * wait until it is done and return. 66340665Smckusick */ 66440665Smckusick if (vp->v_flag & VXLOCK) { 66540665Smckusick vp->v_flag |= VXWANT; 66640665Smckusick sleep((caddr_t)vp, PINOD); 66740665Smckusick return; 66839633Smckusick } 66940665Smckusick /* 67040665Smckusick * Ensure that vp will not be vgone'd while we 67140665Smckusick * are eliminating its aliases. 67240665Smckusick */ 67340665Smckusick vp->v_flag |= VXLOCK; 67440665Smckusick while (vp->v_flag & VALIASED) { 67540665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 67640665Smckusick if (vq->v_rdev != vp->v_rdev || 67740665Smckusick vq->v_type != vp->v_type || vp == vq) 67840665Smckusick continue; 67940665Smckusick vgone(vq); 68040665Smckusick break; 68140665Smckusick } 68240665Smckusick } 68340665Smckusick /* 68440665Smckusick * Remove the lock so that vgone below will 68540665Smckusick * really eliminate the vnode after which time 68640665Smckusick * vgone will awaken any sleepers. 68740665Smckusick */ 68840665Smckusick vp->v_flag &= ~VXLOCK; 68939633Smckusick } 69039633Smckusick vgone(vp); 69139633Smckusick } 69239633Smckusick 69339633Smckusick /* 69439433Smckusick * Eliminate all activity associated with a vnode 69539433Smckusick * in preparation for reuse. 69639433Smckusick */ 69739433Smckusick void vgone(vp) 69839433Smckusick register struct vnode *vp; 69939433Smckusick { 70039809Smckusick register struct vnode *vq; 70139615Smckusick struct vnode *vx; 70239615Smckusick long count; 70339433Smckusick 70439433Smckusick /* 70540548Smckusick * If a vgone (or vclean) is already in progress, 70640548Smckusick * wait until it is done and return. 70740548Smckusick */ 70840548Smckusick if (vp->v_flag & VXLOCK) { 70940548Smckusick vp->v_flag |= VXWANT; 71040548Smckusick sleep((caddr_t)vp, PINOD); 71140548Smckusick return; 71240548Smckusick } 71340548Smckusick /* 71439433Smckusick * Clean out the filesystem specific data. 71539433Smckusick */ 71641300Smckusick vclean(vp, DOCLOSE); 71739433Smckusick /* 71839433Smckusick * Delete from old mount point vnode list, if on one. 71939433Smckusick */ 72039433Smckusick if (vp->v_mountb) { 72139433Smckusick if (vq = vp->v_mountf) 72239433Smckusick vq->v_mountb = vp->v_mountb; 72339433Smckusick *vp->v_mountb = vq; 72439433Smckusick vp->v_mountf = NULL; 72539433Smckusick vp->v_mountb = NULL; 72639433Smckusick } 72739433Smckusick /* 72839433Smckusick * If special device, remove it from special device alias list. 72939433Smckusick */ 73039433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 73139809Smckusick if (*vp->v_hashchain == vp) { 73239809Smckusick *vp->v_hashchain = vp->v_specnext; 73339433Smckusick } else { 73439809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 73539615Smckusick if (vq->v_specnext != vp) 73639433Smckusick continue; 73739615Smckusick vq->v_specnext = vp->v_specnext; 73839433Smckusick break; 73939433Smckusick } 74039615Smckusick if (vq == NULL) 74139433Smckusick panic("missing bdev"); 74239433Smckusick } 74339615Smckusick if (vp->v_flag & VALIASED) { 74439809Smckusick count = 0; 74539809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 74640108Smckusick if (vq->v_rdev != vp->v_rdev || 74740108Smckusick vq->v_type != vp->v_type) 74839615Smckusick continue; 74939615Smckusick count++; 75039615Smckusick vx = vq; 75139615Smckusick } 75239615Smckusick if (count == 0) 75339615Smckusick panic("missing alias"); 75439615Smckusick if (count == 1) 75539615Smckusick vx->v_flag &= ~VALIASED; 75639615Smckusick vp->v_flag &= ~VALIASED; 75739615Smckusick } 75839615Smckusick FREE(vp->v_specinfo, M_VNODE); 75939615Smckusick vp->v_specinfo = NULL; 76039433Smckusick } 76139433Smckusick /* 76239433Smckusick * If it is on the freelist, move it to the head of the list. 76339433Smckusick */ 76439433Smckusick if (vp->v_freeb) { 76539433Smckusick if (vq = vp->v_freef) 76639433Smckusick vq->v_freeb = vp->v_freeb; 76739433Smckusick else 76839433Smckusick vfreet = vp->v_freeb; 76939433Smckusick *vp->v_freeb = vq; 77039433Smckusick vp->v_freef = vfreeh; 77139433Smckusick vp->v_freeb = &vfreeh; 77239433Smckusick vfreeh->v_freeb = &vp->v_freef; 77339433Smckusick vfreeh = vp; 77439433Smckusick } 77539484Smckusick vp->v_type = VBAD; 77639433Smckusick } 77739633Smckusick 77839633Smckusick /* 77939821Smckusick * Lookup a vnode by device number. 78039821Smckusick */ 78139821Smckusick vfinddev(dev, type, vpp) 78239821Smckusick dev_t dev; 78339821Smckusick enum vtype type; 78439821Smckusick struct vnode **vpp; 78539821Smckusick { 78639821Smckusick register struct vnode *vp; 78739821Smckusick 78839821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 78939821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 79039821Smckusick continue; 79139821Smckusick *vpp = vp; 79239821Smckusick return (0); 79339821Smckusick } 79439821Smckusick return (1); 79539821Smckusick } 79639821Smckusick 79739821Smckusick /* 79839633Smckusick * Calculate the total number of references to a special device. 79939633Smckusick */ 80039633Smckusick vcount(vp) 80139633Smckusick register struct vnode *vp; 80239633Smckusick { 80339809Smckusick register struct vnode *vq; 80439633Smckusick int count; 80539633Smckusick 80639633Smckusick if ((vp->v_flag & VALIASED) == 0) 80739809Smckusick return (vp->v_usecount); 80839633Smckusick loop: 80939809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 81040108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 81139633Smckusick continue; 81239633Smckusick /* 81339633Smckusick * Alias, but not in use, so flush it out. 81439633Smckusick */ 81539809Smckusick if (vq->v_usecount == 0) { 81639633Smckusick vgone(vq); 81739633Smckusick goto loop; 81839633Smckusick } 81939809Smckusick count += vq->v_usecount; 82039633Smckusick } 82139633Smckusick return (count); 82239633Smckusick } 82339667Smckusick 82439667Smckusick /* 82539667Smckusick * Print out a description of a vnode. 82639667Smckusick */ 82739667Smckusick static char *typename[] = 82840286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 82939667Smckusick 83039667Smckusick vprint(label, vp) 83139667Smckusick char *label; 83239667Smckusick register struct vnode *vp; 83339667Smckusick { 83439913Smckusick char buf[64]; 83539667Smckusick 83639667Smckusick if (label != NULL) 83739667Smckusick printf("%s: ", label); 83839913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 83939809Smckusick vp->v_usecount, vp->v_holdcnt); 84039913Smckusick buf[0] = '\0'; 84139913Smckusick if (vp->v_flag & VROOT) 84239913Smckusick strcat(buf, "|VROOT"); 84339913Smckusick if (vp->v_flag & VTEXT) 84439913Smckusick strcat(buf, "|VTEXT"); 84541300Smckusick if (vp->v_flag & VSYSTEM) 84641300Smckusick strcat(buf, "|VSYSTEM"); 84739913Smckusick if (vp->v_flag & VEXLOCK) 84839913Smckusick strcat(buf, "|VEXLOCK"); 84939913Smckusick if (vp->v_flag & VSHLOCK) 85039913Smckusick strcat(buf, "|VSHLOCK"); 85139913Smckusick if (vp->v_flag & VLWAIT) 85239913Smckusick strcat(buf, "|VLWAIT"); 85341300Smckusick if (vp->v_flag & VXLOCK) 85441300Smckusick strcat(buf, "|VXLOCK"); 85541300Smckusick if (vp->v_flag & VXWANT) 85641300Smckusick strcat(buf, "|VXWANT"); 85741300Smckusick if (vp->v_flag & VBWAIT) 85841300Smckusick strcat(buf, "|VBWAIT"); 85939913Smckusick if (vp->v_flag & VALIASED) 86039913Smckusick strcat(buf, "|VALIASED"); 86139913Smckusick if (buf[0] != '\0') 86239913Smckusick printf(" flags (%s)", &buf[1]); 86339913Smckusick printf("\n\t"); 86439667Smckusick VOP_PRINT(vp); 86539667Smckusick } 86641110Smarc 86741110Smarc int kinfo_vdebug = 1; 86841110Smarc int kinfo_vgetfailed; 86941110Smarc #define KINFO_VNODESLOP 10 87041110Smarc /* 87141110Smarc * Dump vnode list (via kinfo). 87241110Smarc * Copyout address of vnode followed by vnode. 87341110Smarc */ 87441110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 87541110Smarc char *where; 87641110Smarc int *acopysize, *aneeded; 87741110Smarc { 87841110Smarc register struct mount *mp = rootfs; 87941300Smckusick struct mount *omp; 88041110Smarc struct vnode *vp; 88141110Smarc register needed = 0; 88241110Smarc register char *bp = where, *savebp; 88341110Smarc char *ewhere = where + *acopysize; 88441110Smarc int error; 88541110Smarc 88641110Smarc #define VPTRSZ sizeof (struct vnode *) 88741110Smarc #define VNODESZ sizeof (struct vnode) 88841110Smarc if (where == NULL) { 88941110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 89041110Smarc return (0); 89141110Smarc } 89241110Smarc 89341110Smarc do { 89441300Smckusick if (vfs_busy(mp)) { 89541400Smckusick mp = mp->mnt_next; 89641300Smckusick continue; 89741300Smckusick } 89841110Smarc /* 89941110Smarc * A vget can fail if the vnode is being 90041110Smarc * recycled. In this (rare) case, we have to start 90141110Smarc * over with this filesystem. Also, have to 902*41421Smckusick * check that the next vp is still associated 90341110Smarc * with this filesystem. RACE: could have been 904*41421Smckusick * recycled onto the same filesystem. 90541110Smarc */ 90641110Smarc savebp = bp; 90741110Smarc again: 908*41421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 909*41421Smckusick if (vp->v_mount != mp) { 910*41421Smckusick if (kinfo_vdebug) 911*41421Smckusick printf("kinfo: vp changed\n"); 912*41421Smckusick bp = savebp; 913*41421Smckusick goto again; 914*41421Smckusick } 91541110Smarc if (vget(vp)) { 91641110Smarc if (kinfo_vdebug) 91741110Smarc printf("kinfo: vget failed\n"); 91841110Smarc kinfo_vgetfailed++; 919*41421Smckusick bp = savebp; 920*41421Smckusick goto again; 92141110Smarc } 92241110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 92341110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 92441110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 92541110Smarc VNODESZ)))) { 92641110Smarc vput(vp); 92741110Smarc return (error); 92841110Smarc } 92941110Smarc bp += VPTRSZ + VNODESZ; 93041110Smarc vput(vp); 93141110Smarc } 93241300Smckusick omp = mp; 93341400Smckusick mp = mp->mnt_next; 93441300Smckusick vfs_unbusy(omp); 93541110Smarc } while (mp != rootfs); 93641110Smarc 93741110Smarc *aneeded = bp - where; 93841110Smarc if (bp > ewhere) 93941110Smarc *acopysize = ewhere - where; 94041110Smarc else 94141110Smarc *acopysize = bp - where; 94241110Smarc return (0); 94341110Smarc } 944