137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*48354Smckusick * @(#)vfs_subr.c 7.53 (Berkeley) 04/19/91 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1437488Smckusick #include "param.h" 1548024Smckusick #include "proc.h" 1637488Smckusick #include "mount.h" 1737488Smckusick #include "time.h" 1837488Smckusick #include "vnode.h" 1940652Smckusick #include "specdev.h" 2038265Smckusick #include "namei.h" 2138265Smckusick #include "ucred.h" 2237488Smckusick #include "errno.h" 2339433Smckusick #include "malloc.h" 2437488Smckusick 2537488Smckusick /* 2637488Smckusick * Remove a mount point from the list of mounted filesystems. 2737488Smckusick * Unmount of the root is illegal. 2837488Smckusick */ 2937488Smckusick void 3037488Smckusick vfs_remove(mp) 3137488Smckusick register struct mount *mp; 3237488Smckusick { 3337488Smckusick 3437488Smckusick if (mp == rootfs) 3537488Smckusick panic("vfs_remove: unmounting root"); 3641400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 3741400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 3841400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 3937488Smckusick vfs_unlock(mp); 4037488Smckusick } 4137488Smckusick 4237488Smckusick /* 4337488Smckusick * Lock a filesystem. 4437488Smckusick * Used to prevent access to it while mounting and unmounting. 4537488Smckusick */ 4637488Smckusick vfs_lock(mp) 4737488Smckusick register struct mount *mp; 4837488Smckusick { 4937488Smckusick 5041400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 5141400Smckusick mp->mnt_flag |= MNT_MWAIT; 5239045Smckusick sleep((caddr_t)mp, PVFS); 5339045Smckusick } 5441400Smckusick mp->mnt_flag |= MNT_MLOCK; 5537488Smckusick return (0); 5637488Smckusick } 5737488Smckusick 5837488Smckusick /* 5937488Smckusick * Unlock a locked filesystem. 6037488Smckusick * Panic if filesystem is not locked. 6137488Smckusick */ 6237488Smckusick void 6337488Smckusick vfs_unlock(mp) 6437488Smckusick register struct mount *mp; 6537488Smckusick { 6637488Smckusick 6741400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 6841300Smckusick panic("vfs_unlock: not locked"); 6941400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 7041400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 7141400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 7237488Smckusick wakeup((caddr_t)mp); 7337488Smckusick } 7437488Smckusick } 7537488Smckusick 7637488Smckusick /* 7741300Smckusick * Mark a mount point as busy. 7841300Smckusick * Used to synchronize access and to delay unmounting. 7941300Smckusick */ 8041300Smckusick vfs_busy(mp) 8141300Smckusick register struct mount *mp; 8241300Smckusick { 8341300Smckusick 8441400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 8541400Smckusick mp->mnt_flag |= MNT_MPWANT; 8641400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 8741300Smckusick } 8841419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 8941419Smckusick return (1); 9041400Smckusick mp->mnt_flag |= MNT_MPBUSY; 9141300Smckusick return (0); 9241300Smckusick } 9341300Smckusick 9441300Smckusick /* 9541300Smckusick * Free a busy filesystem. 9641300Smckusick * Panic if filesystem is not busy. 9741300Smckusick */ 9841300Smckusick vfs_unbusy(mp) 9941300Smckusick register struct mount *mp; 10041300Smckusick { 10141300Smckusick 10241400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 10341300Smckusick panic("vfs_unbusy: not busy"); 10441400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 10541400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 10641400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 10741400Smckusick wakeup((caddr_t)&mp->mnt_flag); 10841300Smckusick } 10941300Smckusick } 11041300Smckusick 11141300Smckusick /* 11237488Smckusick * Lookup a mount point by filesystem identifier. 11337488Smckusick */ 11437488Smckusick struct mount * 11537488Smckusick getvfs(fsid) 11637488Smckusick fsid_t *fsid; 11737488Smckusick { 11837488Smckusick register struct mount *mp; 11937488Smckusick 12038288Smckusick mp = rootfs; 12138288Smckusick do { 12241400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 12341400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 12438288Smckusick return (mp); 12537488Smckusick } 12641400Smckusick mp = mp->mnt_next; 12738288Smckusick } while (mp != rootfs); 12838288Smckusick return ((struct mount *)0); 12937488Smckusick } 13037488Smckusick 13137488Smckusick /* 13237488Smckusick * Set vnode attributes to VNOVAL 13337488Smckusick */ 13437488Smckusick void vattr_null(vap) 13537488Smckusick register struct vattr *vap; 13637488Smckusick { 13737488Smckusick 13837488Smckusick vap->va_type = VNON; 13937488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 14037488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 14140643Smckusick vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 14240643Smckusick vap->va_bytes = vap->va_bytes_rsv = 14337488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 14437488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 14538258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 14638258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 14737488Smckusick } 14838265Smckusick 14938265Smckusick /* 15038265Smckusick * Initialize a nameidata structure 15138265Smckusick */ 15238265Smckusick ndinit(ndp) 15338265Smckusick register struct nameidata *ndp; 15438265Smckusick { 15538265Smckusick 15638265Smckusick bzero((caddr_t)ndp, sizeof(struct nameidata)); 15738265Smckusick ndp->ni_iov = &ndp->ni_nd.nd_iovec; 15838265Smckusick ndp->ni_iovcnt = 1; 15938265Smckusick ndp->ni_base = (caddr_t)&ndp->ni_dent; 16038265Smckusick ndp->ni_rw = UIO_WRITE; 16139736Smckusick ndp->ni_uioseg = UIO_SYSSPACE; 16238265Smckusick } 16338265Smckusick 16438265Smckusick /* 16538265Smckusick * Duplicate a nameidata structure 16638265Smckusick */ 16738265Smckusick nddup(ndp, newndp) 16838265Smckusick register struct nameidata *ndp, *newndp; 16938265Smckusick { 17038265Smckusick 17138265Smckusick ndinit(newndp); 17238265Smckusick newndp->ni_cred = ndp->ni_cred; 17338265Smckusick crhold(newndp->ni_cred); 17438265Smckusick } 17538265Smckusick 17638265Smckusick /* 17738265Smckusick * Release a nameidata structure 17838265Smckusick */ 17938265Smckusick ndrele(ndp) 18038265Smckusick register struct nameidata *ndp; 18138265Smckusick { 18238265Smckusick 18338265Smckusick crfree(ndp->ni_cred); 18438265Smckusick } 18539397Smckusick 18639397Smckusick /* 18739397Smckusick * Routines having to do with the management of the vnode table. 18839397Smckusick */ 18939397Smckusick struct vnode *vfreeh, **vfreet; 19039447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 19139635Smckusick extern void vclean(); 19240883Smckusick long numvnodes; 19341363Smckusick struct vattr va_null; 19439397Smckusick 19539397Smckusick /* 19639433Smckusick * Initialize the vnode structures and initialize each file system type. 19739397Smckusick */ 19839433Smckusick vfsinit() 19939397Smckusick { 20039433Smckusick struct vfsops **vfsp; 20139397Smckusick 20239433Smckusick /* 20339433Smckusick * Initialize the vnode name cache 20439433Smckusick */ 20539433Smckusick nchinit(); 20639433Smckusick /* 20739433Smckusick * Initialize each file system type. 20839433Smckusick */ 20941363Smckusick vattr_null(&va_null); 21039433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 21139433Smckusick if (*vfsp == NULL) 21239433Smckusick continue; 21339433Smckusick (*(*vfsp)->vfs_init)(); 21439433Smckusick } 21539397Smckusick } 21639397Smckusick 21739397Smckusick /* 21839397Smckusick * Return the next vnode from the free list. 21939397Smckusick */ 22039397Smckusick getnewvnode(tag, mp, vops, vpp) 22139397Smckusick enum vtagtype tag; 22239397Smckusick struct mount *mp; 22339397Smckusick struct vnodeops *vops; 22439397Smckusick struct vnode **vpp; 22539397Smckusick { 22639397Smckusick register struct vnode *vp, *vq; 22739397Smckusick 22840883Smckusick if (numvnodes < desiredvnodes) { 22945118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 23045118Smckusick M_VNODE, M_WAITOK); 23140883Smckusick bzero((char *)vp, sizeof *vp); 23240883Smckusick numvnodes++; 23340883Smckusick } else { 23440883Smckusick if ((vp = vfreeh) == NULL) { 23540883Smckusick tablefull("vnode"); 23640883Smckusick *vpp = 0; 23740883Smckusick return (ENFILE); 23840883Smckusick } 23940883Smckusick if (vp->v_usecount) 24040883Smckusick panic("free vnode isn't"); 24140883Smckusick if (vq = vp->v_freef) 24240883Smckusick vq->v_freeb = &vfreeh; 24340883Smckusick else 24440883Smckusick vfreet = &vfreeh; 24540883Smckusick vfreeh = vq; 24640883Smckusick vp->v_freef = NULL; 24740883Smckusick vp->v_freeb = NULL; 24840883Smckusick if (vp->v_type != VBAD) 24940883Smckusick vgone(vp); 25040883Smckusick vp->v_flag = 0; 25140883Smckusick vp->v_lastr = 0; 25240883Smckusick vp->v_socket = 0; 25339397Smckusick } 25439512Smckusick vp->v_type = VNON; 25539397Smckusick cache_purge(vp); 25639397Smckusick vp->v_tag = tag; 25739433Smckusick vp->v_op = vops; 25839397Smckusick insmntque(vp, mp); 25939397Smckusick VREF(vp); 26039397Smckusick *vpp = vp; 26139397Smckusick return (0); 26239397Smckusick } 26339397Smckusick 26439397Smckusick /* 26539397Smckusick * Move a vnode from one mount queue to another. 26639397Smckusick */ 26739397Smckusick insmntque(vp, mp) 26839397Smckusick register struct vnode *vp; 26939397Smckusick register struct mount *mp; 27039397Smckusick { 27139397Smckusick struct vnode *vq; 27239397Smckusick 27339397Smckusick /* 27439397Smckusick * Delete from old mount point vnode list, if on one. 27539397Smckusick */ 27639397Smckusick if (vp->v_mountb) { 27739397Smckusick if (vq = vp->v_mountf) 27839397Smckusick vq->v_mountb = vp->v_mountb; 27939397Smckusick *vp->v_mountb = vq; 28039397Smckusick } 28139397Smckusick /* 28239397Smckusick * Insert into list of vnodes for the new mount point, if available. 28339397Smckusick */ 28439621Smckusick vp->v_mount = mp; 28539397Smckusick if (mp == NULL) { 28639397Smckusick vp->v_mountf = NULL; 28739397Smckusick vp->v_mountb = NULL; 28839397Smckusick return; 28939397Smckusick } 29041400Smckusick if (mp->mnt_mounth) { 29141400Smckusick vp->v_mountf = mp->mnt_mounth; 29241400Smckusick vp->v_mountb = &mp->mnt_mounth; 29341400Smckusick mp->mnt_mounth->v_mountb = &vp->v_mountf; 29441400Smckusick mp->mnt_mounth = vp; 29539397Smckusick } else { 29641400Smckusick mp->mnt_mounth = vp; 29741400Smckusick vp->v_mountb = &mp->mnt_mounth; 29839397Smckusick vp->v_mountf = NULL; 29939397Smckusick } 30039397Smckusick } 30139397Smckusick 30239397Smckusick /* 30339433Smckusick * Create a vnode for a block device. 30439433Smckusick * Used for root filesystem, argdev, and swap areas. 30539433Smckusick * Also used for memory file system special devices. 30639397Smckusick */ 30739433Smckusick bdevvp(dev, vpp) 30839433Smckusick dev_t dev; 30939433Smckusick struct vnode **vpp; 31039433Smckusick { 31139433Smckusick register struct vnode *vp; 31239433Smckusick struct vnode *nvp; 31339433Smckusick int error; 31439433Smckusick 31546989Smckusick if (dev == NODEV) 31646989Smckusick return (0); 31739447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 31839433Smckusick if (error) { 31939433Smckusick *vpp = 0; 32039433Smckusick return (error); 32139433Smckusick } 32239433Smckusick vp = nvp; 32339433Smckusick vp->v_type = VBLK; 32439615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 32539433Smckusick vput(vp); 32639433Smckusick vp = nvp; 32739433Smckusick } 32839433Smckusick *vpp = vp; 32939433Smckusick return (0); 33039433Smckusick } 33139433Smckusick 33239433Smckusick /* 33339433Smckusick * Check to see if the new vnode represents a special device 33439433Smckusick * for which we already have a vnode (either because of 33539433Smckusick * bdevvp() or because of a different vnode representing 33639433Smckusick * the same block device). If such an alias exists, deallocate 33739509Smckusick * the existing contents and return the aliased vnode. The 33839433Smckusick * caller is responsible for filling it with its new contents. 33939433Smckusick */ 34039433Smckusick struct vnode * 34139615Smckusick checkalias(nvp, nvp_rdev, mp) 34239433Smckusick register struct vnode *nvp; 34339615Smckusick dev_t nvp_rdev; 34439433Smckusick struct mount *mp; 34539433Smckusick { 34639433Smckusick register struct vnode *vp; 34739615Smckusick struct vnode **vpp; 34839433Smckusick 34939433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 35041400Smckusick return (NULLVP); 35139615Smckusick 35239615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 35339433Smckusick loop: 35439615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 35539615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 35639433Smckusick continue; 35739615Smckusick /* 35839615Smckusick * Alias, but not in use, so flush it out. 35939615Smckusick */ 36039809Smckusick if (vp->v_usecount == 0) { 36139615Smckusick vgone(vp); 36239615Smckusick goto loop; 36339615Smckusick } 36439633Smckusick if (vget(vp)) 36539633Smckusick goto loop; 36639433Smckusick break; 36739433Smckusick } 36839615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 36939615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 37039615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 37139615Smckusick nvp->v_rdev = nvp_rdev; 37239809Smckusick nvp->v_hashchain = vpp; 37339615Smckusick nvp->v_specnext = *vpp; 37442152Smckusick nvp->v_specflags = 0; 37539615Smckusick *vpp = nvp; 37640640Smckusick if (vp != NULL) { 37740640Smckusick nvp->v_flag |= VALIASED; 37840640Smckusick vp->v_flag |= VALIASED; 37940640Smckusick vput(vp); 38040640Smckusick } 38141400Smckusick return (NULLVP); 38239433Smckusick } 38339484Smckusick VOP_UNLOCK(vp); 38439484Smckusick vclean(vp, 0); 38539433Smckusick vp->v_op = nvp->v_op; 38639433Smckusick vp->v_tag = nvp->v_tag; 38739433Smckusick nvp->v_type = VNON; 38839433Smckusick insmntque(vp, mp); 38939433Smckusick return (vp); 39039433Smckusick } 39139433Smckusick 39239433Smckusick /* 39339433Smckusick * Grab a particular vnode from the free list, increment its 39439433Smckusick * reference count and lock it. The vnode lock bit is set the 39539433Smckusick * vnode is being eliminated in vgone. The process is awakened 39639433Smckusick * when the transition is completed, and an error returned to 39739433Smckusick * indicate that the vnode is no longer usable (possibly having 39839433Smckusick * been changed to a new file system type). 39939433Smckusick */ 40039397Smckusick vget(vp) 40139397Smckusick register struct vnode *vp; 40239397Smckusick { 40339397Smckusick register struct vnode *vq; 40439397Smckusick 40539433Smckusick if (vp->v_flag & VXLOCK) { 40639433Smckusick vp->v_flag |= VXWANT; 40739433Smckusick sleep((caddr_t)vp, PINOD); 40839433Smckusick return (1); 40939433Smckusick } 41039809Smckusick if (vp->v_usecount == 0) { 41139433Smckusick if (vq = vp->v_freef) 41239433Smckusick vq->v_freeb = vp->v_freeb; 41339433Smckusick else 41439433Smckusick vfreet = vp->v_freeb; 41539433Smckusick *vp->v_freeb = vq; 41639433Smckusick vp->v_freef = NULL; 41739433Smckusick vp->v_freeb = NULL; 41839433Smckusick } 41939397Smckusick VREF(vp); 42039433Smckusick VOP_LOCK(vp); 42139433Smckusick return (0); 42239397Smckusick } 42339397Smckusick 42439397Smckusick /* 42539397Smckusick * Vnode reference, just increment the count 42639397Smckusick */ 42739397Smckusick void vref(vp) 42839397Smckusick struct vnode *vp; 42939397Smckusick { 43039397Smckusick 43139809Smckusick vp->v_usecount++; 43239397Smckusick } 43339397Smckusick 43439397Smckusick /* 43539397Smckusick * vput(), just unlock and vrele() 43639397Smckusick */ 43739397Smckusick void vput(vp) 43839397Smckusick register struct vnode *vp; 43939397Smckusick { 44039397Smckusick VOP_UNLOCK(vp); 44139397Smckusick vrele(vp); 44239397Smckusick } 44339397Smckusick 44439397Smckusick /* 44539397Smckusick * Vnode release. 44639397Smckusick * If count drops to zero, call inactive routine and return to freelist. 44739397Smckusick */ 44839397Smckusick void vrele(vp) 44939397Smckusick register struct vnode *vp; 45039397Smckusick { 45148024Smckusick struct proc *p = curproc; /* XXX */ 45239397Smckusick 45339397Smckusick if (vp == NULL) 45439433Smckusick panic("vrele: null vp"); 45539809Smckusick vp->v_usecount--; 45639809Smckusick if (vp->v_usecount < 0) 45739667Smckusick vprint("vrele: bad ref count", vp); 45839809Smckusick if (vp->v_usecount > 0) 45939397Smckusick return; 46041400Smckusick if (vfreeh == NULLVP) { 46139397Smckusick /* 46239397Smckusick * insert into empty list 46339397Smckusick */ 46439397Smckusick vfreeh = vp; 46539397Smckusick vp->v_freeb = &vfreeh; 46639397Smckusick } else { 46739397Smckusick /* 46839397Smckusick * insert at tail of list 46939397Smckusick */ 47039397Smckusick *vfreet = vp; 47139397Smckusick vp->v_freeb = vfreet; 47239397Smckusick } 47339433Smckusick vp->v_freef = NULL; 47439433Smckusick vfreet = &vp->v_freef; 47548024Smckusick VOP_INACTIVE(vp, p); 47639397Smckusick } 47739433Smckusick 47839433Smckusick /* 47939809Smckusick * Page or buffer structure gets a reference. 48039809Smckusick */ 48139809Smckusick vhold(vp) 48239809Smckusick register struct vnode *vp; 48339809Smckusick { 48439809Smckusick 48539809Smckusick vp->v_holdcnt++; 48639809Smckusick } 48739809Smckusick 48839809Smckusick /* 48939809Smckusick * Page or buffer structure frees a reference. 49039809Smckusick */ 49139809Smckusick holdrele(vp) 49239809Smckusick register struct vnode *vp; 49339809Smckusick { 49439809Smckusick 49539809Smckusick if (vp->v_holdcnt <= 0) 49639809Smckusick panic("holdrele: holdcnt"); 49739809Smckusick vp->v_holdcnt--; 49839809Smckusick } 49939809Smckusick 50039809Smckusick /* 50139509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 50239509Smckusick * 50339509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 50439509Smckusick * return error if any are found (nb: this is a user error, not a 50539509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 50639509Smckusick * that are found. 50739509Smckusick */ 50839509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 50939509Smckusick 51039509Smckusick vflush(mp, skipvp, flags) 51139509Smckusick struct mount *mp; 51239509Smckusick struct vnode *skipvp; 51339509Smckusick int flags; 51439509Smckusick { 51539509Smckusick register struct vnode *vp, *nvp; 51639509Smckusick int busy = 0; 51739509Smckusick 51841400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 51941300Smckusick panic("vflush: not busy"); 52041421Smckusick loop: 52141400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 52241421Smckusick if (vp->v_mount != mp) 52341421Smckusick goto loop; 52439509Smckusick nvp = vp->v_mountf; 52539509Smckusick /* 52639509Smckusick * Skip over a selected vnode. 52739509Smckusick */ 52839509Smckusick if (vp == skipvp) 52939509Smckusick continue; 53039509Smckusick /* 53141300Smckusick * Skip over a vnodes marked VSYSTEM. 53241300Smckusick */ 53341300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 53441300Smckusick continue; 53541300Smckusick /* 53639809Smckusick * With v_usecount == 0, all we need to do is clear 53739509Smckusick * out the vnode data structures and we are done. 53839509Smckusick */ 53939809Smckusick if (vp->v_usecount == 0) { 54039509Smckusick vgone(vp); 54139509Smckusick continue; 54239509Smckusick } 54339509Smckusick /* 54439509Smckusick * For block or character devices, revert to an 54539509Smckusick * anonymous device. For all other files, just kill them. 54639509Smckusick */ 54741300Smckusick if (flags & FORCECLOSE) { 54839509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 54939509Smckusick vgone(vp); 55039509Smckusick } else { 55139509Smckusick vclean(vp, 0); 55239509Smckusick vp->v_op = &spec_vnodeops; 55339509Smckusick insmntque(vp, (struct mount *)0); 55439509Smckusick } 55539509Smckusick continue; 55639509Smckusick } 55739509Smckusick if (busyprt) 55839667Smckusick vprint("vflush: busy vnode", vp); 55939509Smckusick busy++; 56039509Smckusick } 56139509Smckusick if (busy) 56239509Smckusick return (EBUSY); 56339509Smckusick return (0); 56439509Smckusick } 56539509Smckusick 56639509Smckusick /* 56739433Smckusick * Disassociate the underlying file system from a vnode. 56839433Smckusick */ 56941300Smckusick void vclean(vp, flags) 57039433Smckusick register struct vnode *vp; 57145118Smckusick int flags; 57239433Smckusick { 57339433Smckusick struct vnodeops *origops; 57439484Smckusick int active; 57548024Smckusick struct proc *p = curproc; /* XXX */ 57639433Smckusick 57739484Smckusick /* 57839484Smckusick * Check to see if the vnode is in use. 57939667Smckusick * If so we have to reference it before we clean it out 58039667Smckusick * so that its count cannot fall to zero and generate a 58139667Smckusick * race against ourselves to recycle it. 58239484Smckusick */ 58339809Smckusick if (active = vp->v_usecount) 58439484Smckusick VREF(vp); 58539484Smckusick /* 58639484Smckusick * Prevent the vnode from being recycled or 58739484Smckusick * brought into use while we clean it out. 58839484Smckusick */ 58939667Smckusick if (vp->v_flag & VXLOCK) 59039667Smckusick panic("vclean: deadlock"); 59139433Smckusick vp->v_flag |= VXLOCK; 59239433Smckusick /* 59339667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 59439667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 59539667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 59639667Smckusick * For active vnodes, it ensures that no other activity can 59739667Smckusick * occur while the buffer list is being cleaned out. 59839667Smckusick */ 59939667Smckusick VOP_LOCK(vp); 60041300Smckusick if (flags & DOCLOSE) 60139667Smckusick vinvalbuf(vp, 1); 60239667Smckusick /* 60339433Smckusick * Prevent any further operations on the vnode from 60439433Smckusick * being passed through to the old file system. 60539433Smckusick */ 60639433Smckusick origops = vp->v_op; 60739433Smckusick vp->v_op = &dead_vnodeops; 60839433Smckusick vp->v_tag = VT_NON; 60939433Smckusick /* 61039484Smckusick * If purging an active vnode, it must be unlocked, closed, 61139484Smckusick * and deactivated before being reclaimed. 61239433Smckusick */ 61339667Smckusick (*(origops->vn_unlock))(vp); 61439484Smckusick if (active) { 61541300Smckusick if (flags & DOCLOSE) 616*48354Smckusick (*(origops->vn_close))(vp, IO_NDELAY, NOCRED, p); 61748024Smckusick (*(origops->vn_inactive))(vp, p); 61839433Smckusick } 61939433Smckusick /* 62039433Smckusick * Reclaim the vnode. 62139433Smckusick */ 62239433Smckusick if ((*(origops->vn_reclaim))(vp)) 62339433Smckusick panic("vclean: cannot reclaim"); 62439484Smckusick if (active) 62539484Smckusick vrele(vp); 62639433Smckusick /* 62739433Smckusick * Done with purge, notify sleepers in vget of the grim news. 62839433Smckusick */ 62939433Smckusick vp->v_flag &= ~VXLOCK; 63039433Smckusick if (vp->v_flag & VXWANT) { 63139433Smckusick vp->v_flag &= ~VXWANT; 63239433Smckusick wakeup((caddr_t)vp); 63339433Smckusick } 63439433Smckusick } 63539433Smckusick 63639433Smckusick /* 63739633Smckusick * Eliminate all activity associated with the requested vnode 63839633Smckusick * and with all vnodes aliased to the requested vnode. 63939633Smckusick */ 64039633Smckusick void vgoneall(vp) 64139633Smckusick register struct vnode *vp; 64239633Smckusick { 64339809Smckusick register struct vnode *vq; 64439633Smckusick 64540665Smckusick if (vp->v_flag & VALIASED) { 64640665Smckusick /* 64740665Smckusick * If a vgone (or vclean) is already in progress, 64840665Smckusick * wait until it is done and return. 64940665Smckusick */ 65040665Smckusick if (vp->v_flag & VXLOCK) { 65140665Smckusick vp->v_flag |= VXWANT; 65240665Smckusick sleep((caddr_t)vp, PINOD); 65340665Smckusick return; 65439633Smckusick } 65540665Smckusick /* 65640665Smckusick * Ensure that vp will not be vgone'd while we 65740665Smckusick * are eliminating its aliases. 65840665Smckusick */ 65940665Smckusick vp->v_flag |= VXLOCK; 66040665Smckusick while (vp->v_flag & VALIASED) { 66140665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 66240665Smckusick if (vq->v_rdev != vp->v_rdev || 66340665Smckusick vq->v_type != vp->v_type || vp == vq) 66440665Smckusick continue; 66540665Smckusick vgone(vq); 66640665Smckusick break; 66740665Smckusick } 66840665Smckusick } 66940665Smckusick /* 67040665Smckusick * Remove the lock so that vgone below will 67140665Smckusick * really eliminate the vnode after which time 67240665Smckusick * vgone will awaken any sleepers. 67340665Smckusick */ 67440665Smckusick vp->v_flag &= ~VXLOCK; 67539633Smckusick } 67639633Smckusick vgone(vp); 67739633Smckusick } 67839633Smckusick 67939633Smckusick /* 68039433Smckusick * Eliminate all activity associated with a vnode 68139433Smckusick * in preparation for reuse. 68239433Smckusick */ 68339433Smckusick void vgone(vp) 68439433Smckusick register struct vnode *vp; 68539433Smckusick { 68639809Smckusick register struct vnode *vq; 68739615Smckusick struct vnode *vx; 68839615Smckusick long count; 68939433Smckusick 69039433Smckusick /* 69140548Smckusick * If a vgone (or vclean) is already in progress, 69240548Smckusick * wait until it is done and return. 69340548Smckusick */ 69440548Smckusick if (vp->v_flag & VXLOCK) { 69540548Smckusick vp->v_flag |= VXWANT; 69640548Smckusick sleep((caddr_t)vp, PINOD); 69740548Smckusick return; 69840548Smckusick } 69940548Smckusick /* 70039433Smckusick * Clean out the filesystem specific data. 70139433Smckusick */ 70241300Smckusick vclean(vp, DOCLOSE); 70339433Smckusick /* 70439433Smckusick * Delete from old mount point vnode list, if on one. 70539433Smckusick */ 70639433Smckusick if (vp->v_mountb) { 70739433Smckusick if (vq = vp->v_mountf) 70839433Smckusick vq->v_mountb = vp->v_mountb; 70939433Smckusick *vp->v_mountb = vq; 71039433Smckusick vp->v_mountf = NULL; 71139433Smckusick vp->v_mountb = NULL; 71239433Smckusick } 71339433Smckusick /* 71439433Smckusick * If special device, remove it from special device alias list. 71539433Smckusick */ 71639433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 71739809Smckusick if (*vp->v_hashchain == vp) { 71839809Smckusick *vp->v_hashchain = vp->v_specnext; 71939433Smckusick } else { 72039809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 72139615Smckusick if (vq->v_specnext != vp) 72239433Smckusick continue; 72339615Smckusick vq->v_specnext = vp->v_specnext; 72439433Smckusick break; 72539433Smckusick } 72639615Smckusick if (vq == NULL) 72739433Smckusick panic("missing bdev"); 72839433Smckusick } 72939615Smckusick if (vp->v_flag & VALIASED) { 73039809Smckusick count = 0; 73139809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 73240108Smckusick if (vq->v_rdev != vp->v_rdev || 73340108Smckusick vq->v_type != vp->v_type) 73439615Smckusick continue; 73539615Smckusick count++; 73639615Smckusick vx = vq; 73739615Smckusick } 73839615Smckusick if (count == 0) 73939615Smckusick panic("missing alias"); 74039615Smckusick if (count == 1) 74139615Smckusick vx->v_flag &= ~VALIASED; 74239615Smckusick vp->v_flag &= ~VALIASED; 74339615Smckusick } 74439615Smckusick FREE(vp->v_specinfo, M_VNODE); 74539615Smckusick vp->v_specinfo = NULL; 74639433Smckusick } 74739433Smckusick /* 74839433Smckusick * If it is on the freelist, move it to the head of the list. 74939433Smckusick */ 75039433Smckusick if (vp->v_freeb) { 75139433Smckusick if (vq = vp->v_freef) 75239433Smckusick vq->v_freeb = vp->v_freeb; 75339433Smckusick else 75439433Smckusick vfreet = vp->v_freeb; 75539433Smckusick *vp->v_freeb = vq; 75639433Smckusick vp->v_freef = vfreeh; 75739433Smckusick vp->v_freeb = &vfreeh; 75839433Smckusick vfreeh->v_freeb = &vp->v_freef; 75939433Smckusick vfreeh = vp; 76039433Smckusick } 76139484Smckusick vp->v_type = VBAD; 76239433Smckusick } 76339633Smckusick 76439633Smckusick /* 76539821Smckusick * Lookup a vnode by device number. 76639821Smckusick */ 76739821Smckusick vfinddev(dev, type, vpp) 76839821Smckusick dev_t dev; 76939821Smckusick enum vtype type; 77039821Smckusick struct vnode **vpp; 77139821Smckusick { 77239821Smckusick register struct vnode *vp; 77339821Smckusick 77439821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 77539821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 77639821Smckusick continue; 77739821Smckusick *vpp = vp; 77839821Smckusick return (0); 77939821Smckusick } 78039821Smckusick return (1); 78139821Smckusick } 78239821Smckusick 78339821Smckusick /* 78439633Smckusick * Calculate the total number of references to a special device. 78539633Smckusick */ 78639633Smckusick vcount(vp) 78739633Smckusick register struct vnode *vp; 78839633Smckusick { 78939809Smckusick register struct vnode *vq; 79039633Smckusick int count; 79139633Smckusick 79239633Smckusick if ((vp->v_flag & VALIASED) == 0) 79339809Smckusick return (vp->v_usecount); 79439633Smckusick loop: 79539809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 79640108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 79739633Smckusick continue; 79839633Smckusick /* 79939633Smckusick * Alias, but not in use, so flush it out. 80039633Smckusick */ 80139809Smckusick if (vq->v_usecount == 0) { 80239633Smckusick vgone(vq); 80339633Smckusick goto loop; 80439633Smckusick } 80539809Smckusick count += vq->v_usecount; 80639633Smckusick } 80739633Smckusick return (count); 80839633Smckusick } 80939667Smckusick 81039667Smckusick /* 81139667Smckusick * Print out a description of a vnode. 81239667Smckusick */ 81339667Smckusick static char *typename[] = 81440286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 81539667Smckusick 81639667Smckusick vprint(label, vp) 81739667Smckusick char *label; 81839667Smckusick register struct vnode *vp; 81939667Smckusick { 82039913Smckusick char buf[64]; 82139667Smckusick 82239667Smckusick if (label != NULL) 82339667Smckusick printf("%s: ", label); 82439913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 82539809Smckusick vp->v_usecount, vp->v_holdcnt); 82639913Smckusick buf[0] = '\0'; 82739913Smckusick if (vp->v_flag & VROOT) 82839913Smckusick strcat(buf, "|VROOT"); 82939913Smckusick if (vp->v_flag & VTEXT) 83039913Smckusick strcat(buf, "|VTEXT"); 83141300Smckusick if (vp->v_flag & VSYSTEM) 83241300Smckusick strcat(buf, "|VSYSTEM"); 83341300Smckusick if (vp->v_flag & VXLOCK) 83441300Smckusick strcat(buf, "|VXLOCK"); 83541300Smckusick if (vp->v_flag & VXWANT) 83641300Smckusick strcat(buf, "|VXWANT"); 83741300Smckusick if (vp->v_flag & VBWAIT) 83841300Smckusick strcat(buf, "|VBWAIT"); 83939913Smckusick if (vp->v_flag & VALIASED) 84039913Smckusick strcat(buf, "|VALIASED"); 84139913Smckusick if (buf[0] != '\0') 84239913Smckusick printf(" flags (%s)", &buf[1]); 84339913Smckusick printf("\n\t"); 84439667Smckusick VOP_PRINT(vp); 84539667Smckusick } 84641110Smarc 84741110Smarc int kinfo_vdebug = 1; 84841110Smarc int kinfo_vgetfailed; 84941110Smarc #define KINFO_VNODESLOP 10 85041110Smarc /* 85141110Smarc * Dump vnode list (via kinfo). 85241110Smarc * Copyout address of vnode followed by vnode. 85341110Smarc */ 85445118Smckusick /* ARGSUSED */ 85541110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 85645118Smckusick int op; 85741110Smarc char *where; 85845118Smckusick int *acopysize, arg, *aneeded; 85941110Smarc { 86041110Smarc register struct mount *mp = rootfs; 86141300Smckusick struct mount *omp; 86241110Smarc struct vnode *vp; 86341110Smarc register char *bp = where, *savebp; 86441110Smarc char *ewhere = where + *acopysize; 86541110Smarc int error; 86641110Smarc 86741110Smarc #define VPTRSZ sizeof (struct vnode *) 86841110Smarc #define VNODESZ sizeof (struct vnode) 86941110Smarc if (where == NULL) { 87041110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 87141110Smarc return (0); 87241110Smarc } 87341110Smarc 87441110Smarc do { 87541300Smckusick if (vfs_busy(mp)) { 87641400Smckusick mp = mp->mnt_next; 87741300Smckusick continue; 87841300Smckusick } 87941110Smarc savebp = bp; 88041110Smarc again: 88141421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 88241422Smckusick /* 88341422Smckusick * Check that the vp is still associated with 88441422Smckusick * this filesystem. RACE: could have been 88541422Smckusick * recycled onto the same filesystem. 88641422Smckusick */ 88741421Smckusick if (vp->v_mount != mp) { 88841421Smckusick if (kinfo_vdebug) 88941421Smckusick printf("kinfo: vp changed\n"); 89041421Smckusick bp = savebp; 89141421Smckusick goto again; 89241421Smckusick } 89341110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 89441110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 89541110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 89641422Smckusick VNODESZ)))) 89741110Smarc return (error); 89841110Smarc bp += VPTRSZ + VNODESZ; 89941110Smarc } 90041300Smckusick omp = mp; 90141400Smckusick mp = mp->mnt_next; 90241300Smckusick vfs_unbusy(omp); 90341110Smarc } while (mp != rootfs); 90441110Smarc 90541110Smarc *aneeded = bp - where; 90641110Smarc if (bp > ewhere) 90741110Smarc *acopysize = ewhere - where; 90841110Smarc else 90941110Smarc *acopysize = bp - where; 91041110Smarc return (0); 91141110Smarc } 912