137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 544458Sbostic * %sccs.include.redist.c% 637488Smckusick * 7*46989Smckusick * @(#)vfs_subr.c 7.51 (Berkeley) 03/04/91 837488Smckusick */ 937488Smckusick 1037488Smckusick /* 1137488Smckusick * External virtual filesystem routines 1237488Smckusick */ 1337488Smckusick 1437488Smckusick #include "param.h" 1537488Smckusick #include "mount.h" 1637488Smckusick #include "time.h" 1737488Smckusick #include "vnode.h" 1840652Smckusick #include "specdev.h" 1938265Smckusick #include "namei.h" 2038265Smckusick #include "ucred.h" 2137488Smckusick #include "errno.h" 2239433Smckusick #include "malloc.h" 2337488Smckusick 2437488Smckusick /* 2537488Smckusick * Remove a mount point from the list of mounted filesystems. 2637488Smckusick * Unmount of the root is illegal. 2737488Smckusick */ 2837488Smckusick void 2937488Smckusick vfs_remove(mp) 3037488Smckusick register struct mount *mp; 3137488Smckusick { 3237488Smckusick 3337488Smckusick if (mp == rootfs) 3437488Smckusick panic("vfs_remove: unmounting root"); 3541400Smckusick mp->mnt_prev->mnt_next = mp->mnt_next; 3641400Smckusick mp->mnt_next->mnt_prev = mp->mnt_prev; 3741400Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 3837488Smckusick vfs_unlock(mp); 3937488Smckusick } 4037488Smckusick 4137488Smckusick /* 4237488Smckusick * Lock a filesystem. 4337488Smckusick * Used to prevent access to it while mounting and unmounting. 4437488Smckusick */ 4537488Smckusick vfs_lock(mp) 4637488Smckusick register struct mount *mp; 4737488Smckusick { 4837488Smckusick 4941400Smckusick while(mp->mnt_flag & MNT_MLOCK) { 5041400Smckusick mp->mnt_flag |= MNT_MWAIT; 5139045Smckusick sleep((caddr_t)mp, PVFS); 5239045Smckusick } 5341400Smckusick mp->mnt_flag |= MNT_MLOCK; 5437488Smckusick return (0); 5537488Smckusick } 5637488Smckusick 5737488Smckusick /* 5837488Smckusick * Unlock a locked filesystem. 5937488Smckusick * Panic if filesystem is not locked. 6037488Smckusick */ 6137488Smckusick void 6237488Smckusick vfs_unlock(mp) 6337488Smckusick register struct mount *mp; 6437488Smckusick { 6537488Smckusick 6641400Smckusick if ((mp->mnt_flag & MNT_MLOCK) == 0) 6741300Smckusick panic("vfs_unlock: not locked"); 6841400Smckusick mp->mnt_flag &= ~MNT_MLOCK; 6941400Smckusick if (mp->mnt_flag & MNT_MWAIT) { 7041400Smckusick mp->mnt_flag &= ~MNT_MWAIT; 7137488Smckusick wakeup((caddr_t)mp); 7237488Smckusick } 7337488Smckusick } 7437488Smckusick 7537488Smckusick /* 7641300Smckusick * Mark a mount point as busy. 7741300Smckusick * Used to synchronize access and to delay unmounting. 7841300Smckusick */ 7941300Smckusick vfs_busy(mp) 8041300Smckusick register struct mount *mp; 8141300Smckusick { 8241300Smckusick 8341400Smckusick while(mp->mnt_flag & MNT_MPBUSY) { 8441400Smckusick mp->mnt_flag |= MNT_MPWANT; 8541400Smckusick sleep((caddr_t)&mp->mnt_flag, PVFS); 8641300Smckusick } 8741419Smckusick if (mp->mnt_flag & MNT_UNMOUNT) 8841419Smckusick return (1); 8941400Smckusick mp->mnt_flag |= MNT_MPBUSY; 9041300Smckusick return (0); 9141300Smckusick } 9241300Smckusick 9341300Smckusick /* 9441300Smckusick * Free a busy filesystem. 9541300Smckusick * Panic if filesystem is not busy. 9641300Smckusick */ 9741300Smckusick vfs_unbusy(mp) 9841300Smckusick register struct mount *mp; 9941300Smckusick { 10041300Smckusick 10141400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 10241300Smckusick panic("vfs_unbusy: not busy"); 10341400Smckusick mp->mnt_flag &= ~MNT_MPBUSY; 10441400Smckusick if (mp->mnt_flag & MNT_MPWANT) { 10541400Smckusick mp->mnt_flag &= ~MNT_MPWANT; 10641400Smckusick wakeup((caddr_t)&mp->mnt_flag); 10741300Smckusick } 10841300Smckusick } 10941300Smckusick 11041300Smckusick /* 11137488Smckusick * Lookup a mount point by filesystem identifier. 11237488Smckusick */ 11337488Smckusick struct mount * 11437488Smckusick getvfs(fsid) 11537488Smckusick fsid_t *fsid; 11637488Smckusick { 11737488Smckusick register struct mount *mp; 11837488Smckusick 11938288Smckusick mp = rootfs; 12038288Smckusick do { 12141400Smckusick if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 12241400Smckusick mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 12338288Smckusick return (mp); 12437488Smckusick } 12541400Smckusick mp = mp->mnt_next; 12638288Smckusick } while (mp != rootfs); 12738288Smckusick return ((struct mount *)0); 12837488Smckusick } 12937488Smckusick 13037488Smckusick /* 13137488Smckusick * Set vnode attributes to VNOVAL 13237488Smckusick */ 13337488Smckusick void vattr_null(vap) 13437488Smckusick register struct vattr *vap; 13537488Smckusick { 13637488Smckusick 13737488Smckusick vap->va_type = VNON; 13837488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 13937488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 14040643Smckusick vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 14140643Smckusick vap->va_bytes = vap->va_bytes_rsv = 14237488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 14337488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 14438258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 14538258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 14637488Smckusick } 14738265Smckusick 14838265Smckusick /* 14938265Smckusick * Initialize a nameidata structure 15038265Smckusick */ 15138265Smckusick ndinit(ndp) 15238265Smckusick register struct nameidata *ndp; 15338265Smckusick { 15438265Smckusick 15538265Smckusick bzero((caddr_t)ndp, sizeof(struct nameidata)); 15638265Smckusick ndp->ni_iov = &ndp->ni_nd.nd_iovec; 15738265Smckusick ndp->ni_iovcnt = 1; 15838265Smckusick ndp->ni_base = (caddr_t)&ndp->ni_dent; 15938265Smckusick ndp->ni_rw = UIO_WRITE; 16039736Smckusick ndp->ni_uioseg = UIO_SYSSPACE; 16138265Smckusick } 16238265Smckusick 16338265Smckusick /* 16438265Smckusick * Duplicate a nameidata structure 16538265Smckusick */ 16638265Smckusick nddup(ndp, newndp) 16738265Smckusick register struct nameidata *ndp, *newndp; 16838265Smckusick { 16938265Smckusick 17038265Smckusick ndinit(newndp); 17138265Smckusick newndp->ni_cred = ndp->ni_cred; 17238265Smckusick crhold(newndp->ni_cred); 17338265Smckusick } 17438265Smckusick 17538265Smckusick /* 17638265Smckusick * Release a nameidata structure 17738265Smckusick */ 17838265Smckusick ndrele(ndp) 17938265Smckusick register struct nameidata *ndp; 18038265Smckusick { 18138265Smckusick 18238265Smckusick crfree(ndp->ni_cred); 18338265Smckusick } 18439397Smckusick 18539397Smckusick /* 18639397Smckusick * Routines having to do with the management of the vnode table. 18739397Smckusick */ 18839397Smckusick struct vnode *vfreeh, **vfreet; 18939447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 19039635Smckusick extern void vclean(); 19140883Smckusick long numvnodes; 19241363Smckusick struct vattr va_null; 19339397Smckusick 19439397Smckusick /* 19539433Smckusick * Initialize the vnode structures and initialize each file system type. 19639397Smckusick */ 19739433Smckusick vfsinit() 19839397Smckusick { 19939433Smckusick struct vfsops **vfsp; 20039397Smckusick 20139433Smckusick /* 20239433Smckusick * Initialize the vnode name cache 20339433Smckusick */ 20439433Smckusick nchinit(); 20539433Smckusick /* 20639433Smckusick * Initialize each file system type. 20739433Smckusick */ 20841363Smckusick vattr_null(&va_null); 20939433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 21039433Smckusick if (*vfsp == NULL) 21139433Smckusick continue; 21239433Smckusick (*(*vfsp)->vfs_init)(); 21339433Smckusick } 21439397Smckusick } 21539397Smckusick 21639397Smckusick /* 21739397Smckusick * Return the next vnode from the free list. 21839397Smckusick */ 21939397Smckusick getnewvnode(tag, mp, vops, vpp) 22039397Smckusick enum vtagtype tag; 22139397Smckusick struct mount *mp; 22239397Smckusick struct vnodeops *vops; 22339397Smckusick struct vnode **vpp; 22439397Smckusick { 22539397Smckusick register struct vnode *vp, *vq; 22639397Smckusick 22740883Smckusick if (numvnodes < desiredvnodes) { 22845118Smckusick vp = (struct vnode *)malloc((u_long)sizeof *vp, 22945118Smckusick M_VNODE, M_WAITOK); 23040883Smckusick bzero((char *)vp, sizeof *vp); 23140883Smckusick numvnodes++; 23240883Smckusick } else { 23340883Smckusick if ((vp = vfreeh) == NULL) { 23440883Smckusick tablefull("vnode"); 23540883Smckusick *vpp = 0; 23640883Smckusick return (ENFILE); 23740883Smckusick } 23840883Smckusick if (vp->v_usecount) 23940883Smckusick panic("free vnode isn't"); 24040883Smckusick if (vq = vp->v_freef) 24140883Smckusick vq->v_freeb = &vfreeh; 24240883Smckusick else 24340883Smckusick vfreet = &vfreeh; 24440883Smckusick vfreeh = vq; 24540883Smckusick vp->v_freef = NULL; 24640883Smckusick vp->v_freeb = NULL; 24740883Smckusick if (vp->v_type != VBAD) 24840883Smckusick vgone(vp); 24940883Smckusick vp->v_flag = 0; 25040883Smckusick vp->v_lastr = 0; 25140883Smckusick vp->v_socket = 0; 25239397Smckusick } 25339512Smckusick vp->v_type = VNON; 25439397Smckusick cache_purge(vp); 25539397Smckusick vp->v_tag = tag; 25639433Smckusick vp->v_op = vops; 25739397Smckusick insmntque(vp, mp); 25839397Smckusick VREF(vp); 25939397Smckusick *vpp = vp; 26039397Smckusick return (0); 26139397Smckusick } 26239397Smckusick 26339397Smckusick /* 26439397Smckusick * Move a vnode from one mount queue to another. 26539397Smckusick */ 26639397Smckusick insmntque(vp, mp) 26739397Smckusick register struct vnode *vp; 26839397Smckusick register struct mount *mp; 26939397Smckusick { 27039397Smckusick struct vnode *vq; 27139397Smckusick 27239397Smckusick /* 27339397Smckusick * Delete from old mount point vnode list, if on one. 27439397Smckusick */ 27539397Smckusick if (vp->v_mountb) { 27639397Smckusick if (vq = vp->v_mountf) 27739397Smckusick vq->v_mountb = vp->v_mountb; 27839397Smckusick *vp->v_mountb = vq; 27939397Smckusick } 28039397Smckusick /* 28139397Smckusick * Insert into list of vnodes for the new mount point, if available. 28239397Smckusick */ 28339621Smckusick vp->v_mount = mp; 28439397Smckusick if (mp == NULL) { 28539397Smckusick vp->v_mountf = NULL; 28639397Smckusick vp->v_mountb = NULL; 28739397Smckusick return; 28839397Smckusick } 28941400Smckusick if (mp->mnt_mounth) { 29041400Smckusick vp->v_mountf = mp->mnt_mounth; 29141400Smckusick vp->v_mountb = &mp->mnt_mounth; 29241400Smckusick mp->mnt_mounth->v_mountb = &vp->v_mountf; 29341400Smckusick mp->mnt_mounth = vp; 29439397Smckusick } else { 29541400Smckusick mp->mnt_mounth = vp; 29641400Smckusick vp->v_mountb = &mp->mnt_mounth; 29739397Smckusick vp->v_mountf = NULL; 29839397Smckusick } 29939397Smckusick } 30039397Smckusick 30139397Smckusick /* 30239433Smckusick * Create a vnode for a block device. 30339433Smckusick * Used for root filesystem, argdev, and swap areas. 30439433Smckusick * Also used for memory file system special devices. 30539397Smckusick */ 30639433Smckusick bdevvp(dev, vpp) 30739433Smckusick dev_t dev; 30839433Smckusick struct vnode **vpp; 30939433Smckusick { 31039433Smckusick register struct vnode *vp; 31139433Smckusick struct vnode *nvp; 31239433Smckusick int error; 31339433Smckusick 314*46989Smckusick if (dev == NODEV) 315*46989Smckusick return (0); 31639447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 31739433Smckusick if (error) { 31839433Smckusick *vpp = 0; 31939433Smckusick return (error); 32039433Smckusick } 32139433Smckusick vp = nvp; 32239433Smckusick vp->v_type = VBLK; 32339615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 32439433Smckusick vput(vp); 32539433Smckusick vp = nvp; 32639433Smckusick } 32739433Smckusick *vpp = vp; 32839433Smckusick return (0); 32939433Smckusick } 33039433Smckusick 33139433Smckusick /* 33239433Smckusick * Check to see if the new vnode represents a special device 33339433Smckusick * for which we already have a vnode (either because of 33439433Smckusick * bdevvp() or because of a different vnode representing 33539433Smckusick * the same block device). If such an alias exists, deallocate 33639509Smckusick * the existing contents and return the aliased vnode. The 33739433Smckusick * caller is responsible for filling it with its new contents. 33839433Smckusick */ 33939433Smckusick struct vnode * 34039615Smckusick checkalias(nvp, nvp_rdev, mp) 34139433Smckusick register struct vnode *nvp; 34239615Smckusick dev_t nvp_rdev; 34339433Smckusick struct mount *mp; 34439433Smckusick { 34539433Smckusick register struct vnode *vp; 34639615Smckusick struct vnode **vpp; 34739433Smckusick 34839433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 34941400Smckusick return (NULLVP); 35039615Smckusick 35139615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 35239433Smckusick loop: 35339615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 35439615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 35539433Smckusick continue; 35639615Smckusick /* 35739615Smckusick * Alias, but not in use, so flush it out. 35839615Smckusick */ 35939809Smckusick if (vp->v_usecount == 0) { 36039615Smckusick vgone(vp); 36139615Smckusick goto loop; 36239615Smckusick } 36339633Smckusick if (vget(vp)) 36439633Smckusick goto loop; 36539433Smckusick break; 36639433Smckusick } 36739615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 36839615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 36939615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 37039615Smckusick nvp->v_rdev = nvp_rdev; 37139809Smckusick nvp->v_hashchain = vpp; 37239615Smckusick nvp->v_specnext = *vpp; 37342152Smckusick nvp->v_specflags = 0; 37439615Smckusick *vpp = nvp; 37540640Smckusick if (vp != NULL) { 37640640Smckusick nvp->v_flag |= VALIASED; 37740640Smckusick vp->v_flag |= VALIASED; 37840640Smckusick vput(vp); 37940640Smckusick } 38041400Smckusick return (NULLVP); 38139433Smckusick } 38239484Smckusick VOP_UNLOCK(vp); 38339484Smckusick vclean(vp, 0); 38439433Smckusick vp->v_op = nvp->v_op; 38539433Smckusick vp->v_tag = nvp->v_tag; 38639433Smckusick nvp->v_type = VNON; 38739433Smckusick insmntque(vp, mp); 38839433Smckusick return (vp); 38939433Smckusick } 39039433Smckusick 39139433Smckusick /* 39239433Smckusick * Grab a particular vnode from the free list, increment its 39339433Smckusick * reference count and lock it. The vnode lock bit is set the 39439433Smckusick * vnode is being eliminated in vgone. The process is awakened 39539433Smckusick * when the transition is completed, and an error returned to 39639433Smckusick * indicate that the vnode is no longer usable (possibly having 39739433Smckusick * been changed to a new file system type). 39839433Smckusick */ 39939397Smckusick vget(vp) 40039397Smckusick register struct vnode *vp; 40139397Smckusick { 40239397Smckusick register struct vnode *vq; 40339397Smckusick 40439433Smckusick if (vp->v_flag & VXLOCK) { 40539433Smckusick vp->v_flag |= VXWANT; 40639433Smckusick sleep((caddr_t)vp, PINOD); 40739433Smckusick return (1); 40839433Smckusick } 40939809Smckusick if (vp->v_usecount == 0) { 41039433Smckusick if (vq = vp->v_freef) 41139433Smckusick vq->v_freeb = vp->v_freeb; 41239433Smckusick else 41339433Smckusick vfreet = vp->v_freeb; 41439433Smckusick *vp->v_freeb = vq; 41539433Smckusick vp->v_freef = NULL; 41639433Smckusick vp->v_freeb = NULL; 41739433Smckusick } 41839397Smckusick VREF(vp); 41939433Smckusick VOP_LOCK(vp); 42039433Smckusick return (0); 42139397Smckusick } 42239397Smckusick 42339397Smckusick /* 42439397Smckusick * Vnode reference, just increment the count 42539397Smckusick */ 42639397Smckusick void vref(vp) 42739397Smckusick struct vnode *vp; 42839397Smckusick { 42939397Smckusick 43039809Smckusick vp->v_usecount++; 43139397Smckusick } 43239397Smckusick 43339397Smckusick /* 43439397Smckusick * vput(), just unlock and vrele() 43539397Smckusick */ 43639397Smckusick void vput(vp) 43739397Smckusick register struct vnode *vp; 43839397Smckusick { 43939397Smckusick VOP_UNLOCK(vp); 44039397Smckusick vrele(vp); 44139397Smckusick } 44239397Smckusick 44339397Smckusick /* 44439397Smckusick * Vnode release. 44539397Smckusick * If count drops to zero, call inactive routine and return to freelist. 44639397Smckusick */ 44739397Smckusick void vrele(vp) 44839397Smckusick register struct vnode *vp; 44939397Smckusick { 45039397Smckusick 45139397Smckusick if (vp == NULL) 45239433Smckusick panic("vrele: null vp"); 45339809Smckusick vp->v_usecount--; 45439809Smckusick if (vp->v_usecount < 0) 45539667Smckusick vprint("vrele: bad ref count", vp); 45639809Smckusick if (vp->v_usecount > 0) 45739397Smckusick return; 45841400Smckusick if (vfreeh == NULLVP) { 45939397Smckusick /* 46039397Smckusick * insert into empty list 46139397Smckusick */ 46239397Smckusick vfreeh = vp; 46339397Smckusick vp->v_freeb = &vfreeh; 46439397Smckusick } else { 46539397Smckusick /* 46639397Smckusick * insert at tail of list 46739397Smckusick */ 46839397Smckusick *vfreet = vp; 46939397Smckusick vp->v_freeb = vfreet; 47039397Smckusick } 47139433Smckusick vp->v_freef = NULL; 47239433Smckusick vfreet = &vp->v_freef; 47339433Smckusick VOP_INACTIVE(vp); 47439397Smckusick } 47539433Smckusick 47639433Smckusick /* 47739809Smckusick * Page or buffer structure gets a reference. 47839809Smckusick */ 47939809Smckusick vhold(vp) 48039809Smckusick register struct vnode *vp; 48139809Smckusick { 48239809Smckusick 48339809Smckusick vp->v_holdcnt++; 48439809Smckusick } 48539809Smckusick 48639809Smckusick /* 48739809Smckusick * Page or buffer structure frees a reference. 48839809Smckusick */ 48939809Smckusick holdrele(vp) 49039809Smckusick register struct vnode *vp; 49139809Smckusick { 49239809Smckusick 49339809Smckusick if (vp->v_holdcnt <= 0) 49439809Smckusick panic("holdrele: holdcnt"); 49539809Smckusick vp->v_holdcnt--; 49639809Smckusick } 49739809Smckusick 49839809Smckusick /* 49939509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 50039509Smckusick * 50139509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 50239509Smckusick * return error if any are found (nb: this is a user error, not a 50339509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 50439509Smckusick * that are found. 50539509Smckusick */ 50639509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 50739509Smckusick 50839509Smckusick vflush(mp, skipvp, flags) 50939509Smckusick struct mount *mp; 51039509Smckusick struct vnode *skipvp; 51139509Smckusick int flags; 51239509Smckusick { 51339509Smckusick register struct vnode *vp, *nvp; 51439509Smckusick int busy = 0; 51539509Smckusick 51641400Smckusick if ((mp->mnt_flag & MNT_MPBUSY) == 0) 51741300Smckusick panic("vflush: not busy"); 51841421Smckusick loop: 51941400Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 52041421Smckusick if (vp->v_mount != mp) 52141421Smckusick goto loop; 52239509Smckusick nvp = vp->v_mountf; 52339509Smckusick /* 52439509Smckusick * Skip over a selected vnode. 52539509Smckusick */ 52639509Smckusick if (vp == skipvp) 52739509Smckusick continue; 52839509Smckusick /* 52941300Smckusick * Skip over a vnodes marked VSYSTEM. 53041300Smckusick */ 53141300Smckusick if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 53241300Smckusick continue; 53341300Smckusick /* 53439809Smckusick * With v_usecount == 0, all we need to do is clear 53539509Smckusick * out the vnode data structures and we are done. 53639509Smckusick */ 53739809Smckusick if (vp->v_usecount == 0) { 53839509Smckusick vgone(vp); 53939509Smckusick continue; 54039509Smckusick } 54139509Smckusick /* 54239509Smckusick * For block or character devices, revert to an 54339509Smckusick * anonymous device. For all other files, just kill them. 54439509Smckusick */ 54541300Smckusick if (flags & FORCECLOSE) { 54639509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 54739509Smckusick vgone(vp); 54839509Smckusick } else { 54939509Smckusick vclean(vp, 0); 55039509Smckusick vp->v_op = &spec_vnodeops; 55139509Smckusick insmntque(vp, (struct mount *)0); 55239509Smckusick } 55339509Smckusick continue; 55439509Smckusick } 55539509Smckusick if (busyprt) 55639667Smckusick vprint("vflush: busy vnode", vp); 55739509Smckusick busy++; 55839509Smckusick } 55939509Smckusick if (busy) 56039509Smckusick return (EBUSY); 56139509Smckusick return (0); 56239509Smckusick } 56339509Smckusick 56439509Smckusick /* 56539433Smckusick * Disassociate the underlying file system from a vnode. 56639433Smckusick */ 56741300Smckusick void vclean(vp, flags) 56839433Smckusick register struct vnode *vp; 56945118Smckusick int flags; 57039433Smckusick { 57139433Smckusick struct vnodeops *origops; 57239484Smckusick int active; 57339433Smckusick 57439484Smckusick /* 57539484Smckusick * Check to see if the vnode is in use. 57639667Smckusick * If so we have to reference it before we clean it out 57739667Smckusick * so that its count cannot fall to zero and generate a 57839667Smckusick * race against ourselves to recycle it. 57939484Smckusick */ 58039809Smckusick if (active = vp->v_usecount) 58139484Smckusick VREF(vp); 58239484Smckusick /* 58339484Smckusick * Prevent the vnode from being recycled or 58439484Smckusick * brought into use while we clean it out. 58539484Smckusick */ 58639667Smckusick if (vp->v_flag & VXLOCK) 58739667Smckusick panic("vclean: deadlock"); 58839433Smckusick vp->v_flag |= VXLOCK; 58939433Smckusick /* 59039667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 59139667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 59239667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 59339667Smckusick * For active vnodes, it ensures that no other activity can 59439667Smckusick * occur while the buffer list is being cleaned out. 59539667Smckusick */ 59639667Smckusick VOP_LOCK(vp); 59741300Smckusick if (flags & DOCLOSE) 59839667Smckusick vinvalbuf(vp, 1); 59939667Smckusick /* 60039433Smckusick * Prevent any further operations on the vnode from 60139433Smckusick * being passed through to the old file system. 60239433Smckusick */ 60339433Smckusick origops = vp->v_op; 60439433Smckusick vp->v_op = &dead_vnodeops; 60539433Smckusick vp->v_tag = VT_NON; 60639433Smckusick /* 60739484Smckusick * If purging an active vnode, it must be unlocked, closed, 60839484Smckusick * and deactivated before being reclaimed. 60939433Smckusick */ 61039667Smckusick (*(origops->vn_unlock))(vp); 61139484Smckusick if (active) { 61241300Smckusick if (flags & DOCLOSE) 61339484Smckusick (*(origops->vn_close))(vp, 0, NOCRED); 61439433Smckusick (*(origops->vn_inactive))(vp); 61539433Smckusick } 61639433Smckusick /* 61739433Smckusick * Reclaim the vnode. 61839433Smckusick */ 61939433Smckusick if ((*(origops->vn_reclaim))(vp)) 62039433Smckusick panic("vclean: cannot reclaim"); 62139484Smckusick if (active) 62239484Smckusick vrele(vp); 62339433Smckusick /* 62439433Smckusick * Done with purge, notify sleepers in vget of the grim news. 62539433Smckusick */ 62639433Smckusick vp->v_flag &= ~VXLOCK; 62739433Smckusick if (vp->v_flag & VXWANT) { 62839433Smckusick vp->v_flag &= ~VXWANT; 62939433Smckusick wakeup((caddr_t)vp); 63039433Smckusick } 63139433Smckusick } 63239433Smckusick 63339433Smckusick /* 63439633Smckusick * Eliminate all activity associated with the requested vnode 63539633Smckusick * and with all vnodes aliased to the requested vnode. 63639633Smckusick */ 63739633Smckusick void vgoneall(vp) 63839633Smckusick register struct vnode *vp; 63939633Smckusick { 64039809Smckusick register struct vnode *vq; 64139633Smckusick 64240665Smckusick if (vp->v_flag & VALIASED) { 64340665Smckusick /* 64440665Smckusick * If a vgone (or vclean) is already in progress, 64540665Smckusick * wait until it is done and return. 64640665Smckusick */ 64740665Smckusick if (vp->v_flag & VXLOCK) { 64840665Smckusick vp->v_flag |= VXWANT; 64940665Smckusick sleep((caddr_t)vp, PINOD); 65040665Smckusick return; 65139633Smckusick } 65240665Smckusick /* 65340665Smckusick * Ensure that vp will not be vgone'd while we 65440665Smckusick * are eliminating its aliases. 65540665Smckusick */ 65640665Smckusick vp->v_flag |= VXLOCK; 65740665Smckusick while (vp->v_flag & VALIASED) { 65840665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 65940665Smckusick if (vq->v_rdev != vp->v_rdev || 66040665Smckusick vq->v_type != vp->v_type || vp == vq) 66140665Smckusick continue; 66240665Smckusick vgone(vq); 66340665Smckusick break; 66440665Smckusick } 66540665Smckusick } 66640665Smckusick /* 66740665Smckusick * Remove the lock so that vgone below will 66840665Smckusick * really eliminate the vnode after which time 66940665Smckusick * vgone will awaken any sleepers. 67040665Smckusick */ 67140665Smckusick vp->v_flag &= ~VXLOCK; 67239633Smckusick } 67339633Smckusick vgone(vp); 67439633Smckusick } 67539633Smckusick 67639633Smckusick /* 67739433Smckusick * Eliminate all activity associated with a vnode 67839433Smckusick * in preparation for reuse. 67939433Smckusick */ 68039433Smckusick void vgone(vp) 68139433Smckusick register struct vnode *vp; 68239433Smckusick { 68339809Smckusick register struct vnode *vq; 68439615Smckusick struct vnode *vx; 68539615Smckusick long count; 68639433Smckusick 68739433Smckusick /* 68840548Smckusick * If a vgone (or vclean) is already in progress, 68940548Smckusick * wait until it is done and return. 69040548Smckusick */ 69140548Smckusick if (vp->v_flag & VXLOCK) { 69240548Smckusick vp->v_flag |= VXWANT; 69340548Smckusick sleep((caddr_t)vp, PINOD); 69440548Smckusick return; 69540548Smckusick } 69640548Smckusick /* 69739433Smckusick * Clean out the filesystem specific data. 69839433Smckusick */ 69941300Smckusick vclean(vp, DOCLOSE); 70039433Smckusick /* 70139433Smckusick * Delete from old mount point vnode list, if on one. 70239433Smckusick */ 70339433Smckusick if (vp->v_mountb) { 70439433Smckusick if (vq = vp->v_mountf) 70539433Smckusick vq->v_mountb = vp->v_mountb; 70639433Smckusick *vp->v_mountb = vq; 70739433Smckusick vp->v_mountf = NULL; 70839433Smckusick vp->v_mountb = NULL; 70939433Smckusick } 71039433Smckusick /* 71139433Smckusick * If special device, remove it from special device alias list. 71239433Smckusick */ 71339433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 71439809Smckusick if (*vp->v_hashchain == vp) { 71539809Smckusick *vp->v_hashchain = vp->v_specnext; 71639433Smckusick } else { 71739809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 71839615Smckusick if (vq->v_specnext != vp) 71939433Smckusick continue; 72039615Smckusick vq->v_specnext = vp->v_specnext; 72139433Smckusick break; 72239433Smckusick } 72339615Smckusick if (vq == NULL) 72439433Smckusick panic("missing bdev"); 72539433Smckusick } 72639615Smckusick if (vp->v_flag & VALIASED) { 72739809Smckusick count = 0; 72839809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 72940108Smckusick if (vq->v_rdev != vp->v_rdev || 73040108Smckusick vq->v_type != vp->v_type) 73139615Smckusick continue; 73239615Smckusick count++; 73339615Smckusick vx = vq; 73439615Smckusick } 73539615Smckusick if (count == 0) 73639615Smckusick panic("missing alias"); 73739615Smckusick if (count == 1) 73839615Smckusick vx->v_flag &= ~VALIASED; 73939615Smckusick vp->v_flag &= ~VALIASED; 74039615Smckusick } 74139615Smckusick FREE(vp->v_specinfo, M_VNODE); 74239615Smckusick vp->v_specinfo = NULL; 74339433Smckusick } 74439433Smckusick /* 74539433Smckusick * If it is on the freelist, move it to the head of the list. 74639433Smckusick */ 74739433Smckusick if (vp->v_freeb) { 74839433Smckusick if (vq = vp->v_freef) 74939433Smckusick vq->v_freeb = vp->v_freeb; 75039433Smckusick else 75139433Smckusick vfreet = vp->v_freeb; 75239433Smckusick *vp->v_freeb = vq; 75339433Smckusick vp->v_freef = vfreeh; 75439433Smckusick vp->v_freeb = &vfreeh; 75539433Smckusick vfreeh->v_freeb = &vp->v_freef; 75639433Smckusick vfreeh = vp; 75739433Smckusick } 75839484Smckusick vp->v_type = VBAD; 75939433Smckusick } 76039633Smckusick 76139633Smckusick /* 76239821Smckusick * Lookup a vnode by device number. 76339821Smckusick */ 76439821Smckusick vfinddev(dev, type, vpp) 76539821Smckusick dev_t dev; 76639821Smckusick enum vtype type; 76739821Smckusick struct vnode **vpp; 76839821Smckusick { 76939821Smckusick register struct vnode *vp; 77039821Smckusick 77139821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 77239821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 77339821Smckusick continue; 77439821Smckusick *vpp = vp; 77539821Smckusick return (0); 77639821Smckusick } 77739821Smckusick return (1); 77839821Smckusick } 77939821Smckusick 78039821Smckusick /* 78139633Smckusick * Calculate the total number of references to a special device. 78239633Smckusick */ 78339633Smckusick vcount(vp) 78439633Smckusick register struct vnode *vp; 78539633Smckusick { 78639809Smckusick register struct vnode *vq; 78739633Smckusick int count; 78839633Smckusick 78939633Smckusick if ((vp->v_flag & VALIASED) == 0) 79039809Smckusick return (vp->v_usecount); 79139633Smckusick loop: 79239809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 79340108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 79439633Smckusick continue; 79539633Smckusick /* 79639633Smckusick * Alias, but not in use, so flush it out. 79739633Smckusick */ 79839809Smckusick if (vq->v_usecount == 0) { 79939633Smckusick vgone(vq); 80039633Smckusick goto loop; 80139633Smckusick } 80239809Smckusick count += vq->v_usecount; 80339633Smckusick } 80439633Smckusick return (count); 80539633Smckusick } 80639667Smckusick 80739667Smckusick /* 80839667Smckusick * Print out a description of a vnode. 80939667Smckusick */ 81039667Smckusick static char *typename[] = 81140286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 81239667Smckusick 81339667Smckusick vprint(label, vp) 81439667Smckusick char *label; 81539667Smckusick register struct vnode *vp; 81639667Smckusick { 81739913Smckusick char buf[64]; 81839667Smckusick 81939667Smckusick if (label != NULL) 82039667Smckusick printf("%s: ", label); 82139913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 82239809Smckusick vp->v_usecount, vp->v_holdcnt); 82339913Smckusick buf[0] = '\0'; 82439913Smckusick if (vp->v_flag & VROOT) 82539913Smckusick strcat(buf, "|VROOT"); 82639913Smckusick if (vp->v_flag & VTEXT) 82739913Smckusick strcat(buf, "|VTEXT"); 82841300Smckusick if (vp->v_flag & VSYSTEM) 82941300Smckusick strcat(buf, "|VSYSTEM"); 83041300Smckusick if (vp->v_flag & VXLOCK) 83141300Smckusick strcat(buf, "|VXLOCK"); 83241300Smckusick if (vp->v_flag & VXWANT) 83341300Smckusick strcat(buf, "|VXWANT"); 83441300Smckusick if (vp->v_flag & VBWAIT) 83541300Smckusick strcat(buf, "|VBWAIT"); 83639913Smckusick if (vp->v_flag & VALIASED) 83739913Smckusick strcat(buf, "|VALIASED"); 83839913Smckusick if (buf[0] != '\0') 83939913Smckusick printf(" flags (%s)", &buf[1]); 84039913Smckusick printf("\n\t"); 84139667Smckusick VOP_PRINT(vp); 84239667Smckusick } 84341110Smarc 84441110Smarc int kinfo_vdebug = 1; 84541110Smarc int kinfo_vgetfailed; 84641110Smarc #define KINFO_VNODESLOP 10 84741110Smarc /* 84841110Smarc * Dump vnode list (via kinfo). 84941110Smarc * Copyout address of vnode followed by vnode. 85041110Smarc */ 85145118Smckusick /* ARGSUSED */ 85241110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 85345118Smckusick int op; 85441110Smarc char *where; 85545118Smckusick int *acopysize, arg, *aneeded; 85641110Smarc { 85741110Smarc register struct mount *mp = rootfs; 85841300Smckusick struct mount *omp; 85941110Smarc struct vnode *vp; 86041110Smarc register char *bp = where, *savebp; 86141110Smarc char *ewhere = where + *acopysize; 86241110Smarc int error; 86341110Smarc 86441110Smarc #define VPTRSZ sizeof (struct vnode *) 86541110Smarc #define VNODESZ sizeof (struct vnode) 86641110Smarc if (where == NULL) { 86741110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 86841110Smarc return (0); 86941110Smarc } 87041110Smarc 87141110Smarc do { 87241300Smckusick if (vfs_busy(mp)) { 87341400Smckusick mp = mp->mnt_next; 87441300Smckusick continue; 87541300Smckusick } 87641110Smarc savebp = bp; 87741110Smarc again: 87841421Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 87941422Smckusick /* 88041422Smckusick * Check that the vp is still associated with 88141422Smckusick * this filesystem. RACE: could have been 88241422Smckusick * recycled onto the same filesystem. 88341422Smckusick */ 88441421Smckusick if (vp->v_mount != mp) { 88541421Smckusick if (kinfo_vdebug) 88641421Smckusick printf("kinfo: vp changed\n"); 88741421Smckusick bp = savebp; 88841421Smckusick goto again; 88941421Smckusick } 89041110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 89141110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 89241110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 89341422Smckusick VNODESZ)))) 89441110Smarc return (error); 89541110Smarc bp += VPTRSZ + VNODESZ; 89641110Smarc } 89741300Smckusick omp = mp; 89841400Smckusick mp = mp->mnt_next; 89941300Smckusick vfs_unbusy(omp); 90041110Smarc } while (mp != rootfs); 90141110Smarc 90241110Smarc *aneeded = bp - where; 90341110Smarc if (bp > ewhere) 90441110Smarc *acopysize = ewhere - where; 90541110Smarc else 90641110Smarc *acopysize = bp - where; 90741110Smarc return (0); 90841110Smarc } 909