LCOV - code coverage report
Current view: top level - kern - kern_physio.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 69 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 2 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: kern_physio.c,v 1.43 2015/03/14 03:38:50 jsg Exp $    */
       2             : /*      $NetBSD: kern_physio.c,v 1.28 1997/05/19 10:43:28 pk Exp $      */
       3             : 
       4             : /*-
       5             :  * Copyright (c) 1994 Christopher G. Demetriou
       6             :  * Copyright (c) 1982, 1986, 1990, 1993
       7             :  *      The Regents of the University of California.  All rights reserved.
       8             :  * (c) UNIX System Laboratories, Inc.
       9             :  * All or some portions of this file are derived from material licensed
      10             :  * to the University of California by American Telephone and Telegraph
      11             :  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      12             :  * the permission of UNIX System Laboratories, Inc.
      13             :  *
      14             :  * Redistribution and use in source and binary forms, with or without
      15             :  * modification, are permitted provided that the following conditions
      16             :  * are met:
      17             :  * 1. Redistributions of source code must retain the above copyright
      18             :  *    notice, this list of conditions and the following disclaimer.
      19             :  * 2. Redistributions in binary form must reproduce the above copyright
      20             :  *    notice, this list of conditions and the following disclaimer in the
      21             :  *    documentation and/or other materials provided with the distribution.
      22             :  * 3. 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             :  *      @(#)kern_physio.c       8.1 (Berkeley) 6/10/93
      39             :  */
      40             : 
      41             : #include <sys/param.h>
      42             : #include <sys/systm.h>
      43             : #include <sys/buf.h>
      44             : #include <sys/pool.h>
      45             : 
      46             : #include <uvm/uvm_extern.h>
      47             : 
      48             : /*
      49             :  * The routines implemented in this file are described in:
      50             :  *      Leffler, et al.: The Design and Implementation of the 4.3BSD
      51             :  *          UNIX Operating System (Addison Welley, 1989)
      52             :  * on pages 231-233.
      53             :  */
      54             : 
      55             : /*
      56             :  * Do "physical I/O" on behalf of a user.  "Physical I/O" is I/O directly
      57             :  * from the raw device to user buffers, and bypasses the buffer cache.
      58             :  *
      59             :  * Comments in brackets are from Leffler, et al.'s pseudo-code implementation.
      60             :  */
      61             : int
      62           0 : physio(void (*strategy)(struct buf *), dev_t dev, int flags,
      63             :     void (*minphys)(struct buf *), struct uio *uio)
      64             : {
      65             :         struct iovec *iovp;
      66           0 :         struct proc *p = curproc;
      67             :         int error, done, i, s, todo;
      68             :         struct buf *bp;
      69             : 
      70           0 :         if ((uio->uio_offset % DEV_BSIZE) != 0)
      71           0 :                 return (EINVAL);
      72             : 
      73             :         error = 0;
      74           0 :         flags &= B_READ | B_WRITE;
      75             : 
      76             :         /* Create a buffer. */
      77           0 :         s = splbio();
      78           0 :         bp = pool_get(&bufpool, PR_WAITOK | PR_ZERO);
      79             : 
      80             :         /* [set up the fixed part of the buffer for a transfer] */
      81           0 :         bp->b_vnbufs.le_next = NOLIST;
      82           0 :         bp->b_dev = dev;
      83           0 :         bp->b_error = 0;
      84           0 :         bp->b_proc = p;
      85           0 :         bp->b_flags = B_BUSY;
      86           0 :         LIST_INIT(&bp->b_dep);
      87           0 :         splx(s);
      88             : 
      89             :         /*
      90             :          * [while there are data to transfer and no I/O error]
      91             :          * Note that I/O errors are handled with a 'goto' at the bottom
      92             :          * of the 'while' loop.
      93             :          */
      94           0 :         for (i = 0; i < uio->uio_iovcnt; i++) {
      95           0 :                 iovp = &uio->uio_iov[i];
      96           0 :                 while (iovp->iov_len > 0) {
      97           0 :                         void *map = NULL;
      98             : 
      99             :                         /*
     100             :                          * [mark the buffer busy for physical I/O]
     101             :                          * (i.e. set B_PHYS (because it's an I/O to user
     102             :                          * memory), and B_RAW, because B_RAW is to be
     103             :                          * "Set by physio for raw transfers.", in addition
     104             :                          * to the "busy" and read/write flag.)
     105             :                          */
     106           0 :                         CLR(bp->b_flags, B_DONE | B_ERROR);
     107           0 :                         bp->b_flags |= (B_BUSY | B_PHYS | B_RAW | flags);
     108             : 
     109             :                         /* [set up the buffer for a maximum-sized transfer] */
     110           0 :                         bp->b_blkno = btodb(uio->uio_offset);
     111             : 
     112             :                         /*
     113             :                          * Because iov_len is unsigned but b_bcount is signed,
     114             :                          * an overflow is possible. Therefore bound to MAXPHYS
     115             :                          * before calling minphys.
     116             :                          */
     117           0 :                         if (iovp->iov_len > MAXPHYS)
     118           0 :                                 bp->b_bcount = MAXPHYS;
     119             :                         else
     120           0 :                                 bp->b_bcount = iovp->iov_len;
     121             : 
     122             :                         /*
     123             :                          * [call minphys to bound the transfer size]
     124             :                          * and remember the amount of data to transfer,
     125             :                          * for later comparison.
     126             :                          */
     127           0 :                         (*minphys)(bp);
     128           0 :                         todo = bp->b_bcount;
     129           0 :                         KASSERTMSG(todo >= 0, "minphys broken");
     130           0 :                         KASSERTMSG(todo <= MAXPHYS, "minphys broken");
     131             : 
     132             :                         /*
     133             :                          * [lock the part of the user address space involved
     134             :                          *    in the transfer]
     135             :                          * Beware vmapbuf(); it clobbers b_data and
     136             :                          * saves it in b_saveaddr.  However, vunmapbuf()
     137             :                          * restores it.
     138             :                          */
     139           0 :                         error = uvm_vslock_device(p, iovp->iov_base, todo,
     140           0 :                             (flags & B_READ) ?
     141             :                             PROT_READ | PROT_WRITE : PROT_READ, &map);
     142           0 :                         if (error)
     143           0 :                                 goto done;
     144           0 :                         if (map) {
     145           0 :                                 bp->b_data = map;
     146           0 :                         } else {
     147           0 :                                 bp->b_data = iovp->iov_base;
     148           0 :                                 vmapbuf(bp, todo);
     149             :                         }
     150             : 
     151             :                         /* [call strategy to start the transfer] */
     152           0 :                         (*strategy)(bp);
     153             : 
     154             :                         /*
     155             :                          * Note that the raise/wait/lower/get error
     156             :                          * steps below would be done by biowait(), but
     157             :                          * we want to unlock the address space before
     158             :                          * we lower the priority.
     159             :                          *
     160             :                          * [raise the priority level to splbio]
     161             :                          */
     162           0 :                         s = splbio();
     163             : 
     164             :                         /* [wait for the transfer to complete] */
     165           0 :                         while ((bp->b_flags & B_DONE) == 0)
     166           0 :                                 tsleep(bp, PRIBIO + 1, "physio", 0);
     167             : 
     168             :                         /* Mark it busy again, so nobody else will use it. */
     169           0 :                         bp->b_flags |= B_BUSY;
     170             : 
     171             :                         /* [lower the priority level] */
     172           0 :                         splx(s);
     173             : 
     174             :                         /*
     175             :                          * [unlock the part of the address space previously
     176             :                          *    locked]
     177             :                          */
     178           0 :                         if (!map)
     179           0 :                                 vunmapbuf(bp, todo);
     180           0 :                         uvm_vsunlock_device(p, iovp->iov_base, todo, map);
     181             : 
     182             :                         /* remember error value (save a splbio/splx pair) */
     183           0 :                         if (bp->b_flags & B_ERROR)
     184           0 :                                 error = (bp->b_error ? bp->b_error : EIO);
     185             : 
     186             :                         /*
     187             :                          * [deduct the transfer size from the total number
     188             :                          *    of data to transfer]
     189             :                          */
     190           0 :                         done = bp->b_bcount - bp->b_resid;
     191           0 :                         KASSERTMSG(done >= 0, "strategy broken");
     192           0 :                         KASSERTMSG(done <= todo, "strategy broken");
     193           0 :                         iovp->iov_len -= done;
     194           0 :                         iovp->iov_base = (caddr_t)iovp->iov_base + done;
     195           0 :                         uio->uio_offset += done;
     196           0 :                         uio->uio_resid -= done;
     197             : 
     198             :                         /*
     199             :                          * Now, check for an error.
     200             :                          * Also, handle weird end-of-disk semantics.
     201             :                          */
     202           0 :                         if (error || done < todo)
     203           0 :                                 goto done;
     204           0 :                 }
     205             :         }
     206             : 
     207             : done:
     208             :         /*
     209             :          * [clean up the state of the buffer]
     210             :          */
     211           0 :         s = splbio();
     212             :         /* XXXCDC: is this necessary? */
     213           0 :         if (bp->b_vp)
     214           0 :                 brelvp(bp);
     215           0 :         splx(s);
     216           0 :         pool_put(&bufpool, bp);
     217             : 
     218           0 :         return (error);
     219           0 : }
     220             : 
     221             : /*
     222             :  * Leffler, et al., says on p. 231:
     223             :  * "The minphys() routine is called by physio() to adjust the
     224             :  * size of each I/O transfer before the latter is passed to
     225             :  * the strategy routine..."
     226             :  *
     227             :  * so, just adjust the buffer's count accounting to MAXPHYS here,
     228             :  * and return the new count;
     229             :  */
     230             : void
     231           0 : minphys(struct buf *bp)
     232             : {
     233             : 
     234           0 :         if (bp->b_bcount > MAXPHYS)
     235           0 :                 bp->b_bcount = MAXPHYS;
     236           0 : }

Generated by: LCOV version 1.13