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