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 + -
显示快捷键?