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*41110Smarc * @(#)vfs_subr.c 7.39 (Berkeley) 04/27/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"); 4537488Smckusick mp->m_prev->m_next = mp->m_next; 4637488Smckusick mp->m_next->m_prev = mp->m_prev; 4737488Smckusick mp->m_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 5939045Smckusick while(mp->m_flag & M_MLOCK) { 6039045Smckusick mp->m_flag |= M_MWAIT; 6139045Smckusick sleep((caddr_t)mp, PVFS); 6239045Smckusick } 6337488Smckusick mp->m_flag |= M_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 7637488Smckusick if ((mp->m_flag & M_MLOCK) == 0) 7737488Smckusick panic("vfs_unlock: locked fs"); 7837488Smckusick mp->m_flag &= ~M_MLOCK; 7937488Smckusick if (mp->m_flag & M_MWAIT) { 8037488Smckusick mp->m_flag &= ~M_MWAIT; 8137488Smckusick wakeup((caddr_t)mp); 8237488Smckusick } 8337488Smckusick } 8437488Smckusick 8537488Smckusick /* 8637488Smckusick * Lookup a mount point by filesystem identifier. 8737488Smckusick */ 8837488Smckusick struct mount * 8937488Smckusick getvfs(fsid) 9037488Smckusick fsid_t *fsid; 9137488Smckusick { 9237488Smckusick register struct mount *mp; 9337488Smckusick 9438288Smckusick mp = rootfs; 9538288Smckusick do { 9640342Smckusick if (mp->m_stat.f_fsid.val[0] == fsid->val[0] && 9740342Smckusick mp->m_stat.f_fsid.val[1] == fsid->val[1]) { 9838288Smckusick return (mp); 9937488Smckusick } 10038288Smckusick mp = mp->m_next; 10138288Smckusick } while (mp != rootfs); 10238288Smckusick return ((struct mount *)0); 10337488Smckusick } 10437488Smckusick 10537488Smckusick /* 10637488Smckusick * Set vnode attributes to VNOVAL 10737488Smckusick */ 10837488Smckusick void vattr_null(vap) 10937488Smckusick register struct vattr *vap; 11037488Smckusick { 11137488Smckusick 11237488Smckusick vap->va_type = VNON; 11337488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 11437488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 11540643Smckusick vap->va_size_rsv = vap->va_blocksize = vap->va_rdev = 11640643Smckusick vap->va_bytes = vap->va_bytes_rsv = 11737488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 11837488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 11938258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 12038258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 12137488Smckusick } 12238265Smckusick 12338265Smckusick /* 12438265Smckusick * Initialize a nameidata structure 12538265Smckusick */ 12638265Smckusick ndinit(ndp) 12738265Smckusick register struct nameidata *ndp; 12838265Smckusick { 12938265Smckusick 13038265Smckusick bzero((caddr_t)ndp, sizeof(struct nameidata)); 13138265Smckusick ndp->ni_iov = &ndp->ni_nd.nd_iovec; 13238265Smckusick ndp->ni_iovcnt = 1; 13338265Smckusick ndp->ni_base = (caddr_t)&ndp->ni_dent; 13438265Smckusick ndp->ni_rw = UIO_WRITE; 13539736Smckusick ndp->ni_uioseg = UIO_SYSSPACE; 13638265Smckusick } 13738265Smckusick 13838265Smckusick /* 13938265Smckusick * Duplicate a nameidata structure 14038265Smckusick */ 14138265Smckusick nddup(ndp, newndp) 14238265Smckusick register struct nameidata *ndp, *newndp; 14338265Smckusick { 14438265Smckusick 14538265Smckusick ndinit(newndp); 14638265Smckusick newndp->ni_cdir = ndp->ni_cdir; 14738348Smckusick VREF(newndp->ni_cdir); 14838265Smckusick newndp->ni_rdir = ndp->ni_rdir; 14938265Smckusick if (newndp->ni_rdir) 15038348Smckusick VREF(newndp->ni_rdir); 15138265Smckusick newndp->ni_cred = ndp->ni_cred; 15238265Smckusick crhold(newndp->ni_cred); 15338265Smckusick } 15438265Smckusick 15538265Smckusick /* 15638265Smckusick * Release a nameidata structure 15738265Smckusick */ 15838265Smckusick ndrele(ndp) 15938265Smckusick register struct nameidata *ndp; 16038265Smckusick { 16138265Smckusick 16238265Smckusick vrele(ndp->ni_cdir); 16338265Smckusick if (ndp->ni_rdir) 16438265Smckusick vrele(ndp->ni_rdir); 16538265Smckusick crfree(ndp->ni_cred); 16638265Smckusick } 16739397Smckusick 16839397Smckusick /* 16939397Smckusick * Routines having to do with the management of the vnode table. 17039397Smckusick */ 17139397Smckusick struct vnode *vfreeh, **vfreet; 17239447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops; 17339635Smckusick extern void vclean(); 17440883Smckusick long numvnodes; 17539397Smckusick 17639397Smckusick /* 17739433Smckusick * Initialize the vnode structures and initialize each file system type. 17839397Smckusick */ 17939433Smckusick vfsinit() 18039397Smckusick { 18139433Smckusick struct vfsops **vfsp; 18239397Smckusick 18339433Smckusick /* 18439433Smckusick * Initialize the vnode name cache 18539433Smckusick */ 18639433Smckusick nchinit(); 18739433Smckusick /* 18839433Smckusick * Initialize each file system type. 18939433Smckusick */ 19039433Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 19139433Smckusick if (*vfsp == NULL) 19239433Smckusick continue; 19339433Smckusick (*(*vfsp)->vfs_init)(); 19439433Smckusick } 19539397Smckusick } 19639397Smckusick 19739397Smckusick /* 19839397Smckusick * Return the next vnode from the free list. 19939397Smckusick */ 20039397Smckusick getnewvnode(tag, mp, vops, vpp) 20139397Smckusick enum vtagtype tag; 20239397Smckusick struct mount *mp; 20339397Smckusick struct vnodeops *vops; 20439397Smckusick struct vnode **vpp; 20539397Smckusick { 20639397Smckusick register struct vnode *vp, *vq; 20739397Smckusick 20840883Smckusick if (numvnodes < desiredvnodes) { 20940883Smckusick vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK); 21040883Smckusick bzero((char *)vp, sizeof *vp); 21140883Smckusick numvnodes++; 21240883Smckusick } else { 21340883Smckusick if ((vp = vfreeh) == NULL) { 21440883Smckusick tablefull("vnode"); 21540883Smckusick *vpp = 0; 21640883Smckusick return (ENFILE); 21740883Smckusick } 21840883Smckusick if (vp->v_usecount) 21940883Smckusick panic("free vnode isn't"); 22040883Smckusick if (vq = vp->v_freef) 22140883Smckusick vq->v_freeb = &vfreeh; 22240883Smckusick else 22340883Smckusick vfreet = &vfreeh; 22440883Smckusick vfreeh = vq; 22540883Smckusick vp->v_freef = NULL; 22640883Smckusick vp->v_freeb = NULL; 22740883Smckusick if (vp->v_type != VBAD) 22840883Smckusick vgone(vp); 22940883Smckusick vp->v_flag = 0; 23040883Smckusick vp->v_shlockc = 0; 23140883Smckusick vp->v_exlockc = 0; 23240883Smckusick vp->v_lastr = 0; 23340883Smckusick vp->v_socket = 0; 23439397Smckusick } 23539512Smckusick vp->v_type = VNON; 23639397Smckusick cache_purge(vp); 23739397Smckusick vp->v_tag = tag; 23839433Smckusick vp->v_op = vops; 23939397Smckusick insmntque(vp, mp); 24039397Smckusick VREF(vp); 24139397Smckusick *vpp = vp; 24239397Smckusick return (0); 24339397Smckusick } 24439397Smckusick 24539397Smckusick /* 24639397Smckusick * Move a vnode from one mount queue to another. 24739397Smckusick */ 24839397Smckusick insmntque(vp, mp) 24939397Smckusick register struct vnode *vp; 25039397Smckusick register struct mount *mp; 25139397Smckusick { 25239397Smckusick struct vnode *vq; 25339397Smckusick 25439397Smckusick /* 25539397Smckusick * Delete from old mount point vnode list, if on one. 25639397Smckusick */ 25739397Smckusick if (vp->v_mountb) { 25839397Smckusick if (vq = vp->v_mountf) 25939397Smckusick vq->v_mountb = vp->v_mountb; 26039397Smckusick *vp->v_mountb = vq; 26139397Smckusick } 26239397Smckusick /* 26339397Smckusick * Insert into list of vnodes for the new mount point, if available. 26439397Smckusick */ 26539621Smckusick vp->v_mount = mp; 26639397Smckusick if (mp == NULL) { 26739397Smckusick vp->v_mountf = NULL; 26839397Smckusick vp->v_mountb = NULL; 26939397Smckusick return; 27039397Smckusick } 27139397Smckusick if (mp->m_mounth) { 27239397Smckusick vp->v_mountf = mp->m_mounth; 27339397Smckusick vp->v_mountb = &mp->m_mounth; 27439397Smckusick mp->m_mounth->v_mountb = &vp->v_mountf; 27539397Smckusick mp->m_mounth = vp; 27639397Smckusick } else { 27739397Smckusick mp->m_mounth = vp; 27839397Smckusick vp->v_mountb = &mp->m_mounth; 27939397Smckusick vp->v_mountf = NULL; 28039397Smckusick } 28139397Smckusick } 28239397Smckusick 28339397Smckusick /* 28439433Smckusick * Create a vnode for a block device. 28539433Smckusick * Used for root filesystem, argdev, and swap areas. 28639433Smckusick * Also used for memory file system special devices. 28739397Smckusick */ 28839433Smckusick bdevvp(dev, vpp) 28939433Smckusick dev_t dev; 29039433Smckusick struct vnode **vpp; 29139433Smckusick { 29239433Smckusick register struct vnode *vp; 29339433Smckusick struct vnode *nvp; 29439433Smckusick int error; 29539433Smckusick 29639447Smckusick error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp); 29739433Smckusick if (error) { 29839433Smckusick *vpp = 0; 29939433Smckusick return (error); 30039433Smckusick } 30139433Smckusick vp = nvp; 30239433Smckusick vp->v_type = VBLK; 30339615Smckusick if (nvp = checkalias(vp, dev, (struct mount *)0)) { 30439433Smckusick vput(vp); 30539433Smckusick vp = nvp; 30639433Smckusick } 30739433Smckusick *vpp = vp; 30839433Smckusick return (0); 30939433Smckusick } 31039433Smckusick 31139433Smckusick /* 31239433Smckusick * Check to see if the new vnode represents a special device 31339433Smckusick * for which we already have a vnode (either because of 31439433Smckusick * bdevvp() or because of a different vnode representing 31539433Smckusick * the same block device). If such an alias exists, deallocate 31639509Smckusick * the existing contents and return the aliased vnode. The 31739433Smckusick * caller is responsible for filling it with its new contents. 31839433Smckusick */ 31939433Smckusick struct vnode * 32039615Smckusick checkalias(nvp, nvp_rdev, mp) 32139433Smckusick register struct vnode *nvp; 32239615Smckusick dev_t nvp_rdev; 32339433Smckusick struct mount *mp; 32439433Smckusick { 32539433Smckusick register struct vnode *vp; 32639615Smckusick struct vnode **vpp; 32739433Smckusick 32839433Smckusick if (nvp->v_type != VBLK && nvp->v_type != VCHR) 32939433Smckusick return ((struct vnode *)0); 33039615Smckusick 33139615Smckusick vpp = &speclisth[SPECHASH(nvp_rdev)]; 33239433Smckusick loop: 33339615Smckusick for (vp = *vpp; vp; vp = vp->v_specnext) { 33439615Smckusick if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type) 33539433Smckusick continue; 33639615Smckusick /* 33739615Smckusick * Alias, but not in use, so flush it out. 33839615Smckusick */ 33939809Smckusick if (vp->v_usecount == 0) { 34039615Smckusick vgone(vp); 34139615Smckusick goto loop; 34239615Smckusick } 34339633Smckusick if (vget(vp)) 34439633Smckusick goto loop; 34539433Smckusick break; 34639433Smckusick } 34739615Smckusick if (vp == NULL || vp->v_tag != VT_NON) { 34839615Smckusick MALLOC(nvp->v_specinfo, struct specinfo *, 34939615Smckusick sizeof(struct specinfo), M_VNODE, M_WAITOK); 35039615Smckusick nvp->v_rdev = nvp_rdev; 35139809Smckusick nvp->v_hashchain = vpp; 35239615Smckusick nvp->v_specnext = *vpp; 35339615Smckusick *vpp = nvp; 35440640Smckusick if (vp != NULL) { 35540640Smckusick nvp->v_flag |= VALIASED; 35640640Smckusick vp->v_flag |= VALIASED; 35740640Smckusick vput(vp); 35840640Smckusick } 35939433Smckusick return ((struct vnode *)0); 36039433Smckusick } 36139484Smckusick VOP_UNLOCK(vp); 36239484Smckusick vclean(vp, 0); 36339433Smckusick vp->v_op = nvp->v_op; 36439433Smckusick vp->v_tag = nvp->v_tag; 36539433Smckusick nvp->v_type = VNON; 36639433Smckusick insmntque(vp, mp); 36739433Smckusick return (vp); 36839433Smckusick } 36939433Smckusick 37039433Smckusick /* 37139433Smckusick * Grab a particular vnode from the free list, increment its 37239433Smckusick * reference count and lock it. The vnode lock bit is set the 37339433Smckusick * vnode is being eliminated in vgone. The process is awakened 37439433Smckusick * when the transition is completed, and an error returned to 37539433Smckusick * indicate that the vnode is no longer usable (possibly having 37639433Smckusick * been changed to a new file system type). 37739433Smckusick */ 37839397Smckusick vget(vp) 37939397Smckusick register struct vnode *vp; 38039397Smckusick { 38139397Smckusick register struct vnode *vq; 38239397Smckusick 38339433Smckusick if (vp->v_flag & VXLOCK) { 38439433Smckusick vp->v_flag |= VXWANT; 38539433Smckusick sleep((caddr_t)vp, PINOD); 38639433Smckusick return (1); 38739433Smckusick } 38839809Smckusick if (vp->v_usecount == 0) { 38939433Smckusick if (vq = vp->v_freef) 39039433Smckusick vq->v_freeb = vp->v_freeb; 39139433Smckusick else 39239433Smckusick vfreet = vp->v_freeb; 39339433Smckusick *vp->v_freeb = vq; 39439433Smckusick vp->v_freef = NULL; 39539433Smckusick vp->v_freeb = NULL; 39639433Smckusick } 39739397Smckusick VREF(vp); 39839433Smckusick VOP_LOCK(vp); 39939433Smckusick return (0); 40039397Smckusick } 40139397Smckusick 40239397Smckusick /* 40339397Smckusick * Vnode reference, just increment the count 40439397Smckusick */ 40539397Smckusick void vref(vp) 40639397Smckusick struct vnode *vp; 40739397Smckusick { 40839397Smckusick 40939809Smckusick vp->v_usecount++; 41039397Smckusick } 41139397Smckusick 41239397Smckusick /* 41339397Smckusick * vput(), just unlock and vrele() 41439397Smckusick */ 41539397Smckusick void vput(vp) 41639397Smckusick register struct vnode *vp; 41739397Smckusick { 41839397Smckusick VOP_UNLOCK(vp); 41939397Smckusick vrele(vp); 42039397Smckusick } 42139397Smckusick 42239397Smckusick /* 42339397Smckusick * Vnode release. 42439397Smckusick * If count drops to zero, call inactive routine and return to freelist. 42539397Smckusick */ 42639397Smckusick void vrele(vp) 42739397Smckusick register struct vnode *vp; 42839397Smckusick { 42939397Smckusick 43039397Smckusick if (vp == NULL) 43139433Smckusick panic("vrele: null vp"); 43239809Smckusick vp->v_usecount--; 43339809Smckusick if (vp->v_usecount < 0) 43439667Smckusick vprint("vrele: bad ref count", vp); 43539809Smckusick if (vp->v_usecount > 0) 43639397Smckusick return; 43739397Smckusick if (vfreeh == (struct vnode *)0) { 43839397Smckusick /* 43939397Smckusick * insert into empty list 44039397Smckusick */ 44139397Smckusick vfreeh = vp; 44239397Smckusick vp->v_freeb = &vfreeh; 44339397Smckusick } else { 44439397Smckusick /* 44539397Smckusick * insert at tail of list 44639397Smckusick */ 44739397Smckusick *vfreet = vp; 44839397Smckusick vp->v_freeb = vfreet; 44939397Smckusick } 45039433Smckusick vp->v_freef = NULL; 45139433Smckusick vfreet = &vp->v_freef; 45239433Smckusick VOP_INACTIVE(vp); 45339397Smckusick } 45439433Smckusick 45539433Smckusick /* 45639809Smckusick * Page or buffer structure gets a reference. 45739809Smckusick */ 45839809Smckusick vhold(vp) 45939809Smckusick register struct vnode *vp; 46039809Smckusick { 46139809Smckusick 46239809Smckusick vp->v_holdcnt++; 46339809Smckusick } 46439809Smckusick 46539809Smckusick /* 46639809Smckusick * Page or buffer structure frees a reference. 46739809Smckusick */ 46839809Smckusick holdrele(vp) 46939809Smckusick register struct vnode *vp; 47039809Smckusick { 47139809Smckusick 47239809Smckusick if (vp->v_holdcnt <= 0) 47339809Smckusick panic("holdrele: holdcnt"); 47439809Smckusick vp->v_holdcnt--; 47539809Smckusick } 47639809Smckusick 47739809Smckusick /* 47839509Smckusick * Remove any vnodes in the vnode table belonging to mount point mp. 47939509Smckusick * 48039509Smckusick * If MNT_NOFORCE is specified, there should not be any active ones, 48139509Smckusick * return error if any are found (nb: this is a user error, not a 48239509Smckusick * system error). If MNT_FORCE is specified, detach any active vnodes 48339509Smckusick * that are found. 48439509Smckusick */ 48539509Smckusick int busyprt = 0; /* patch to print out busy vnodes */ 48639509Smckusick 48739509Smckusick vflush(mp, skipvp, flags) 48839509Smckusick struct mount *mp; 48939509Smckusick struct vnode *skipvp; 49039509Smckusick int flags; 49139509Smckusick { 49239509Smckusick register struct vnode *vp, *nvp; 49339509Smckusick int busy = 0; 49439509Smckusick 49539509Smckusick for (vp = mp->m_mounth; vp; vp = nvp) { 49639509Smckusick nvp = vp->v_mountf; 49739509Smckusick /* 49839509Smckusick * Skip over a selected vnode. 49939509Smckusick * Used by ufs to skip over the quota structure inode. 50039509Smckusick */ 50139509Smckusick if (vp == skipvp) 50239509Smckusick continue; 50339509Smckusick /* 50439809Smckusick * With v_usecount == 0, all we need to do is clear 50539509Smckusick * out the vnode data structures and we are done. 50639509Smckusick */ 50739809Smckusick if (vp->v_usecount == 0) { 50839509Smckusick vgone(vp); 50939509Smckusick continue; 51039509Smckusick } 51139509Smckusick /* 51239509Smckusick * For block or character devices, revert to an 51339509Smckusick * anonymous device. For all other files, just kill them. 51439509Smckusick */ 51539509Smckusick if (flags & MNT_FORCE) { 51639509Smckusick if (vp->v_type != VBLK && vp->v_type != VCHR) { 51739509Smckusick vgone(vp); 51839509Smckusick } else { 51939509Smckusick vclean(vp, 0); 52039509Smckusick vp->v_op = &spec_vnodeops; 52139509Smckusick insmntque(vp, (struct mount *)0); 52239509Smckusick } 52339509Smckusick continue; 52439509Smckusick } 52539509Smckusick if (busyprt) 52639667Smckusick vprint("vflush: busy vnode", vp); 52739509Smckusick busy++; 52839509Smckusick } 52939509Smckusick if (busy) 53039509Smckusick return (EBUSY); 53139509Smckusick return (0); 53239509Smckusick } 53339509Smckusick 53439509Smckusick /* 53539433Smckusick * Disassociate the underlying file system from a vnode. 53639433Smckusick */ 53739484Smckusick void vclean(vp, doclose) 53839433Smckusick register struct vnode *vp; 53939484Smckusick long doclose; 54039433Smckusick { 54139433Smckusick struct vnodeops *origops; 54239484Smckusick int active; 54339433Smckusick 54439484Smckusick /* 54539484Smckusick * Check to see if the vnode is in use. 54639667Smckusick * If so we have to reference it before we clean it out 54739667Smckusick * so that its count cannot fall to zero and generate a 54839667Smckusick * race against ourselves to recycle it. 54939484Smckusick */ 55039809Smckusick if (active = vp->v_usecount) 55139484Smckusick VREF(vp); 55239484Smckusick /* 55339484Smckusick * Prevent the vnode from being recycled or 55439484Smckusick * brought into use while we clean it out. 55539484Smckusick */ 55639667Smckusick if (vp->v_flag & VXLOCK) 55739667Smckusick panic("vclean: deadlock"); 55839433Smckusick vp->v_flag |= VXLOCK; 55939433Smckusick /* 56039667Smckusick * Even if the count is zero, the VOP_INACTIVE routine may still 56139667Smckusick * have the object locked while it cleans it out. The VOP_LOCK 56239667Smckusick * ensures that the VOP_INACTIVE routine is done with its work. 56339667Smckusick * For active vnodes, it ensures that no other activity can 56439667Smckusick * occur while the buffer list is being cleaned out. 56539667Smckusick */ 56639667Smckusick VOP_LOCK(vp); 56739667Smckusick if (doclose) 56839667Smckusick vinvalbuf(vp, 1); 56939667Smckusick /* 57039433Smckusick * Prevent any further operations on the vnode from 57139433Smckusick * being passed through to the old file system. 57239433Smckusick */ 57339433Smckusick origops = vp->v_op; 57439433Smckusick vp->v_op = &dead_vnodeops; 57539433Smckusick vp->v_tag = VT_NON; 57639433Smckusick /* 57739484Smckusick * If purging an active vnode, it must be unlocked, closed, 57839484Smckusick * and deactivated before being reclaimed. 57939433Smckusick */ 58039667Smckusick (*(origops->vn_unlock))(vp); 58139484Smckusick if (active) { 58239484Smckusick if (doclose) 58339484Smckusick (*(origops->vn_close))(vp, 0, NOCRED); 58439433Smckusick (*(origops->vn_inactive))(vp); 58539433Smckusick } 58639433Smckusick /* 58739433Smckusick * Reclaim the vnode. 58839433Smckusick */ 58939433Smckusick if ((*(origops->vn_reclaim))(vp)) 59039433Smckusick panic("vclean: cannot reclaim"); 59139484Smckusick if (active) 59239484Smckusick vrele(vp); 59339433Smckusick /* 59439433Smckusick * Done with purge, notify sleepers in vget of the grim news. 59539433Smckusick */ 59639433Smckusick vp->v_flag &= ~VXLOCK; 59739433Smckusick if (vp->v_flag & VXWANT) { 59839433Smckusick vp->v_flag &= ~VXWANT; 59939433Smckusick wakeup((caddr_t)vp); 60039433Smckusick } 60139433Smckusick } 60239433Smckusick 60339433Smckusick /* 60439633Smckusick * Eliminate all activity associated with the requested vnode 60539633Smckusick * and with all vnodes aliased to the requested vnode. 60639633Smckusick */ 60739633Smckusick void vgoneall(vp) 60839633Smckusick register struct vnode *vp; 60939633Smckusick { 61039809Smckusick register struct vnode *vq; 61139633Smckusick 61240665Smckusick if (vp->v_flag & VALIASED) { 61340665Smckusick /* 61440665Smckusick * If a vgone (or vclean) is already in progress, 61540665Smckusick * wait until it is done and return. 61640665Smckusick */ 61740665Smckusick if (vp->v_flag & VXLOCK) { 61840665Smckusick vp->v_flag |= VXWANT; 61940665Smckusick sleep((caddr_t)vp, PINOD); 62040665Smckusick return; 62139633Smckusick } 62240665Smckusick /* 62340665Smckusick * Ensure that vp will not be vgone'd while we 62440665Smckusick * are eliminating its aliases. 62540665Smckusick */ 62640665Smckusick vp->v_flag |= VXLOCK; 62740665Smckusick while (vp->v_flag & VALIASED) { 62840665Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 62940665Smckusick if (vq->v_rdev != vp->v_rdev || 63040665Smckusick vq->v_type != vp->v_type || vp == vq) 63140665Smckusick continue; 63240665Smckusick vgone(vq); 63340665Smckusick break; 63440665Smckusick } 63540665Smckusick } 63640665Smckusick /* 63740665Smckusick * Remove the lock so that vgone below will 63840665Smckusick * really eliminate the vnode after which time 63940665Smckusick * vgone will awaken any sleepers. 64040665Smckusick */ 64140665Smckusick vp->v_flag &= ~VXLOCK; 64239633Smckusick } 64339633Smckusick vgone(vp); 64439633Smckusick } 64539633Smckusick 64639633Smckusick /* 64739433Smckusick * Eliminate all activity associated with a vnode 64839433Smckusick * in preparation for reuse. 64939433Smckusick */ 65039433Smckusick void vgone(vp) 65139433Smckusick register struct vnode *vp; 65239433Smckusick { 65339809Smckusick register struct vnode *vq; 65439615Smckusick struct vnode *vx; 65539615Smckusick long count; 65639433Smckusick 65739433Smckusick /* 65840548Smckusick * If a vgone (or vclean) is already in progress, 65940548Smckusick * wait until it is done and return. 66040548Smckusick */ 66140548Smckusick if (vp->v_flag & VXLOCK) { 66240548Smckusick vp->v_flag |= VXWANT; 66340548Smckusick sleep((caddr_t)vp, PINOD); 66440548Smckusick return; 66540548Smckusick } 66640548Smckusick /* 66739433Smckusick * Clean out the filesystem specific data. 66839433Smckusick */ 66939484Smckusick vclean(vp, 1); 67039433Smckusick /* 67139433Smckusick * Delete from old mount point vnode list, if on one. 67239433Smckusick */ 67339433Smckusick if (vp->v_mountb) { 67439433Smckusick if (vq = vp->v_mountf) 67539433Smckusick vq->v_mountb = vp->v_mountb; 67639433Smckusick *vp->v_mountb = vq; 67739433Smckusick vp->v_mountf = NULL; 67839433Smckusick vp->v_mountb = NULL; 67939433Smckusick } 68039433Smckusick /* 68139433Smckusick * If special device, remove it from special device alias list. 68239433Smckusick */ 68339433Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR) { 68439809Smckusick if (*vp->v_hashchain == vp) { 68539809Smckusick *vp->v_hashchain = vp->v_specnext; 68639433Smckusick } else { 68739809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 68839615Smckusick if (vq->v_specnext != vp) 68939433Smckusick continue; 69039615Smckusick vq->v_specnext = vp->v_specnext; 69139433Smckusick break; 69239433Smckusick } 69339615Smckusick if (vq == NULL) 69439433Smckusick panic("missing bdev"); 69539433Smckusick } 69639615Smckusick if (vp->v_flag & VALIASED) { 69739809Smckusick count = 0; 69839809Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 69940108Smckusick if (vq->v_rdev != vp->v_rdev || 70040108Smckusick vq->v_type != vp->v_type) 70139615Smckusick continue; 70239615Smckusick count++; 70339615Smckusick vx = vq; 70439615Smckusick } 70539615Smckusick if (count == 0) 70639615Smckusick panic("missing alias"); 70739615Smckusick if (count == 1) 70839615Smckusick vx->v_flag &= ~VALIASED; 70939615Smckusick vp->v_flag &= ~VALIASED; 71039615Smckusick } 71139615Smckusick FREE(vp->v_specinfo, M_VNODE); 71239615Smckusick vp->v_specinfo = NULL; 71339433Smckusick } 71439433Smckusick /* 71539433Smckusick * If it is on the freelist, move it to the head of the list. 71639433Smckusick */ 71739433Smckusick if (vp->v_freeb) { 71839433Smckusick if (vq = vp->v_freef) 71939433Smckusick vq->v_freeb = vp->v_freeb; 72039433Smckusick else 72139433Smckusick vfreet = vp->v_freeb; 72239433Smckusick *vp->v_freeb = vq; 72339433Smckusick vp->v_freef = vfreeh; 72439433Smckusick vp->v_freeb = &vfreeh; 72539433Smckusick vfreeh->v_freeb = &vp->v_freef; 72639433Smckusick vfreeh = vp; 72739433Smckusick } 72839484Smckusick vp->v_type = VBAD; 72939433Smckusick } 73039633Smckusick 73139633Smckusick /* 73239821Smckusick * Lookup a vnode by device number. 73339821Smckusick */ 73439821Smckusick vfinddev(dev, type, vpp) 73539821Smckusick dev_t dev; 73639821Smckusick enum vtype type; 73739821Smckusick struct vnode **vpp; 73839821Smckusick { 73939821Smckusick register struct vnode *vp; 74039821Smckusick 74139821Smckusick for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 74239821Smckusick if (dev != vp->v_rdev || type != vp->v_type) 74339821Smckusick continue; 74439821Smckusick *vpp = vp; 74539821Smckusick return (0); 74639821Smckusick } 74739821Smckusick return (1); 74839821Smckusick } 74939821Smckusick 75039821Smckusick /* 75139633Smckusick * Calculate the total number of references to a special device. 75239633Smckusick */ 75339633Smckusick vcount(vp) 75439633Smckusick register struct vnode *vp; 75539633Smckusick { 75639809Smckusick register struct vnode *vq; 75739633Smckusick int count; 75839633Smckusick 75939633Smckusick if ((vp->v_flag & VALIASED) == 0) 76039809Smckusick return (vp->v_usecount); 76139633Smckusick loop: 76239809Smckusick for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 76340108Smckusick if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) 76439633Smckusick continue; 76539633Smckusick /* 76639633Smckusick * Alias, but not in use, so flush it out. 76739633Smckusick */ 76839809Smckusick if (vq->v_usecount == 0) { 76939633Smckusick vgone(vq); 77039633Smckusick goto loop; 77139633Smckusick } 77239809Smckusick count += vq->v_usecount; 77339633Smckusick } 77439633Smckusick return (count); 77539633Smckusick } 77639667Smckusick 77739667Smckusick /* 77839667Smckusick * Print out a description of a vnode. 77939667Smckusick */ 78039667Smckusick static char *typename[] = 78140286Smckusick { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; 78239667Smckusick 78339667Smckusick vprint(label, vp) 78439667Smckusick char *label; 78539667Smckusick register struct vnode *vp; 78639667Smckusick { 78739913Smckusick char buf[64]; 78839667Smckusick 78939667Smckusick if (label != NULL) 79039667Smckusick printf("%s: ", label); 79139913Smckusick printf("type %s, usecount %d, refcount %d,", typename[vp->v_type], 79239809Smckusick vp->v_usecount, vp->v_holdcnt); 79339913Smckusick buf[0] = '\0'; 79439913Smckusick if (vp->v_flag & VROOT) 79539913Smckusick strcat(buf, "|VROOT"); 79639913Smckusick if (vp->v_flag & VTEXT) 79739913Smckusick strcat(buf, "|VTEXT"); 79839913Smckusick if (vp->v_flag & VXLOCK) 79939913Smckusick strcat(buf, "|VXLOCK"); 80039913Smckusick if (vp->v_flag & VXWANT) 80139913Smckusick strcat(buf, "|VXWANT"); 80239913Smckusick if (vp->v_flag & VEXLOCK) 80339913Smckusick strcat(buf, "|VEXLOCK"); 80439913Smckusick if (vp->v_flag & VSHLOCK) 80539913Smckusick strcat(buf, "|VSHLOCK"); 80639913Smckusick if (vp->v_flag & VLWAIT) 80739913Smckusick strcat(buf, "|VLWAIT"); 80839913Smckusick if (vp->v_flag & VALIASED) 80939913Smckusick strcat(buf, "|VALIASED"); 81039913Smckusick if (vp->v_flag & VBWAIT) 81139913Smckusick strcat(buf, "|VBWAIT"); 81239913Smckusick if (buf[0] != '\0') 81339913Smckusick printf(" flags (%s)", &buf[1]); 81439913Smckusick printf("\n\t"); 81539667Smckusick VOP_PRINT(vp); 81639667Smckusick } 817*41110Smarc 818*41110Smarc int kinfo_vdebug = 1; 819*41110Smarc int kinfo_vgetfailed; 820*41110Smarc #define KINFO_VNODESLOP 10 821*41110Smarc /* 822*41110Smarc * Dump vnode list (via kinfo). 823*41110Smarc * Copyout address of vnode followed by vnode. 824*41110Smarc */ 825*41110Smarc kinfo_vnode(op, where, acopysize, arg, aneeded) 826*41110Smarc char *where; 827*41110Smarc int *acopysize, *aneeded; 828*41110Smarc { 829*41110Smarc register struct mount *mp = rootfs; 830*41110Smarc register struct vnode *nextvp; 831*41110Smarc struct vnode *vp; 832*41110Smarc register needed = 0; 833*41110Smarc register char *bp = where, *savebp; 834*41110Smarc char *ewhere = where + *acopysize; 835*41110Smarc int error; 836*41110Smarc 837*41110Smarc #define VPTRSZ sizeof (struct vnode *) 838*41110Smarc #define VNODESZ sizeof (struct vnode) 839*41110Smarc if (where == NULL) { 840*41110Smarc *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 841*41110Smarc return (0); 842*41110Smarc } 843*41110Smarc 844*41110Smarc #define RETRY bp = savebp ; goto again 845*41110Smarc do { 846*41110Smarc /* 847*41110Smarc * A vget can fail if the vnode is being 848*41110Smarc * recycled. In this (rare) case, we have to start 849*41110Smarc * over with this filesystem. Also, have to 850*41110Smarc * check that nextvp is still associated 851*41110Smarc * with this filesystem. RACE: could have been 852*41110Smarc * recycled onto same filesystem. 853*41110Smarc */ 854*41110Smarc savebp = bp; 855*41110Smarc again: 856*41110Smarc nextvp = mp->m_mounth; 857*41110Smarc while (vp = nextvp) { 858*41110Smarc if (vget(vp)) { 859*41110Smarc if (kinfo_vdebug) 860*41110Smarc printf("kinfo: vget failed\n"); 861*41110Smarc kinfo_vgetfailed++; 862*41110Smarc RETRY; 863*41110Smarc } 864*41110Smarc if (vp->v_mount != mp) { 865*41110Smarc if (kinfo_vdebug) 866*41110Smarc printf("kinfo: vp changed\n"); 867*41110Smarc vput(vp); 868*41110Smarc RETRY; 869*41110Smarc } 870*41110Smarc if ((bp + VPTRSZ + VNODESZ <= ewhere) && 871*41110Smarc ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) || 872*41110Smarc (error = copyout((caddr_t)vp, bp + VPTRSZ, 873*41110Smarc VNODESZ)))) { 874*41110Smarc vput(vp); 875*41110Smarc return (error); 876*41110Smarc } 877*41110Smarc bp += VPTRSZ + VNODESZ; 878*41110Smarc nextvp = vp->v_mountf; 879*41110Smarc vput(vp); 880*41110Smarc } 881*41110Smarc mp = mp->m_next; 882*41110Smarc } while (mp != rootfs); 883*41110Smarc 884*41110Smarc *aneeded = bp - where; 885*41110Smarc if (bp > ewhere) 886*41110Smarc *acopysize = ewhere - where; 887*41110Smarc else 888*41110Smarc *acopysize = bp - where; 889*41110Smarc return (0); 890*41110Smarc } 891