|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 University of Utah. ! 3: * Copyright (c) 1990 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * the Systems Programming Group of the University of Utah Computer ! 8: * Science Department. ! 9: * ! 10: * Redistribution and use in source and binary forms, with or without ! 11: * modification, are permitted provided that the following conditions ! 12: * are met: ! 13: * 1. Redistributions of source code must retain the above copyright ! 14: * notice, this list of conditions and the following disclaimer. ! 15: * 2. Redistributions in binary form must reproduce the above copyright ! 16: * notice, this list of conditions and the following disclaimer in the ! 17: * documentation and/or other materials provided with the distribution. ! 18: * 3. All advertising materials mentioning features or use of this software ! 19: * must display the following acknowledgement: ! 20: * This product includes software developed by the University of ! 21: * California, Berkeley and its contributors. ! 22: * 4. Neither the name of the University nor the names of its contributors ! 23: * may be used to endorse or promote products derived from this software ! 24: * without specific prior written permission. ! 25: * ! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 36: * SUCH DAMAGE. ! 37: * ! 38: * from: Utah $Hdr: vn.c 1.1 91/04/30$ ! 39: * ! 40: * @(#)vn.c 7.6 (Berkeley) 6/21/91 ! 41: */ ! 42: ! 43: /* ! 44: * Vnode disk driver. ! 45: * ! 46: * Block/character interface to a vnode. Allows one to treat a file ! 47: * as a disk (e.g. build a filesystem in it, mount it, etc.). ! 48: * ! 49: * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode ! 50: * instead of a simple VOP_RDWR. We do this to avoid distorting the ! 51: * local buffer cache. ! 52: * ! 53: * NOTE 2: There is a security issue involved with this driver. ! 54: * Once mounted all access to the contents of the "mapped" file via ! 55: * the special file is controlled by the permissions on the special ! 56: * file, the protection of the mapped file is ignored (effectively, ! 57: * by using root credentials in all transactions). ! 58: */ ! 59: #include "vn.h" ! 60: #if NVN > 0 ! 61: ! 62: #include "sys/param.h" ! 63: #include "sys/systm.h" ! 64: #include "sys/namei.h" ! 65: #include "sys/proc.h" ! 66: #include "sys/errno.h" ! 67: #include "sys/dkstat.h" ! 68: #include "sys/buf.h" ! 69: #include "sys/malloc.h" ! 70: #include "sys/ioctl.h" ! 71: #include "sys/mount.h" ! 72: #include "sys/vnode.h" ! 73: #include "sys/specdev.h" ! 74: #include "sys/file.h" ! 75: #include "sys/uio.h" ! 76: ! 77: #include "vnioctl.h" ! 78: ! 79: #ifdef DEBUG ! 80: int vndebug = 0x00; ! 81: #define VDB_FOLLOW 0x01 ! 82: #define VDB_INIT 0x02 ! 83: #define VDB_IO 0x04 ! 84: #endif ! 85: ! 86: struct buf vnbuf[NVN]; ! 87: struct buf vntab[NVN]; ! 88: ! 89: #define b_cylin b_resid ! 90: ! 91: #define vnunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */ ! 92: ! 93: #define getvnbuf() \ ! 94: ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK)) ! 95: #define putvnbuf(bp) \ ! 96: free((caddr_t)(bp), M_DEVBUF) ! 97: ! 98: struct vn_softc { ! 99: int sc_flags; /* flags */ ! 100: size_t sc_size; /* size of vn */ ! 101: struct vnode *sc_vp; /* vnode */ ! 102: struct ucred *sc_cred; /* credentials */ ! 103: int sc_maxactive; /* max # of active requests */ ! 104: } vn_softc[NVN]; ! 105: ! 106: /* sc_flags */ ! 107: #define VNF_ALIVE 0x01 ! 108: #define VNF_INITED 0x02 ! 109: ! 110: int ! 111: vnopen(dev, flags, mode, p) ! 112: dev_t dev; ! 113: int flags, mode; ! 114: struct proc *p; ! 115: { ! 116: int unit = vnunit(dev); ! 117: ! 118: #ifdef DEBUG ! 119: if (vndebug & VDB_FOLLOW) ! 120: printf("vnopen(%x, %x, %x, %x)\n", dev, flags, mode, p); ! 121: #endif ! 122: if (unit >= NVN) ! 123: return(ENXIO); ! 124: return(0); ! 125: } ! 126: ! 127: /* ! 128: * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY. ! 129: * Note that this driver can only be used for swapping over NFS on the hp ! 130: * since nfs_strategy on the vax cannot handle u-areas and page tables. ! 131: */ ! 132: vnstrategy(bp) ! 133: register struct buf *bp; ! 134: { ! 135: int unit = vnunit(bp->b_dev); ! 136: register struct vn_softc *vn = &vn_softc[unit]; ! 137: register struct buf *nbp; ! 138: register int bn, bsize, resid; ! 139: register caddr_t addr; ! 140: int sz, flags; ! 141: extern int vniodone(); ! 142: ! 143: #ifdef DEBUG ! 144: if (vndebug & VDB_FOLLOW) ! 145: printf("vnstrategy(%x): unit %d\n", bp, unit); ! 146: #endif ! 147: if ((vn->sc_flags & VNF_INITED) == 0) { ! 148: bp->b_error = ENXIO; ! 149: bp->b_flags |= B_ERROR; ! 150: biodone(bp); ! 151: return; ! 152: } ! 153: bn = bp->b_blkno; ! 154: sz = howmany(bp->b_bcount, DEV_BSIZE); ! 155: bp->b_resid = bp->b_bcount; ! 156: if (bn < 0 || bn + sz > vn->sc_size) { ! 157: if (bn != vn->sc_size) { ! 158: bp->b_error = EINVAL; ! 159: bp->b_flags |= B_ERROR; ! 160: } ! 161: biodone(bp); ! 162: return; ! 163: } ! 164: bn = dbtob(bn); ! 165: bsize = vn->sc_vp->v_mount->mnt_stat.f_bsize; ! 166: addr = bp->b_un.b_addr; ! 167: flags = bp->b_flags | B_CALL; ! 168: for (resid = bp->b_resid; resid; resid -= sz) { ! 169: struct vnode *vp; ! 170: daddr_t nbn; ! 171: int off, s; ! 172: ! 173: nbp = getvnbuf(); ! 174: off = bn % bsize; ! 175: sz = MIN(bsize - off, resid); ! 176: (void) VOP_BMAP(vn->sc_vp, bn / bsize, &vp, &nbn); ! 177: #ifdef DEBUG ! 178: if (vndebug & VDB_IO) ! 179: printf("vnstrategy: vp %x/%x bn %x/%x\n", ! 180: vn->sc_vp, vp, bn, nbn); ! 181: #endif ! 182: nbp->b_flags = flags; ! 183: nbp->b_bcount = sz; ! 184: nbp->b_bufsize = bp->b_bufsize; ! 185: nbp->b_error = 0; ! 186: if (vp->v_type == VBLK || vp->v_type == VCHR) ! 187: nbp->b_dev = vp->v_rdev; ! 188: else ! 189: nbp->b_dev = NODEV; ! 190: nbp->b_un.b_addr = addr; ! 191: nbp->b_blkno = nbn + btodb(off); ! 192: nbp->b_proc = bp->b_proc; ! 193: nbp->b_iodone = vniodone; ! 194: nbp->b_vp = vp; ! 195: nbp->b_pfcent = (int) bp; /* XXX */ ! 196: /* ! 197: * Just sort by block number ! 198: */ ! 199: nbp->b_cylin = nbp->b_blkno; ! 200: s = splbio(); ! 201: disksort(&vntab[unit], nbp); ! 202: if (vntab[unit].b_active < vn->sc_maxactive) { ! 203: vntab[unit].b_active++; ! 204: vnstart(unit); ! 205: } ! 206: splx(s); ! 207: bn += sz; ! 208: addr += sz; ! 209: } ! 210: } ! 211: ! 212: /* ! 213: * Feed requests sequentially. ! 214: * We do it this way to keep from flooding NFS servers if we are connected ! 215: * to an NFS file. This places the burden on the client rather than the ! 216: * server. ! 217: */ ! 218: vnstart(unit) ! 219: { ! 220: register struct vn_softc *vn = &vn_softc[unit]; ! 221: register struct buf *bp; ! 222: ! 223: /* ! 224: * Dequeue now since lower level strategy routine might ! 225: * queue using same links ! 226: */ ! 227: bp = vntab[unit].b_actf; ! 228: vntab[unit].b_actf = bp->b_actf; ! 229: #ifdef DEBUG ! 230: if (vndebug & VDB_IO) ! 231: printf("vnstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n", ! 232: unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr, ! 233: bp->b_bcount); ! 234: #endif ! 235: VOP_STRATEGY(bp); ! 236: } ! 237: ! 238: vniodone(bp) ! 239: register struct buf *bp; ! 240: { ! 241: register struct buf *pbp = (struct buf *)bp->b_pfcent; /* XXX */ ! 242: register int unit = vnunit(pbp->b_dev); ! 243: int s; ! 244: ! 245: s = splbio(); ! 246: #ifdef DEBUG ! 247: if (vndebug & VDB_IO) ! 248: printf("vniodone(%d): bp %x vp %x blkno %x addr %x cnt %x\n", ! 249: unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr, ! 250: bp->b_bcount); ! 251: #endif ! 252: if (bp->b_error) { ! 253: #ifdef DEBUG ! 254: if (vndebug & VDB_IO) ! 255: printf("vniodone: bp %x error %d\n", bp, bp->b_error); ! 256: #endif ! 257: pbp->b_flags |= B_ERROR; ! 258: pbp->b_error = biowait(bp); ! 259: } ! 260: pbp->b_resid -= bp->b_bcount; ! 261: putvnbuf(bp); ! 262: if (pbp->b_resid == 0) { ! 263: #ifdef DEBUG ! 264: if (vndebug & VDB_IO) ! 265: printf("vniodone: pbp %x iodone\n", pbp); ! 266: #endif ! 267: biodone(pbp); ! 268: } ! 269: if (vntab[unit].b_actf) ! 270: vnstart(unit); ! 271: else ! 272: vntab[unit].b_active--; ! 273: splx(s); ! 274: } ! 275: ! 276: vnread(dev, uio, flags, p) ! 277: dev_t dev; ! 278: struct uio *uio; ! 279: int flags; ! 280: struct proc *p; ! 281: { ! 282: register int unit = vnunit(dev); ! 283: ! 284: #ifdef DEBUG ! 285: if (vndebug & VDB_FOLLOW) ! 286: printf("vnread(%x, %x, %x, %x)\n", dev, uio, flags, p); ! 287: #endif ! 288: #if 0 ! 289: return(physio(vnstrategy, &vnbuf[unit], dev, B_READ, minphys, uio)); ! 290: #else ! 291: return rawread (dev, uio); ! 292: #endif ! 293: } ! 294: ! 295: vnwrite(dev, uio, flags, p) ! 296: dev_t dev; ! 297: struct uio *uio; ! 298: int flags; ! 299: struct proc *p; ! 300: { ! 301: register int unit = vnunit(dev); ! 302: ! 303: #ifdef DEBUG ! 304: if (vndebug & VDB_FOLLOW) ! 305: printf("vnwrite(%x, %x, %x, %x)\n", dev, uio, flags, p); ! 306: #endif ! 307: #if 0 ! 308: return(physio(vnstrategy, &vnbuf[unit], dev, B_WRITE, minphys, uio)); ! 309: #else ! 310: return rawwrite (dev, uio); ! 311: #endif ! 312: } ! 313: ! 314: /* ARGSUSED */ ! 315: vnioctl(dev, cmd, data, flag, p) ! 316: dev_t dev; ! 317: u_long cmd; ! 318: caddr_t data; ! 319: int flag; ! 320: struct proc *p; ! 321: { ! 322: int unit = vnunit(dev); ! 323: register struct vn_softc *vn; ! 324: struct vn_ioctl *vio; ! 325: struct vattr vattr; ! 326: struct nameidata nd; ! 327: int error; ! 328: ! 329: #ifdef DEBUG ! 330: if (vndebug & VDB_FOLLOW) ! 331: printf("vnioctl(%x, %x, %x, %x, %x): unit %d\n", ! 332: dev, cmd, data, flag, p, unit); ! 333: #endif ! 334: error = suser(p->p_ucred, &p->p_acflag); ! 335: if (error) ! 336: return (error); ! 337: if (unit >= NVN) ! 338: return (ENXIO); ! 339: ! 340: vn = &vn_softc[unit]; ! 341: vio = (struct vn_ioctl *)data; ! 342: switch (cmd) { ! 343: ! 344: case VNIOCSET: ! 345: if (vn->sc_flags & VNF_INITED) ! 346: return(EBUSY); ! 347: /* ! 348: * Always open for read and write. ! 349: * This is probably bogus, but it lets vn_open() ! 350: * weed out directories, sockets, etc. so we don't ! 351: * have to worry about them. ! 352: */ ! 353: nd.ni_segflg = UIO_USERSPACE; ! 354: nd.ni_dirp = vio->vn_file; ! 355: if (error = vn_open(&nd, p, FREAD|FWRITE, 0)) ! 356: return(error); ! 357: if (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p)) { ! 358: VOP_UNLOCK(nd.ni_vp); ! 359: (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p); ! 360: return(error); ! 361: } ! 362: VOP_UNLOCK(nd.ni_vp); ! 363: vn->sc_vp = nd.ni_vp; ! 364: vn->sc_size = btodb(vattr.va_size); /* note truncation */ ! 365: if (error = vnsetcred(vn, p->p_ucred)) { ! 366: (void) vn_close(vn->sc_vp, FREAD|FWRITE, p->p_ucred, p); ! 367: return(error); ! 368: } ! 369: vnthrottle(vn, vn->sc_vp); ! 370: vio->vn_size = dbtob(vn->sc_size); ! 371: vn->sc_flags |= VNF_INITED; ! 372: #ifdef DEBUG ! 373: if (vndebug & VDB_INIT) ! 374: printf("vnioctl: SET vp %x size %x\n", ! 375: vn->sc_vp, vn->sc_size); ! 376: #endif ! 377: break; ! 378: ! 379: case VNIOCCLR: ! 380: if ((vn->sc_flags & VNF_INITED) == 0) ! 381: return(ENXIO); ! 382: vnclear(vn); ! 383: #ifdef DEBUG ! 384: if (vndebug & VDB_INIT) ! 385: printf("vnioctl: CLRed\n"); ! 386: #endif ! 387: break; ! 388: ! 389: default: ! 390: return(ENXIO); ! 391: } ! 392: return(0); ! 393: } ! 394: ! 395: /* ! 396: * Duplicate the current processes' credentials. Since we are called only ! 397: * as the result of a SET ioctl and only root can do that, any future access ! 398: * to this "disk" is essentially as root. Note that credentials may change ! 399: * if some other uid can write directly to the mapped file (NFS). ! 400: */ ! 401: vnsetcred(vn, cred) ! 402: register struct vn_softc *vn; ! 403: struct ucred *cred; ! 404: { ! 405: struct uio auio; ! 406: struct iovec aiov; ! 407: char tmpbuf[DEV_BSIZE]; ! 408: ! 409: vn->sc_cred = crdup(cred); ! 410: /* XXX: Horrible kludge to establish credentials for NFS */ ! 411: aiov.iov_base = tmpbuf; ! 412: aiov.iov_len = MIN(DEV_BSIZE, dbtob(vn->sc_size)); ! 413: auio.uio_iov = &aiov; ! 414: auio.uio_iovcnt = 1; ! 415: auio.uio_offset = 0; ! 416: auio.uio_rw = UIO_READ; ! 417: auio.uio_segflg = UIO_SYSSPACE; ! 418: auio.uio_resid = aiov.iov_len; ! 419: return(VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred)); ! 420: } ! 421: ! 422: /* ! 423: * Set maxactive based on FS type ! 424: */ ! 425: vnthrottle(vn, vp) ! 426: register struct vn_softc *vn; ! 427: struct vnode *vp; ! 428: { ! 429: extern struct vnodeops ufs_vnodeops, nfsv2_vnodeops; ! 430: ! 431: if (vp->v_op == &nfsv2_vnodeops) ! 432: vn->sc_maxactive = 2; ! 433: else ! 434: vn->sc_maxactive = 8; ! 435: ! 436: if (vn->sc_maxactive < 1) ! 437: vn->sc_maxactive = 1; ! 438: } ! 439: ! 440: vnshutdown() ! 441: { ! 442: register struct vn_softc *vn; ! 443: ! 444: for (vn = &vn_softc[0]; vn < &vn_softc[NVN]; vn++) ! 445: if (vn->sc_flags & VNF_INITED) ! 446: vnclear(vn); ! 447: } ! 448: ! 449: vnclear(vn) ! 450: register struct vn_softc *vn; ! 451: { ! 452: register struct vnode *vp = vn->sc_vp; ! 453: struct proc *p = curproc; /* XXX */ ! 454: ! 455: #ifdef DEBUG ! 456: if (vndebug & VDB_FOLLOW) ! 457: printf("vnclear(%x): vp %x\n", vp); ! 458: #endif ! 459: vn->sc_flags &= ~VNF_INITED; ! 460: if (vp == (struct vnode *)0) ! 461: panic("vnioctl: null vp"); ! 462: #if 0 ! 463: /* XXX - this doesn't work right now */ ! 464: (void) VOP_FSYNC(vp, 0, vn->sc_cred, MNT_WAIT, p); ! 465: #endif ! 466: (void) vn_close(vp, FREAD|FWRITE, vn->sc_cred, p); ! 467: crfree(vn->sc_cred); ! 468: vn->sc_vp = (struct vnode *)0; ! 469: vn->sc_cred = (struct ucred *)0; ! 470: vn->sc_size = 0; ! 471: } ! 472: ! 473: vnsize(dev) ! 474: dev_t dev; ! 475: { ! 476: int unit = vnunit(dev); ! 477: register struct vn_softc *vn = &vn_softc[unit]; ! 478: ! 479: if (unit >= NVN || (vn->sc_flags & VNF_INITED) == 0) ! 480: return(-1); ! 481: return(vn->sc_size); ! 482: } ! 483: ! 484: vndump(dev) ! 485: { ! 486: return(ENXIO); ! 487: } ! 488: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.