]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_physio.c
xnu-1228.tar.gz
[apple/xnu.git] / bsd / kern / kern_physio.c
index 2b6ba906219dd51664afb6dea9d4a735cb43bde1..2255daf1dc052389654ec75c8a3c486a27208d66 100644 (file)
@@ -1,23 +1,29 @@
 /*
  * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*-
  * Copyright (c) 1982, 1986, 1990, 1993
 #include <sys/conf.h>
 #include <sys/proc_internal.h>
 #include <sys/uio_internal.h>
+#include <kern/assert.h>
+
+int rawread(dev_t dev, struct uio *uio);
+int rawwrite(dev_t dev, struct uio *uio);
 
 int
-physio(strategy, bp, dev, flags, minphys, uio, blocksize)
-       void (*strategy)(); 
-       buf_t bp;
-       dev_t dev;
-       int flags;
-       u_int (*minphys)();
-       struct uio *uio;
-       int blocksize;
+physio( void (*f_strategy)(buf_t), 
+       buf_t bp,
+       dev_t dev,
+       int flags,
+       u_int (*f_minphys)(buf_t),
+       struct uio *uio,
+       int blocksize)
 {
        struct proc *p = current_proc();
-       int error, i, nobuf, todo, iosize;
+       int error, i, buf_allocated, todo, iosize;
+       int orig_bflags = 0;
 #if LP64KERN
        int64_t done;
 #else
@@ -91,6 +101,7 @@ physio(strategy, bp, dev, flags, minphys, uio, blocksize)
 
        error = 0;
        flags &= B_READ | B_WRITE;
+       buf_allocated = 0;
 
        /*
         * [check user read/write access to the data buffer]
@@ -100,32 +111,46 @@ physio(strategy, bp, dev, flags, minphys, uio, blocksize)
         * we're doing a read, that's a *write* to user-space.
         */
        for (i = 0; i < uio->uio_iovcnt; i++) {
-               if(UIO_SEG_IS_USER_SPACE(uio->uio_segflg)) {
+               if (UIO_SEG_IS_USER_SPACE(uio->uio_segflg)) {
                        if (!useracc(uio_iov_base_at(uio, i),
                                        uio_iov_len_at(uio, i),
                                (flags == B_READ) ? B_WRITE : B_READ))
                        return (EFAULT);
                }
        }
-       /* Make sure we have a buffer, creating one if necessary. */
-       if (nobuf = (bp == NULL)) {
-                       bp = buf_alloc((vnode_t)0);
-               }
-
-       /* [while the buffer is marked busy] */
-       while (((error = (int)buf_acquire(bp, 0, 0, 0)) == EAGAIN));
-       
-       if (error) {
-                       if (nobuf)
-                               buf_free(bp);
-               return (error);
-       }
+       /*
+        * Make sure we have a buffer, creating one if necessary.
+        */
+       if (bp == NULL) {
+               bp = buf_alloc((vnode_t)0);
+               buf_allocated = 1;
+       } else
+               orig_bflags = buf_flags(bp);
+       /*
+        * at this point we should have a buffer
+        * that is marked BL_BUSY... we either 
+        * acquired it via buf_alloc, or it was
+        * passed into us... if it was passed
+        * in, it needs to already be owned by
+        * the caller (i.e. BL_BUSY is set)
+        */
+       assert(bp->b_lflags & BL_BUSY);
 
-       /* [set up the fixed part of the buffer for a transfer] */
+       /*
+        * [set up the fixed part of the buffer for a transfer]
+        */
        bp->b_dev = dev;
        bp->b_proc = p;
 
-       buf_seterror(bp, 0);
+       /*
+        * [mark the buffer busy for physical I/O]
+        * (i.e. set B_PHYS (because it's an I/O to user
+        * memory, and B_RAW, because B_RAW is to be
+        * "Set by physio for raw transfers.", in addition
+        * to the read/write flag.)
+        */
+        buf_setflags(bp, B_PHYS | B_RAW);
+
        /*
         * [while there is data to transfer and no I/O error]
         * Note that I/O errors are handled with a 'goto' at the bottom
@@ -133,30 +158,27 @@ physio(strategy, bp, dev, flags, minphys, uio, blocksize)
         */
        for (i = 0; i < uio->uio_iovcnt; i++) {
                while (uio_iov_len_at(uio, i) > 0) {
-                       /*
-                        * [mark the buffer busy for physical I/O]
-                        * (i.e. set B_PHYS (because it's an I/O to user
-                        * memory, and B_RAW, because B_RAW is to be
-                        * "Set by physio for raw transfers.", in addition
-                        * to the read/write flag.)
-                        */
-                       buf_setflags(bp, B_PHYS | B_RAW | flags);
                        
                        if ( (iosize = uio_iov_len_at(uio, i)) > MAXPHYSIO_WIRED)
                                iosize = MAXPHYSIO_WIRED;
+                       /*
+                        * make sure we're set to issue a fresh I/O
+                        * in the right direction
+                        */
+                       buf_reset(bp, flags);
 
                        /* [set up the buffer for a maximum-sized transfer] */
                        buf_setblkno(bp, uio->uio_offset / blocksize);
                        buf_setcount(bp, iosize);
                        // LP64todo - fix this!
-                       buf_setdataptr(bp, CAST_DOWN(caddr_t, uio_iov_base_at(uio, i)));
+                       buf_setdataptr(bp, (uintptr_t)CAST_DOWN(caddr_t, uio_iov_base_at(uio, i)));
                        
                        /*
-                        * [call minphys to bound the tranfer size]
+                        * [call f_minphys to bound the tranfer size]
                         * and remember the amount of data to transfer,
                         * for later comparison.
                         */
-                       (*minphys)(bp);
+                       (*f_minphys)(bp);
                        todo = buf_count(bp);
 
                        /*
@@ -164,12 +186,15 @@ physio(strategy, bp, dev, flags, minphys, uio, blocksize)
                         *    in the transfer]
                         */
 
-                       if(UIO_SEG_IS_USER_SPACE(uio->uio_segflg))
-                               vslock(CAST_USER_ADDR_T(buf_dataptr(bp)),
-                                      (user_size_t)todo);
+                       if(UIO_SEG_IS_USER_SPACE(uio->uio_segflg)) {
+                               error = vslock(CAST_USER_ADDR_T(buf_dataptr(bp)),
+                                              (user_size_t)todo);
+                               if (error)
+                                       goto done;
+                       }
                        
-                       /* [call strategy to start the transfer] */
-                       (*strategy)(bp);
+                       /* [call f_strategy to start the transfer] */
+                       (*f_strategy)(bp);
 
 
                        /* [wait for the transfer to complete] */
@@ -204,19 +229,10 @@ physio(strategy, bp, dev, flags, minphys, uio, blocksize)
        }
 
 done:
-       /*
-        * [clean up the state of the buffer]
-        * Remember if somebody wants it, so we can wake them up below.
-        * Also, if we had to steal it, give it back.
-        */
-
-       buf_clearflags(bp, B_PHYS | B_RAW);
-       if (nobuf)
-               buf_free(bp);
-       else 
-               {
-                       buf_drop(bp);
-               }
+       if (buf_allocated)
+               buf_free(bp);
+       else
+               buf_setflags(bp, orig_bflags);
 
        return (error);
 }
@@ -231,8 +247,7 @@ done:
  * and return the new count;
  */
 u_int
-minphys(bp)
-       struct buf *bp;
+minphys(struct buf *bp)
 {
 
        buf_setcount(bp, min(MAXPHYS, buf_count(bp)));
@@ -242,9 +257,8 @@ minphys(bp)
 /*
  * Do a read on a device for a user process.
  */
-rawread(dev, uio)
-       dev_t dev;
-       struct uio *uio;
+int
+rawread(dev_t dev, struct uio *uio)
 {
        return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
            dev, B_READ, minphys, uio, DEV_BSIZE));
@@ -253,9 +267,8 @@ rawread(dev, uio)
 /*
  * Do a write on a device for a user process.
  */
-rawwrite(dev, uio)
-       dev_t dev;
-       struct uio *uio;
+int
+rawwrite(dev_t dev, struct uio *uio)
 {
        return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
            dev, B_WRITE, minphys, uio, DEV_BSIZE));