|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * from: @(#)kern_physio.c 7.20 (Berkeley) 5/11/91
1.1.1.2 ! root 34: * kern_physio.c,v 1.6 1993/07/08 10:53:40 cgd Exp
1.1 root 35: */
36:
37: #include "param.h"
38: #include "systm.h"
39: #include "buf.h"
40: #include "conf.h"
41: #include "proc.h"
1.1.1.2 ! root 42: /* #include "seg.h" XXX - cgd */
1.1 root 43: #include "trace.h"
1.1.1.2 ! root 44: /* #include "map.h" XXX - cgd */
1.1 root 45: #include "vnode.h"
46: #include "specdev.h"
47:
48: #ifdef HPUXCOMPAT
49: #include "user.h"
50: #endif
51:
1.1.1.2 ! root 52: #include "malloc.h" /* XXX -- i had to add this, so it could very
! 53: * well be wrong... -- cgd
! 54: */
1.1 root 55: /*
56: * This routine does raw device I/O for a user process.
57: *
58: * If the user has the proper access privileges, the process is
59: * marked 'delayed unlock' and the pages involved in the I/O are
60: * faulted and locked. After the completion of the I/O, the pages
61: * are unlocked.
62: */
1.1.1.2 ! root 63: int
1.1 root 64: physio(strat, bp, dev, rw, mincnt, uio)
65: int (*strat)();
66: register struct buf *bp;
67: dev_t dev;
68: int rw;
69: u_int (*mincnt)();
70: struct uio *uio;
71: {
72: /*
1.1.1.2 ! root 73: * Body deleted
! 74: *
! 75: * And reimplemented by cgd.
! 76: * comments in brackets are my own, the rest come from
! 77: * _The Design and Implementation of the 4.3 BSD UNIX Operating System_
! 78: * by Leffler, McKusick, et al., page 232
! 79: *
! 80: * also, parts of this snarfed from wfj's physio, but *it*
! 81: * was mostly ick.
1.1 root 82: */
1.1.1.2 ! root 83: int s, i;
! 84: int error, wanted,
! 85: nobuf = (bp == NULL);
! 86:
! 87: if (nobuf) { /* [ if we have no buffer, we need one... ] */
! 88: /* [ so malloc it... XXX? ] */
! 89: bp = (struct buf *)malloc(sizeof(*bp), M_TEMP, M_WAITOK);
! 90: bzero(bp, sizeof(*bp));
! 91: }
! 92:
! 93: /* check user read/write access to the data buffer
! 94: * [ and if no access, then return EFAULT ]
! 95: */
! 96: for (i = 0; i < uio->uio_iovcnt; i++) {
! 97: /* [ check each iov one by one. note that we're
! 98: * given an rw param, so we ignore the uio's
! 99: * rw parameter... also note that if we're
! 100: * doing a read, that's a *write* to user-space... ]
! 101: */
! 102: if (!useracc(uio->uio_iov[i].iov_base,
! 103: uio->uio_iov[i].iov_len,
! 104: (rw == B_READ) ? B_WRITE : B_READ)) {
! 105: if (nobuf)
! 106: free(bp, M_TEMP);
! 107: return EFAULT;
! 108: }
! 109: }
! 110:
! 111: s = splbio(); /* raise the processor priority to splbio */
! 112:
! 113: /* while (the buffer is marked busy) { */
! 114: while (bp->b_flags & B_BUSY) {
! 115: bp->b_flags |= B_WANTED; /* mark the buffer wanted */
! 116: /* wait until the buffer is available */
! 117: tsleep((caddr_t) bp, PRIBIO+1, "physbuf", 0);
! 118: } /* } */
! 119:
! 120: /* [ mark it as busy so it's not reused by somebody else ] */
! 121: bp->b_flags |= B_BUSY;
! 122:
! 123: splx(s); /* lower the priority level */
! 124:
! 125: error = 0;
! 126:
! 127: /* [ for each element of the iov ] */
! 128: for (i = 0; i < uio->uio_iovcnt && !error; i++) {
! 129: struct iovec *iovp;
! 130: iovp = &uio->uio_iov[i];
! 131:
! 132: /* set up the fixed part of the buffer for a transfer */
! 133: /* [ also, clear error flag, but that's done later ] */
! 134: bp->b_error = 0; /* no error yet */
! 135: bp->b_proc = curproc; /* on behalf of this process */
! 136:
! 137: /* while (there are data to transfer and no I/O error) { */
! 138: while (iovp->iov_len > 0 && !error) {
! 139: int todo, done;
! 140: caddr_t tmp;
! 141:
! 142: /* mark the buffer busy for physical I/O
! 143: */
! 144: bp->b_flags = B_BUSY | B_PHYS | rw;
! 145:
! 146: /* set up the buffer for a maximum-sized transfer */
! 147: bp->b_dev = dev;
! 148: bp->b_blkno = btodb(uio->uio_offset);
! 149: bp->b_bcount = iovp->iov_len;
! 150: /* [ base of buffer is iov's ] */
! 151: bp->b_un.b_addr = iovp->iov_base;
! 152:
! 153: /* call minphys [actually mincnt] to bound the transfer size */
! 154: todo = (*mincnt)(bp);
! 155:
! 156: /* [ and if it returns zero, e.g. in the "end of disk"
! 157: * case, bail... ] */
! 158: if (todo == 0)
! 159: goto leave;
! 160:
! 161: /* lock the part of the user address space involved in
! 162: * the transfer
! 163: * [ vmapbuf clobbers the b_addr, so save it first ]
! 164: */
! 165: tmp = bp->b_un.b_addr;
! 166: vslock(bp->b_un.b_addr, todo);
! 167: vmapbuf(bp);
! 168:
! 169: /* call strategy to start the transfer
! 170: * [ some of the next bit snarfed from wfj's machdep.c ]
! 171: */
! 172: (*strat)(bp);
! 173:
! 174: s = splbio(); /* raise the priority level to splbio */
! 175: /* wait for the transfer to complete */
! 176: while ((bp->b_flags & B_DONE) == 0)
! 177: tsleep((caddr_t) bp, PRIBIO, "physio", 0);
! 178:
! 179: /* unlock the part of the address space previously locked */
! 180: vunmapbuf(bp);
! 181: vsunlock(tmp, todo, 0); /* [ 3rd param unused!!! ] */
! 182:
! 183: splx(s); /* lower the priority level */
! 184:
! 185: /* deduct the transfer size from the total number
! 186: * of data to transfer
! 187: */
! 188: done = bp->b_bcount - bp->b_resid;
! 189: iovp->iov_len -= done;
! 190: iovp->iov_base += done;
! 191: uio->uio_offset += done;
! 192: uio->uio_resid -= done;
! 193:
! 194: /* [ set error from the buffer's error code, and
! 195: * do other miscellaneous cleanup on the buffer ]
! 196: */
! 197: /* [ XXX this B_INVAL trick is bullshit for broken
! 198: * vfs_bio where it wants to rehash a buf if
! 199: * and error, but buf is not already B_INVAL ]
! 200: */
! 201: if (nobuf && ((bp->b_flags & B_ERROR) || bp->b_error))
! 202: bp->b_flags |= B_INVAL; /* XXX */
! 203: error = biowait(bp);
! 204: /* [ handle disks like they want to be handled ] */
! 205: if (bp->b_flags & B_ERROR || done < todo)
! 206: goto leave;
! 207: } /* } */
! 208: }
! 209:
! 210: leave:
! 211: if (nobuf) { /* [ if we had to allocate it, get rid of it ] */
! 212: if (bp->b_vp) /* [ have a vnode; dissociate from it ] */
! 213: brelvp(bp);
! 214: /* XXX any other buf fields which should be taken care of
! 215: * if they had values?
! 216: */
! 217: free(bp, M_TEMP);
! 218: } else {
! 219: /* clean up the state of the buffer */
! 220: wanted = bp->b_flags & B_WANTED;
! 221: bp->b_flags &= ~(B_BUSY | B_WANTED | B_PHYS | B_RAW);
! 222:
! 223: /* if (another process is waiting for the raw I/O buffer) */
! 224: if (wanted)
! 225: /* wake up process waiting to do physical I/O */
! 226: wakeup((caddr_t) bp);
! 227: }
! 228:
! 229: /* [ finally, if there's an error, return it ] */
! 230: return error;
1.1 root 231: }
232:
233: /*
234: * Calculate the maximum size of I/O request that can be requested
235: * in a single operation. This limit is necessary to prevent a single
236: * process from being able to lock more than a fixed amount of memory
237: * in the kernel.
238: */
239: u_int
240: minphys(bp)
241: struct buf *bp;
242: {
243:
244: /*
245: * Body deleted.
1.1.1.2 ! root 246: *
! 247: * and reimplemented by cgd.
! 248: * Leffler, McKusick, et al., says on p. 231:
! 249: * "The minphys() routine is called by physio() to adjust the
! 250: * size of each I/O transfer before the latter is passed to
! 251: * the strategy routine..."
! 252: *
! 253: * so, just adjust the buffer's count accounting to MAXPHYS here,
! 254: * and return the new count;
1.1 root 255: */
1.1.1.2 ! root 256: bp->b_bcount = min(MAXPHYS, bp->b_bcount);
! 257: return bp->b_bcount;
1.1 root 258: }
259:
260: /*
261: * Do a read on a device for a user process.
262: */
1.1.1.2 ! root 263: int
1.1 root 264: rawread(dev, uio)
265: dev_t dev;
266: struct uio *uio;
267: {
268: return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
269: dev, B_READ, minphys, uio));
270: }
271:
272: /*
273: * Do a write on a device for a user process.
274: */
1.1.1.2 ! root 275: int
1.1 root 276: rawwrite(dev, uio)
277: dev_t dev;
278: struct uio *uio;
279: {
280: return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
281: dev, B_WRITE, minphys, uio));
282: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.