home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / hp300 / dev / vn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-21  |  11.8 KB  |  481 lines

  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.     return(physio(vnstrategy, &vnbuf[unit], dev, B_READ, minphys, uio));
  289. }
  290.  
  291. vnwrite(dev, uio, flags, p)
  292.     dev_t dev;
  293.     struct uio *uio;
  294.     int flags;
  295.     struct proc *p;
  296. {
  297.     register int unit = vnunit(dev);
  298.  
  299. #ifdef DEBUG
  300.     if (vndebug & VDB_FOLLOW)
  301.         printf("vnwrite(%x, %x, %x, %x)\n", dev, uio, flags, p);
  302. #endif
  303.     return(physio(vnstrategy, &vnbuf[unit], dev, B_WRITE, minphys, uio));
  304. }
  305.  
  306. /* ARGSUSED */
  307. vnioctl(dev, cmd, data, flag, p)
  308.     dev_t dev;
  309.     u_long cmd;
  310.     caddr_t data;
  311.     int flag;
  312.     struct proc *p;
  313. {
  314.     int unit = vnunit(dev);
  315.     register struct vn_softc *vn;
  316.     struct vn_ioctl *vio;
  317.     struct vattr vattr;
  318.     struct nameidata nd;
  319.     int error;
  320.  
  321. #ifdef DEBUG
  322.     if (vndebug & VDB_FOLLOW)
  323.         printf("vnioctl(%x, %x, %x, %x, %x): unit %d\n",
  324.                dev, cmd, data, flag, p, unit);
  325. #endif
  326.     error = suser(p->p_ucred, &p->p_acflag);
  327.     if (error)
  328.         return (error);
  329.     if (unit >= NVN)
  330.         return (ENXIO);
  331.  
  332.     vn = &vn_softc[unit];
  333.     vio = (struct vn_ioctl *)data;
  334.     switch (cmd) {
  335.  
  336.     case VNIOCSET:
  337.         if (vn->sc_flags & VNF_INITED)
  338.             return(EBUSY);
  339.         /*
  340.          * Always open for read and write.
  341.          * This is probably bogus, but it lets vn_open()
  342.          * weed out directories, sockets, etc. so we don't
  343.          * have to worry about them.
  344.          */
  345.         nd.ni_segflg = UIO_USERSPACE;
  346.         nd.ni_dirp = vio->vn_file;
  347.         if (error = vn_open(&nd, p, FREAD|FWRITE, 0))
  348.             return(error);
  349.         if (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p)) {
  350.             VOP_UNLOCK(nd.ni_vp);
  351.             (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
  352.             return(error);
  353.         }
  354.         VOP_UNLOCK(nd.ni_vp);
  355.         vn->sc_vp = nd.ni_vp;
  356.         vn->sc_size = btodb(vattr.va_size);    /* note truncation */
  357.         if (error = vnsetcred(vn, p->p_ucred)) {
  358.             (void) vn_close(vn->sc_vp, FREAD|FWRITE, p->p_ucred, p);
  359.             return(error);
  360.         }
  361.         vnthrottle(vn, vn->sc_vp);
  362.         vio->vn_size = dbtob(vn->sc_size);
  363.         vn->sc_flags |= VNF_INITED;
  364. #ifdef DEBUG
  365.         if (vndebug & VDB_INIT)
  366.             printf("vnioctl: SET vp %x size %x\n",
  367.                    vn->sc_vp, vn->sc_size);
  368. #endif
  369.         break;
  370.  
  371.     case VNIOCCLR:
  372.         if ((vn->sc_flags & VNF_INITED) == 0)
  373.             return(ENXIO);
  374.         vnclear(vn);
  375. #ifdef DEBUG
  376.         if (vndebug & VDB_INIT)
  377.             printf("vnioctl: CLRed\n");
  378. #endif
  379.         break;
  380.  
  381.     default:
  382.         return(ENXIO);
  383.     }
  384.     return(0);
  385. }
  386.  
  387. /*
  388.  * Duplicate the current processes' credentials.  Since we are called only
  389.  * as the result of a SET ioctl and only root can do that, any future access
  390.  * to this "disk" is essentially as root.  Note that credentials may change
  391.  * if some other uid can write directly to the mapped file (NFS).
  392.  */
  393. vnsetcred(vn, cred)
  394.     register struct vn_softc *vn;
  395.     struct ucred cred;
  396. {
  397.     struct uio auio;
  398.     struct iovec aiov;
  399.     char tmpbuf[DEV_BSIZE];
  400.  
  401.     vn->sc_cred = crdup(cred);
  402.     /* XXX: Horrible kludge to establish credentials for NFS */
  403.     aiov.iov_base = tmpbuf;
  404.     aiov.iov_len = MIN(DEV_BSIZE, dbtob(vn->sc_size));
  405.     auio.uio_iov = &aiov;
  406.     auio.uio_iovcnt = 1;
  407.     auio.uio_offset = 0;
  408.     auio.uio_rw = UIO_READ;
  409.     auio.uio_segflg = UIO_SYSSPACE;
  410.     auio.uio_resid = aiov.iov_len;
  411.     return(VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred));
  412. }
  413.  
  414. /*
  415.  * Set maxactive based on FS type
  416.  */
  417. vnthrottle(vn, vp)
  418.     register struct vn_softc *vn;
  419.     struct vnode *vp;
  420. {
  421.     extern struct vnodeops ufs_vnodeops, nfsv2_vnodeops;
  422.  
  423.     if (vp->v_op == &nfsv2_vnodeops)
  424.         vn->sc_maxactive = 2;
  425.     else
  426.         vn->sc_maxactive = 8;
  427.  
  428.     if (vn->sc_maxactive < 1)
  429.         vn->sc_maxactive = 1;
  430. }
  431.  
  432. vnshutdown()
  433. {
  434.     register struct vn_softc *vn;
  435.  
  436.     for (vn = &vn_softc[0]; vn < &vn_softc[NVN]; vn++)
  437.         if (vn->sc_flags & VNF_INITED)
  438.             vnclear(vn);
  439. }
  440.  
  441. vnclear(vn)
  442.     register struct vn_softc *vn;
  443. {
  444.     register struct vnode *vp = vn->sc_vp;
  445.     struct proc *p = curproc;        /* XXX */
  446.  
  447. #ifdef DEBUG
  448.     if (vndebug & VDB_FOLLOW)
  449.         printf("vnclear(%x): vp %x\n", vp);
  450. #endif
  451.     vn->sc_flags &= ~VNF_INITED;
  452.     if (vp == (struct vnode *)0)
  453.         panic("vnioctl: null vp");
  454. #if 0
  455.     /* XXX - this doesn't work right now */
  456.     (void) VOP_FSYNC(vp, 0, vn->sc_cred, MNT_WAIT, p);
  457. #endif
  458.     (void) vn_close(vp, FREAD|FWRITE, vn->sc_cred, p);
  459.     crfree(vn->sc_cred);
  460.     vn->sc_vp = (struct vnode *)0;
  461.     vn->sc_cred = (struct ucred *)0;
  462.     vn->sc_size = 0;
  463. }
  464.  
  465. vnsize(dev)
  466.     dev_t dev;
  467. {
  468.     int unit = vnunit(dev);
  469.     register struct vn_softc *vn = &vn_softc[unit];
  470.  
  471.     if (unit >= NVN || (vn->sc_flags & VNF_INITED) == 0)
  472.         return(-1);
  473.     return(vn->sc_size);
  474. }
  475.  
  476. vndump(dev)
  477. {
  478.     return(ENXIO);
  479. }
  480. #endif
  481.