X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/0a7648b9333fb5113d573ed36bfb52cc80346a60..HEAD:/sys/kern/kern_xio.c diff --git a/sys/kern/kern_xio.c b/sys/kern/kern_xio.c index 03442d2759..b789dac4e2 100644 --- a/sys/kern/kern_xio.c +++ b/sys/kern/kern_xio.c @@ -30,8 +30,6 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * 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 $ */ /* * Kernel XIO interface. An initialized XIO is basically a collection of @@ -49,12 +47,14 @@ #include #include +#include #include #include #include #include #include -#include + +#include #include #include @@ -83,65 +83,15 @@ xio_init(xio_t xio) xio->xio_pages = xio->xio_internal_pages; } -/* - * Initialize an XIO given a userspace buffer. 0 is returned on success, - * an error code on failure. The actual number of bytes that could be - * accomodated in the XIO will be stored in xio_bytes and the page offset - * will be stored in xio_offset. - */ -int -xio_init_ubuf(xio_t xio, void *ubase, size_t ubytes, int flags) -{ - vm_offset_t addr; - vm_page_t m; - int error; - int i; - int n; - int vmprot; - - addr = trunc_page((vm_offset_t)ubase); - xio->xio_flags = flags; - xio->xio_bytes = 0; - xio->xio_error = 0; - if (ubytes == 0) { - xio->xio_offset = 0; - xio->xio_npages = 0; - } else { - vmprot = (flags & XIOF_WRITE) ? VM_PROT_WRITE : VM_PROT_READ; - xio->xio_offset = (vm_offset_t)ubase & PAGE_MASK; - xio->xio_pages = xio->xio_internal_pages; - if ((n = PAGE_SIZE - xio->xio_offset) > ubytes) - n = ubytes; - for (i = 0; n && i < XIO_INTERNAL_PAGES; ++i) { - m = vm_fault_page_quick(addr, vmprot, &error); - if (m == NULL) - break; - xio->xio_pages[i] = m; - ubytes -= n; - xio->xio_bytes += n; - if ((n = ubytes) > PAGE_SIZE) - n = PAGE_SIZE; - addr += PAGE_SIZE; - } - xio->xio_npages = i; - - /* - * If a failure occured clean out what we loaded and return EFAULT. - * Return 0 on success. - */ - if (i < XIO_INTERNAL_PAGES && n) { - xio_release(xio); - xio->xio_error = EFAULT; - } - } - return(xio->xio_error); -} - /* * Initialize an XIO given a kernelspace buffer. 0 is returned on success, * an error code on failure. The actual number of bytes that could be * accomodated in the XIO will be stored in xio_bytes and the page offset * will be stored in xio_offset. + * + * WARNING! We cannot map user memory directly into an xio unless we also + * make the mapping use managed pages, otherwise modifications to + * the memory will race against pageouts and flushes. */ int xio_init_kbuf(xio_t xio, void *kbase, size_t kbytes) @@ -163,10 +113,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; @@ -187,6 +135,30 @@ xio_init_kbuf(xio_t xio, void *kbase, size_t kbytes) return(xio->xio_error); } +/* + * 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 +169,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 +194,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 +229,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 +245,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 +278,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 +294,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 +325,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 +341,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 +374,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 +390,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)