|
|
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 is only permitted until one year after the first shipment ! 11: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 12: * binary forms are permitted provided that: (1) source distributions retain ! 13: * this entire copyright notice and comment, and (2) distributions including ! 14: * binaries display the following acknowledgement: This product includes ! 15: * software developed by the University of California, Berkeley and its ! 16: * contributors'' in the documentation or other materials provided with the ! 17: * distribution and in all advertising materials mentioning features or use ! 18: * of this software. Neither the name of the University nor the names of ! 19: * its contributors may be used to endorse or promote products derived from ! 20: * this software without specific prior written permission. ! 21: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 22: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 23: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 24: * ! 25: * from: Utah $Hdr: fd.c 1.3 89/12/03$ ! 26: * ! 27: * @(#)fd.c 7.1 (Berkeley) 5/8/90 ! 28: */ ! 29: ! 30: /* ! 31: * File (vnode) disk driver. ! 32: * ! 33: * Block/character interface to a vnode. Note that this uses the ! 34: * VOP_BMAP/VOP_STRATEGY interface to the vnode instead of a simple ! 35: * VOP_RDWR. We do this to avoid distorting the local buffer cache. ! 36: * ! 37: * NOTE: There is a security issue involved with this driver. ! 38: * Once mounted all access to the contents of the "mapped" file via ! 39: * the special file is controlled by the permissions on the special ! 40: * file, the protection of the mapped file is ignored (effectively, ! 41: * by using root credentials in all transactions). ! 42: */ ! 43: #include "fd.h" ! 44: #if NFD > 0 ! 45: ! 46: #include "param.h" ! 47: #include "systm.h" ! 48: #include "buf.h" ! 49: #include "errno.h" ! 50: #include "dkstat.h" ! 51: #include "ioctl.h" ! 52: #include "user.h" ! 53: #include "vfs.h" ! 54: #include "vnode.h" ! 55: #include "file.h" ! 56: #include "uio.h" ! 57: #include "malloc.h" ! 58: ! 59: #include "fdioctl.h" ! 60: ! 61: #ifdef DEBUG ! 62: int fddebug = 0x00; ! 63: #define FDB_FOLLOW 0x01 ! 64: #define FDB_INIT 0x02 ! 65: #define FDB_IO 0x04 ! 66: #endif ! 67: ! 68: struct buf fdbuf[NFD]; ! 69: struct buf fdtab[NFD]; ! 70: ! 71: #define b_cylin b_resid ! 72: ! 73: #define fdunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */ ! 74: ! 75: #define getfdbuf() \ ! 76: ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK)) ! 77: #define putfdbuf(bp) \ ! 78: free((caddr_t)(bp), M_DEVBUF) ! 79: ! 80: struct fd_softc { ! 81: int sc_flags; /* flags */ ! 82: size_t sc_size; /* size of fd */ ! 83: struct vnode *sc_vp; /* vnode */ ! 84: struct ucred *sc_cred; /* credentials */ ! 85: int sc_maxactive; /* max # of active requests */ ! 86: } fd_softc[NFD]; ! 87: ! 88: /* sc_flags */ ! 89: #define FDF_ALIVE 0x01 ! 90: #define FDF_INITED 0x02 ! 91: ! 92: fdopen(dev, flags) ! 93: dev_t dev; ! 94: { ! 95: int unit = fdunit(dev); ! 96: ! 97: #ifdef DEBUG ! 98: if (fddebug & FDB_FOLLOW) ! 99: printf("fdopen(%x, %x)\n", dev, flags); ! 100: #endif ! 101: if (unit >= NFD) ! 102: return(ENXIO); ! 103: return(0); ! 104: } ! 105: ! 106: /* ! 107: * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY. ! 108: * Note that this driver can only be used for swapping over NFS on the hp ! 109: * since nfs_strategy on the vax cannot handle u-areas and page tables. ! 110: */ ! 111: fdstrategy(bp) ! 112: register struct buf *bp; ! 113: { ! 114: int unit = fdunit(bp->b_dev); ! 115: register struct fd_softc *fs = &fd_softc[unit]; ! 116: register struct buf *nbp; ! 117: register int bn, bsize, resid; ! 118: register caddr_t addr; ! 119: int sz, flags; ! 120: extern int fdiodone(); ! 121: ! 122: #ifdef DEBUG ! 123: if (fddebug & FDB_FOLLOW) ! 124: printf("fdstrategy(%x): unit %d\n", bp, unit); ! 125: #endif ! 126: if ((fs->sc_flags & FDF_INITED) == 0) { ! 127: bp->b_error = ENXIO; ! 128: bp->b_flags |= B_ERROR; ! 129: iodone(bp); ! 130: return; ! 131: } ! 132: bn = bp->b_blkno; ! 133: sz = howmany(bp->b_bcount, DEV_BSIZE); ! 134: bp->b_resid = bp->b_bcount; ! 135: if (bn < 0 || bn + sz > fs->sc_size) { ! 136: if (bn != fs->sc_size) { ! 137: bp->b_error = EINVAL; ! 138: bp->b_flags |= B_ERROR; ! 139: } ! 140: iodone(bp); ! 141: return; ! 142: } ! 143: bn = dbtob(bn); ! 144: bsize = fs->sc_vp->v_vfsp->vfs_bsize; ! 145: addr = bp->b_un.b_addr; ! 146: flags = bp->b_flags | B_CALL; ! 147: for (resid = bp->b_resid; resid; resid -= sz) { ! 148: struct vnode *vp; ! 149: daddr_t nbn; ! 150: int off, s; ! 151: ! 152: nbp = getfdbuf(); ! 153: off = bn % bsize; ! 154: sz = MIN(bsize - off, resid); ! 155: (void) VOP_BMAP(fs->sc_vp, bn / bsize, &vp, &nbn); ! 156: #ifdef DEBUG ! 157: if (fddebug & FDB_IO) ! 158: printf("fdstrategy: vp %x/%x bn %x/%x dev %x\n", ! 159: fs->sc_vp, vp, bn, nbn, vp->v_rdev); ! 160: #endif ! 161: nbp->b_flags = flags; ! 162: nbp->b_bcount = sz; ! 163: nbp->b_bufsize = bp->b_bufsize; ! 164: nbp->b_error = 0; ! 165: nbp->b_dev = vp->v_rdev; ! 166: nbp->b_un.b_addr = addr; ! 167: nbp->b_blkno = nbn + btodb(off); ! 168: nbp->b_proc = bp->b_proc; ! 169: nbp->b_iodone = fdiodone; ! 170: nbp->b_vp = vp; ! 171: nbp->b_pfcent = (int) bp; /* XXX */ ! 172: /* ! 173: * Just sort by block number ! 174: */ ! 175: nbp->b_cylin = nbp->b_blkno; ! 176: s = splbio(); ! 177: disksort(&fdtab[unit], nbp); ! 178: if (fdtab[unit].b_active < fs->sc_maxactive) { ! 179: fdtab[unit].b_active++; ! 180: fdstart(unit); ! 181: } ! 182: splx(s); ! 183: bn += sz; ! 184: addr += sz; ! 185: } ! 186: } ! 187: ! 188: /* ! 189: * Feed requests sequentially. ! 190: * We do it this way to keep from flooding NFS servers if we are connected ! 191: * to an NFS file. This places the burden on the client rather than the ! 192: * server. ! 193: */ ! 194: fdstart(unit) ! 195: { ! 196: register struct fd_softc *fs = &fd_softc[unit]; ! 197: register struct buf *bp; ! 198: ! 199: /* ! 200: * Dequeue now since lower level strategy routine might ! 201: * queue using same links ! 202: */ ! 203: bp = fdtab[unit].b_actf; ! 204: fdtab[unit].b_actf = bp->b_actf; ! 205: #ifdef DEBUG ! 206: if (fddebug & FDB_IO) ! 207: printf("fdstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n", ! 208: unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr, ! 209: bp->b_bcount); ! 210: #endif ! 211: VOP_STRATEGY(bp); ! 212: } ! 213: ! 214: fdiodone(bp) ! 215: register struct buf *bp; ! 216: { ! 217: register struct buf *pbp = (struct buf *)bp->b_pfcent; /* XXX */ ! 218: register int unit = fdunit(pbp->b_dev); ! 219: int s; ! 220: ! 221: s = splbio(); ! 222: #ifdef DEBUG ! 223: if (fddebug & FDB_IO) ! 224: printf("fdiodone(%d): bp %x vp %x blkno %x addr %x cnt %x\n", ! 225: unit, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr, ! 226: bp->b_bcount); ! 227: #endif ! 228: if (bp->b_error) { ! 229: #ifdef DEBUG ! 230: if (fddebug & FDB_IO) ! 231: printf("fdiodone: bp %x error %d\n", bp, bp->b_error); ! 232: #endif ! 233: pbp->b_flags |= B_ERROR; ! 234: pbp->b_error = geterror(bp); ! 235: } ! 236: pbp->b_resid -= bp->b_bcount; ! 237: putfdbuf(bp); ! 238: if (pbp->b_resid == 0) { ! 239: #ifdef DEBUG ! 240: if (fddebug & FDB_IO) ! 241: printf("fdiodone: pbp %x iodone\n", pbp); ! 242: #endif ! 243: iodone(pbp); ! 244: } ! 245: if (fdtab[unit].b_actf) ! 246: fdstart(unit); ! 247: else ! 248: fdtab[unit].b_active--; ! 249: splx(s); ! 250: } ! 251: ! 252: fdread(dev, uio) ! 253: dev_t dev; ! 254: struct uio *uio; ! 255: { ! 256: register int unit = fdunit(dev); ! 257: ! 258: #ifdef DEBUG ! 259: if (fddebug & FDB_FOLLOW) ! 260: printf("fdread(%x, %x)\n", dev, uio); ! 261: #endif ! 262: return(physio(fdstrategy, &fdbuf[unit], dev, B_READ, minphys, uio)); ! 263: } ! 264: ! 265: fdwrite(dev, uio) ! 266: dev_t dev; ! 267: struct uio *uio; ! 268: { ! 269: register int unit = fdunit(dev); ! 270: ! 271: #ifdef DEBUG ! 272: if (fddebug & FDB_FOLLOW) ! 273: printf("fdwrite(%x, %x)\n", dev, uio); ! 274: #endif ! 275: return(physio(fdstrategy, &fdbuf[unit], dev, B_WRITE, minphys, uio)); ! 276: } ! 277: ! 278: /* ARGSUSED */ ! 279: fdioctl(dev, cmd, data, flag) ! 280: dev_t dev; ! 281: u_long cmd; ! 282: caddr_t data; ! 283: int flag; ! 284: { ! 285: int unit = fdunit(dev); ! 286: register struct fd_softc *fs; ! 287: struct fd_ioctl *fio; ! 288: struct vattr vattr; ! 289: struct vnode *vp; ! 290: int error; ! 291: ! 292: #ifdef DEBUG ! 293: if (fddebug & FDB_FOLLOW) ! 294: printf("fdioctl(%x, %x, %x, %x): unit %d\n", ! 295: dev, cmd, data, flag, unit); ! 296: #endif ! 297: error = suser(u.u_cred, &u.u_acflag); ! 298: if (error) ! 299: return (error); ! 300: if (unit >= NFD) ! 301: return (ENXIO); ! 302: ! 303: fs = &fd_softc[unit]; ! 304: fio = (struct fd_ioctl *)data; ! 305: switch (cmd) { ! 306: ! 307: case FDIOCSET: ! 308: if (fs->sc_flags & FDF_INITED) ! 309: return(EBUSY); ! 310: /* ! 311: * Always open for read and write. ! 312: * This is probably bogus, but it lets vn_open() ! 313: * weed out directories, sockets, etc. so we don't ! 314: * have to worry about them. ! 315: */ ! 316: error = vn_open(fio->fd_file, UIO_USERSPACE, ! 317: FREAD|FWRITE, 0, &vp); ! 318: if (error) ! 319: return(error); ! 320: error = VOP_GETATTR(vp, &vattr, u.u_cred); ! 321: if (error) { ! 322: vn_close(vp, FREAD|FWRITE); ! 323: VN_RELE(vp); ! 324: return(error); ! 325: } ! 326: fs->sc_vp = vp; ! 327: fs->sc_size = btodb(vattr.va_size); /* note truncation */ ! 328: error = fdsetcred(fs); ! 329: if (error) { ! 330: vn_close(vp, FREAD|FWRITE); ! 331: VN_RELE(vp); ! 332: return(error); ! 333: } ! 334: fdthrottle(fs, vp); ! 335: fio->fd_size = dbtob(fs->sc_size); ! 336: fs->sc_flags |= FDF_INITED; ! 337: #ifdef DEBUG ! 338: if (fddebug & FDB_INIT) ! 339: printf("fdioctl: SET vp %x size %x\n", ! 340: fs->sc_vp, fs->sc_size); ! 341: #endif ! 342: break; ! 343: ! 344: case FDIOCCLR: ! 345: if ((fs->sc_flags & FDF_INITED) == 0) ! 346: return(ENXIO); ! 347: fdclear(fs); ! 348: #ifdef DEBUG ! 349: if (fddebug & FDB_INIT) ! 350: printf("fdioctl: CLRed\n"); ! 351: #endif ! 352: break; ! 353: ! 354: default: ! 355: return(ENXIO); ! 356: } ! 357: return(0); ! 358: } ! 359: ! 360: /* ! 361: * Duplicate the current processes' credentials. Since we are called only ! 362: * as the result of a SET ioctl and only root can do that, any future access ! 363: * to this "disk" is essentially as root. Note that credentials may change ! 364: * if some other uid can write directly to the mapped file (NFS). ! 365: */ ! 366: fdsetcred(fs) ! 367: register struct fd_softc *fs; ! 368: { ! 369: struct uio auio; ! 370: struct iovec aiov; ! 371: char tmpbuf[DEV_BSIZE]; ! 372: ! 373: fs->sc_cred = crdup(u.u_cred); ! 374: /* XXX: Horrible kludge to establish credentials for NFS */ ! 375: aiov.iov_base = tmpbuf; ! 376: aiov.iov_len = MIN(DEV_BSIZE, dbtob(fs->sc_size)); ! 377: auio.uio_iov = &aiov; ! 378: auio.uio_iovcnt = 1; ! 379: auio.uio_offset = 0; ! 380: auio.uio_rw = UIO_READ; ! 381: auio.uio_segflg = UIO_SYSSPACE; ! 382: auio.uio_resid = aiov.iov_len; ! 383: return(VOP_READ(fs->sc_vp, &auio, 0, fs->sc_cred)); ! 384: } ! 385: ! 386: /* ! 387: * Set maxactive based on FS type ! 388: */ ! 389: fdthrottle(fs, vp) ! 390: register struct fd_softc *fs; ! 391: struct vnode *vp; ! 392: { ! 393: extern struct vnodeops ufs_vnodeops, nfs_vnodeops; ! 394: ! 395: if (vp->v_op == &nfs_vnodeops) ! 396: fs->sc_maxactive = 2; ! 397: else ! 398: fs->sc_maxactive = 8; ! 399: ! 400: if (fs->sc_maxactive < 1) ! 401: fs->sc_maxactive = 1; ! 402: } ! 403: ! 404: fdshutdown() ! 405: { ! 406: register struct fd_softc *fs; ! 407: ! 408: for (fs = &fd_softc[0]; fs < &fd_softc[NFD]; fs++) ! 409: if (fs->sc_flags & FDF_INITED) ! 410: fdclear(fs); ! 411: } ! 412: ! 413: fdclear(fs) ! 414: register struct fd_softc *fs; ! 415: { ! 416: register struct vnode *vp = fs->sc_vp; ! 417: ! 418: #ifdef DEBUG ! 419: if (fddebug & FDB_FOLLOW) ! 420: printf("fdclear(%x): vp %x\n", vp); ! 421: #endif ! 422: fs->sc_flags &= ~FDF_INITED; ! 423: if (vp == (struct vnode *)0) ! 424: panic("fdioctl: null vp"); ! 425: #if 0 ! 426: /* XXX - this doesn't work right now */ ! 427: (void) VOP_FSYNC(vp, fs->sc_cred); ! 428: #endif ! 429: vn_close(vp, FREAD|FWRITE); ! 430: VN_RELE(vp); ! 431: crfree(fs->sc_cred); ! 432: fs->sc_vp = (struct vnode *)0; ! 433: fs->sc_cred = (struct ucred *)0; ! 434: fs->sc_size = 0; ! 435: } ! 436: ! 437: fdsize(dev) ! 438: dev_t dev; ! 439: { ! 440: int unit = fdunit(dev); ! 441: register struct fd_softc *fs = &fd_softc[unit]; ! 442: ! 443: if (unit >= NFD || (fs->sc_flags & FDF_INITED) == 0) ! 444: return(-1); ! 445: return(fs->sc_size); ! 446: } ! 447: ! 448: fddump(dev) ! 449: { ! 450: return(ENXIO); ! 451: } ! 452: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.