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