vfs_subr.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,613 行 · 第 1/3 页

C
1,613
字号
/*	$NetBSD: vfs_subr.c,v 1.53 1996/04/22 01:39:13 christos Exp $	*//* * Copyright (c) 1989, 1993 *	The Regents of the University of California.  All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)vfs_subr.c	8.13 (Berkeley) 4/18/94 *//* * External virtual filesystem routines */#include <sys/param.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/mount.h>#include <sys/time.h>#include <sys/fcntl.h>#include <sys/vnode.h>#include <sys/stat.h>#include <sys/namei.h>#include <sys/ucred.h>#include <sys/buf.h>#include <sys/errno.h>#include <sys/malloc.h>#include <sys/domain.h>#include <sys/mbuf.h>#include <sys/syscallargs.h>#include <vm/vm.h>#include <sys/sysctl.h>#include <miscfs/specfs/specdev.h>enum vtype iftovt_tab[16] = {	VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,	VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,};int	vttoif_tab[9] = {	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,	S_IFSOCK, S_IFIFO, S_IFMT,};int doforce = 1;		/* 1 => permit forcible unmounting */int prtactive = 0;		/* 1 => print out reclaim of active vnodes *//* * Insq/Remq for the vnode usage lists. */#define	bufinsvn(bp, dp)	LIST_INSERT_HEAD(dp, bp, b_vnbufs)#define	bufremvn(bp) {							\	LIST_REMOVE(bp, b_vnbufs);					\	(bp)->b_vnbufs.le_next = NOLIST;				\}  TAILQ_HEAD(freelst, vnode) vnode_free_list;	/* vnode free list */struct mntlist mountlist;			/* mounted filesystem list */int vfs_lock __P((struct mount *));void vfs_unlock __P((struct mount *));struct mount *getvfs __P((fsid_t *));long makefstype __P((char *));void vattr_null __P((struct vattr *));int getnewvnode __P((enum vtagtype, struct mount *, int (**)(void *),		     struct vnode **));void insmntque __P((struct vnode *, struct mount *));int vinvalbuf __P((struct vnode *, int, struct ucred *, struct proc *, int,		   int));void vflushbuf __P((struct vnode *, int));void brelvp __P((struct buf *));int bdevvp __P((dev_t, struct vnode **));int cdevvp __P((dev_t, struct vnode **));int getdevvp __P((dev_t, struct vnode **, enum vtype));struct vnode *checkalias __P((struct vnode *, dev_t, struct mount *));int vget __P((struct vnode *, int));void vref __P((struct vnode *));void vput __P((struct vnode *));void vrele __P((struct vnode *));void vhold __P((struct vnode *));void holdrele __P((struct vnode *));int vflush __P((struct mount *, struct vnode *, int));void vgoneall __P((struct vnode *));void vgone __P((struct vnode *));int vcount __P((struct vnode *));void vprint __P((char *, struct vnode *));int vfs_mountedon __P((struct vnode *));int vfs_export __P((struct mount *, struct netexport *, struct export_args *));struct netcred *vfs_export_lookup __P((struct mount *, struct netexport *,				       struct mbuf *));int vaccess __P((mode_t, uid_t, gid_t, mode_t, struct ucred *));void vfs_unmountall __P((void));void vfs_shutdown __P((void));static int vfs_hang_addrlist __P((struct mount *, struct netexport *,				  struct export_args *));static int vfs_free_netcred __P((struct radix_node *, void *));static void vfs_free_addrlist __P((struct netexport *));#ifdef DEBUGvoid printlockedvnodes __P((void));#endif/* * Initialize the vnode management data structures. */voidvntblinit(){	TAILQ_INIT(&vnode_free_list);	CIRCLEQ_INIT(&mountlist);}/* * Lock a filesystem. * Used to prevent access to it while mounting and unmounting. */intvfs_lock(mp)	register struct mount *mp;{	while (mp->mnt_flag & MNT_MLOCK) {		mp->mnt_flag |= MNT_MWAIT;		tsleep((caddr_t)mp, PVFS, "vfslock", 0);	}	mp->mnt_flag |= MNT_MLOCK;	return (0);}/* * Unlock a locked filesystem. * Panic if filesystem is not locked. */voidvfs_unlock(mp)	register struct mount *mp;{	if ((mp->mnt_flag & MNT_MLOCK) == 0)		panic("vfs_unlock: not locked");	mp->mnt_flag &= ~MNT_MLOCK;	if (mp->mnt_flag & MNT_MWAIT) {		mp->mnt_flag &= ~MNT_MWAIT;		wakeup((caddr_t)mp);	}}/* * Mark a mount point as busy. * Used to synchronize access and to delay unmounting. */intvfs_busy(mp)	register struct mount *mp;{	while(mp->mnt_flag & MNT_MPBUSY) {		mp->mnt_flag |= MNT_MPWANT;		tsleep((caddr_t)&mp->mnt_flag, PVFS, "vfsbusy", 0);	}	if (mp->mnt_flag & MNT_UNMOUNT)		return (1);	mp->mnt_flag |= MNT_MPBUSY;	return (0);}/* * Free a busy filesystem. * Panic if filesystem is not busy. */voidvfs_unbusy(mp)	register struct mount *mp;{	if ((mp->mnt_flag & MNT_MPBUSY) == 0)		panic("vfs_unbusy: not busy");	mp->mnt_flag &= ~MNT_MPBUSY;	if (mp->mnt_flag & MNT_MPWANT) {		mp->mnt_flag &= ~MNT_MPWANT;		wakeup((caddr_t)&mp->mnt_flag);	}}/* * Lookup a mount point by filesystem identifier. */struct mount *getvfs(fsid)	fsid_t *fsid;{	register struct mount *mp;	for (mp = mountlist.cqh_first; mp != (void *)&mountlist;	     mp = mp->mnt_list.cqe_next)		if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&		    mp->mnt_stat.f_fsid.val[1] == fsid->val[1])			return (mp);	return ((struct mount *)0);}/* * Get a new unique fsid */voidgetnewfsid(mp, mtype)	struct mount *mp;	int mtype;{	static u_short xxxfs_mntid;	fsid_t tfsid;	mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + 11, 0);	/* XXX */	mp->mnt_stat.f_fsid.val[1] = mtype;	if (xxxfs_mntid == 0)		++xxxfs_mntid;	tfsid.val[0] = makedev((nblkdev + mtype) & 0xff, xxxfs_mntid);	tfsid.val[1] = mtype;	if (mountlist.cqh_first != (void *)&mountlist) {		while (getvfs(&tfsid)) {			tfsid.val[0]++;			xxxfs_mntid++;		}	}	mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];}/* * Make a 'unique' number from a mount type name. */longmakefstype(type)	char *type;{	long rv;	for (rv = 0; *type; type++) {		rv <<= 2;		rv ^= *type;	}	return rv;}/* * Set vnode attributes to VNOVAL */voidvattr_null(vap)	register struct vattr *vap;{	vap->va_type = VNON;	/* XXX These next two used to be one line, but for a GCC bug. */	vap->va_size = VNOVAL;	vap->va_bytes = VNOVAL;	vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =		vap->va_fsid = vap->va_fileid =		vap->va_blocksize = vap->va_rdev =		vap->va_atime.tv_sec = vap->va_atime.tv_nsec =		vap->va_mtime.tv_sec = vap->va_mtime.tv_nsec =		vap->va_ctime.tv_sec = vap->va_ctime.tv_nsec =		vap->va_flags = vap->va_gen = VNOVAL;	vap->va_vaflags = 0;}/* * Routines having to do with the management of the vnode table. */extern int (**dead_vnodeop_p) __P((void *));long numvnodes;/* * Return the next vnode from the free list. */intgetnewvnode(tag, mp, vops, vpp)	enum vtagtype tag;	struct mount *mp;	int (**vops) __P((void *));	struct vnode **vpp;{	register struct vnode *vp;#ifdef DIAGNOSTIC	int s;#endif	if ((vnode_free_list.tqh_first == NULL &&	     numvnodes < 2 * desiredvnodes) ||	    numvnodes < desiredvnodes) {		vp = (struct vnode *)malloc((u_long)sizeof *vp,		    M_VNODE, M_WAITOK);		bzero((char *)vp, sizeof *vp);		numvnodes++;	} else {		if ((vp = vnode_free_list.tqh_first) == NULL) {			tablefull("vnode");			*vpp = 0;			return (ENFILE);		}		if (vp->v_usecount) {			vprint("free vnode", vp);			panic("free vnode isn't");		}		TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);		/* see comment on why 0xdeadb is set at end of vgone (below) */		vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb;		vp->v_lease = NULL;		if (vp->v_type != VBAD)			vgone(vp);#ifdef DIAGNOSTIC		if (vp->v_data) {			vprint("cleaned vnode", vp);			panic("cleaned vnode isn't");		}		s = splbio();		if (vp->v_numoutput)			panic("Clean vnode has pending I/O's");		splx(s);#endif		vp->v_flag = 0;		vp->v_lastr = 0;		vp->v_ralen = 0;		vp->v_maxra = 0;		vp->v_lastw = 0;		vp->v_lasta = 0;		vp->v_cstart = 0;		vp->v_clen = 0;		vp->v_socket = 0;	}	vp->v_type = VNON;	cache_purge(vp);	vp->v_tag = tag;	vp->v_op = vops;	insmntque(vp, mp);	*vpp = vp;	vp->v_usecount = 1;	vp->v_data = 0;	return (0);}/* * Move a vnode from one mount queue to another. */voidinsmntque(vp, mp)	register struct vnode *vp;	register struct mount *mp;{	/*	 * Delete from old mount point vnode list, if on one.	 */	if (vp->v_mount != NULL)		LIST_REMOVE(vp, v_mntvnodes);	/*	 * Insert into list of vnodes for the new mount point, if available.	 */	if ((vp->v_mount = mp) == NULL)		return;	LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes);}/* * Update outstanding I/O count and do wakeup if requested. */voidvwakeup(bp)	register struct buf *bp;{	register struct vnode *vp;	bp->b_flags &= ~B_WRITEINPROG;	if ((vp = bp->b_vp) != NULL) {		if (--vp->v_numoutput < 0)			panic("vwakeup: neg numoutput");		if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {			vp->v_flag &= ~VBWAIT;			wakeup((caddr_t)&vp->v_numoutput);		}	}}/* * Flush out and invalidate all buffers associated with a vnode. * Called with the underlying object locked. */intvinvalbuf(vp, flags, cred, p, slpflag, slptimeo)	register struct vnode *vp;	int flags;	struct ucred *cred;	struct proc *p;	int slpflag, slptimeo;{	register struct buf *bp;	struct buf *nbp, *blist;	int s, error;	if (flags & V_SAVE) {		if ((error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) != 0)			return (error);		if (vp->v_dirtyblkhd.lh_first != NULL)			panic("vinvalbuf: dirty bufs");	}	for (;;) {		if ((blist = vp->v_cleanblkhd.lh_first) && flags & V_SAVEMETA)			while (blist && blist->b_lblkno < 0)				blist = blist->b_vnbufs.le_next;		if (!blist && (blist = vp->v_dirtyblkhd.lh_first) &&		    (flags & V_SAVEMETA))			while (blist && blist->b_lblkno < 0)				blist = blist->b_vnbufs.le_next;		if (!blist)			break;		for (bp = blist; bp; bp = nbp) {			nbp = bp->b_vnbufs.le_next;			if (flags & V_SAVEMETA && bp->b_lblkno < 0)				continue;			s = splbio();			if (bp->b_flags & B_BUSY) {				bp->b_flags |= B_WANTED;				error = tsleep((caddr_t)bp,					slpflag | (PRIBIO + 1), "vinvalbuf",					slptimeo);				splx(s);				if (error)					return (error);				break;			}			bremfree(bp);			bp->b_flags |= B_BUSY;			splx(s);			/*			 * XXX Since there are no node locks for NFS, I believe			 * there is a slight chance that a delayed write will			 * occur while sleeping just above, so check for it.			 */			if ((bp->b_flags & B_DELWRI) && (flags & V_SAVE)) {				(void) VOP_BWRITE(bp);				break;			}			bp->b_flags |= B_INVAL;			brelse(bp);		}	}	if (!(flags & V_SAVEMETA) &&	    (vp->v_dirtyblkhd.lh_first || vp->v_cleanblkhd.lh_first))		panic("vinvalbuf: flush failed");	return (0);}voidvflushbuf(vp, sync)	register struct vnode *vp;	int sync;{	register struct buf *bp, *nbp;	int s;loop:	s = splbio();	for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {		nbp = bp->b_vnbufs.le_next;		if ((bp->b_flags & B_BUSY))			continue;		if ((bp->b_flags & B_DELWRI) == 0)			panic("vflushbuf: not dirty");		bremfree(bp);		bp->b_flags |= B_BUSY;		splx(s);		/*		 * Wait for I/O associated with indirect blocks to complete,		 * since there is no way to quickly wait for them below.		 */		if (bp->b_vp == vp || sync == 0)			(void) bawrite(bp);		else			(void) bwrite(bp);		goto loop;	}	if (sync == 0) {		splx(s);		return;	}	while (vp->v_numoutput) {		vp->v_flag |= VBWAIT;		tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "vflushbuf", 0);	}	splx(s);	if (vp->v_dirtyblkhd.lh_first != NULL) {		vprint("vflushbuf: dirty", vp);		goto loop;	}}/* * Associate a buffer with a vnode. */voidbgetvp(vp, bp)	register struct vnode *vp;	register struct buf *bp;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?