vn.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 686 行 · 第 1/2 页
C
686 行
/* * Copyright (c) 1988 University of Utah. * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * 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. * * from: Utah Hdr: vn.c 1.13 94/04/02 * * from: @(#)vn.c 8.6 (Berkeley) 4/1/94 * $Id: vn.c,v 1.71.2.1 1999/03/13 00:32:36 julian Exp $ *//* * Vnode disk driver. * * Block/character interface to a vnode. Allows one to treat a file * as a disk (e.g. build a filesystem in it, mount it, etc.). * * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode * instead of a simple VOP_RDWR. We do this to avoid distorting the * local buffer cache. * * NOTE 2: There is a security issue involved with this driver. * Once mounted all access to the contents of the "mapped" file via * the special file is controlled by the permissions on the special * file, the protection of the mapped file is ignored (effectively, * by using root credentials in all transactions). * * NOTE 3: Doesn't interact with leases, should it? */#include "vn.h"#if NVN > 0/* default is to have 8 VN's */#if NVN < 8#undef NVN#define NVN 8#endif#include "opt_devfs.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/namei.h>#include <sys/proc.h>#include <sys/buf.h>#include <sys/malloc.h>#include <sys/mount.h>#include <sys/vnode.h>#include <sys/fcntl.h>#include <sys/disklabel.h>#include <sys/diskslice.h>#include <sys/stat.h>#include <sys/conf.h>#ifdef DEVFS#include <sys/devfsext.h>#endif /*DEVFS*/#include <miscfs/specfs/specdev.h>#include <sys/vnioctl.h>static d_ioctl_t vnioctl;static d_open_t vnopen;static d_read_t vnread;static d_write_t vnwrite;static d_close_t vnclose;static d_dump_t vndump;static d_psize_t vnsize;static d_strategy_t vnstrategy;#define CDEV_MAJOR 43#define BDEV_MAJOR 15static struct cdevsw vn_cdevsw = { vnopen, vnclose, vnread, vnwrite, vnioctl, nostop, nullreset, nodevtotty, seltrue, nommap, vnstrategy, "vn", NULL, -1, vndump, vnsize, D_DISK|D_NOCLUSTERRW, 0, -1 };#define vnunit(dev) dkunit(dev)#define getvnbuf() \ ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))#define putvnbuf(bp) \ free((caddr_t)(bp), M_DEVBUF)struct vn_softc { int sc_flags; /* flags */ size_t sc_size; /* size of vn */ struct diskslices *sc_slices; struct vnode *sc_vp; /* vnode */ struct ucred *sc_cred; /* credentials */ int sc_maxactive; /* max # of active requests */ struct buf sc_tab; /* transfer queue */ u_long sc_options; /* options */#ifdef DEVFS void *r_devfs_token; void *devfs_token;#endif};/* sc_flags */#define VNF_INITED 0x01static struct vn_softc *vn_softc[NVN];static u_long vn_options;#define IFOPT(vn,opt) if (((vn)->sc_options|vn_options) & (opt))static void vniodone (struct buf *bp);static int vnsetcred (struct vn_softc *vn, struct ucred *cred);static void vnshutdown (int, void *);static void vnclear (struct vn_softc *vn);static intvnclose(dev_t dev, int flags, int mode, struct proc *p){ struct vn_softc *vn = vn_softc[vnunit(dev)]; IFOPT(vn, VN_LABELS) if (vn->sc_slices != NULL) dsclose(dev, mode, vn->sc_slices); return (0);}static intvnopen(dev_t dev, int flags, int mode, struct proc *p){ int unit = vnunit(dev); struct vn_softc *vn; if (unit >= NVN) { if (vn_options & VN_FOLLOW) printf("vnopen(0x%lx, 0x%x, 0x%x, %p)\n", (u_long)dev, flags, mode, (void *)p); return(ENOENT); } vn = vn_softc[unit]; if (!vn) { vn = malloc(sizeof *vn, M_DEVBUF, M_WAITOK); if (!vn) return (ENOMEM); bzero(vn, sizeof *vn); vn_softc[unit] = vn; } IFOPT(vn, VN_FOLLOW) printf("vnopen(0x%lx, 0x%x, 0x%x, %p)\n", (u_long)dev, flags, mode, (void *)p); IFOPT(vn, VN_LABELS) { if (vn->sc_flags & VNF_INITED) { struct disklabel label; /* Build label for whole disk. */ bzero(&label, sizeof label); label.d_secsize = DEV_BSIZE; label.d_nsectors = 32; label.d_ntracks = 64; label.d_ncylinders = vn->sc_size / (32 * 64); label.d_secpercyl = 32 * 64; label.d_secperunit = label.d_partitions[RAW_PART].p_size = vn->sc_size; return (dsopen("vn", dev, mode, 0, &vn->sc_slices, &label, vnstrategy, (ds_setgeom_t *)NULL, &vn_cdevsw)); } if (dkslice(dev) != WHOLE_DISK_SLICE || dkpart(dev) != RAW_PART || mode != S_IFCHR) return (ENXIO); } return(0);}static intvnread(dev_t dev, struct uio *uio, int ioflag){ return (physio(vnstrategy, NULL, dev, 1, minphys, uio));}static intvnwrite(dev_t dev, struct uio *uio, int ioflag){ return (physio(vnstrategy, NULL, dev, 0, minphys, uio));}/* * this code does I/O calls through the appropriate VOP entry point... * unless a swap_pager I/O request is being done. This strategy (-)) * allows for coherency with mmap except in the case of paging. This * is necessary, because the VOP calls use lots of memory (and actually * are not extremely efficient -- but we want to keep semantics correct), * and the pageout daemon gets really unhappy (and so does the rest of the * system) when it runs out of memory. */static voidvnstrategy(struct buf *bp){ int unit = vnunit(bp->b_dev); register struct vn_softc *vn = vn_softc[unit]; register daddr_t bn; int error; int isvplocked = 0; long sz; struct uio auio; struct iovec aiov; IFOPT(vn, VN_DEBUG) printf("vnstrategy(%p): unit %d\n", bp, unit); if ((vn->sc_flags & VNF_INITED) == 0) { bp->b_error = ENXIO; bp->b_flags |= B_ERROR; biodone(bp); return; } IFOPT(vn, VN_LABELS) { bp->b_resid = bp->b_bcount;/* XXX best place to set this? */ if (vn->sc_slices != NULL && dscheck(bp, vn->sc_slices) <= 0) { biodone(bp); return; } bn = bp->b_pblkno; bp->b_resid = bp->b_bcount;/* XXX best place to set this? */ } else { bn = bp->b_blkno; sz = howmany(bp->b_bcount, DEV_BSIZE); bp->b_resid = bp->b_bcount; if (bn < 0 || bn + sz > vn->sc_size) { if (bn != vn->sc_size) { bp->b_error = EINVAL; bp->b_flags |= B_ERROR; } biodone(bp); return; } } if( (bp->b_flags & B_PAGING) == 0) { aiov.iov_base = bp->b_data; aiov.iov_len = bp->b_bcount; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = dbtob(bn); auio.uio_segflg = UIO_SYSSPACE; if( bp->b_flags & B_READ) auio.uio_rw = UIO_READ; else auio.uio_rw = UIO_WRITE; auio.uio_resid = bp->b_bcount; auio.uio_procp = curproc; if (!VOP_ISLOCKED(vn->sc_vp)) { isvplocked = 1; vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, curproc); } if( bp->b_flags & B_READ) error = VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred); else error = VOP_WRITE(vn->sc_vp, &auio, 0, vn->sc_cred); if (isvplocked) { VOP_UNLOCK(vn->sc_vp, 0, curproc); isvplocked = 0; } bp->b_resid = auio.uio_resid; if( error ) bp->b_flags |= B_ERROR; biodone(bp); } else { long bsize, resid; off_t byten; int flags; caddr_t addr; struct buf *nbp; nbp = getvnbuf(); bzero(nbp, sizeof(struct buf)); LIST_INIT(&nbp->b_dep); byten = dbtob(bn); bsize = vn->sc_vp->v_mount->mnt_stat.f_iosize; addr = bp->b_data; flags = bp->b_flags | B_CALL; for (resid = bp->b_resid; resid; ) { struct vnode *vp; daddr_t nbn; int off, s, nra; nra = 0; if (!VOP_ISLOCKED(vn->sc_vp)) { isvplocked = 1; vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, curproc); } error = VOP_BMAP(vn->sc_vp, (daddr_t)(byten / bsize), &vp, &nbn, &nra, NULL); if (isvplocked) { VOP_UNLOCK(vn->sc_vp, 0, curproc); isvplocked = 0; } if (error == 0 && nbn == -1) error = EIO; IFOPT(vn, VN_DONTCLUSTER) nra = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?