xref: /csrg-svn/sys/kern/vfs_subr.c (revision 39433)
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*39433Smckusick  *	@(#)vfs_subr.c	7.9 (Berkeley) 10/29/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"
31*39433Smckusick #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;
13438265Smckusick 	ndp->ni_segflg = 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;
171*39433Smckusick extern struct vnodeops dead_vnodeops, blk_vnodeops;
172*39433Smckusick struct speclist *speclisth;
173*39433Smckusick struct speclist {
174*39433Smckusick 	struct speclist *sl_next;
175*39433Smckusick 	struct vnode *sl_vp;
176*39433Smckusick };
17739397Smckusick 
17839397Smckusick /*
179*39433Smckusick  * Initialize the vnode structures and initialize each file system type.
18039397Smckusick  */
181*39433Smckusick vfsinit()
18239397Smckusick {
18339397Smckusick 	register struct vnode *vp = vnode;
184*39433Smckusick 	struct vfsops **vfsp;
18539397Smckusick 
186*39433Smckusick 	/*
187*39433Smckusick 	 * Build vnode free list.
188*39433Smckusick 	 */
18939397Smckusick 	vfreeh = vp;
19039397Smckusick 	vfreet = &vp->v_freef;
19139397Smckusick 	vp->v_freeb = &vfreeh;
19239397Smckusick 	vp->v_op = &dead_vnodeops;
19339397Smckusick 	for (vp++; vp < vnodeNVNODE; vp++) {
19439397Smckusick 		*vfreet = vp;
19539397Smckusick 		vp->v_freeb = vfreet;
19639397Smckusick 		vfreet = &vp->v_freef;
19739397Smckusick 		vp->v_op = &dead_vnodeops;
19839397Smckusick 	}
19939397Smckusick 	vp--;
20039397Smckusick 	vp->v_freef = NULL;
201*39433Smckusick 	/*
202*39433Smckusick 	 * Initialize the vnode name cache
203*39433Smckusick 	 */
204*39433Smckusick 	nchinit();
205*39433Smckusick 	/*
206*39433Smckusick 	 * Initialize each file system type.
207*39433Smckusick 	 */
208*39433Smckusick 	for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
209*39433Smckusick 		if (*vfsp == NULL)
210*39433Smckusick 			continue;
211*39433Smckusick 		(*(*vfsp)->vfs_init)();
212*39433Smckusick 	}
21339397Smckusick }
21439397Smckusick 
21539397Smckusick /*
21639397Smckusick  * Return the next vnode from the free list.
21739397Smckusick  */
21839397Smckusick getnewvnode(tag, mp, vops, vpp)
21939397Smckusick 	enum vtagtype tag;
22039397Smckusick 	struct mount *mp;
22139397Smckusick 	struct vnodeops *vops;
22239397Smckusick 	struct vnode **vpp;
22339397Smckusick {
22439397Smckusick 	register struct vnode *vp, *vq;
22539397Smckusick 
22639397Smckusick 	if ((vp = vfreeh) == NULL) {
22739397Smckusick 		tablefull("vnode");
22839397Smckusick 		*vpp = 0;
22939397Smckusick 		return (ENFILE);
23039397Smckusick 	}
231*39433Smckusick 	if (vp->v_count)
23239397Smckusick 		panic("free vnode isn't");
23339397Smckusick 	if (vq = vp->v_freef)
23439397Smckusick 		vq->v_freeb = &vfreeh;
23539397Smckusick 	vfreeh = vq;
23639397Smckusick 	vp->v_freef = NULL;
23739397Smckusick 	vp->v_freeb = NULL;
238*39433Smckusick 	if (vp->v_type != VNON)
239*39433Smckusick 		vgone(vp);
24039397Smckusick 	vp->v_flag = 0;
24139397Smckusick 	vp->v_shlockc = 0;
24239397Smckusick 	vp->v_exlockc = 0;
24339397Smckusick 	vp->v_socket = 0;
24439397Smckusick 	cache_purge(vp);
24539397Smckusick 	vp->v_tag = tag;
246*39433Smckusick 	vp->v_op = vops;
24739397Smckusick 	vp->v_mount = mp;
24839397Smckusick 	insmntque(vp, mp);
24939397Smckusick 	VREF(vp);
25039397Smckusick 	*vpp = vp;
25139397Smckusick 	return (0);
25239397Smckusick }
25339397Smckusick 
25439397Smckusick /*
25539397Smckusick  * Move a vnode from one mount queue to another.
25639397Smckusick  */
25739397Smckusick insmntque(vp, mp)
25839397Smckusick 	register struct vnode *vp;
25939397Smckusick 	register struct mount *mp;
26039397Smckusick {
26139397Smckusick 	struct vnode *vq;
26239397Smckusick 
26339397Smckusick 	/*
26439397Smckusick 	 * Delete from old mount point vnode list, if on one.
26539397Smckusick 	 */
26639397Smckusick 	if (vp->v_mountb) {
26739397Smckusick 		if (vq = vp->v_mountf)
26839397Smckusick 			vq->v_mountb = vp->v_mountb;
26939397Smckusick 		*vp->v_mountb = vq;
27039397Smckusick 	}
27139397Smckusick 	/*
27239397Smckusick 	 * Insert into list of vnodes for the new mount point, if available.
27339397Smckusick 	 */
27439397Smckusick 	if (mp == NULL) {
27539397Smckusick 		vp->v_mountf = NULL;
27639397Smckusick 		vp->v_mountb = NULL;
27739397Smckusick 		return;
27839397Smckusick 	}
27939397Smckusick 	if (mp->m_mounth) {
28039397Smckusick 		vp->v_mountf = mp->m_mounth;
28139397Smckusick 		vp->v_mountb = &mp->m_mounth;
28239397Smckusick 		mp->m_mounth->v_mountb = &vp->v_mountf;
28339397Smckusick 		mp->m_mounth = vp;
28439397Smckusick 	} else {
28539397Smckusick 		mp->m_mounth = vp;
28639397Smckusick 		vp->v_mountb = &mp->m_mounth;
28739397Smckusick 		vp->v_mountf = NULL;
28839397Smckusick 	}
28939397Smckusick }
29039397Smckusick 
29139397Smckusick /*
292*39433Smckusick  * Create a vnode for a block device.
293*39433Smckusick  * Used for root filesystem, argdev, and swap areas.
294*39433Smckusick  * Also used for memory file system special devices.
29539397Smckusick  */
296*39433Smckusick bdevvp(dev, vpp)
297*39433Smckusick 	dev_t dev;
298*39433Smckusick 	struct vnode **vpp;
299*39433Smckusick {
300*39433Smckusick 	register struct inode *ip;
301*39433Smckusick 	register struct vnode *vp;
302*39433Smckusick 	struct vnode *nvp;
303*39433Smckusick 	int error;
304*39433Smckusick 
305*39433Smckusick 	error = getnewvnode(VT_NON, (struct mount *)0, &blk_vnodeops, &nvp);
306*39433Smckusick 	if (error) {
307*39433Smckusick 		*vpp = 0;
308*39433Smckusick 		return (error);
309*39433Smckusick 	}
310*39433Smckusick 	vp = nvp;
311*39433Smckusick 	vp->v_type = VBLK;
312*39433Smckusick 	vp->v_rdev = dev;
313*39433Smckusick 	if (nvp = checkalias(vp, (struct mount *)0)) {
314*39433Smckusick 		vput(vp);
315*39433Smckusick 		vp = nvp;
316*39433Smckusick 	}
317*39433Smckusick 	*vpp = vp;
318*39433Smckusick 	return (0);
319*39433Smckusick }
320*39433Smckusick 
321*39433Smckusick /*
322*39433Smckusick  * Check to see if the new vnode represents a special device
323*39433Smckusick  * for which we already have a vnode (either because of
324*39433Smckusick  * bdevvp() or because of a different vnode representing
325*39433Smckusick  * the same block device). If such an alias exists, deallocate
326*39433Smckusick  * the existing contents and return the aliased inode. The
327*39433Smckusick  * caller is responsible for filling it with its new contents.
328*39433Smckusick  */
329*39433Smckusick struct vnode *
330*39433Smckusick checkalias(nvp, mp)
331*39433Smckusick 	register struct vnode *nvp;
332*39433Smckusick 	struct mount *mp;
333*39433Smckusick {
334*39433Smckusick 	register struct vnode *vp;
335*39433Smckusick 	register struct speclist *slp;
336*39433Smckusick 
337*39433Smckusick 	if (nvp->v_type != VBLK && nvp->v_type != VCHR)
338*39433Smckusick 		return ((struct vnode *)0);
339*39433Smckusick loop:
340*39433Smckusick 	for (slp = speclisth; slp; slp = slp->sl_next) {
341*39433Smckusick 		vp = slp->sl_vp;
342*39433Smckusick 		if (nvp->v_rdev != vp->v_rdev ||
343*39433Smckusick 		    nvp->v_type != vp->v_type)
344*39433Smckusick 			continue;
345*39433Smckusick 		if (vget(vp))
346*39433Smckusick 			goto loop;
347*39433Smckusick 		break;
348*39433Smckusick 	}
349*39433Smckusick 	if (slp == NULL) {
350*39433Smckusick 		MALLOC(slp, struct speclist *, sizeof(*slp), M_VNODE, M_WAITOK);
351*39433Smckusick 		slp->sl_vp = nvp;
352*39433Smckusick 		slp->sl_next = speclisth;
353*39433Smckusick 		speclisth = slp;
354*39433Smckusick 		return ((struct vnode *)0);
355*39433Smckusick 	}
356*39433Smckusick 	vclean(vp);
357*39433Smckusick 	vp->v_op = nvp->v_op;
358*39433Smckusick 	vp->v_tag = nvp->v_tag;
359*39433Smckusick 	nvp->v_type = VNON;
360*39433Smckusick 	insmntque(vp, mp);
361*39433Smckusick 	return (vp);
362*39433Smckusick }
363*39433Smckusick 
364*39433Smckusick /*
365*39433Smckusick  * Grab a particular vnode from the free list, increment its
366*39433Smckusick  * reference count and lock it. The vnode lock bit is set the
367*39433Smckusick  * vnode is being eliminated in vgone. The process is awakened
368*39433Smckusick  * when the transition is completed, and an error returned to
369*39433Smckusick  * indicate that the vnode is no longer usable (possibly having
370*39433Smckusick  * been changed to a new file system type).
371*39433Smckusick  */
37239397Smckusick vget(vp)
37339397Smckusick 	register struct vnode *vp;
37439397Smckusick {
37539397Smckusick 	register struct vnode *vq;
37639397Smckusick 
377*39433Smckusick 	if (vp->v_flag & VXLOCK) {
378*39433Smckusick 		vp->v_flag |= VXWANT;
379*39433Smckusick 		sleep((caddr_t)vp, PINOD);
380*39433Smckusick 		return (1);
381*39433Smckusick 	}
382*39433Smckusick 	if (vp->v_count == 0) {
383*39433Smckusick 		if (vq = vp->v_freef)
384*39433Smckusick 			vq->v_freeb = vp->v_freeb;
385*39433Smckusick 		else
386*39433Smckusick 			vfreet = vp->v_freeb;
387*39433Smckusick 		*vp->v_freeb = vq;
388*39433Smckusick 		vp->v_freef = NULL;
389*39433Smckusick 		vp->v_freeb = NULL;
390*39433Smckusick 	}
39139397Smckusick 	VREF(vp);
392*39433Smckusick 	VOP_LOCK(vp);
393*39433Smckusick 	return (0);
39439397Smckusick }
39539397Smckusick 
39639397Smckusick /*
39739397Smckusick  * Vnode reference, just increment the count
39839397Smckusick  */
39939397Smckusick void vref(vp)
40039397Smckusick 	struct vnode *vp;
40139397Smckusick {
40239397Smckusick 
40339397Smckusick 	vp->v_count++;
40439397Smckusick }
40539397Smckusick 
40639397Smckusick /*
40739397Smckusick  * vput(), just unlock and vrele()
40839397Smckusick  */
40939397Smckusick void vput(vp)
41039397Smckusick 	register struct vnode *vp;
41139397Smckusick {
41239397Smckusick 	VOP_UNLOCK(vp);
41339397Smckusick 	vrele(vp);
41439397Smckusick }
41539397Smckusick 
41639397Smckusick /*
41739397Smckusick  * Vnode release.
41839397Smckusick  * If count drops to zero, call inactive routine and return to freelist.
41939397Smckusick  */
42039397Smckusick void vrele(vp)
42139397Smckusick 	register struct vnode *vp;
42239397Smckusick {
42339397Smckusick 
42439397Smckusick 	if (vp == NULL)
425*39433Smckusick 		panic("vrele: null vp");
42639397Smckusick 	vp->v_count--;
42739397Smckusick 	if (vp->v_count < 0)
42839397Smckusick 		printf("vnode bad ref count %d, type %d, tag %d\n",
42939397Smckusick 			vp->v_count, vp->v_type, vp->v_tag);
43039397Smckusick 	if (vp->v_count > 0)
43139397Smckusick 		return;
43239397Smckusick 	if (vfreeh == (struct vnode *)0) {
43339397Smckusick 		/*
43439397Smckusick 		 * insert into empty list
43539397Smckusick 		 */
43639397Smckusick 		vfreeh = vp;
43739397Smckusick 		vp->v_freeb = &vfreeh;
43839397Smckusick 	} else {
43939397Smckusick 		/*
44039397Smckusick 		 * insert at tail of list
44139397Smckusick 		 */
44239397Smckusick 		*vfreet = vp;
44339397Smckusick 		vp->v_freeb = vfreet;
44439397Smckusick 	}
445*39433Smckusick 	vp->v_freef = NULL;
446*39433Smckusick 	vfreet = &vp->v_freef;
447*39433Smckusick 	VOP_INACTIVE(vp);
44839397Smckusick }
449*39433Smckusick 
450*39433Smckusick /*
451*39433Smckusick  * Disassociate the underlying file system from a vnode.
452*39433Smckusick  * If this operation is done on an active vnode (i.e. v_count > 0)
453*39433Smckusick  * then the vnode must be delivered locked.
454*39433Smckusick  */
455*39433Smckusick void vclean(vp)
456*39433Smckusick 	register struct vnode *vp;
457*39433Smckusick {
458*39433Smckusick 	struct vnodeops *origops;
459*39433Smckusick 
460*39433Smckusick 	while (vp->v_flag & VXLOCK) {
461*39433Smckusick 		vp->v_flag |= VXWANT;
462*39433Smckusick 		sleep((caddr_t)vp, PINOD);
463*39433Smckusick 	}
464*39433Smckusick 	vp->v_flag |= VXLOCK;
465*39433Smckusick 	/*
466*39433Smckusick 	 * Prevent any further operations on the vnode from
467*39433Smckusick 	 * being passed through to the old file system.
468*39433Smckusick 	 */
469*39433Smckusick 	origops = vp->v_op;
470*39433Smckusick 	vp->v_op = &dead_vnodeops;
471*39433Smckusick 	vp->v_tag = VT_NON;
472*39433Smckusick 	/*
473*39433Smckusick 	 * If purging an active vnode, it must be unlocked and
474*39433Smckusick 	 * deactivated before being reclaimed.
475*39433Smckusick 	 */
476*39433Smckusick 	if (vp->v_count > 0) {
477*39433Smckusick 		(*(origops->vn_unlock))(vp);
478*39433Smckusick 		(*(origops->vn_inactive))(vp);
479*39433Smckusick 	}
480*39433Smckusick 	/*
481*39433Smckusick 	 * Reclaim the vnode.
482*39433Smckusick 	 */
483*39433Smckusick 	if ((*(origops->vn_reclaim))(vp))
484*39433Smckusick 		panic("vclean: cannot reclaim");
485*39433Smckusick 	/*
486*39433Smckusick 	 * Done with purge, notify sleepers in vget of the grim news.
487*39433Smckusick 	 */
488*39433Smckusick 	vp->v_flag &= ~VXLOCK;
489*39433Smckusick 	if (vp->v_flag & VXWANT) {
490*39433Smckusick 		vp->v_flag &= ~VXWANT;
491*39433Smckusick 		wakeup((caddr_t)vp);
492*39433Smckusick 	}
493*39433Smckusick }
494*39433Smckusick 
495*39433Smckusick /*
496*39433Smckusick  * Eliminate all activity associated with a vnode
497*39433Smckusick  * in preparation for reuse.
498*39433Smckusick  */
499*39433Smckusick void vgone(vp)
500*39433Smckusick 	register struct vnode *vp;
501*39433Smckusick {
502*39433Smckusick 	register struct speclist *slp;
503*39433Smckusick 	struct speclist *pslp;
504*39433Smckusick 	register struct vnode *vq;
505*39433Smckusick 
506*39433Smckusick 	if (vp->v_count > 0)
507*39433Smckusick 		panic("vgone: cannot reclaim");
508*39433Smckusick 	/*
509*39433Smckusick 	 * Clean out the filesystem specific data.
510*39433Smckusick 	 */
511*39433Smckusick 	vclean(vp);
512*39433Smckusick 	/*
513*39433Smckusick 	 * Delete from old mount point vnode list, if on one.
514*39433Smckusick 	 */
515*39433Smckusick 	if (vp->v_mountb) {
516*39433Smckusick 		if (vq = vp->v_mountf)
517*39433Smckusick 			vq->v_mountb = vp->v_mountb;
518*39433Smckusick 		*vp->v_mountb = vq;
519*39433Smckusick 		vp->v_mountf = NULL;
520*39433Smckusick 		vp->v_mountb = NULL;
521*39433Smckusick 	}
522*39433Smckusick 	/*
523*39433Smckusick 	 * If special device, remove it from special device alias list.
524*39433Smckusick 	 */
525*39433Smckusick 	if (vp->v_type == VBLK || vp->v_type == VCHR) {
526*39433Smckusick 		if (speclisth->sl_vp == vp) {
527*39433Smckusick 			slp = speclisth;
528*39433Smckusick 			speclisth = slp->sl_next;
529*39433Smckusick 		} else {
530*39433Smckusick 			for (slp = speclisth; slp;
531*39433Smckusick 			     pslp = slp, slp = slp->sl_next) {
532*39433Smckusick 				if (slp->sl_vp != vp)
533*39433Smckusick 					continue;
534*39433Smckusick 				pslp->sl_next = slp->sl_next;
535*39433Smckusick 				break;
536*39433Smckusick 			}
537*39433Smckusick 			if (slp == NULL)
538*39433Smckusick 				panic("missing bdev");
539*39433Smckusick 		}
540*39433Smckusick 		FREE(slp, M_VNODE);
541*39433Smckusick 	}
542*39433Smckusick 	/*
543*39433Smckusick 	 * If it is on the freelist, move it to the head of the list.
544*39433Smckusick 	 */
545*39433Smckusick 	if (vp->v_freeb) {
546*39433Smckusick 		if (vq = vp->v_freef)
547*39433Smckusick 			vq->v_freeb = vp->v_freeb;
548*39433Smckusick 		else
549*39433Smckusick 			vfreet = vp->v_freeb;
550*39433Smckusick 		*vp->v_freeb = vq;
551*39433Smckusick 		vp->v_freef = vfreeh;
552*39433Smckusick 		vp->v_freeb = &vfreeh;
553*39433Smckusick 		vfreeh->v_freeb = &vp->v_freef;
554*39433Smckusick 		vfreeh = vp;
555*39433Smckusick 	}
556*39433Smckusick 	vp->v_type = VNON;
557*39433Smckusick }
558