xref: /csrg-svn/sys/kern/vfs_subr.c (revision 39736)
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*39736Smckusick  *	@(#)vfs_subr.c	7.20 (Berkeley) 12/19/89
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"
2838265Smckusick #include "namei.h"
2938265Smckusick #include "ucred.h"
3037488Smckusick #include "errno.h"
3139433Smckusick #include "malloc.h"
3237488Smckusick 
3337488Smckusick /*
3437488Smckusick  * Remove a mount point from the list of mounted filesystems.
3537488Smckusick  * Unmount of the root is illegal.
3637488Smckusick  */
3737488Smckusick void
3837488Smckusick vfs_remove(mp)
3937488Smckusick 	register struct mount *mp;
4037488Smckusick {
4137488Smckusick 
4237488Smckusick 	if (mp == rootfs)
4337488Smckusick 		panic("vfs_remove: unmounting root");
4437488Smckusick 	mp->m_prev->m_next = mp->m_next;
4537488Smckusick 	mp->m_next->m_prev = mp->m_prev;
4637488Smckusick 	mp->m_vnodecovered->v_mountedhere = (struct mount *)0;
4737488Smckusick 	vfs_unlock(mp);
4837488Smckusick }
4937488Smckusick 
5037488Smckusick /*
5137488Smckusick  * Lock a filesystem.
5237488Smckusick  * Used to prevent access to it while mounting and unmounting.
5337488Smckusick  */
5437488Smckusick vfs_lock(mp)
5537488Smckusick 	register struct mount *mp;
5637488Smckusick {
5737488Smckusick 
5839045Smckusick 	while(mp->m_flag & M_MLOCK) {
5939045Smckusick 		mp->m_flag |= M_MWAIT;
6039045Smckusick 		sleep((caddr_t)mp, PVFS);
6139045Smckusick 	}
6237488Smckusick 	mp->m_flag |= M_MLOCK;
6337488Smckusick 	return (0);
6437488Smckusick }
6537488Smckusick 
6637488Smckusick /*
6737488Smckusick  * Unlock a locked filesystem.
6837488Smckusick  * Panic if filesystem is not locked.
6937488Smckusick  */
7037488Smckusick void
7137488Smckusick vfs_unlock(mp)
7237488Smckusick 	register struct mount *mp;
7337488Smckusick {
7437488Smckusick 
7537488Smckusick 	if ((mp->m_flag & M_MLOCK) == 0)
7637488Smckusick 		panic("vfs_unlock: locked fs");
7737488Smckusick 	mp->m_flag &= ~M_MLOCK;
7837488Smckusick 	if (mp->m_flag & M_MWAIT) {
7937488Smckusick 		mp->m_flag &= ~M_MWAIT;
8037488Smckusick 		wakeup((caddr_t)mp);
8137488Smckusick 	}
8237488Smckusick }
8337488Smckusick 
8437488Smckusick /*
8537488Smckusick  * Lookup a mount point by filesystem identifier.
8637488Smckusick  */
8737488Smckusick struct mount *
8837488Smckusick getvfs(fsid)
8937488Smckusick 	fsid_t *fsid;
9037488Smckusick {
9137488Smckusick 	register struct mount *mp;
9237488Smckusick 
9338288Smckusick 	mp = rootfs;
9438288Smckusick 	do {
9537488Smckusick 		if (mp->m_fsid.val[0] == fsid->val[0] &&
9637488Smckusick 		    mp->m_fsid.val[1] == fsid->val[1]) {
9738288Smckusick 			return (mp);
9837488Smckusick 		}
9938288Smckusick 		mp = mp->m_next;
10038288Smckusick 	} while (mp != rootfs);
10138288Smckusick 	return ((struct mount *)0);
10237488Smckusick }
10337488Smckusick 
10437488Smckusick /*
10537488Smckusick  * Set vnode attributes to VNOVAL
10637488Smckusick  */
10737488Smckusick void vattr_null(vap)
10837488Smckusick 	register struct vattr *vap;
10937488Smckusick {
11037488Smckusick 
11137488Smckusick 	vap->va_type = VNON;
11237488Smckusick 	vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
11337488Smckusick 		vap->va_fsid = vap->va_fileid = vap->va_size =
11437488Smckusick 		vap->va_size1 = vap->va_blocksize = vap->va_rdev =
11537488Smckusick 		vap->va_bytes = vap->va_bytes1 =
11637488Smckusick 		vap->va_atime.tv_sec = vap->va_atime.tv_usec =
11737488Smckusick 		vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
11838258Smckusick 		vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
11938258Smckusick 		vap->va_flags = vap->va_gen = VNOVAL;
12037488Smckusick }
12138265Smckusick 
12238265Smckusick /*
12338265Smckusick  * Initialize a nameidata structure
12438265Smckusick  */
12538265Smckusick ndinit(ndp)
12638265Smckusick 	register struct nameidata *ndp;
12738265Smckusick {
12838265Smckusick 
12938265Smckusick 	bzero((caddr_t)ndp, sizeof(struct nameidata));
13038265Smckusick 	ndp->ni_iov = &ndp->ni_nd.nd_iovec;
13138265Smckusick 	ndp->ni_iovcnt = 1;
13238265Smckusick 	ndp->ni_base = (caddr_t)&ndp->ni_dent;
13338265Smckusick 	ndp->ni_rw = UIO_WRITE;
134*39736Smckusick 	ndp->ni_uioseg = UIO_SYSSPACE;
13538265Smckusick }
13638265Smckusick 
13738265Smckusick /*
13838265Smckusick  * Duplicate a nameidata structure
13938265Smckusick  */
14038265Smckusick nddup(ndp, newndp)
14138265Smckusick 	register struct nameidata *ndp, *newndp;
14238265Smckusick {
14338265Smckusick 
14438265Smckusick 	ndinit(newndp);
14538265Smckusick 	newndp->ni_cdir = ndp->ni_cdir;
14638348Smckusick 	VREF(newndp->ni_cdir);
14738265Smckusick 	newndp->ni_rdir = ndp->ni_rdir;
14838265Smckusick 	if (newndp->ni_rdir)
14938348Smckusick 		VREF(newndp->ni_rdir);
15038265Smckusick 	newndp->ni_cred = ndp->ni_cred;
15138265Smckusick 	crhold(newndp->ni_cred);
15238265Smckusick }
15338265Smckusick 
15438265Smckusick /*
15538265Smckusick  * Release a nameidata structure
15638265Smckusick  */
15738265Smckusick ndrele(ndp)
15838265Smckusick 	register struct nameidata *ndp;
15938265Smckusick {
16038265Smckusick 
16138265Smckusick 	vrele(ndp->ni_cdir);
16238265Smckusick 	if (ndp->ni_rdir)
16338265Smckusick 		vrele(ndp->ni_rdir);
16438265Smckusick 	crfree(ndp->ni_cred);
16538265Smckusick }
16639397Smckusick 
16739397Smckusick /*
16839397Smckusick  * Routines having to do with the management of the vnode table.
16939397Smckusick  */
17039397Smckusick struct vnode *vfreeh, **vfreet;
17139447Smckusick extern struct vnodeops dead_vnodeops, spec_vnodeops;
17239635Smckusick extern void vclean();
17339397Smckusick 
17439615Smckusick #define	SPECHSZ	64
17539615Smckusick #if	((SPECHSZ&(SPECHSZ-1)) == 0)
17639615Smckusick #define	SPECHASH(rdev)	(((rdev>>5)+(rdev))&(SPECHSZ-1))
17739615Smckusick #else
17839615Smckusick #define	SPECHASH(rdev)	(((unsigned)((rdev>>5)+(rdev)))%SPECHSZ)
17939615Smckusick #endif
18039615Smckusick struct vnode *speclisth[SPECHSZ];
18139615Smckusick 
18239397Smckusick /*
18339433Smckusick  * Initialize the vnode structures and initialize each file system type.
18439397Smckusick  */
18539433Smckusick vfsinit()
18639397Smckusick {
18739397Smckusick 	register struct vnode *vp = vnode;
18839433Smckusick 	struct vfsops **vfsp;
18939397Smckusick 
19039433Smckusick 	/*
19139433Smckusick 	 * Build vnode free list.
19239433Smckusick 	 */
19339397Smckusick 	vfreeh = vp;
19439397Smckusick 	vfreet = &vp->v_freef;
19539397Smckusick 	vp->v_freeb = &vfreeh;
19639397Smckusick 	vp->v_op = &dead_vnodeops;
19739397Smckusick 	for (vp++; vp < vnodeNVNODE; vp++) {
19839397Smckusick 		*vfreet = vp;
19939397Smckusick 		vp->v_freeb = vfreet;
20039397Smckusick 		vfreet = &vp->v_freef;
20139397Smckusick 		vp->v_op = &dead_vnodeops;
20239397Smckusick 	}
20339397Smckusick 	vp--;
20439397Smckusick 	vp->v_freef = NULL;
20539433Smckusick 	/*
20639433Smckusick 	 * Initialize the vnode name cache
20739433Smckusick 	 */
20839433Smckusick 	nchinit();
20939433Smckusick 	/*
21039433Smckusick 	 * Initialize each file system type.
21139433Smckusick 	 */
21239433Smckusick 	for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
21339433Smckusick 		if (*vfsp == NULL)
21439433Smckusick 			continue;
21539433Smckusick 		(*(*vfsp)->vfs_init)();
21639433Smckusick 	}
21739397Smckusick }
21839397Smckusick 
21939397Smckusick /*
22039397Smckusick  * Return the next vnode from the free list.
22139397Smckusick  */
22239397Smckusick getnewvnode(tag, mp, vops, vpp)
22339397Smckusick 	enum vtagtype tag;
22439397Smckusick 	struct mount *mp;
22539397Smckusick 	struct vnodeops *vops;
22639397Smckusick 	struct vnode **vpp;
22739397Smckusick {
22839397Smckusick 	register struct vnode *vp, *vq;
22939397Smckusick 
23039397Smckusick 	if ((vp = vfreeh) == NULL) {
23139397Smckusick 		tablefull("vnode");
23239397Smckusick 		*vpp = 0;
23339397Smckusick 		return (ENFILE);
23439397Smckusick 	}
23539433Smckusick 	if (vp->v_count)
23639397Smckusick 		panic("free vnode isn't");
23739397Smckusick 	if (vq = vp->v_freef)
23839397Smckusick 		vq->v_freeb = &vfreeh;
23939397Smckusick 	vfreeh = vq;
24039397Smckusick 	vp->v_freef = NULL;
24139397Smckusick 	vp->v_freeb = NULL;
24239512Smckusick 	if (vp->v_type != VNON && vp->v_type != VBAD)
24339433Smckusick 		vgone(vp);
24439512Smckusick 	vp->v_type = VNON;
24539397Smckusick 	vp->v_flag = 0;
24639397Smckusick 	vp->v_shlockc = 0;
24739397Smckusick 	vp->v_exlockc = 0;
24839397Smckusick 	vp->v_socket = 0;
24939397Smckusick 	cache_purge(vp);
25039397Smckusick 	vp->v_tag = tag;
25139433Smckusick 	vp->v_op = vops;
25239397Smckusick 	insmntque(vp, mp);
25339397Smckusick 	VREF(vp);
25439397Smckusick 	*vpp = vp;
25539397Smckusick 	return (0);
25639397Smckusick }
25739397Smckusick 
25839397Smckusick /*
25939397Smckusick  * Move a vnode from one mount queue to another.
26039397Smckusick  */
26139397Smckusick insmntque(vp, mp)
26239397Smckusick 	register struct vnode *vp;
26339397Smckusick 	register struct mount *mp;
26439397Smckusick {
26539397Smckusick 	struct vnode *vq;
26639397Smckusick 
26739397Smckusick 	/*
26839397Smckusick 	 * Delete from old mount point vnode list, if on one.
26939397Smckusick 	 */
27039397Smckusick 	if (vp->v_mountb) {
27139397Smckusick 		if (vq = vp->v_mountf)
27239397Smckusick 			vq->v_mountb = vp->v_mountb;
27339397Smckusick 		*vp->v_mountb = vq;
27439397Smckusick 	}
27539397Smckusick 	/*
27639397Smckusick 	 * Insert into list of vnodes for the new mount point, if available.
27739397Smckusick 	 */
27839621Smckusick 	vp->v_mount = mp;
27939397Smckusick 	if (mp == NULL) {
28039397Smckusick 		vp->v_mountf = NULL;
28139397Smckusick 		vp->v_mountb = NULL;
28239397Smckusick 		return;
28339397Smckusick 	}
28439397Smckusick 	if (mp->m_mounth) {
28539397Smckusick 		vp->v_mountf = mp->m_mounth;
28639397Smckusick 		vp->v_mountb = &mp->m_mounth;
28739397Smckusick 		mp->m_mounth->v_mountb = &vp->v_mountf;
28839397Smckusick 		mp->m_mounth = vp;
28939397Smckusick 	} else {
29039397Smckusick 		mp->m_mounth = vp;
29139397Smckusick 		vp->v_mountb = &mp->m_mounth;
29239397Smckusick 		vp->v_mountf = NULL;
29339397Smckusick 	}
29439397Smckusick }
29539397Smckusick 
29639397Smckusick /*
29739433Smckusick  * Create a vnode for a block device.
29839433Smckusick  * Used for root filesystem, argdev, and swap areas.
29939433Smckusick  * Also used for memory file system special devices.
30039397Smckusick  */
30139433Smckusick bdevvp(dev, vpp)
30239433Smckusick 	dev_t dev;
30339433Smckusick 	struct vnode **vpp;
30439433Smckusick {
30539433Smckusick 	register struct vnode *vp;
30639433Smckusick 	struct vnode *nvp;
30739433Smckusick 	int error;
30839433Smckusick 
30939447Smckusick 	error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
31039433Smckusick 	if (error) {
31139433Smckusick 		*vpp = 0;
31239433Smckusick 		return (error);
31339433Smckusick 	}
31439433Smckusick 	vp = nvp;
31539433Smckusick 	vp->v_type = VBLK;
31639615Smckusick 	if (nvp = checkalias(vp, dev, (struct mount *)0)) {
31739433Smckusick 		vput(vp);
31839433Smckusick 		vp = nvp;
31939433Smckusick 	}
32039433Smckusick 	*vpp = vp;
32139433Smckusick 	return (0);
32239433Smckusick }
32339433Smckusick 
32439433Smckusick /*
32539433Smckusick  * Check to see if the new vnode represents a special device
32639433Smckusick  * for which we already have a vnode (either because of
32739433Smckusick  * bdevvp() or because of a different vnode representing
32839433Smckusick  * the same block device). If such an alias exists, deallocate
32939509Smckusick  * the existing contents and return the aliased vnode. The
33039433Smckusick  * caller is responsible for filling it with its new contents.
33139433Smckusick  */
33239433Smckusick struct vnode *
33339615Smckusick checkalias(nvp, nvp_rdev, mp)
33439433Smckusick 	register struct vnode *nvp;
33539615Smckusick 	dev_t nvp_rdev;
33639433Smckusick 	struct mount *mp;
33739433Smckusick {
33839433Smckusick 	register struct vnode *vp;
33939615Smckusick 	struct vnode **vpp;
34039433Smckusick 
34139433Smckusick 	if (nvp->v_type != VBLK && nvp->v_type != VCHR)
34239433Smckusick 		return ((struct vnode *)0);
34339615Smckusick 
34439615Smckusick 	vpp = &speclisth[SPECHASH(nvp_rdev)];
34539433Smckusick loop:
34639615Smckusick 	for (vp = *vpp; vp; vp = vp->v_specnext) {
34739615Smckusick 		if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
34839433Smckusick 			continue;
34939615Smckusick 		/*
35039615Smckusick 		 * Alias, but not in use, so flush it out.
35139615Smckusick 		 */
35239633Smckusick 		if (vp->v_count == 0) {
35339615Smckusick 			vgone(vp);
35439615Smckusick 			goto loop;
35539615Smckusick 		}
35639633Smckusick 		if (vget(vp))
35739633Smckusick 			goto loop;
35839433Smckusick 		break;
35939433Smckusick 	}
36039615Smckusick 	if (vp == NULL || vp->v_tag != VT_NON) {
36139615Smckusick 		if (vp != NULL) {
36239621Smckusick 			nvp->v_flag |= VALIASED;
36339615Smckusick 			vp->v_flag |= VALIASED;
36439621Smckusick 			vput(vp);
36539615Smckusick 		}
36639615Smckusick 		MALLOC(nvp->v_specinfo, struct specinfo *,
36739615Smckusick 			sizeof(struct specinfo), M_VNODE, M_WAITOK);
36839615Smckusick 		nvp->v_rdev = nvp_rdev;
36939615Smckusick 		nvp->v_mounton = NULL;
37039615Smckusick 		nvp->v_lastr = 0;
37139615Smckusick 		nvp->v_specnext = *vpp;
37239615Smckusick 		*vpp = nvp;
37339433Smckusick 		return ((struct vnode *)0);
37439433Smckusick 	}
37539484Smckusick 	VOP_UNLOCK(vp);
37639484Smckusick 	vclean(vp, 0);
37739433Smckusick 	vp->v_op = nvp->v_op;
37839433Smckusick 	vp->v_tag = nvp->v_tag;
37939433Smckusick 	nvp->v_type = VNON;
38039433Smckusick 	insmntque(vp, mp);
38139433Smckusick 	return (vp);
38239433Smckusick }
38339433Smckusick 
38439433Smckusick /*
38539433Smckusick  * Grab a particular vnode from the free list, increment its
38639433Smckusick  * reference count and lock it. The vnode lock bit is set the
38739433Smckusick  * vnode is being eliminated in vgone. The process is awakened
38839433Smckusick  * when the transition is completed, and an error returned to
38939433Smckusick  * indicate that the vnode is no longer usable (possibly having
39039433Smckusick  * been changed to a new file system type).
39139433Smckusick  */
39239397Smckusick vget(vp)
39339397Smckusick 	register struct vnode *vp;
39439397Smckusick {
39539397Smckusick 	register struct vnode *vq;
39639397Smckusick 
39739433Smckusick 	if (vp->v_flag & VXLOCK) {
39839433Smckusick 		vp->v_flag |= VXWANT;
39939433Smckusick 		sleep((caddr_t)vp, PINOD);
40039433Smckusick 		return (1);
40139433Smckusick 	}
40239433Smckusick 	if (vp->v_count == 0) {
40339433Smckusick 		if (vq = vp->v_freef)
40439433Smckusick 			vq->v_freeb = vp->v_freeb;
40539433Smckusick 		else
40639433Smckusick 			vfreet = vp->v_freeb;
40739433Smckusick 		*vp->v_freeb = vq;
40839433Smckusick 		vp->v_freef = NULL;
40939433Smckusick 		vp->v_freeb = NULL;
41039433Smckusick 	}
41139397Smckusick 	VREF(vp);
41239433Smckusick 	VOP_LOCK(vp);
41339433Smckusick 	return (0);
41439397Smckusick }
41539397Smckusick 
41639397Smckusick /*
41739397Smckusick  * Vnode reference, just increment the count
41839397Smckusick  */
41939397Smckusick void vref(vp)
42039397Smckusick 	struct vnode *vp;
42139397Smckusick {
42239397Smckusick 
42339397Smckusick 	vp->v_count++;
42439397Smckusick }
42539397Smckusick 
42639397Smckusick /*
42739397Smckusick  * vput(), just unlock and vrele()
42839397Smckusick  */
42939397Smckusick void vput(vp)
43039397Smckusick 	register struct vnode *vp;
43139397Smckusick {
43239397Smckusick 	VOP_UNLOCK(vp);
43339397Smckusick 	vrele(vp);
43439397Smckusick }
43539397Smckusick 
43639397Smckusick /*
43739397Smckusick  * Vnode release.
43839397Smckusick  * If count drops to zero, call inactive routine and return to freelist.
43939397Smckusick  */
44039397Smckusick void vrele(vp)
44139397Smckusick 	register struct vnode *vp;
44239397Smckusick {
44339397Smckusick 
44439397Smckusick 	if (vp == NULL)
44539433Smckusick 		panic("vrele: null vp");
44639397Smckusick 	vp->v_count--;
44739397Smckusick 	if (vp->v_count < 0)
44839667Smckusick 		vprint("vrele: bad ref count", vp);
44939397Smckusick 	if (vp->v_count > 0)
45039397Smckusick 		return;
45139397Smckusick 	if (vfreeh == (struct vnode *)0) {
45239397Smckusick 		/*
45339397Smckusick 		 * insert into empty list
45439397Smckusick 		 */
45539397Smckusick 		vfreeh = vp;
45639397Smckusick 		vp->v_freeb = &vfreeh;
45739397Smckusick 	} else {
45839397Smckusick 		/*
45939397Smckusick 		 * insert at tail of list
46039397Smckusick 		 */
46139397Smckusick 		*vfreet = vp;
46239397Smckusick 		vp->v_freeb = vfreet;
46339397Smckusick 	}
46439433Smckusick 	vp->v_freef = NULL;
46539433Smckusick 	vfreet = &vp->v_freef;
46639433Smckusick 	VOP_INACTIVE(vp);
46739397Smckusick }
46839433Smckusick 
46939433Smckusick /*
47039509Smckusick  * Remove any vnodes in the vnode table belonging to mount point mp.
47139509Smckusick  *
47239509Smckusick  * If MNT_NOFORCE is specified, there should not be any active ones,
47339509Smckusick  * return error if any are found (nb: this is a user error, not a
47439509Smckusick  * system error). If MNT_FORCE is specified, detach any active vnodes
47539509Smckusick  * that are found.
47639509Smckusick  */
47739509Smckusick int busyprt = 0;	/* patch to print out busy vnodes */
47839509Smckusick 
47939509Smckusick vflush(mp, skipvp, flags)
48039509Smckusick 	struct mount *mp;
48139509Smckusick 	struct vnode *skipvp;
48239509Smckusick 	int flags;
48339509Smckusick {
48439509Smckusick 	register struct vnode *vp, *nvp;
48539509Smckusick 	int busy = 0;
48639509Smckusick 
48739509Smckusick 	for (vp = mp->m_mounth; vp; vp = nvp) {
48839509Smckusick 		nvp = vp->v_mountf;
48939509Smckusick 		/*
49039509Smckusick 		 * Skip over a selected vnode.
49139509Smckusick 		 * Used by ufs to skip over the quota structure inode.
49239509Smckusick 		 */
49339509Smckusick 		if (vp == skipvp)
49439509Smckusick 			continue;
49539509Smckusick 		/*
49639509Smckusick 		 * With v_count == 0, all we need to do is clear
49739509Smckusick 		 * out the vnode data structures and we are done.
49839509Smckusick 		 */
49939509Smckusick 		if (vp->v_count == 0) {
50039509Smckusick 			vgone(vp);
50139509Smckusick 			continue;
50239509Smckusick 		}
50339509Smckusick 		/*
50439509Smckusick 		 * For block or character devices, revert to an
50539509Smckusick 		 * anonymous device. For all other files, just kill them.
50639509Smckusick 		 */
50739509Smckusick 		if (flags & MNT_FORCE) {
50839509Smckusick 			if (vp->v_type != VBLK && vp->v_type != VCHR) {
50939509Smckusick 				vgone(vp);
51039509Smckusick 			} else {
51139509Smckusick 				vclean(vp, 0);
51239509Smckusick 				vp->v_op = &spec_vnodeops;
51339509Smckusick 				insmntque(vp, (struct mount *)0);
51439509Smckusick 			}
51539509Smckusick 			continue;
51639509Smckusick 		}
51739509Smckusick 		if (busyprt)
51839667Smckusick 			vprint("vflush: busy vnode", vp);
51939509Smckusick 		busy++;
52039509Smckusick 	}
52139509Smckusick 	if (busy)
52239509Smckusick 		return (EBUSY);
52339509Smckusick 	return (0);
52439509Smckusick }
52539509Smckusick 
52639509Smckusick /*
52739433Smckusick  * Disassociate the underlying file system from a vnode.
52839433Smckusick  */
52939484Smckusick void vclean(vp, doclose)
53039433Smckusick 	register struct vnode *vp;
53139484Smckusick 	long doclose;
53239433Smckusick {
53339433Smckusick 	struct vnodeops *origops;
53439484Smckusick 	int active;
53539433Smckusick 
53639484Smckusick 	/*
53739484Smckusick 	 * Check to see if the vnode is in use.
53839667Smckusick 	 * If so we have to reference it before we clean it out
53939667Smckusick 	 * so that its count cannot fall to zero and generate a
54039667Smckusick 	 * race against ourselves to recycle it.
54139484Smckusick 	 */
54239667Smckusick 	if (active = vp->v_count)
54339484Smckusick 		VREF(vp);
54439484Smckusick 	/*
54539484Smckusick 	 * Prevent the vnode from being recycled or
54639484Smckusick 	 * brought into use while we clean it out.
54739484Smckusick 	 */
54839667Smckusick 	if (vp->v_flag & VXLOCK)
54939667Smckusick 		panic("vclean: deadlock");
55039433Smckusick 	vp->v_flag |= VXLOCK;
55139433Smckusick 	/*
55239667Smckusick 	 * Even if the count is zero, the VOP_INACTIVE routine may still
55339667Smckusick 	 * have the object locked while it cleans it out. The VOP_LOCK
55439667Smckusick 	 * ensures that the VOP_INACTIVE routine is done with its work.
55539667Smckusick 	 * For active vnodes, it ensures that no other activity can
55639667Smckusick 	 * occur while the buffer list is being cleaned out.
55739667Smckusick 	 */
55839667Smckusick 	VOP_LOCK(vp);
55939667Smckusick 	if (doclose)
56039667Smckusick 		vinvalbuf(vp, 1);
56139667Smckusick 	/*
56239433Smckusick 	 * Prevent any further operations on the vnode from
56339433Smckusick 	 * being passed through to the old file system.
56439433Smckusick 	 */
56539433Smckusick 	origops = vp->v_op;
56639433Smckusick 	vp->v_op = &dead_vnodeops;
56739433Smckusick 	vp->v_tag = VT_NON;
56839433Smckusick 	/*
56939484Smckusick 	 * If purging an active vnode, it must be unlocked, closed,
57039484Smckusick 	 * and deactivated before being reclaimed.
57139433Smckusick 	 */
57239667Smckusick 	(*(origops->vn_unlock))(vp);
57339484Smckusick 	if (active) {
57439484Smckusick 		if (doclose)
57539484Smckusick 			(*(origops->vn_close))(vp, 0, NOCRED);
57639433Smckusick 		(*(origops->vn_inactive))(vp);
57739433Smckusick 	}
57839433Smckusick 	/*
57939433Smckusick 	 * Reclaim the vnode.
58039433Smckusick 	 */
58139433Smckusick 	if ((*(origops->vn_reclaim))(vp))
58239433Smckusick 		panic("vclean: cannot reclaim");
58339484Smckusick 	if (active)
58439484Smckusick 		vrele(vp);
58539433Smckusick 	/*
58639433Smckusick 	 * Done with purge, notify sleepers in vget of the grim news.
58739433Smckusick 	 */
58839433Smckusick 	vp->v_flag &= ~VXLOCK;
58939433Smckusick 	if (vp->v_flag & VXWANT) {
59039433Smckusick 		vp->v_flag &= ~VXWANT;
59139433Smckusick 		wakeup((caddr_t)vp);
59239433Smckusick 	}
59339433Smckusick }
59439433Smckusick 
59539433Smckusick /*
59639633Smckusick  * Eliminate all activity associated with  the requested vnode
59739633Smckusick  * and with all vnodes aliased to the requested vnode.
59839633Smckusick  */
59939633Smckusick void vgoneall(vp)
60039633Smckusick 	register struct vnode *vp;
60139633Smckusick {
60239633Smckusick 	register struct vnode *vq, **vpp;
60339633Smckusick 
60439633Smckusick 	if (vp->v_flag & VALIASED) {
60539633Smckusick 		vpp = &speclisth[SPECHASH(vp->v_rdev)];
60639633Smckusick 	loop:
60739633Smckusick 		for (vq = *vpp; vq; vq = vq->v_specnext) {
60839633Smckusick 			if (vq->v_rdev != vp->v_rdev || vp == vq)
60939633Smckusick 				continue;
61039633Smckusick 			vgone(vq);
61139633Smckusick 			goto loop;
61239633Smckusick 		}
61339633Smckusick 	}
61439633Smckusick 	vgone(vp);
61539633Smckusick }
61639633Smckusick 
61739633Smckusick /*
61839433Smckusick  * Eliminate all activity associated with a vnode
61939433Smckusick  * in preparation for reuse.
62039433Smckusick  */
62139433Smckusick void vgone(vp)
62239433Smckusick 	register struct vnode *vp;
62339433Smckusick {
62439615Smckusick 	register struct vnode *vq, **vpp;
62539615Smckusick 	struct vnode *vx;
62639615Smckusick 	long count;
62739433Smckusick 
62839433Smckusick 	/*
62939433Smckusick 	 * Clean out the filesystem specific data.
63039433Smckusick 	 */
63139484Smckusick 	vclean(vp, 1);
63239433Smckusick 	/*
63339433Smckusick 	 * Delete from old mount point vnode list, if on one.
63439433Smckusick 	 */
63539433Smckusick 	if (vp->v_mountb) {
63639433Smckusick 		if (vq = vp->v_mountf)
63739433Smckusick 			vq->v_mountb = vp->v_mountb;
63839433Smckusick 		*vp->v_mountb = vq;
63939433Smckusick 		vp->v_mountf = NULL;
64039433Smckusick 		vp->v_mountb = NULL;
64139433Smckusick 	}
64239433Smckusick 	/*
64339433Smckusick 	 * If special device, remove it from special device alias list.
64439433Smckusick 	 */
64539433Smckusick 	if (vp->v_type == VBLK || vp->v_type == VCHR) {
64639615Smckusick 		vpp = &speclisth[SPECHASH(vp->v_rdev)];
64739615Smckusick 		if (*vpp == vp) {
64839615Smckusick 			*vpp = vp->v_specnext;
64939433Smckusick 		} else {
65039615Smckusick 			for (vq = *vpp; vq; vq = vq->v_specnext) {
65139615Smckusick 				if (vq->v_specnext != vp)
65239433Smckusick 					continue;
65339615Smckusick 				vq->v_specnext = vp->v_specnext;
65439433Smckusick 				break;
65539433Smckusick 			}
65639615Smckusick 			if (vq == NULL)
65739433Smckusick 				panic("missing bdev");
65839433Smckusick 		}
65939615Smckusick 		if (vp->v_flag & VALIASED) {
66039615Smckusick 			for (count = 0, vq = *vpp; vq; vq = vq->v_specnext) {
66139615Smckusick 				if (vq->v_rdev != vp->v_rdev)
66239615Smckusick 					continue;
66339615Smckusick 				count++;
66439615Smckusick 				vx = vq;
66539615Smckusick 			}
66639615Smckusick 			if (count == 0)
66739615Smckusick 				panic("missing alias");
66839615Smckusick 			if (count == 1)
66939615Smckusick 				vx->v_flag &= ~VALIASED;
67039615Smckusick 			vp->v_flag &= ~VALIASED;
67139615Smckusick 		}
67239615Smckusick 		FREE(vp->v_specinfo, M_VNODE);
67339615Smckusick 		vp->v_specinfo = NULL;
67439433Smckusick 	}
67539433Smckusick 	/*
67639433Smckusick 	 * If it is on the freelist, move it to the head of the list.
67739433Smckusick 	 */
67839433Smckusick 	if (vp->v_freeb) {
67939433Smckusick 		if (vq = vp->v_freef)
68039433Smckusick 			vq->v_freeb = vp->v_freeb;
68139433Smckusick 		else
68239433Smckusick 			vfreet = vp->v_freeb;
68339433Smckusick 		*vp->v_freeb = vq;
68439433Smckusick 		vp->v_freef = vfreeh;
68539433Smckusick 		vp->v_freeb = &vfreeh;
68639433Smckusick 		vfreeh->v_freeb = &vp->v_freef;
68739433Smckusick 		vfreeh = vp;
68839433Smckusick 	}
68939484Smckusick 	vp->v_type = VBAD;
69039433Smckusick }
69139633Smckusick 
69239633Smckusick /*
69339633Smckusick  * Calculate the total number of references to a special device.
69439633Smckusick  */
69539633Smckusick vcount(vp)
69639633Smckusick 	register struct vnode *vp;
69739633Smckusick {
69839633Smckusick 	register struct vnode *vq, **vpp;
69939633Smckusick 	int count;
70039633Smckusick 
70139633Smckusick 	if ((vp->v_flag & VALIASED) == 0)
70239633Smckusick 		return (vp->v_count);
70339633Smckusick 	vpp = &speclisth[SPECHASH(vp->v_rdev)];
70439633Smckusick loop:
70539633Smckusick 	for (count = 0, vq = *vpp; vq; vq = vq->v_specnext) {
70639633Smckusick 		if (vq->v_rdev != vp->v_rdev)
70739633Smckusick 			continue;
70839633Smckusick 		/*
70939633Smckusick 		 * Alias, but not in use, so flush it out.
71039633Smckusick 		 */
71139633Smckusick 		if (vq->v_count == 0) {
71239633Smckusick 			vgone(vq);
71339633Smckusick 			goto loop;
71439633Smckusick 		}
71539633Smckusick 		count += vq->v_count;
71639633Smckusick 	}
71739633Smckusick 	return (count);
71839633Smckusick }
71939667Smckusick 
72039667Smckusick /*
72139667Smckusick  * Print out a description of a vnode.
72239667Smckusick  */
72339667Smckusick static char *typename[] =
72439667Smckusick 	{ "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VBAD" };
72539667Smckusick 
72639667Smckusick vprint(label, vp)
72739667Smckusick 	char *label;
72839667Smckusick 	register struct vnode *vp;
72939667Smckusick {
73039667Smckusick 
73139667Smckusick 	if (label != NULL)
73239667Smckusick 		printf("%s: ", label);
73339667Smckusick 	printf("type %s, count %d, ", typename[vp->v_type], vp->v_count);
73439667Smckusick 	VOP_PRINT(vp);
73539667Smckusick }
736