vn.c

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

C
686
字号
			off = byten % bsize;			if (off)				sz = bsize - off;			else				sz = (1 + nra) * bsize;			if (resid < sz)				sz = resid;			if (error) {				bp->b_resid -= (resid - sz);				bp->b_flags |= B_ERROR;				biodone(bp);				putvnbuf(nbp);				return;			}			IFOPT(vn,VN_IO)				printf(			/* XXX no %qx in kernel.  Synthesize it. */			"vnstrategy: vp %p/%p bn 0x%lx%08lx/0x%lx sz 0x%lx\n",				   (void *)vn->sc_vp, (void *)vp,				   (u_long)(byten >> 32), (u_long)byten,				   (u_long)nbn, sz);			nbp->b_flags = flags;			nbp->b_bcount = sz;			nbp->b_bufsize = sz;			nbp->b_error = 0;			if (vp->v_type == VBLK || vp->v_type == VCHR)				nbp->b_dev = vp->v_rdev;			else				nbp->b_dev = NODEV;			nbp->b_data = addr;			nbp->b_blkno = nbn + btodb(off);			nbp->b_offset = dbtob(nbn) + off;			nbp->b_proc = bp->b_proc;			nbp->b_iodone = vniodone;			nbp->b_vp = vp;			nbp->b_rcred = vn->sc_cred;	/* XXX crdup? */			nbp->b_wcred = vn->sc_cred;	/* XXX crdup? */			nbp->b_dirtyoff = bp->b_dirtyoff;			nbp->b_dirtyend = bp->b_dirtyend;			nbp->b_validoff = bp->b_validoff;			nbp->b_validend = bp->b_validend;			if ((nbp->b_flags & B_READ) == 0)				nbp->b_vp->v_numoutput++;			VOP_STRATEGY(vp, nbp);			s = splbio();			while ((nbp->b_flags & B_DONE) == 0) {				nbp->b_flags |= B_WANTED;				tsleep(nbp, PRIBIO, "vnwait", 0);			}			splx(s);			if( nbp->b_flags & B_ERROR) {				bp->b_flags |= B_ERROR;				bp->b_resid -= (resid - sz);				biodone(bp);				putvnbuf(nbp);				return;			}			byten += sz;			addr += sz;			resid -= sz;		}		bp->b_resid = resid;		biodone(bp);		putvnbuf(nbp);	}}voidvniodone( struct buf *bp) {	bp->b_flags |= B_DONE;	wakeup((caddr_t) bp);}/* ARGSUSED */static	intvnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p){	struct vn_softc *vn = vn_softc[vnunit(dev)];	struct vn_ioctl *vio;	struct vattr vattr;	struct nameidata nd;	int error;	u_long *f;	IFOPT(vn,VN_FOLLOW)		printf("vnioctl(0x%lx, 0x%lx, %p, 0x%x, %p): unit %d\n",		   (u_long)dev, cmd, (void *)data, flag, (void *)p,		   vnunit(dev));	switch (cmd) {	case VNIOCATTACH:	case VNIOCDETACH:	case VNIOCGSET:	case VNIOCGCLEAR:	case VNIOCUSET:	case VNIOCUCLEAR:		goto vn_specific;	}	IFOPT(vn,VN_LABELS) {		if (vn->sc_slices != NULL) {			error = dsioctl("vn", dev, cmd, data, flag,					&vn->sc_slices, vnstrategy,					(ds_setgeom_t *)NULL);			if (error != ENOIOCTL)				return (error);		}		if (dkslice(dev) != WHOLE_DISK_SLICE ||		    dkpart(dev) != RAW_PART)			return (ENOTTY);	}    vn_specific:	error = suser(p->p_ucred, &p->p_acflag);	if (error)		return (error);	vio = (struct vn_ioctl *)data;	f = (u_long*)data;	switch (cmd) {	case VNIOCATTACH:		if (vn->sc_flags & VNF_INITED)			return(EBUSY);		/*		 * Always open for read and write.		 * This is probably bogus, but it lets vn_open()		 * weed out directories, sockets, etc. so we don't		 * have to worry about them.		 */		NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vn_file, p);		error = vn_open(&nd, FREAD|FWRITE, 0);		if (error)			return(error);		error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);		if (error) {			VOP_UNLOCK(nd.ni_vp, 0, p);			(void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);			return(error);		}		VOP_UNLOCK(nd.ni_vp, 0, p);		vn->sc_vp = nd.ni_vp;		vn->sc_size = btodb(vattr.va_size);	/* note truncation */		error = vnsetcred(vn, p->p_ucred);		if (error) {			(void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);			return(error);		}		vio->vn_size = dbtob(vn->sc_size);		vn->sc_flags |= VNF_INITED;		IFOPT(vn, VN_LABELS) {			/*			 * Reopen so that `ds' knows which devices are open.			 * If this is the first VNIOCSET, then we've			 * guaranteed that the device is the cdev and that			 * no other slices or labels are open.  Otherwise,			 * we rely on VNIOCCLR not being abused.			 */			error = vnopen(dev, flag, S_IFCHR, p);			if (error)				vnclear(vn);		}		IFOPT(vn, VN_FOLLOW)			printf("vnioctl: SET vp %p size %x\n",			       vn->sc_vp, vn->sc_size);		break;	case VNIOCDETACH:		if ((vn->sc_flags & VNF_INITED) == 0)			return(ENXIO);		/*		 * XXX handle i/o in progress.  Return EBUSY, or wait, or		 * flush the i/o.		 * XXX handle multiple opens of the device.  Return EBUSY,		 * or revoke the fd's.		 * How are these problems handled for removable and failing		 * hardware devices?		 */		vnclear(vn);		IFOPT(vn, VN_FOLLOW)			printf("vnioctl: CLRed\n");		break;	case VNIOCGSET:		vn_options |= *f;		*f = vn_options;		break;	case VNIOCGCLEAR:		vn_options &= ~(*f);		*f = vn_options;		break;	case VNIOCUSET:		vn->sc_options |= *f;		*f = vn->sc_options;		break;	case VNIOCUCLEAR:		vn->sc_options &= ~(*f);		*f = vn->sc_options;		break;	default:		return (ENOTTY);	}	return(0);}/* * Duplicate the current processes' credentials.  Since we are called only * as the result of a SET ioctl and only root can do that, any future access * to this "disk" is essentially as root.  Note that credentials may change * if some other uid can write directly to the mapped file (NFS). */intvnsetcred(struct vn_softc *vn, struct ucred *cred){	struct uio auio;	struct iovec aiov;	char *tmpbuf;	int error;	vn->sc_cred = crdup(cred);	tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);	/* XXX: Horrible kludge to establish credentials for NFS */	aiov.iov_base = tmpbuf;	aiov.iov_len = min(DEV_BSIZE, dbtob(vn->sc_size));	auio.uio_iov = &aiov;	auio.uio_iovcnt = 1;	auio.uio_offset = 0;	auio.uio_rw = UIO_READ;	auio.uio_segflg = UIO_SYSSPACE;	auio.uio_resid = aiov.iov_len;	vn_lock(vn->sc_vp, LK_EXCLUSIVE | LK_RETRY, curproc);	error = VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred);	VOP_UNLOCK(vn->sc_vp, 0, curproc);	free(tmpbuf, M_TEMP);	return (error);}voidvnshutdown(int howto, void *ignored){	int i;	for (i = 0; i < NVN; i++)		if (vn_softc[i] && vn_softc[i]->sc_flags & VNF_INITED)			vnclear(vn_softc[i]);}voidvnclear(struct vn_softc *vn){	register struct vnode *vp = vn->sc_vp;	struct proc *p = curproc;		/* XXX */	IFOPT(vn, VN_FOLLOW)		printf("vnclear(%p): vp=%p\n", vn, vp);	if (vn->sc_slices != NULL)		dsgone(&vn->sc_slices);	vn->sc_flags &= ~VNF_INITED;	if (vp == (struct vnode *)0)		panic("vnclear: null vp");	(void) vn_close(vp, FREAD|FWRITE, vn->sc_cred, p);	crfree(vn->sc_cred);	vn->sc_vp = (struct vnode *)0;	vn->sc_cred = (struct ucred *)0;	vn->sc_size = 0;}static	intvnsize(dev_t dev){	int unit = vnunit(dev);	if (unit >= NVN || (!vn_softc[unit]) ||	    (vn_softc[unit]->sc_flags & VNF_INITED) == 0)		return(-1);	return(vn_softc[unit]->sc_size);}static	intvndump(dev_t dev){	return (ENODEV);}static vn_devsw_installed = 0;static void vn_drvinit(void *unused){#ifdef DEVFS	int unit;#endif	if(!vn_devsw_installed ) {		if (at_shutdown(&vnshutdown, NULL, SHUTDOWN_POST_SYNC)) {			printf("vn: could not install shutdown hook\n");			return;		}		cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &vn_cdevsw);		vn_devsw_installed = 1;	}#ifdef DEVFS	for (unit = 0; unit < NVN; unit++) {		struct vn_softc *vn;		vn = malloc(sizeof *vn, M_DEVBUF, M_NOWAIT);		if (!vn)			return;		bzero(vn, sizeof *vn);		vn_softc[unit] = vn;		vn->r_devfs_token = devfs_add_devswf(&vn_cdevsw, 						     dkmakeminor(unit, 0, 0),                                 		     DV_CHR, UID_ROOT, 						     GID_OPERATOR, 0640,                                 		     "rvn%d", unit);        	vn->devfs_token = devfs_add_devswf(&vn_cdevsw,						   dkmakeminor(unit, 0, 0),                                 		   DV_BLK, UID_ROOT, 						   GID_OPERATOR, 0640,                                 		   "vn%d", unit);	}#endif}SYSINIT(vndev, SI_SUB_DRIVERS, SI_ORDER_ANY, vn_drvinit, NULL)#endif

⌨️ 快捷键说明

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