The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/kern_physio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*-
   26  * Copyright (c) 1982, 1986, 1990, 1993
   27  *      The Regents of the University of California.  All rights reserved.
   28  * (c) UNIX System Laboratories, Inc.
   29  * All or some portions of this file are derived from material licensed
   30  * to the University of California by American Telephone and Telegraph
   31  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   32  * the permission of UNIX System Laboratories, Inc.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions
   36  * are met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *    notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce the above copyright
   40  *    notice, this list of conditions and the following disclaimer in the
   41  *    documentation and/or other materials provided with the distribution.
   42  * 3. All advertising materials mentioning features or use of this software
   43  *    must display the following acknowledgement:
   44  *      This product includes software developed by the University of
   45  *      California, Berkeley and its contributors.
   46  * 4. Neither the name of the University nor the names of its contributors
   47  *    may be used to endorse or promote products derived from this software
   48  *    without specific prior written permission.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   60  * SUCH DAMAGE.
   61  *
   62  *      from: @(#)kern_physio.c 8.1 (Berkeley) 6/10/93
   63  */
   64 /*
   65  * HISTORY
   66  * 27-July-97  Umesh Vaishampayan  (umeshv@apple.com)
   67  *      Allow physio() to kernel space.
   68  */
   69 
   70 #include <sys/param.h>
   71 #include <sys/systm.h>
   72 #include <sys/buf.h>
   73 #include <sys/conf.h>
   74 #include <sys/proc.h>
   75 
   76 int
   77 physio(strategy, bp, dev, flags, minphys, uio, blocksize)
   78         void (*strategy)(); 
   79         struct buf *bp;
   80         dev_t dev;
   81         int flags;
   82         u_int (*minphys)();
   83         struct uio *uio;
   84         int blocksize;
   85 {
   86         struct iovec *iovp;
   87         struct proc *p = current_proc();
   88         int error, done, i, nobuf, s, todo;
   89 
   90         error = 0;
   91         flags &= B_READ | B_WRITE;
   92 
   93         /*
   94          * [check user read/write access to the data buffer]
   95          *
   96          * Check each iov one by one.  Note that we know if we're reading or
   97          * writing, so we ignore the uio's rw parameter.  Also note that if
   98          * we're doing a read, that's a *write* to user-space.
   99          */
  100         for (i = 0; i < uio->uio_iovcnt; i++) {
  101                 if(uio->uio_segflg != UIO_SYSSPACE) {
  102                         if (!useracc(uio->uio_iov[i].iov_base,
  103                                 uio->uio_iov[i].iov_len,
  104                                 (flags == B_READ) ? B_WRITE : B_READ))
  105                         return (EFAULT);
  106                 }
  107         }
  108         /* Make sure we have a buffer, creating one if necessary. */
  109         if (nobuf = (bp == NULL)) {
  110 //              bp = getphysbuf();
  111                 panic("physio: null buf pointer\n");
  112                 }
  113 
  114         /* [raise the processor priority level to splbio;] */
  115         s = splbio();
  116 
  117         /* [while the buffer is marked busy] */
  118         while (bp->b_flags & B_BUSY) {
  119                 /* [mark the buffer wanted] */
  120                 bp->b_flags |= B_WANTED;
  121                 /* [wait until the buffer is available] */
  122                 tsleep((caddr_t)bp, PRIBIO+1, "physbuf", 0);
  123         }
  124 
  125         /* Mark it busy, so nobody else will use it. */
  126         bp->b_flags |= B_BUSY;
  127 
  128         /* [lower the priority level] */
  129         splx(s);
  130 
  131         /* [set up the fixed part of the buffer for a transfer] */
  132         bp->b_dev = dev;
  133         bp->b_error = 0;
  134         bp->b_proc = p;
  135 
  136         /*
  137          * [while there are data to transfer and no I/O error]
  138          * Note that I/O errors are handled with a 'goto' at the bottom
  139          * of the 'while' loop.
  140          */
  141         for (i = 0; i < uio->uio_iovcnt; i++) {
  142                 iovp = &uio->uio_iov[i];
  143                 while (iovp->iov_len > 0) {
  144                         /*
  145                          * [mark the buffer busy for physical I/O]
  146                          * (i.e. set B_PHYS (because it's an I/O to user
  147                          * memory, and B_RAW, because B_RAW is to be
  148                          * "Set by physio for raw transfers.", in addition
  149                          * to the "busy" and read/write flag.)
  150                          */
  151                         s = splbio();
  152                         bp->b_flags = B_BUSY | B_PHYS | B_RAW | flags;
  153                         splx(s);
  154 
  155                         /* [set up the buffer for a maximum-sized transfer] */
  156                         bp->b_blkno = uio->uio_offset / blocksize;
  157                         bp->b_bcount = iovp->iov_len;
  158                         bp->b_data = iovp->iov_base;
  159                         
  160                         /*
  161                          * [call minphys to bound the tranfer size]
  162                          * and remember the amount of data to transfer,
  163                          * for later comparison.
  164                          */
  165                         (*minphys)(bp);
  166                         todo = bp->b_bcount;
  167 
  168                         /*
  169                          * [lock the part of the user address space involved
  170                          *    in the transfer]
  171                          * Beware vmapbuf(); it clobbers b_data and
  172                          * saves it in b_saveaddr.  However, vunmapbuf()
  173                          * restores it.
  174                          */
  175 
  176                         if(uio->uio_segflg != UIO_SYSSPACE)
  177                                 vslock(bp->b_data, todo);
  178                         
  179 #if 0
  180                         vmapbuf(bp, todo);
  181 #endif /* 0 */
  182                         /* [call strategy to start the transfer] */
  183                         (*strategy)(bp);
  184 
  185                         /*
  186                          * Note that the raise/wait/lower/get error
  187                          * steps below would be done by biowait(), but
  188                          * we want to unlock the address space before
  189                          * we lower the priority.
  190                          *
  191                          * [raise the priority level to splbio]
  192                          */
  193                         s = splbio();
  194 
  195                         /* [wait for the transfer to complete] */
  196                         while ((bp->b_flags & B_DONE) == 0)
  197                                 tsleep((caddr_t) bp, PRIBIO + 1, "physio", 0);
  198 
  199                         /*
  200                          * [unlock the part of the address space previously
  201                          *    locked]
  202                          */
  203 #if 0
  204                         vunmapbuf(bp, todo);
  205 #endif /* 0 */
  206                         if(uio->uio_segflg != UIO_SYSSPACE)
  207                                 vsunlock(bp->b_data, todo);
  208 
  209                         /* remember error value (save a splbio/splx pair) */
  210                         if (bp->b_flags & B_ERROR)
  211                                 error = (bp->b_error ? bp->b_error : EIO);
  212 
  213                         /* [lower the priority level] */
  214                         splx(s);
  215 
  216                         /*
  217                          * [deduct the transfer size from the total number
  218                          *    of data to transfer]
  219                          */
  220                         done = bp->b_bcount - bp->b_resid;
  221                         iovp->iov_len -= done;
  222                         iovp->iov_base += done;
  223                         uio->uio_offset += done;
  224                         uio->uio_resid -= done;
  225 
  226                         /*
  227                          * Now, check for an error.
  228                          * Also, handle weird end-of-disk semantics.
  229                          */
  230                         if (error || done < todo)
  231                                 goto done;
  232                 }
  233         }
  234 
  235 done:
  236         /*
  237          * [clean up the state of the buffer]
  238          * Remember if somebody wants it, so we can wake them up below.
  239          * Also, if we had to steal it, give it back.
  240          */
  241         s = splbio();
  242         bp->b_flags &= ~(B_BUSY | B_PHYS | B_RAW);
  243 #if 0
  244         if (nobuf)
  245                 putphysbuf(bp);
  246 
  247         else 
  248 #endif /* 0 */
  249                 {
  250                 /*
  251                  * [if another process is waiting for the raw I/O buffer,
  252                  *    wake up processes waiting to do physical I/O;
  253                  */
  254                 if (bp->b_flags & B_WANTED) {
  255                         bp->b_flags &= ~B_WANTED;
  256                         wakeup(bp);
  257                 }
  258         }
  259         splx(s);
  260 
  261         return (error);
  262 }
  263 
  264 /*
  265  * Leffler, et al., says on p. 231:
  266  * "The minphys() routine is called by physio() to adjust the
  267  * size of each I/O transfer before the latter is passed to
  268  * the strategy routine..." 
  269  *
  270  * so, just adjust the buffer's count accounting to MAXPHYS here,
  271  * and return the new count;
  272  */
  273 u_int
  274 minphys(bp)
  275         struct buf *bp;
  276 {
  277 
  278         bp->b_bcount = min(MAXPHYS, bp->b_bcount);
  279         return bp->b_bcount;
  280 }
  281 
  282 /*
  283  * Do a read on a device for a user process.
  284  */
  285 rawread(dev, uio)
  286         dev_t dev;
  287         struct uio *uio;
  288 {
  289         return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
  290             dev, B_READ, minphys, uio, DEV_BSIZE));
  291 }
  292 
  293 /*
  294  * Do a write on a device for a user process.
  295  */
  296 rawwrite(dev, uio)
  297         dev_t dev;
  298         struct uio *uio;
  299 {
  300         return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
  301             dev, B_WRITE, minphys, uio, DEV_BSIZE));
  302 }

Cache object: f44fe3b81e4d96f0dd0caf088b052526


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.