kernel - Redo struct vmspace allocator and ref-count handling.
[dragonfly.git] / sys / kern / kern_xio.c
index 03442d2..6697006 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/kern/kern_xio.c,v 1.13 2007/06/29 00:18:05 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_xio.c,v 1.16 2008/05/09 07:24:45 dillon Exp $
  */
 /*
  * Kernel XIO interface.  An initialized XIO is basically a collection of
@@ -54,7 +54,8 @@
 #include <sys/vmmeter.h>
 #include <sys/vnode.h>
 #include <sys/xio.h>
-#include <sys/sfbuf.h>
+
+#include <cpu/lwbuf.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -94,6 +95,7 @@ xio_init_ubuf(xio_t xio, void *ubase, size_t ubytes, int flags)
 {
     vm_offset_t addr;
     vm_page_t m;
+    vm_page_t m0;
     int error;
     int i;
     int n;
@@ -112,6 +114,7 @@ xio_init_ubuf(xio_t xio, void *ubase, size_t ubytes, int flags)
        xio->xio_pages = xio->xio_internal_pages;
        if ((n = PAGE_SIZE - xio->xio_offset) > ubytes)
            n = ubytes;
+       m0 = NULL;
        for (i = 0; n && i < XIO_INTERNAL_PAGES; ++i) {
            m = vm_fault_page_quick(addr, vmprot, &error);
            if (m == NULL)
@@ -122,14 +125,28 @@ xio_init_ubuf(xio_t xio, void *ubase, size_t ubytes, int flags)
            if ((n = ubytes) > PAGE_SIZE)
                n = PAGE_SIZE;
            addr += PAGE_SIZE;
+
+           /*
+            * Check linearity, used by syslink to memory map DMA buffers.
+            */
+           if (flags & XIOF_VMLINEAR) {
+               if (i == 0) {
+                   m0 = m;
+               } else 
+               if (m->object != m0->object || m->pindex != m0->pindex + i) {
+                   error = EINVAL;
+                   break;
+               }
+           }
        }
        xio->xio_npages = i;
 
        /*
         * If a failure occured clean out what we loaded and return EFAULT.
-        * Return 0 on success.
+        * Return 0 on success.  Do not dirty the pages.
         */
        if (i < XIO_INTERNAL_PAGES && n) {
+           xio->xio_flags &= ~XIOF_WRITE;
            xio_release(xio);
            xio->xio_error = EFAULT;
        }
@@ -163,10 +180,8 @@ xio_init_kbuf(xio_t xio, void *kbase, size_t kbytes)
     for (i = 0; n && i < XIO_INTERNAL_PAGES; ++i) {
        if ((paddr = pmap_kextract(addr)) == 0)
            break;
-       crit_enter();
        m = PHYS_TO_VM_PAGE(paddr);
        vm_page_hold(m);
-       crit_exit();
        xio->xio_pages[i] = m;
        kbytes -= n;
        xio->xio_bytes += n;
@@ -188,6 +203,30 @@ xio_init_kbuf(xio_t xio, void *kbase, size_t kbytes)
 }
 
 /*
+ * Initialize an XIO given an array of vm_page pointers.  The caller is
+ * responsible for any modified state changes for the pages.
+ */
+int
+xio_init_pages(xio_t xio, struct vm_page **mbase, int npages, int xflags)
+{
+    int i;
+
+    KKASSERT(npages <= XIO_INTERNAL_PAGES);
+
+    xio->xio_flags = xflags;
+    xio->xio_offset = 0;
+    xio->xio_bytes = npages * PAGE_SIZE;
+    xio->xio_pages = xio->xio_internal_pages;
+    xio->xio_npages = npages;
+    xio->xio_error = 0;
+    for (i = 0; i < npages; ++i) {
+       vm_page_hold(mbase[i]);
+       xio->xio_pages[i] = mbase[i];
+    }
+    return(0);
+}
+
+/*
  * Cleanup an XIO so it can be destroyed.  The pages associated with the
  * XIO are released.
  */
@@ -197,12 +236,12 @@ xio_release(xio_t xio)
     int i;
     vm_page_t m;
 
-    crit_enter();
     for (i = 0; i < xio->xio_npages; ++i) {
        m = xio->xio_pages[i];
+       if (xio->xio_flags & XIOF_WRITE)
+               vm_page_dirty(m);
        vm_page_unhold(m);
     }
-    crit_exit();
     xio->xio_offset = 0;
     xio->xio_npages = 0;
     xio->xio_bytes = 0;
@@ -222,10 +261,10 @@ xio_release(xio_t xio)
  * UIO_WRITE   uio -> xio
  */
 int
-xio_uio_copy(xio_t xio, int uoffset, struct uio *uio, int *sizep)
+xio_uio_copy(xio_t xio, int uoffset, struct uio *uio, size_t *sizep)
 {
+    size_t bytes;
     int error;
-    int bytes;
 
     bytes = xio->xio_bytes - uoffset;
     if (bytes > uio->uio_resid)
@@ -257,7 +296,8 @@ xio_copy_xtou(xio_t xio, int uoffset, void *uptr, int bytes)
     int error;
     int offset;
     vm_page_t m;
-    struct sf_buf *sf;
+    struct lwbuf *lwb;
+    struct lwbuf lwb_cache;
 
     if (uoffset + bytes > xio->xio_bytes)
        return(EFAULT);
@@ -272,9 +312,9 @@ xio_copy_xtou(xio_t xio, int uoffset, void *uptr, int bytes)
         ++i
     ) {
        m = xio->xio_pages[i];
-       sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
-       error = copyout((char *)sf_buf_kva(sf) + offset, uptr, n);
-       sf_buf_free(sf);
+       lwb = lwbuf_alloc(m, &lwb_cache);
+       error = copyout((char *)lwbuf_kva(lwb) + offset, uptr, n);
+       lwbuf_free(lwb);
        if (error)
            break;
        bytes -= n;
@@ -305,7 +345,8 @@ xio_copy_xtok(xio_t xio, int uoffset, void *kptr, int bytes)
     int error;
     int offset;
     vm_page_t m;
-    struct sf_buf *sf;
+    struct lwbuf *lwb;
+    struct lwbuf lwb_cache;
 
     if (bytes + uoffset > xio->xio_bytes)
        return(EFAULT);
@@ -320,9 +361,9 @@ xio_copy_xtok(xio_t xio, int uoffset, void *kptr, int bytes)
         ++i
     ) {
        m = xio->xio_pages[i];
-       sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
-       bcopy((char *)sf_buf_kva(sf) + offset, kptr, n);
-       sf_buf_free(sf);
+       lwb = lwbuf_alloc(m, &lwb_cache);
+       bcopy((char *)lwbuf_kva(lwb) + offset, kptr, n);
+       lwbuf_free(lwb);
        bytes -= n;
        kptr = (char *)kptr + n;
        if (bytes == 0)
@@ -351,7 +392,8 @@ xio_copy_utox(xio_t xio, int uoffset, const void *uptr, int bytes)
     int error;
     int offset;
     vm_page_t m;
-    struct sf_buf *sf;
+    struct lwbuf *lwb;
+    struct lwbuf lwb_cache;
 
     if (uoffset + bytes > xio->xio_bytes)
        return(EFAULT);
@@ -366,9 +408,9 @@ xio_copy_utox(xio_t xio, int uoffset, const void *uptr, int bytes)
         ++i
     ) {
        m = xio->xio_pages[i];
-       sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
-       error = copyin(uptr, (char *)sf_buf_kva(sf) + offset, n);
-       sf_buf_free(sf);
+       lwb = lwbuf_alloc(m, &lwb_cache);
+       error = copyin(uptr, (char *)lwbuf_kva(lwb) + offset, n);
+       lwbuf_free(lwb);
        if (error)
            break;
        bytes -= n;
@@ -399,7 +441,8 @@ xio_copy_ktox(xio_t xio, int uoffset, const void *kptr, int bytes)
     int error;
     int offset;
     vm_page_t m;
-    struct sf_buf *sf;
+    struct lwbuf *lwb;
+    struct lwbuf lwb_cache;
 
     if (uoffset + bytes > xio->xio_bytes)
        return(EFAULT);
@@ -414,9 +457,9 @@ xio_copy_ktox(xio_t xio, int uoffset, const void *kptr, int bytes)
         ++i
     ) {
        m = xio->xio_pages[i];
-       sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
-       bcopy(kptr, (char *)sf_buf_kva(sf) + offset, n);
-       sf_buf_free(sf);
+       lwb = lwbuf_alloc(m, &lwb_cache);
+       bcopy(kptr, (char *)lwbuf_kva(lwb) + offset, n);
+       lwbuf_free(lwb);
        bytes -= n;
        kptr = (const char *)kptr + n;
        if (bytes == 0)