📄 vfs_subr.c
字号:
/* * 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/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 <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,};/* * 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 *//* * Initialize the vnode management data structures. */vntblinit(){ TAILQ_INIT(&vnode_free_list); TAILQ_INIT(&mountlist);}/* * Lock a filesystem. * Used to prevent access to it while mounting and unmounting. */vfs_lock(mp) register struct mount *mp;{ while(mp->mnt_flag & MNT_MLOCK) { mp->mnt_flag |= MNT_MWAIT; sleep((caddr_t)mp, PVFS); } 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. */vfs_busy(mp) register struct mount *mp;{ while(mp->mnt_flag & MNT_MPBUSY) { mp->mnt_flag |= MNT_MPWANT; sleep((caddr_t)&mp->mnt_flag, PVFS); } 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. */vfs_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.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_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 + mtype, 0); mp->mnt_stat.f_fsid.val[1] = mtype; if (xxxfs_mntid == 0) ++xxxfs_mntid; tfsid.val[0] = makedev(nblkdev + mtype, xxxfs_mntid); tfsid.val[1] = mtype; if (mountlist.tqh_first != NULL) { while (getvfs(&tfsid)) { tfsid.val[0]++; xxxfs_mntid++; } } mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];}/* * Set vnode attributes to VNOVAL */void vattr_null(vap) register struct vattr *vap;{ vap->va_type = VNON; vap->va_size = 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.ts_sec = vap->va_atime.ts_nsec = vap->va_mtime.ts_sec = vap->va_mtime.ts_nsec = vap->va_ctime.ts_sec = vap->va_ctime.ts_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)();extern void vclean();long numvnodes;extern struct vattr va_null;/* * Return the next vnode from the free list. */getnewvnode(tag, mp, vops, vpp) enum vtagtype tag; struct mount *mp; int (**vops)(); struct vnode **vpp;{ register struct vnode *vp; int s; 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) 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) 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. */insmntque(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. */vwakeup(bp) register struct buf *bp;{ register struct vnode *vp; bp->b_flags &= ~B_WRITEINPROG; if (vp = bp->b_vp) { vp->v_numoutput--; if (vp->v_numoutput < 0) panic("vwakeup: neg numoutput"); if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) { if (vp->v_numoutput < 0) panic("vwakeup: neg numoutput"); 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)) 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);}/* * Associate a buffer with a vnode. */bgetvp(vp, bp) register struct vnode *vp; register struct buf *bp;{ if (bp->b_vp) panic("bgetvp: not free"); VHOLD(vp); bp->b_vp = vp; if (vp->v_type == VBLK || vp->v_type == VCHR) bp->b_dev = vp->v_rdev; else bp->b_dev = NODEV; /* * Insert onto list for new vnode. */ bufinsvn(bp, &vp->v_cleanblkhd);}/* * Disassociate a buffer from a vnode. */brelvp(bp) register struct buf *bp;{ struct vnode *vp; if (bp->b_vp == (struct vnode *) 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -