xref: /csrg-svn/sys/kern/vfs_subr.c (revision 39397)
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*39397Smckusick  *	@(#)vfs_subr.c	7.8 (Berkeley) 10/24/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"
3137488Smckusick 
3237488Smckusick /*
3337488Smckusick  * Remove a mount point from the list of mounted filesystems.
3437488Smckusick  * Unmount of the root is illegal.
3537488Smckusick  */
3637488Smckusick void
3737488Smckusick vfs_remove(mp)
3837488Smckusick 	register struct mount *mp;
3937488Smckusick {
4037488Smckusick 
4137488Smckusick 	if (mp == rootfs)
4237488Smckusick 		panic("vfs_remove: unmounting root");
4337488Smckusick 	mp->m_prev->m_next = mp->m_next;
4437488Smckusick 	mp->m_next->m_prev = mp->m_prev;
4537488Smckusick 	mp->m_vnodecovered->v_mountedhere = (struct mount *)0;
4637488Smckusick 	vfs_unlock(mp);
4737488Smckusick }
4837488Smckusick 
4937488Smckusick /*
5037488Smckusick  * Lock a filesystem.
5137488Smckusick  * Used to prevent access to it while mounting and unmounting.
5237488Smckusick  */
5337488Smckusick vfs_lock(mp)
5437488Smckusick 	register struct mount *mp;
5537488Smckusick {
5637488Smckusick 
5739045Smckusick 	while(mp->m_flag & M_MLOCK) {
5839045Smckusick 		mp->m_flag |= M_MWAIT;
5939045Smckusick 		sleep((caddr_t)mp, PVFS);
6039045Smckusick 	}
6137488Smckusick 	mp->m_flag |= M_MLOCK;
6237488Smckusick 	return (0);
6337488Smckusick }
6437488Smckusick 
6537488Smckusick /*
6637488Smckusick  * Unlock a locked filesystem.
6737488Smckusick  * Panic if filesystem is not locked.
6837488Smckusick  */
6937488Smckusick void
7037488Smckusick vfs_unlock(mp)
7137488Smckusick 	register struct mount *mp;
7237488Smckusick {
7337488Smckusick 
7437488Smckusick 	if ((mp->m_flag & M_MLOCK) == 0)
7537488Smckusick 		panic("vfs_unlock: locked fs");
7637488Smckusick 	mp->m_flag &= ~M_MLOCK;
7737488Smckusick 	if (mp->m_flag & M_MWAIT) {
7837488Smckusick 		mp->m_flag &= ~M_MWAIT;
7937488Smckusick 		wakeup((caddr_t)mp);
8037488Smckusick 	}
8137488Smckusick }
8237488Smckusick 
8337488Smckusick /*
8437488Smckusick  * Lookup a mount point by filesystem identifier.
8537488Smckusick  */
8637488Smckusick struct mount *
8737488Smckusick getvfs(fsid)
8837488Smckusick 	fsid_t *fsid;
8937488Smckusick {
9037488Smckusick 	register struct mount *mp;
9137488Smckusick 
9238288Smckusick 	mp = rootfs;
9338288Smckusick 	do {
9437488Smckusick 		if (mp->m_fsid.val[0] == fsid->val[0] &&
9537488Smckusick 		    mp->m_fsid.val[1] == fsid->val[1]) {
9638288Smckusick 			return (mp);
9737488Smckusick 		}
9838288Smckusick 		mp = mp->m_next;
9938288Smckusick 	} while (mp != rootfs);
10038288Smckusick 	return ((struct mount *)0);
10137488Smckusick }
10237488Smckusick 
10337488Smckusick /*
10437488Smckusick  * Set vnode attributes to VNOVAL
10537488Smckusick  */
10637488Smckusick void vattr_null(vap)
10737488Smckusick 	register struct vattr *vap;
10837488Smckusick {
10937488Smckusick 
11037488Smckusick 	vap->va_type = VNON;
11137488Smckusick 	vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
11237488Smckusick 		vap->va_fsid = vap->va_fileid = vap->va_size =
11337488Smckusick 		vap->va_size1 = vap->va_blocksize = vap->va_rdev =
11437488Smckusick 		vap->va_bytes = vap->va_bytes1 =
11537488Smckusick 		vap->va_atime.tv_sec = vap->va_atime.tv_usec =
11637488Smckusick 		vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
11738258Smckusick 		vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
11838258Smckusick 		vap->va_flags = vap->va_gen = VNOVAL;
11937488Smckusick }
12038265Smckusick 
12138265Smckusick /*
12238265Smckusick  * Initialize a nameidata structure
12338265Smckusick  */
12438265Smckusick ndinit(ndp)
12538265Smckusick 	register struct nameidata *ndp;
12638265Smckusick {
12738265Smckusick 
12838265Smckusick 	bzero((caddr_t)ndp, sizeof(struct nameidata));
12938265Smckusick 	ndp->ni_iov = &ndp->ni_nd.nd_iovec;
13038265Smckusick 	ndp->ni_iovcnt = 1;
13138265Smckusick 	ndp->ni_base = (caddr_t)&ndp->ni_dent;
13238265Smckusick 	ndp->ni_rw = UIO_WRITE;
13338265Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
13438265Smckusick }
13538265Smckusick 
13638265Smckusick /*
13738265Smckusick  * Duplicate a nameidata structure
13838265Smckusick  */
13938265Smckusick nddup(ndp, newndp)
14038265Smckusick 	register struct nameidata *ndp, *newndp;
14138265Smckusick {
14238265Smckusick 
14338265Smckusick 	ndinit(newndp);
14438265Smckusick 	newndp->ni_cdir = ndp->ni_cdir;
14538348Smckusick 	VREF(newndp->ni_cdir);
14638265Smckusick 	newndp->ni_rdir = ndp->ni_rdir;
14738265Smckusick 	if (newndp->ni_rdir)
14838348Smckusick 		VREF(newndp->ni_rdir);
14938265Smckusick 	newndp->ni_cred = ndp->ni_cred;
15038265Smckusick 	crhold(newndp->ni_cred);
15138265Smckusick }
15238265Smckusick 
15338265Smckusick /*
15438265Smckusick  * Release a nameidata structure
15538265Smckusick  */
15638265Smckusick ndrele(ndp)
15738265Smckusick 	register struct nameidata *ndp;
15838265Smckusick {
15938265Smckusick 
16038265Smckusick 	vrele(ndp->ni_cdir);
16138265Smckusick 	if (ndp->ni_rdir)
16238265Smckusick 		vrele(ndp->ni_rdir);
16338265Smckusick 	crfree(ndp->ni_cred);
16438265Smckusick }
165*39397Smckusick 
166*39397Smckusick /*
167*39397Smckusick  * Routines having to do with the management of the vnode table.
168*39397Smckusick  */
169*39397Smckusick struct vnode *vfreeh, **vfreet;
170*39397Smckusick extern struct vnodeops dead_vnodeops;
171*39397Smckusick 
172*39397Smckusick /*
173*39397Smckusick  * Build vnode free list.
174*39397Smckusick  */
175*39397Smckusick vhinit()
176*39397Smckusick {
177*39397Smckusick 	register struct vnode *vp = vnode;
178*39397Smckusick 
179*39397Smckusick 	vfreeh = vp;
180*39397Smckusick 	vfreet = &vp->v_freef;
181*39397Smckusick 	vp->v_freeb = &vfreeh;
182*39397Smckusick 	vp->v_op = &dead_vnodeops;
183*39397Smckusick 	for (vp++; vp < vnodeNVNODE; vp++) {
184*39397Smckusick 		*vfreet = vp;
185*39397Smckusick 		vp->v_freeb = vfreet;
186*39397Smckusick 		vfreet = &vp->v_freef;
187*39397Smckusick 		vp->v_op = &dead_vnodeops;
188*39397Smckusick 	}
189*39397Smckusick 	vp--;
190*39397Smckusick 	vp->v_freef = NULL;
191*39397Smckusick }
192*39397Smckusick 
193*39397Smckusick /*
194*39397Smckusick  * Return the next vnode from the free list.
195*39397Smckusick  */
196*39397Smckusick getnewvnode(tag, mp, vops, vpp)
197*39397Smckusick 	enum vtagtype tag;
198*39397Smckusick 	struct mount *mp;
199*39397Smckusick 	struct vnodeops *vops;
200*39397Smckusick 	struct vnode **vpp;
201*39397Smckusick {
202*39397Smckusick 	register struct vnode *vp, *vq;
203*39397Smckusick 
204*39397Smckusick 	if ((vp = vfreeh) == NULL) {
205*39397Smckusick 		tablefull("vnode");
206*39397Smckusick 		*vpp = 0;
207*39397Smckusick 		return (ENFILE);
208*39397Smckusick 	}
209*39397Smckusick 	if (vp->v_count || VOP_RECLAIM(vp))
210*39397Smckusick 		panic("free vnode isn't");
211*39397Smckusick 	if (vq = vp->v_freef)
212*39397Smckusick 		vq->v_freeb = &vfreeh;
213*39397Smckusick 	vfreeh = vq;
214*39397Smckusick 	vp->v_freef = NULL;
215*39397Smckusick 	vp->v_freeb = NULL;
216*39397Smckusick 	vp->v_type = VNON;
217*39397Smckusick 	vp->v_flag = 0;
218*39397Smckusick 	vp->v_shlockc = 0;
219*39397Smckusick 	vp->v_exlockc = 0;
220*39397Smckusick 	vp->v_socket = 0;
221*39397Smckusick 	vp->v_op = vops;
222*39397Smckusick 	cache_purge(vp);
223*39397Smckusick 	vp->v_tag = tag;
224*39397Smckusick 	vp->v_mount = mp;
225*39397Smckusick 	insmntque(vp, mp);
226*39397Smckusick 	VREF(vp);
227*39397Smckusick 	*vpp = vp;
228*39397Smckusick 	return (0);
229*39397Smckusick }
230*39397Smckusick 
231*39397Smckusick /*
232*39397Smckusick  * Move a vnode from one mount queue to another.
233*39397Smckusick  */
234*39397Smckusick insmntque(vp, mp)
235*39397Smckusick 	register struct vnode *vp;
236*39397Smckusick 	register struct mount *mp;
237*39397Smckusick {
238*39397Smckusick 	struct vnode *vq;
239*39397Smckusick 
240*39397Smckusick 	/*
241*39397Smckusick 	 * Delete from old mount point vnode list, if on one.
242*39397Smckusick 	 */
243*39397Smckusick 	if (vp->v_mountb) {
244*39397Smckusick 		if (vq = vp->v_mountf)
245*39397Smckusick 			vq->v_mountb = vp->v_mountb;
246*39397Smckusick 		*vp->v_mountb = vq;
247*39397Smckusick 	}
248*39397Smckusick 	/*
249*39397Smckusick 	 * Insert into list of vnodes for the new mount point, if available.
250*39397Smckusick 	 */
251*39397Smckusick 	if (mp == NULL) {
252*39397Smckusick 		vp->v_mountf = NULL;
253*39397Smckusick 		vp->v_mountb = NULL;
254*39397Smckusick 		return;
255*39397Smckusick 	}
256*39397Smckusick 	if (mp->m_mounth) {
257*39397Smckusick 		vp->v_mountf = mp->m_mounth;
258*39397Smckusick 		vp->v_mountb = &mp->m_mounth;
259*39397Smckusick 		mp->m_mounth->v_mountb = &vp->v_mountf;
260*39397Smckusick 		mp->m_mounth = vp;
261*39397Smckusick 	} else {
262*39397Smckusick 		mp->m_mounth = vp;
263*39397Smckusick 		vp->v_mountb = &mp->m_mounth;
264*39397Smckusick 		vp->v_mountf = NULL;
265*39397Smckusick 	}
266*39397Smckusick }
267*39397Smckusick 
268*39397Smckusick /*
269*39397Smckusick  * Grab a particular vnode from the free list.
270*39397Smckusick  */
271*39397Smckusick vget(vp)
272*39397Smckusick 	register struct vnode *vp;
273*39397Smckusick {
274*39397Smckusick 	register struct vnode *vq;
275*39397Smckusick 
276*39397Smckusick 	if (vq = vp->v_freef)
277*39397Smckusick 		vq->v_freeb = vp->v_freeb;
278*39397Smckusick 	else
279*39397Smckusick 		vfreet = vp->v_freeb;
280*39397Smckusick 	*vp->v_freeb = vq;
281*39397Smckusick 	vp->v_freef = NULL;
282*39397Smckusick 	vp->v_freeb = NULL;
283*39397Smckusick 	VREF(vp);
284*39397Smckusick }
285*39397Smckusick 
286*39397Smckusick /*
287*39397Smckusick  * Vnode reference, just increment the count
288*39397Smckusick  */
289*39397Smckusick void vref(vp)
290*39397Smckusick 	struct vnode *vp;
291*39397Smckusick {
292*39397Smckusick 
293*39397Smckusick 	vp->v_count++;
294*39397Smckusick }
295*39397Smckusick 
296*39397Smckusick /*
297*39397Smckusick  * vput(), just unlock and vrele()
298*39397Smckusick  */
299*39397Smckusick void vput(vp)
300*39397Smckusick 	register struct vnode *vp;
301*39397Smckusick {
302*39397Smckusick 	VOP_UNLOCK(vp);
303*39397Smckusick 	vrele(vp);
304*39397Smckusick }
305*39397Smckusick 
306*39397Smckusick /*
307*39397Smckusick  * Vnode release.
308*39397Smckusick  * If count drops to zero, call inactive routine and return to freelist.
309*39397Smckusick  */
310*39397Smckusick void vrele(vp)
311*39397Smckusick 	register struct vnode *vp;
312*39397Smckusick {
313*39397Smckusick 
314*39397Smckusick 	if (vp == NULL)
315*39397Smckusick 		return;
316*39397Smckusick 	vp->v_count--;
317*39397Smckusick 	if (vp->v_count < 0)
318*39397Smckusick 		printf("vnode bad ref count %d, type %d, tag %d\n",
319*39397Smckusick 			vp->v_count, vp->v_type, vp->v_tag);
320*39397Smckusick 	if (vp->v_count > 0)
321*39397Smckusick 		return;
322*39397Smckusick 	VOP_INACTIVE(vp);
323*39397Smckusick 	if (vfreeh == (struct vnode *)0) {
324*39397Smckusick 		/*
325*39397Smckusick 		 * insert into empty list
326*39397Smckusick 		 */
327*39397Smckusick 		vfreeh = vp;
328*39397Smckusick 		vp->v_freeb = &vfreeh;
329*39397Smckusick 		vp->v_freef = NULL;
330*39397Smckusick 		vfreet = &vp->v_freef;
331*39397Smckusick 	} else if (vp->v_type == VNON) {
332*39397Smckusick 		/*
333*39397Smckusick 		 * insert at head of list
334*39397Smckusick 		 */
335*39397Smckusick 		vp->v_freef = vfreeh;
336*39397Smckusick 		vp->v_freeb = &vfreeh;
337*39397Smckusick 		vfreeh->v_freeb = &vp->v_freef;
338*39397Smckusick 		vfreeh = vp;
339*39397Smckusick 	} else {
340*39397Smckusick 		/*
341*39397Smckusick 		 * insert at tail of list
342*39397Smckusick 		 */
343*39397Smckusick 		*vfreet = vp;
344*39397Smckusick 		vp->v_freeb = vfreet;
345*39397Smckusick 		vp->v_freef = NULL;
346*39397Smckusick 		vfreet = &vp->v_freef;
347*39397Smckusick 	}
348*39397Smckusick }
349