141480Smckusick /* 241480Smckusick * Copyright (c) 1988 University of Utah. 3*63145Sbostic * Copyright (c) 1990, 1993 4*63145Sbostic * The Regents of the University of California. All rights reserved. 541480Smckusick * 641480Smckusick * This code is derived from software contributed to Berkeley by 741480Smckusick * the Systems Programming Group of the University of Utah Computer 841480Smckusick * Science Department. 941480Smckusick * 1041480Smckusick * %sccs.include.redist.c% 1141480Smckusick * 1257301Shibler * from: Utah $Hdr: vn.c 1.8 92/12/20$ 1341480Smckusick * 14*63145Sbostic * @(#)vn.c 8.1 (Berkeley) 06/10/93 1541480Smckusick */ 1641480Smckusick 1741480Smckusick /* 1849299Shibler * Vnode disk driver. 1941480Smckusick * 2049299Shibler * Block/character interface to a vnode. Allows one to treat a file 2149299Shibler * as a disk (e.g. build a filesystem in it, mount it, etc.). 2241480Smckusick * 2349299Shibler * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode 2449299Shibler * instead of a simple VOP_RDWR. We do this to avoid distorting the 2549299Shibler * local buffer cache. 2649299Shibler * 2749299Shibler * NOTE 2: There is a security issue involved with this driver. 2841480Smckusick * Once mounted all access to the contents of the "mapped" file via 2941480Smckusick * the special file is controlled by the permissions on the special 3041480Smckusick * file, the protection of the mapped file is ignored (effectively, 3141480Smckusick * by using root credentials in all transactions). 3257301Shibler * 3357301Shibler * NOTE 3: Doesn't interact with leases, should it? 3441480Smckusick */ 3549299Shibler #include "vn.h" 3649299Shibler #if NVN > 0 3741480Smckusick 3855159Spendry #include <sys/param.h> 3955159Spendry #include <sys/systm.h> 4055159Spendry #include <sys/namei.h> 4155159Spendry #include <sys/proc.h> 4255159Spendry #include <sys/errno.h> 4355159Spendry #include <sys/dkstat.h> 4455159Spendry #include <sys/buf.h> 4555159Spendry #include <sys/malloc.h> 4655159Spendry #include <sys/ioctl.h> 4755159Spendry #include <sys/mount.h> 4855159Spendry #include <sys/vnode.h> 4955159Spendry #include <sys/file.h> 5055159Spendry #include <sys/uio.h> 5141480Smckusick 5255159Spendry #include <miscfs/specfs/specdev.h> 5355159Spendry 5456503Sbostic #include <dev/vnioctl.h> 5541480Smckusick 5641480Smckusick #ifdef DEBUG 5749299Shibler int vndebug = 0x00; 5849299Shibler #define VDB_FOLLOW 0x01 5949299Shibler #define VDB_INIT 0x02 6049299Shibler #define VDB_IO 0x04 6141480Smckusick #endif 6241480Smckusick 6341480Smckusick #define b_cylin b_resid 6441480Smckusick 6549299Shibler #define vnunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */ 6641480Smckusick 6749299Shibler #define getvnbuf() \ 6841480Smckusick ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK)) 6949299Shibler #define putvnbuf(bp) \ 7041480Smckusick free((caddr_t)(bp), M_DEVBUF) 7141480Smckusick 7249299Shibler struct vn_softc { 7341480Smckusick int sc_flags; /* flags */ 7449299Shibler size_t sc_size; /* size of vn */ 7541480Smckusick struct vnode *sc_vp; /* vnode */ 7641480Smckusick struct ucred *sc_cred; /* credentials */ 7741480Smckusick int sc_maxactive; /* max # of active requests */ 7859342Shibler struct buf sc_tab; /* transfer queue */ 7959342Shibler }; 8041480Smckusick 8141480Smckusick /* sc_flags */ 8249299Shibler #define VNF_ALIVE 0x01 8349299Shibler #define VNF_INITED 0x02 8441480Smckusick 8559342Shibler #if 0 /* if you need static allocation */ 8659342Shibler struct vn_softc vn_softc[NVN]; 8759342Shibler int numvnd = NVN; 8859342Shibler #else 8959342Shibler struct vn_softc *vn_softc; 9059342Shibler int numvnd; 9159342Shibler #endif 9259342Shibler 9359342Shibler void 9459342Shibler vnattach(num) 9559342Shibler int num; 9659342Shibler { 9759342Shibler char *mem; 9859342Shibler register u_long size; 9959342Shibler 10059342Shibler if (num <= 0) 10159342Shibler return; 10259342Shibler size = num * sizeof(struct vn_softc); 10359342Shibler mem = malloc(size, M_DEVBUF, M_NOWAIT); 10459342Shibler if (mem == NULL) { 10559342Shibler printf("WARNING: no memory for vnode disks\n"); 10659342Shibler return; 10759342Shibler } 10859342Shibler bzero(mem, size); 10959342Shibler vn_softc = (struct vn_softc *)mem; 11059342Shibler numvnd = num; 11159342Shibler } 11259342Shibler 11349299Shibler int 11449299Shibler vnopen(dev, flags, mode, p) 11541480Smckusick dev_t dev; 11649299Shibler int flags, mode; 11749299Shibler struct proc *p; 11841480Smckusick { 11949299Shibler int unit = vnunit(dev); 12041480Smckusick 12141480Smckusick #ifdef DEBUG 12249299Shibler if (vndebug & VDB_FOLLOW) 12349299Shibler printf("vnopen(%x, %x, %x, %x)\n", dev, flags, mode, p); 12441480Smckusick #endif 12559342Shibler if (unit >= numvnd) 12641480Smckusick return(ENXIO); 12741480Smckusick return(0); 12841480Smckusick } 12941480Smckusick 13041480Smckusick /* 13141480Smckusick * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY. 13241480Smckusick * Note that this driver can only be used for swapping over NFS on the hp 13341480Smckusick * since nfs_strategy on the vax cannot handle u-areas and page tables. 13441480Smckusick */ 13549299Shibler vnstrategy(bp) 13641480Smckusick register struct buf *bp; 13741480Smckusick { 13849299Shibler int unit = vnunit(bp->b_dev); 13949299Shibler register struct vn_softc *vn = &vn_softc[unit]; 14041480Smckusick register struct buf *nbp; 14141480Smckusick register int bn, bsize, resid; 14241480Smckusick register caddr_t addr; 14341480Smckusick int sz, flags; 14453921Shibler extern void vniodone(); 14541480Smckusick 14641480Smckusick #ifdef DEBUG 14749299Shibler if (vndebug & VDB_FOLLOW) 14849299Shibler printf("vnstrategy(%x): unit %d\n", bp, unit); 14941480Smckusick #endif 15049299Shibler if ((vn->sc_flags & VNF_INITED) == 0) { 15141480Smckusick bp->b_error = ENXIO; 15241480Smckusick bp->b_flags |= B_ERROR; 15349299Shibler biodone(bp); 15441480Smckusick return; 15541480Smckusick } 15641480Smckusick bn = bp->b_blkno; 15741480Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 15841480Smckusick bp->b_resid = bp->b_bcount; 15949299Shibler if (bn < 0 || bn + sz > vn->sc_size) { 16049299Shibler if (bn != vn->sc_size) { 16141480Smckusick bp->b_error = EINVAL; 16241480Smckusick bp->b_flags |= B_ERROR; 16341480Smckusick } 16449299Shibler biodone(bp); 16541480Smckusick return; 16641480Smckusick } 16741480Smckusick bn = dbtob(bn); 16851945Smckusick bsize = vn->sc_vp->v_mount->mnt_stat.f_iosize; 16941480Smckusick addr = bp->b_un.b_addr; 17041480Smckusick flags = bp->b_flags | B_CALL; 17141480Smckusick for (resid = bp->b_resid; resid; resid -= sz) { 17241480Smckusick struct vnode *vp; 17341480Smckusick daddr_t nbn; 17441480Smckusick int off, s; 17541480Smckusick 17649299Shibler nbp = getvnbuf(); 17741480Smckusick off = bn % bsize; 17855159Spendry sz = min(bsize - off, resid); 17956453Smargo (void) VOP_BMAP(vn->sc_vp, bn / bsize, &vp, &nbn, NULL); 18041480Smckusick #ifdef DEBUG 18149299Shibler if (vndebug & VDB_IO) 18249299Shibler printf("vnstrategy: vp %x/%x bn %x/%x\n", 18349299Shibler vn->sc_vp, vp, bn, nbn); 18441480Smckusick #endif 18541480Smckusick nbp->b_flags = flags; 18641480Smckusick nbp->b_bcount = sz; 18741480Smckusick nbp->b_bufsize = bp->b_bufsize; 18841480Smckusick nbp->b_error = 0; 18949299Shibler if (vp->v_type == VBLK || vp->v_type == VCHR) 19049299Shibler nbp->b_dev = vp->v_rdev; 19149299Shibler else 19249299Shibler nbp->b_dev = NODEV; 19341480Smckusick nbp->b_un.b_addr = addr; 19441480Smckusick nbp->b_blkno = nbn + btodb(off); 19541480Smckusick nbp->b_proc = bp->b_proc; 19649299Shibler nbp->b_iodone = vniodone; 19741480Smckusick nbp->b_vp = vp; 19841480Smckusick nbp->b_pfcent = (int) bp; /* XXX */ 19957301Shibler nbp->b_rcred = vn->sc_cred; /* XXX crdup? */ 20057301Shibler nbp->b_wcred = vn->sc_cred; /* XXX crdup? */ 20157301Shibler nbp->b_dirtyoff = bp->b_dirtyoff; 20257301Shibler nbp->b_dirtyend = bp->b_dirtyend; 20357301Shibler nbp->b_validoff = bp->b_validoff; 20457301Shibler nbp->b_validend = bp->b_validend; 20541480Smckusick /* 20641480Smckusick * Just sort by block number 20741480Smckusick */ 20841480Smckusick nbp->b_cylin = nbp->b_blkno; 20941480Smckusick s = splbio(); 21059342Shibler disksort(&vn->sc_tab, nbp); 21159342Shibler if (vn->sc_tab.b_active < vn->sc_maxactive) { 21259342Shibler vn->sc_tab.b_active++; 21359342Shibler vnstart(vn); 21441480Smckusick } 21541480Smckusick splx(s); 21641480Smckusick bn += sz; 21741480Smckusick addr += sz; 21841480Smckusick } 21941480Smckusick } 22041480Smckusick 22141480Smckusick /* 22241480Smckusick * Feed requests sequentially. 22341480Smckusick * We do it this way to keep from flooding NFS servers if we are connected 22441480Smckusick * to an NFS file. This places the burden on the client rather than the 22541480Smckusick * server. 22641480Smckusick */ 22759342Shibler vnstart(vn) 22859342Shibler register struct vn_softc *vn; 22941480Smckusick { 23041480Smckusick register struct buf *bp; 23141480Smckusick 23241480Smckusick /* 23341480Smckusick * Dequeue now since lower level strategy routine might 23441480Smckusick * queue using same links 23541480Smckusick */ 23659342Shibler bp = vn->sc_tab.b_actf; 23759342Shibler vn->sc_tab.b_actf = bp->b_actf; 23841480Smckusick #ifdef DEBUG 23949299Shibler if (vndebug & VDB_IO) 24049299Shibler printf("vnstart(%d): bp %x vp %x blkno %x addr %x cnt %x\n", 24159342Shibler vn-vn_softc, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr, 24241480Smckusick bp->b_bcount); 24341480Smckusick #endif 24457301Shibler if ((bp->b_flags & B_READ) == 0) 24557301Shibler bp->b_vp->v_numoutput++; 24641480Smckusick VOP_STRATEGY(bp); 24741480Smckusick } 24841480Smckusick 24953921Shibler void 25049299Shibler vniodone(bp) 25141480Smckusick register struct buf *bp; 25241480Smckusick { 25341480Smckusick register struct buf *pbp = (struct buf *)bp->b_pfcent; /* XXX */ 25459342Shibler register struct vn_softc *vn = &vn_softc[vnunit(pbp->b_dev)]; 25541480Smckusick int s; 25641480Smckusick 25741480Smckusick s = splbio(); 25841480Smckusick #ifdef DEBUG 25949299Shibler if (vndebug & VDB_IO) 26049299Shibler printf("vniodone(%d): bp %x vp %x blkno %x addr %x cnt %x\n", 26159342Shibler vn-vn_softc, bp, bp->b_vp, bp->b_blkno, bp->b_un.b_addr, 26241480Smckusick bp->b_bcount); 26341480Smckusick #endif 26441480Smckusick if (bp->b_error) { 26541480Smckusick #ifdef DEBUG 26649299Shibler if (vndebug & VDB_IO) 26749299Shibler printf("vniodone: bp %x error %d\n", bp, bp->b_error); 26841480Smckusick #endif 26941480Smckusick pbp->b_flags |= B_ERROR; 27049299Shibler pbp->b_error = biowait(bp); 27141480Smckusick } 27241480Smckusick pbp->b_resid -= bp->b_bcount; 27349299Shibler putvnbuf(bp); 27441480Smckusick if (pbp->b_resid == 0) { 27541480Smckusick #ifdef DEBUG 27649299Shibler if (vndebug & VDB_IO) 27749299Shibler printf("vniodone: pbp %x iodone\n", pbp); 27841480Smckusick #endif 27949299Shibler biodone(pbp); 28041480Smckusick } 28159342Shibler if (vn->sc_tab.b_actf) 28259342Shibler vnstart(vn); 28341480Smckusick else 28459342Shibler vn->sc_tab.b_active--; 28541480Smckusick splx(s); 28641480Smckusick } 28741480Smckusick 28849299Shibler vnread(dev, uio, flags, p) 28941480Smckusick dev_t dev; 29041480Smckusick struct uio *uio; 29149299Shibler int flags; 29249299Shibler struct proc *p; 29341480Smckusick { 29441480Smckusick 29541480Smckusick #ifdef DEBUG 29649299Shibler if (vndebug & VDB_FOLLOW) 29749299Shibler printf("vnread(%x, %x, %x, %x)\n", dev, uio, flags, p); 29841480Smckusick #endif 29959342Shibler return(physio(vnstrategy, NULL, dev, B_READ, minphys, uio)); 30041480Smckusick } 30141480Smckusick 30249299Shibler vnwrite(dev, uio, flags, p) 30341480Smckusick dev_t dev; 30441480Smckusick struct uio *uio; 30549299Shibler int flags; 30649299Shibler struct proc *p; 30741480Smckusick { 30841480Smckusick 30941480Smckusick #ifdef DEBUG 31049299Shibler if (vndebug & VDB_FOLLOW) 31149299Shibler printf("vnwrite(%x, %x, %x, %x)\n", dev, uio, flags, p); 31241480Smckusick #endif 31359342Shibler return(physio(vnstrategy, NULL, dev, B_WRITE, minphys, uio)); 31441480Smckusick } 31541480Smckusick 31641480Smckusick /* ARGSUSED */ 31749299Shibler vnioctl(dev, cmd, data, flag, p) 31841480Smckusick dev_t dev; 31941480Smckusick u_long cmd; 32041480Smckusick caddr_t data; 32141480Smckusick int flag; 32249299Shibler struct proc *p; 32341480Smckusick { 32449299Shibler int unit = vnunit(dev); 32549299Shibler register struct vn_softc *vn; 32649299Shibler struct vn_ioctl *vio; 32741480Smckusick struct vattr vattr; 32849299Shibler struct nameidata nd; 32941480Smckusick int error; 33041480Smckusick 33141480Smckusick #ifdef DEBUG 33249299Shibler if (vndebug & VDB_FOLLOW) 33349299Shibler printf("vnioctl(%x, %x, %x, %x, %x): unit %d\n", 33449299Shibler dev, cmd, data, flag, p, unit); 33541480Smckusick #endif 33649299Shibler error = suser(p->p_ucred, &p->p_acflag); 33741480Smckusick if (error) 33841480Smckusick return (error); 33959342Shibler if (unit >= numvnd) 34041480Smckusick return (ENXIO); 34141480Smckusick 34249299Shibler vn = &vn_softc[unit]; 34349299Shibler vio = (struct vn_ioctl *)data; 34441480Smckusick switch (cmd) { 34541480Smckusick 34649299Shibler case VNIOCSET: 34749299Shibler if (vn->sc_flags & VNF_INITED) 34841480Smckusick return(EBUSY); 34941480Smckusick /* 35041480Smckusick * Always open for read and write. 35141480Smckusick * This is probably bogus, but it lets vn_open() 35241480Smckusick * weed out directories, sockets, etc. so we don't 35341480Smckusick * have to worry about them. 35441480Smckusick */ 35552761Shibler NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vn_file, p); 35652761Shibler if (error = vn_open(&nd, FREAD|FWRITE, 0)) 35741480Smckusick return(error); 35850115Smckusick if (error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p)) { 35950115Smckusick VOP_UNLOCK(nd.ni_vp); 36050115Smckusick (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p); 36141480Smckusick return(error); 36241480Smckusick } 36350115Smckusick VOP_UNLOCK(nd.ni_vp); 36449299Shibler vn->sc_vp = nd.ni_vp; 36549299Shibler vn->sc_size = btodb(vattr.va_size); /* note truncation */ 36650115Smckusick if (error = vnsetcred(vn, p->p_ucred)) { 36750115Smckusick (void) vn_close(vn->sc_vp, FREAD|FWRITE, p->p_ucred, p); 36841480Smckusick return(error); 36941480Smckusick } 37049299Shibler vnthrottle(vn, vn->sc_vp); 37149299Shibler vio->vn_size = dbtob(vn->sc_size); 37249299Shibler vn->sc_flags |= VNF_INITED; 37341480Smckusick #ifdef DEBUG 37449299Shibler if (vndebug & VDB_INIT) 37549299Shibler printf("vnioctl: SET vp %x size %x\n", 37649299Shibler vn->sc_vp, vn->sc_size); 37741480Smckusick #endif 37841480Smckusick break; 37941480Smckusick 38049299Shibler case VNIOCCLR: 38149299Shibler if ((vn->sc_flags & VNF_INITED) == 0) 38241480Smckusick return(ENXIO); 38349299Shibler vnclear(vn); 38441480Smckusick #ifdef DEBUG 38549299Shibler if (vndebug & VDB_INIT) 38649299Shibler printf("vnioctl: CLRed\n"); 38741480Smckusick #endif 38841480Smckusick break; 38941480Smckusick 39041480Smckusick default: 39141480Smckusick return(ENXIO); 39241480Smckusick } 39341480Smckusick return(0); 39441480Smckusick } 39541480Smckusick 39641480Smckusick /* 39741480Smckusick * Duplicate the current processes' credentials. Since we are called only 39841480Smckusick * as the result of a SET ioctl and only root can do that, any future access 39941480Smckusick * to this "disk" is essentially as root. Note that credentials may change 40041480Smckusick * if some other uid can write directly to the mapped file (NFS). 40141480Smckusick */ 40249299Shibler vnsetcred(vn, cred) 40349299Shibler register struct vn_softc *vn; 40449299Shibler struct ucred cred; 40541480Smckusick { 40641480Smckusick struct uio auio; 40741480Smckusick struct iovec aiov; 40841480Smckusick char tmpbuf[DEV_BSIZE]; 40941480Smckusick 41049299Shibler vn->sc_cred = crdup(cred); 41141480Smckusick /* XXX: Horrible kludge to establish credentials for NFS */ 41241480Smckusick aiov.iov_base = tmpbuf; 41355159Spendry aiov.iov_len = min(DEV_BSIZE, dbtob(vn->sc_size)); 41441480Smckusick auio.uio_iov = &aiov; 41541480Smckusick auio.uio_iovcnt = 1; 41641480Smckusick auio.uio_offset = 0; 41741480Smckusick auio.uio_rw = UIO_READ; 41841480Smckusick auio.uio_segflg = UIO_SYSSPACE; 41941480Smckusick auio.uio_resid = aiov.iov_len; 42049299Shibler return(VOP_READ(vn->sc_vp, &auio, 0, vn->sc_cred)); 42141480Smckusick } 42241480Smckusick 42341480Smckusick /* 42441480Smckusick * Set maxactive based on FS type 42541480Smckusick */ 42649299Shibler vnthrottle(vn, vp) 42749299Shibler register struct vn_softc *vn; 42841480Smckusick struct vnode *vp; 42941480Smckusick { 43053517Sheideman extern int (**nfsv2_vnodeop_p)(); 43141480Smckusick 43253517Sheideman if (vp->v_op == nfsv2_vnodeop_p) 43349299Shibler vn->sc_maxactive = 2; 43441480Smckusick else 43549299Shibler vn->sc_maxactive = 8; 43641480Smckusick 43749299Shibler if (vn->sc_maxactive < 1) 43849299Shibler vn->sc_maxactive = 1; 43941480Smckusick } 44041480Smckusick 44149299Shibler vnshutdown() 44241480Smckusick { 44349299Shibler register struct vn_softc *vn; 44441480Smckusick 44559342Shibler for (vn = &vn_softc[0]; vn < &vn_softc[numvnd]; vn++) 44649299Shibler if (vn->sc_flags & VNF_INITED) 44749299Shibler vnclear(vn); 44841480Smckusick } 44941480Smckusick 45049299Shibler vnclear(vn) 45149299Shibler register struct vn_softc *vn; 45241480Smckusick { 45349299Shibler register struct vnode *vp = vn->sc_vp; 45450115Smckusick struct proc *p = curproc; /* XXX */ 45541480Smckusick 45641480Smckusick #ifdef DEBUG 45749299Shibler if (vndebug & VDB_FOLLOW) 45849299Shibler printf("vnclear(%x): vp %x\n", vp); 45941480Smckusick #endif 46049299Shibler vn->sc_flags &= ~VNF_INITED; 46141480Smckusick if (vp == (struct vnode *)0) 46249299Shibler panic("vnioctl: null vp"); 46341480Smckusick #if 0 46441480Smckusick /* XXX - this doesn't work right now */ 46549299Shibler (void) VOP_FSYNC(vp, 0, vn->sc_cred, MNT_WAIT, p); 46641480Smckusick #endif 46750115Smckusick (void) vn_close(vp, FREAD|FWRITE, vn->sc_cred, p); 46849299Shibler crfree(vn->sc_cred); 46949299Shibler vn->sc_vp = (struct vnode *)0; 47049299Shibler vn->sc_cred = (struct ucred *)0; 47149299Shibler vn->sc_size = 0; 47241480Smckusick } 47341480Smckusick 47449299Shibler vnsize(dev) 47541480Smckusick dev_t dev; 47641480Smckusick { 47749299Shibler int unit = vnunit(dev); 47849299Shibler register struct vn_softc *vn = &vn_softc[unit]; 47941480Smckusick 48059342Shibler if (unit >= numvnd || (vn->sc_flags & VNF_INITED) == 0) 48141480Smckusick return(-1); 48249299Shibler return(vn->sc_size); 48341480Smckusick } 48441480Smckusick 48549299Shibler vndump(dev) 48641480Smckusick { 48741480Smckusick return(ENXIO); 48841480Smckusick } 48941480Smckusick #endif 490