xref: /csrg-svn/sys/kern/vfs_subr.c (revision 40883)
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*40883Smckusick  *	@(#)vfs_subr.c	7.38 (Berkeley) 04/10/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();
174*40883Smckusick 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 
208*40883Smckusick 	if (numvnodes < desiredvnodes) {
209*40883Smckusick 		vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK);
210*40883Smckusick 		bzero((char *)vp, sizeof *vp);
211*40883Smckusick 		numvnodes++;
212*40883Smckusick 	} else {
213*40883Smckusick 		if ((vp = vfreeh) == NULL) {
214*40883Smckusick 			tablefull("vnode");
215*40883Smckusick 			*vpp = 0;
216*40883Smckusick 			return (ENFILE);
217*40883Smckusick 		}
218*40883Smckusick 		if (vp->v_usecount)
219*40883Smckusick 			panic("free vnode isn't");
220*40883Smckusick 		if (vq = vp->v_freef)
221*40883Smckusick 			vq->v_freeb = &vfreeh;
222*40883Smckusick 		else
223*40883Smckusick 			vfreet = &vfreeh;
224*40883Smckusick 		vfreeh = vq;
225*40883Smckusick 		vp->v_freef = NULL;
226*40883Smckusick 		vp->v_freeb = NULL;
227*40883Smckusick 		if (vp->v_type != VBAD)
228*40883Smckusick 			vgone(vp);
229*40883Smckusick 		vp->v_flag = 0;
230*40883Smckusick 		vp->v_shlockc = 0;
231*40883Smckusick 		vp->v_exlockc = 0;
232*40883Smckusick 		vp->v_lastr = 0;
233*40883Smckusick 		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