Annotation of Net2/kern/kern_physio.c, revision 1.1.1.2

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.