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*41419Smckusick * @(#)vfs_subr.c 7.43 (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 } 97*41419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 98*41419Smckusick 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"); 53541400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 53639509Smckusick nvp = vp->v_mountf; 53739509Smckusick /* 53839509Smckusick * Skip over a selected vnode. 53939509Smckusick */ 54039509Smckusick if (vp == skipvp) 54139509Smckusick continue; 54239509Smckusick /* 54341300Smckusick * Skip over a vnodes marked VSYSTEM. 54441300Smckusick */ 54541300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 54641300Smckusick continue; 54741300Smckusick /* 54839809Smckusick * With v_usecount == 0, all we need to do is clear 54939509Smckusick * out the vnode data structures and we are done. 55039509Smckusick */ 55139809Smckusick if (vp->v_usecount == 0) { 55239509Smckusick vgone(vp); 55339509Smckusick continue; 55439509Smckusick } 55539509Smckusick /* 55639509Smckusick * For block or character devices, revert to an 55739509Smckusick * anonymous device. For all other files, just kill them. 55839509Smckusick */ 55941300Smckusick if (flags & FORCECLOSE) { 56039509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 56139509Smckusick vgone(vp); 56239509Smckusick } else { 56339509Smckusick vclean(vp, 0); 56439509Smckusick vp->v_op = &spec_vnodeops; 56539509Smckusick insmntque(vp, (struct mount *)0); 56639509Smckusick } 56739509Smckusick continue; 56839509Smckusick } 56939509Smckusick if (busyprt) 57039667Smckusick vprint("vflush: busy vnode", vp); 57139509Smckusick busy++; 57239509Smckusick } 57339509Smckusick if (busy) 57439509Smckusick return (EBUSY); 57539509Smckusick return (0); 57639509Smckusick } 57739509Smckusick 57839509Smckusick /* 57939433Smckusick * Disassociate the underlying file system from a vnode. 58039433Smckusick */ 58141300Smckusick void vclean(vp, flags) 58239433Smckusick register struct vnode *vp; 58341300Smckusick long flags; 58439433Smckusick { 58539433Smckusick struct vnodeops *origops; 58639484Smckusick int active; 58739433Smckusick 58839484Smckusick /* 58939484Smckusick * Check to see if the vnode is in use. 59039667Smckusick * If so we have to reference it before we clean it out 59139667Smckusick * so that its count cannot fall to zero and generate a 59239667Smckusick * race against ourselves to recycle it. 59339484Smckusick */ 59439809Smckusick if (active = vp->v_usecount) 59539484Smckusick VREF(vp); 59639484Smckusick /* 59739484Smckusick * Prevent the vnode from being recycled or 59839484Smckusick * brought into use while we clean it out. 59939484Smckusick */ 60039667Smckusick if (vp->v_flag & VXLOCK) 60139667Smckusick panic("vclean: deadlock"); 60239433Smckusick vp->v_flag |= VXLOCK; 60339433Smckusick /* 60439667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 60539667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 60639667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 60739667Smckusick * For active vnodes, it ensures that no other activity can 60839667Smckusick * occur while the buffer list is being cleaned out. 60939667Smckusick */ 61039667Smckusick VOP_LOCK(vp); 61141300Smckusick if (flags & DOCLOSE) 61239667Smckusick vinvalbuf(vp, 1); 61339667Smckusick /* 61439433Smckusick * Prevent any further operations on the vnode from 61539433Smckusick * being passed through to the old file system. 61639433Smckusick */ 61739433Smckusick origops = vp->v_op; 61839433Smckusick vp->v_op = &dead_vnodeops; 61939433Smckusick vp->v_tag = VT_NON; 62039433Smckusick /* 62139484Smckusick * If purging an active vnode, it must be unlocked, closed, 62239484Smckusick * and deactivated before being reclaimed. 62339433Smckusick */ 62439667Smckusick (*(origops->vn_unlock))(vp); 62539484Smckusick if (active) { 62641300Smckusick if (flags & DOCLOSE) 62739484Smckusick (*(origops->vn_close))(vp, 0, NOCRED); 62839433Smckusick (*(origops->vn_inactive))(vp); 62939433Smckusick } 63039433Smckusick /* 63139433Smckusick * Reclaim the vnode. 63239433Smckusick */ 63339433Smckusick if ((*(origops->vn_reclaim))(vp)) 63439433Smckusick panic("vclean: cannot reclaim"); 63539484Smckusick if (active) 63639484Smckusick vrele(vp); 63739433Smckusick /* 63839433Smckusick * Done with purge, notify sleepers in vget of the grim news. 63939433Smckusick */ 64039433Smckusick vp->v_flag &= ~VXLOCK; 64139433Smckusick if (vp->v_flag & VXWANT) { 64239433Smckusick vp->v_flag &= ~VXWANT; 64339433Smckusick wakeup((caddr_t)vp); 64439433Smckusick } 64539433Smckusick } 64639433Smckusick 64739433Smckusick /* 64839633Smckusick * Eliminate all activity associated with the requested vnode 64939633Smckusick * and with all vnodes aliased to the requested vnode. 65039633Smckusick */ 65139633Smckusick void vgoneall(vp) 65239633Smckusick register struct vnode *vp; 65339633Smckusick { 65439809Smckusick register struct vnode *vq; 65539633Smckusick 65640665Smckusick if (vp->v_flag & VALIASED) { 65740665Smckusick /* 65840665Smckusick * If a vgone (or vclean) is already in progress, 65940665Smckusick * wait until it is done and return. 66040665Smckusick */ 66140665Smckusick if (vp->v_flag & VXLOCK) { 66240665Smckusick vp->v_flag |= VXWANT; 66340665Smckusick sleep((caddr_t)vp, PINOD); 66440665Smckusick return; 66539633Smckusick } 66640665Smckusick /* 66740665Smckusick * Ensure that vp will not be vgone'd while we 66840665Smckusick * are eliminating its aliases. 66940665Smckusick */ 67040665Smckusick vp->v_flag |= VXLOCK; 67140665Smckusick while (vp->v_flag & VALIASED) { 67240665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 67340665Smckusick if (vq->v_rdev != vp->v_rdev || 67440665Smckusick vq->v_type != vp->v_type || vp == vq) 67540665Smckusick continue; 67640665Smckusick vgone(vq); 67740665Smckusick break; 67840665Smckusick } 67940665Smckusick } 68040665Smckusick /* 68140665Smckusick * Remove the lock so that vgone below will 68240665Smckusick * really eliminate the vnode after which time 68340665Smckusick * vgone will awaken any sleepers. 68440665Smckusick */ 68540665Smckusick vp->v_flag &= ~VXLOCK; 68639633Smckusick } 68739633Smckusick vgone(vp); 68839633Smckusick } 68939633Smckusick 69039633Smckusick /* 69139433Smckusick * Eliminate all activity associated with a vnode 69239433Smckusick * in preparation for reuse. 69339433Smckusick */ 69439433Smckusick void vgone(vp) 69539433Smckusick register struct vnode *vp; 69639433Smckusick { 69739809Smckusick register struct vnode *vq; 69839615Smckusick struct vnode *vx; 69939615Smckusick long count; 70039433Smckusick 70139433Smckusick /* 70240548Smckusick * If a vgone (or vclean) is already in progress, 70340548Smckusick * wait until it is done and return. 70440548Smckusick */ 70540548Smckusick if (vp->v_flag & VXLOCK) { 70640548Smckusick vp->v_flag |= VXWANT; 70740548Smckusick sleep((caddr_t)vp, PINOD); 70840548Smckusick return; 70940548Smckusick } 71040548Smckusick /* 71139433Smckusick * Clean out the filesystem specific data. 71239433Smckusick */ 71341300Smckusick vclean(vp, DOCLOSE); 71439433Smckusick /* 71539433Smckusick * Delete from old mount point vnode list, if on one. 71639433Smckusick */ 71739433Smckusick if (vp->v_mountb) { 71839433Smckusick if (vq = vp->v_mountf) 71939433Smckusick vq->v_mountb = vp->v_mountb; 72039433Smckusick *vp->v_mountb = vq; 72139433Smckusick vp->v_mountf = NULL; 72239433Smckusick vp->v_mountb = NULL; 72339433Smckusick } 72439433Smckusick /* 72539433Smckusick * If special device, remove it from special device alias list. 72639433Smckusick */ 72739433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 72839809Smckusick if (*vp->v_hashchain == vp) { 72939809Smckusick *vp->v_hashchain = vp->v_specnext; 73039433Smckusick } else { 73139809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 73239615Smckusick if (vq->v_specnext != vp) 73339433Smckusick continue; 73439615Smckusick vq->v_specnext = vp->v_specnext; 73539433Smckusick break; 73639433Smckusick } 73739615Smckusick if (vq == NULL) 73839433Smckusick panic("missing bdev"); 73939433Smckusick } 74039615Smckusick if (vp->v_flag & VALIASED) { 74139809Smckusick count = 0; 74239809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 74340108Smckusick if (vq->v_rdev != vp->v_rdev || 74440108Smckusick vq->v_type != vp->v_type) 74539615Smckusick continue; 74639615Smckusick count++; 74739615Smckusick vx = vq; 74839615Smckusick } 74939615Smckusick if (count == 0) 75039615Smckusick panic("missing alias"); 75139615Smckusick if (count == 1) 75239615Smckusick vx->v_flag &= ~VALIASED; 75339615Smckusick vp->v_flag &= ~VALIASED; 75439615Smckusick } 75539615Smckusick FREE(vp->v_specinfo, M_VNODE); 75639615Smckusick vp->v_specinfo = NULL; 75739433Smckusick } 75839433Smckusick /* 75939433Smckusick * If it is on the freelist, move it to the head of the list. 76039433Smckusick */ 76139433Smckusick if (vp->v_freeb) { 76239433Smckusick if (vq = vp->v_freef) 76339433Smckusick vq->v_freeb = vp->v_freeb; 76439433Smckusick else 76539433Smckusick vfreet = vp->v_freeb; 76639433Smckusick *vp->v_freeb = vq; 76739433Smckusick vp->v_freef = vfreeh; 76839433Smckusick vp->v_freeb = &vfreeh; 76939433Smckusick vfreeh->v_freeb = &vp->v_freef; 77039433Smckusick vfreeh = vp; 77139433Smckusick } 77239484Smckusick vp->v_type = VBAD; 77339433Smckusick } 77439633Smckusick 77539633Smckusick /* 77639821Smckusick * Lookup a vnode by device number. 77739821Smckusick */ 77839821Smckusick vfinddev(dev, type, vpp) 77939821Smckusick dev_t dev; 78039821Smckusick enum vtype type; 78139821Smckusick struct vnode **vpp; 78239821Smckusick { 78339821Smckusick register struct vnode *vp; 78439821Smckusick 78539821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 78639821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 78739821Smckusick continue; 78839821Smckusick *vpp = vp; 78939821Smckusick return (0); 79039821Smckusick } 79139821Smckusick return (1); 79239821Smckusick } 79339821Smckusick 79439821Smckusick /* 79539633Smckusick * Calculate the total number of references to a special device. 79639633Smckusick */ 79739633Smckusick vcount(vp) 79839633Smckusick register struct vnode *vp; 79939633Smckusick { 80039809Smckusick register struct vnode *vq; 80139633Smckusick int count; 80239633Smckusick 80339633Smckusick if ((vp->v_flag & VALIASED) == 0) 80439809Smckusick return (vp->v_usecount); 80539633Smckusick loop: 80639809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 80740108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 80839633Smckusick continue; 80939633Smckusick /* 81039633Smckusick * Alias, but not in use, so flush it out. 81139633Smckusick */ 81239809Smckusick if (vq->v_usecount == 0) { 81339633Smckusick vgone(vq); 81439633Smckusick goto loop; 81539633Smckusick } 81639809Smckusick count += vq->v_usecount; 81739633Smckusick } 81839633Smckusick return (count); 81939633Smckusick } 82039667Smckusick 82139667Smckusick /* 82239667Smckusick * Print out a description of a vnode. 82339667Smckusick */ 82439667Smckusick static char *typename[] = 82540286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 82639667Smckusick 82739667Smckusick vprint(label, vp) 82839667Smckusick char *label; 82939667Smckusick register struct vnode *vp; 83039667Smckusick { 83139913Smckusick char buf[64]; 83239667Smckusick 83339667Smckusick if (label != NULL) 83439667Smckusick printf("%s: ", label); 83539913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 83639809Smckusick vp->v_usecount, vp->v_holdcnt); 83739913Smckusick buf[0] = '\0'; 83839913Smckusick if (vp->v_flag & VROOT) 83939913Smckusick strcat(buf, "|VROOT"); 84039913Smckusick if (vp->v_flag & VTEXT) 84139913Smckusick strcat(buf, "|VTEXT"); 84241300Smckusick if (vp->v_flag & VSYSTEM) 84341300Smckusick strcat(buf, "|VSYSTEM"); 84439913Smckusick if (vp->v_flag & VEXLOCK) 84539913Smckusick strcat(buf, "|VEXLOCK"); 84639913Smckusick if (vp->v_flag & VSHLOCK) 84739913Smckusick strcat(buf, "|VSHLOCK"); 84839913Smckusick if (vp->v_flag & VLWAIT) 84939913Smckusick strcat(buf, "|VLWAIT"); 85041300Smckusick if (vp->v_flag & VXLOCK) 85141300Smckusick strcat(buf, "|VXLOCK"); 85241300Smckusick if (vp->v_flag & VXWANT) 85341300Smckusick strcat(buf, "|VXWANT"); 85441300Smckusick if (vp->v_flag & VBWAIT) 85541300Smckusick strcat(buf, "|VBWAIT"); 85639913Smckusick if (vp->v_flag & VALIASED) 85739913Smckusick strcat(buf, "|VALIASED"); 85839913Smckusick if (buf[0] != '\0') 85939913Smckusick printf(" flags (%s)", &buf[1]); 86039913Smckusick printf("\n\t"); 86139667Smckusick VOP_PRINT(vp); 86239667Smckusick } 86341110Smarc 86441110Smarc int kinfo_vdebug = 1; 86541110Smarc int kinfo_vgetfailed; 86641110Smarc #define KINFO_VNODESLOP 10 86741110Smarc /* 86841110Smarc * Dump vnode list (via kinfo). 86941110Smarc * Copyout address of vnode followed by vnode. 87041110Smarc */ 87141110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 87241110Smarc char *where; 87341110Smarc int *acopysize, *aneeded; 87441110Smarc { 87541110Smarc register struct mount *mp = rootfs; 87641110Smarc register struct vnode *nextvp; 87741300Smckusick struct mount *omp; 87841110Smarc struct vnode *vp; 87941110Smarc register needed = 0; 88041110Smarc register char *bp = where, *savebp; 88141110Smarc char *ewhere = where + *acopysize; 88241110Smarc int error; 88341110Smarc 88441110Smarc #define VPTRSZ sizeof (struct vnode *) 88541110Smarc #define VNODESZ sizeof (struct vnode) 88641110Smarc if (where == NULL) { 88741110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 88841110Smarc return (0); 88941110Smarc } 89041110Smarc 89141110Smarc #define RETRY bp = savebp ; goto again 89241110Smarc do { 89341300Smckusick if (vfs_busy(mp)) { 89441400Smckusick mp = mp->mnt_next; 89541300Smckusick continue; 89641300Smckusick } 89741110Smarc /* 89841110Smarc * A vget can fail if the vnode is being 89941110Smarc * recycled. In this (rare) case, we have to start 90041110Smarc * over with this filesystem. Also, have to 90141110Smarc * check that nextvp is still associated 90241110Smarc * with this filesystem. RACE: could have been 90341110Smarc * recycled onto same filesystem. 90441110Smarc */ 90541110Smarc savebp = bp; 90641110Smarc again: 90741400Smckusick nextvp = mp->mnt_mounth; 90841110Smarc while (vp = nextvp) { 90941110Smarc if (vget(vp)) { 91041110Smarc if (kinfo_vdebug) 91141110Smarc printf("kinfo: vget failed\n"); 91241110Smarc kinfo_vgetfailed++; 91341110Smarc RETRY; 91441110Smarc } 91541110Smarc if (vp->v_mount != mp) { 91641110Smarc if (kinfo_vdebug) 91741110Smarc printf("kinfo: vp changed\n"); 91841110Smarc vput(vp); 91941110Smarc RETRY; 92041110Smarc } 92141110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 92241110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 92341110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 92441110Smarc VNODESZ)))) { 92541110Smarc vput(vp); 92641110Smarc return (error); 92741110Smarc } 92841110Smarc bp += VPTRSZ + VNODESZ; 92941110Smarc nextvp = vp->v_mountf; 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