Module Name: src Committed By: pooka Date: Mon Apr 29 12:56:04 UTC 2013
Modified Files: src/lib/librumpuser: Makefile rumpuser.c rumpuser_int.h rumpuser_pth.c src/sys/rump/include/rump: rumpuser.h src/sys/rump/librump/rumpvfs: rump_vfs.c rumpblk.c Added Files: src/lib/librumpuser: rumpuser_bio.c Log Message: Rework how the bio hypercalls work, part 1/n: Reduce the set of hypercalls to one: "do block i/o". This not only eliminates a lot of pseudo-duplicate code, it also gives the hypervisor a lot more freedom on how to optimize the i/o. To generate a diff of this commit: cvs rdiff -u -r1.9 -r1.10 src/lib/librumpuser/Makefile cvs rdiff -u -r1.37 -r1.38 src/lib/librumpuser/rumpuser.c cvs rdiff -u -r0 -r1.1 src/lib/librumpuser/rumpuser_bio.c cvs rdiff -u -r1.5 -r1.6 src/lib/librumpuser/rumpuser_int.h cvs rdiff -u -r1.16 -r1.17 src/lib/librumpuser/rumpuser_pth.c cvs rdiff -u -r1.88 -r1.89 src/sys/rump/include/rump/rumpuser.h cvs rdiff -u -r1.73 -r1.74 src/sys/rump/librump/rumpvfs/rump_vfs.c cvs rdiff -u -r1.48 -r1.49 src/sys/rump/librump/rumpvfs/rumpblk.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/librumpuser/Makefile diff -u src/lib/librumpuser/Makefile:1.9 src/lib/librumpuser/Makefile:1.10 --- src/lib/librumpuser/Makefile:1.9 Mon Mar 18 13:14:10 2013 +++ src/lib/librumpuser/Makefile Mon Apr 29 12:56:04 2013 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.9 2013/03/18 13:14:10 pooka Exp $ +# $NetBSD: Makefile,v 1.10 2013/04/29 12:56:04 pooka Exp $ # WARNS?= 5 @@ -13,7 +13,7 @@ CPPFLAGS+= -DLIBRUMPUSER SRCS= rumpuser.c SRCS+= rumpuser_pth.c -SRCS+= rumpuser_dl.c rumpuser_sp.c rumpuser_daemonize.c +SRCS+= rumpuser_dl.c rumpuser_sp.c rumpuser_daemonize.c rumpuser_bio.c SRCS+= rumpuser_component.c INCSDIR= /usr/include/rump Index: src/lib/librumpuser/rumpuser.c diff -u src/lib/librumpuser/rumpuser.c:1.37 src/lib/librumpuser/rumpuser.c:1.38 --- src/lib/librumpuser/rumpuser.c:1.37 Sun Apr 28 13:39:13 2013 +++ src/lib/librumpuser/rumpuser.c Mon Apr 29 12:56:04 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: rumpuser.c,v 1.37 2013/04/28 13:39:13 pooka Exp $ */ +/* $NetBSD: rumpuser.c,v 1.38 2013/04/29 12:56:04 pooka Exp $ */ /* * Copyright (c) 2007-2010 Antti Kantee. All Rights Reserved. @@ -28,7 +28,7 @@ #include "rumpuser_port.h" #if !defined(lint) -__RCSID("$NetBSD: rumpuser.c,v 1.37 2013/04/28 13:39:13 pooka Exp $"); +__RCSID("$NetBSD: rumpuser.c,v 1.38 2013/04/29 12:56:04 pooka Exp $"); #endif /* !lint */ #include <sys/ioctl.h> @@ -403,22 +403,6 @@ rumpuser_pread(int fd, void *data, size_ return rv; } -void -rumpuser_read_bio(int fd, void *data, size_t size, off_t offset, - rump_biodone_fn biodone, void *biodonecookie) -{ - ssize_t rv; - int error = 0; - - rv = rumpuser_pread(fd, data, size, offset, &error); - /* check against <0 instead of ==-1 to get typing below right */ - if (rv < 0) - rv = 0; - - /* LINTED: see above */ - biodone(biodonecookie, rv, error); -} - ssize_t rumpuser_write(int fd, const void *data, size_t size, int *error) { @@ -443,22 +427,6 @@ rumpuser_pwrite(int fd, const void *data return rv; } -void -rumpuser_write_bio(int fd, const void *data, size_t size, off_t offset, - rump_biodone_fn biodone, void *biodonecookie) -{ - ssize_t rv; - int error = 0; - - rv = rumpuser_pwrite(fd, data, size, offset, &error); - /* check against <0 instead of ==-1 to get typing below right */ - if (rv < 0) - rv = 0; - - /* LINTED: see above */ - biodone(biodonecookie, rv, error); -} - ssize_t rumpuser_readv(int fd, const struct rumpuser_iovec *riov, int iovcnt, int *error) Index: src/lib/librumpuser/rumpuser_int.h diff -u src/lib/librumpuser/rumpuser_int.h:1.5 src/lib/librumpuser/rumpuser_int.h:1.6 --- src/lib/librumpuser/rumpuser_int.h:1.5 Sat Apr 27 14:59:08 2013 +++ src/lib/librumpuser/rumpuser_int.h Mon Apr 29 12:56:04 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: rumpuser_int.h,v 1.5 2013/04/27 14:59:08 pooka Exp $ */ +/* $NetBSD: rumpuser_int.h,v 1.6 2013/04/29 12:56:04 pooka Exp $ */ /* * Copyright (c) 2008 Antti Kantee. All Rights Reserved. @@ -68,3 +68,15 @@ do { \ } void rumpuser__thrinit(void); + +#define NOFAIL(a) do {if (!(a)) abort();} while (/*CONSTCOND*/0) + +#define NOFAIL_ERRNO(a) \ +do { \ + int fail_rv = (a); \ + if (fail_rv) { \ + printf("panic: rumpuser fatal failure %d (%s)\n", \ + fail_rv, strerror(fail_rv)); \ + abort(); \ + } \ +} while (/*CONSTCOND*/0) Index: src/lib/librumpuser/rumpuser_pth.c diff -u src/lib/librumpuser/rumpuser_pth.c:1.16 src/lib/librumpuser/rumpuser_pth.c:1.17 --- src/lib/librumpuser/rumpuser_pth.c:1.16 Sun Apr 28 13:37:51 2013 +++ src/lib/librumpuser/rumpuser_pth.c Mon Apr 29 12:56:04 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: rumpuser_pth.c,v 1.16 2013/04/28 13:37:51 pooka Exp $ */ +/* $NetBSD: rumpuser_pth.c,v 1.17 2013/04/29 12:56:04 pooka Exp $ */ /* * Copyright (c) 2007-2010 Antti Kantee. All Rights Reserved. @@ -28,7 +28,7 @@ #include "rumpuser_port.h" #if !defined(lint) -__RCSID("$NetBSD: rumpuser_pth.c,v 1.16 2013/04/28 13:37:51 pooka Exp $"); +__RCSID("$NetBSD: rumpuser_pth.c,v 1.17 2013/04/29 12:56:04 pooka Exp $"); #endif /* !lint */ #include <assert.h> @@ -47,17 +47,6 @@ __RCSID("$NetBSD: rumpuser_pth.c,v 1.16 static pthread_key_t curlwpkey; -#define NOFAIL(a) do {if (!(a)) abort();} while (/*CONSTCOND*/0) -#define NOFAIL_ERRNO(a) \ -do { \ - int fail_rv = (a); \ - if (fail_rv) { \ - printf("panic: rumpuser fatal failure %d (%s)\n", \ - fail_rv, strerror(fail_rv)); \ - abort(); \ - } \ -} while (/*CONSTCOND*/0) - struct rumpuser_mtx { pthread_mutex_t pthmtx; struct lwp *owner; @@ -106,84 +95,13 @@ struct rumpuser_cv { int nwaiters; }; -struct rumpuser_mtx rumpuser_aio_mtx; -struct rumpuser_cv rumpuser_aio_cv; -int rumpuser_aio_head, rumpuser_aio_tail; -struct rumpuser_aio rumpuser_aios[N_AIOS]; - void rumpuser__thrinit(void) { - pthread_mutex_init(&rumpuser_aio_mtx.pthmtx, NULL); - pthread_cond_init(&rumpuser_aio_cv.pthcv, NULL); pthread_key_create(&curlwpkey, NULL); } -void -/*ARGSUSED*/ -rumpuser_biothread(void *arg) -{ - struct rumpuser_aio *rua; - rump_biodone_fn biodone = arg; - ssize_t rv; - int error, dummy; - - /* unschedule from CPU. we reschedule before running the interrupt */ - rumpuser__unschedule(0, &dummy, NULL); - assert(dummy == 0); - - NOFAIL_ERRNO(pthread_mutex_lock(&rumpuser_aio_mtx.pthmtx)); - for (;;) { - while (rumpuser_aio_head == rumpuser_aio_tail) { - NOFAIL_ERRNO(pthread_cond_wait(&rumpuser_aio_cv.pthcv, - &rumpuser_aio_mtx.pthmtx)); - } - - rua = &rumpuser_aios[rumpuser_aio_tail]; - assert(rua->rua_bp != NULL); - pthread_mutex_unlock(&rumpuser_aio_mtx.pthmtx); - - if (rua->rua_op & RUA_OP_READ) { - error = 0; - rv = pread(rua->rua_fd, rua->rua_data, - rua->rua_dlen, rua->rua_off); - if (rv < 0) { - rv = 0; - error = errno; - } - } else { - error = 0; - rv = pwrite(rua->rua_fd, rua->rua_data, - rua->rua_dlen, rua->rua_off); - if (rv < 0) { - rv = 0; - error = errno; - } else if (rua->rua_op & RUA_OP_SYNC) { -#ifdef __NetBSD__ - fsync_range(rua->rua_fd, FDATASYNC, - rua->rua_off, rua->rua_dlen); -#else - fsync(rua->rua_fd); -#endif - } - } - rumpuser__reschedule(0, NULL); - biodone(rua->rua_bp, (size_t)rv, error); - rumpuser__unschedule(0, &dummy, NULL); - - rua->rua_bp = NULL; - - NOFAIL_ERRNO(pthread_mutex_lock(&rumpuser_aio_mtx.pthmtx)); - rumpuser_aio_tail = (rumpuser_aio_tail+1) % N_AIOS; - pthread_cond_signal(&rumpuser_aio_cv.pthcv); - } - - /*NOTREACHED*/ - fprintf(stderr, "error: rumpuser_biothread reached unreachable\n"); - abort(); -} - int rumpuser_thread_create(void *(*f)(void *), void *arg, const char *thrname, int joinable, void **ptcookie) Index: src/sys/rump/include/rump/rumpuser.h diff -u src/sys/rump/include/rump/rumpuser.h:1.88 src/sys/rump/include/rump/rumpuser.h:1.89 --- src/sys/rump/include/rump/rumpuser.h:1.88 Sun Apr 28 13:17:24 2013 +++ src/sys/rump/include/rump/rumpuser.h Mon Apr 29 12:56:03 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: rumpuser.h,v 1.88 2013/04/28 13:17:24 pooka Exp $ */ +/* $NetBSD: rumpuser.h,v 1.89 2013/04/29 12:56:03 pooka Exp $ */ /* * Copyright (c) 2007-2013 Antti Kantee. All Rights Reserved. @@ -65,31 +65,29 @@ void *rumpuser_filemmap(int fd, off_t, s void rumpuser_unmap(void *, size_t); int rumpuser_memsync(void *, size_t, int *); -/* - * Open modes. these "accidentally" happen to match the respective - * NetBSD bit representations to preserve NetBSD binary compat for - * current users. If you need to add new ones, just pick any numbers. - */ -#define RUMPUSER_OPEN_RDONLY 0x000000 -#define RUMPUSER_OPEN_WRONLY 0x000001 -#define RUMPUSER_OPEN_RDWR 0x000002 -#define RUMPUSER_OPEN_ACCMODE 0x000003 /* "yay" */ -#define RUMPUSER_OPEN_CREATE 0x000200 -#define RUMPUSER_OPEN_EXCL 0x000800 -#define RUMPUSER_OPEN_DIRECT 0x080000 +#define RUMPUSER_OPEN_RDONLY 0x0000 +#define RUMPUSER_OPEN_WRONLY 0x0001 +#define RUMPUSER_OPEN_RDWR 0x0002 +#define RUMPUSER_OPEN_ACCMODE 0x0003 /* "yay" */ +#define RUMPUSER_OPEN_CREATE 0x0004 /* create file if it doesn't exist */ +#define RUMPUSER_OPEN_EXCL 0x0008 /* exclusive open */ +#define RUMPUSER_OPEN_DIRECT 0x0010 /* use direct i/o */ +#define RUMPUSER_OPEN_BIO 0x0020 /* open device for block i/o */ int rumpuser_open(const char *, int, int *); int rumpuser_close(int, int *); int rumpuser_fsync(int, int *); +#define RUMPUSER_BIO_READ 0x01 +#define RUMPUSER_BIO_WRITE 0x02 +#define RUMPUSER_BIO_SYNC 0x04 typedef void (*rump_biodone_fn)(void *, size_t, int); +void rumpuser_bio(int, int, void *, size_t, off_t, rump_biodone_fn, void *); ssize_t rumpuser_read(int, void *, size_t, int *); ssize_t rumpuser_pread(int, void *, size_t, off_t, int *); ssize_t rumpuser_write(int, const void *, size_t, int *); ssize_t rumpuser_pwrite(int, const void *, size_t, off_t, int *); -void rumpuser_read_bio(int, void *, size_t, off_t, rump_biodone_fn, void *); -void rumpuser_write_bio(int, const void *, size_t, off_t,rump_biodone_fn,void*); struct rumpuser_iovec { void *iov_base; @@ -124,8 +122,6 @@ int rumpuser_getnhostcpu(void); #define RUMPUSER_RANDOM_NOWAIT 0x02 size_t rumpuser_getrandom(void *, size_t, int); -__dead void rumpuser_biothread(void *); - int rumpuser_thread_create(void *(*f)(void *), void *, const char *, int, void **); void rumpuser_thread_exit(void) __dead; @@ -167,25 +163,6 @@ void rumpuser_cv_signal(struct rumpuser_ void rumpuser_cv_broadcast(struct rumpuser_cv *); int rumpuser_cv_has_waiters(struct rumpuser_cv *); -/* "aio" stuff for being able to fire of a B_ASYNC I/O and continue */ -struct rumpuser_aio { - int rua_fd; - uint8_t *rua_data; - size_t rua_dlen; - off_t rua_off; - void *rua_bp; - int rua_op; -}; -#define RUA_OP_READ 0x01 -#define RUA_OP_WRITE 0x02 -#define RUA_OP_SYNC 0x04 - -#define N_AIOS 1024 -extern struct rumpuser_mtx rumpuser_aio_mtx; -extern struct rumpuser_cv rumpuser_aio_cv; -extern struct rumpuser_aio rumpuser_aios[N_AIOS]; -extern int rumpuser_aio_head, rumpuser_aio_tail; - /* rumpuser dynloader */ struct modinfo; Index: src/sys/rump/librump/rumpvfs/rump_vfs.c diff -u src/sys/rump/librump/rumpvfs/rump_vfs.c:1.73 src/sys/rump/librump/rumpvfs/rump_vfs.c:1.74 --- src/sys/rump/librump/rumpvfs/rump_vfs.c:1.73 Thu Apr 4 11:21:37 2013 +++ src/sys/rump/librump/rumpvfs/rump_vfs.c Mon Apr 29 12:56:03 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: rump_vfs.c,v 1.73 2013/04/04 11:21:37 pooka Exp $ */ +/* $NetBSD: rump_vfs.c,v 1.74 2013/04/29 12:56:03 pooka Exp $ */ /* * Copyright (c) 2008 Antti Kantee. All Rights Reserved. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: rump_vfs.c,v 1.73 2013/04/04 11:21:37 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rump_vfs.c,v 1.74 2013/04/29 12:56:03 pooka Exp $"); #include <sys/param.h> #include <sys/buf.h> @@ -126,12 +126,6 @@ RUMP_COMPONENT(RUMP__FACTION_VFS) spec_init(); fstrans_init(); - if (rump_threads) { - if ((rv = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, - rumpuser_biothread, rump_biodone, NULL, "rmpabio")) != 0) - panic("syncer thread create failed: %d", rv); - } - root_device = &rump_rootdev; /* bootstrap cwdi (rest done in vfs_mountroot() */ Index: src/sys/rump/librump/rumpvfs/rumpblk.c diff -u src/sys/rump/librump/rumpvfs/rumpblk.c:1.48 src/sys/rump/librump/rumpvfs/rumpblk.c:1.49 --- src/sys/rump/librump/rumpvfs/rumpblk.c:1.48 Fri Sep 14 16:29:21 2012 +++ src/sys/rump/librump/rumpvfs/rumpblk.c Mon Apr 29 12:56:03 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: rumpblk.c,v 1.48 2012/09/14 16:29:21 pooka Exp $ */ +/* $NetBSD: rumpblk.c,v 1.49 2013/04/29 12:56:03 pooka Exp $ */ /* * Copyright (c) 2009 Antti Kantee. All Rights Reserved. @@ -52,7 +52,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: rumpblk.c,v 1.48 2012/09/14 16:29:21 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rumpblk.c,v 1.49 2013/04/29 12:56:03 pooka Exp $"); #include <sys/param.h> #include <sys/buf.h> @@ -504,9 +504,11 @@ backend_open(struct rblkdev *rblk, const int error, fd; KASSERT(rblk->rblk_fd == -1); - fd = rumpuser_open(path, RUMPUSER_OPEN_RDWR, &error); + fd = rumpuser_open(path, + RUMPUSER_OPEN_RDWR | RUMPUSER_OPEN_BIO, &error); if (error) { - fd = rumpuser_open(path, RUMPUSER_OPEN_RDONLY, &error); + fd = rumpuser_open(path, + RUMPUSER_OPEN_RDONLY | RUMPUSER_OPEN_BIO, &error); if (error) return error; rblk->rblk_mode = FREAD; @@ -689,7 +691,7 @@ dostrategy(struct buf *bp) struct rblkdev *rblk = &minors[minor(bp->b_dev)]; off_t off; int async = bp->b_flags & B_ASYNC; - int error; + int error, op; if (bp->b_bcount % (1<<sectshift) != 0) { rump_biodone(bp, 0, EINVAL); @@ -780,73 +782,13 @@ dostrategy(struct buf *bp) } rump_biodone(bp, bp->b_bcount, 0); - return; - } - - /* - * Do I/O. We have different paths for async and sync I/O. - * Async I/O is done by passing a request to rumpuser where - * it is executed. The rumpuser routine then calls - * biodone() to signal any waiters in the kernel. I/O's are - * executed in series. Technically executing them in parallel - * would produce better results, but then we'd need either - * more threads or posix aio. Maybe worth investigating - * this later. - * - * Using bufq here might be a good idea. - */ - - if (rump_threads) { - struct rumpuser_aio *rua; - int op, fd; - - fd = rblk->rblk_fd; - if (BUF_ISREAD(bp)) { - op = RUA_OP_READ; - } else { - op = RUA_OP_WRITE; - if (!async) { - /* O_DIRECT not fully automatic yet */ -#ifdef HAS_ODIRECT - if ((off & ((1<<sectshift)-1)) == 0 - && ((intptr_t)bp->b_data - & ((1<<sectshift)-1)) == 0 - && (bp->b_bcount & ((1<<sectshift)-1)) == 0) - fd = rblk->rblk_dfd; - else -#endif - op |= RUA_OP_SYNC; - } - } - - rumpuser_mutex_enter(&rumpuser_aio_mtx); - while ((rumpuser_aio_head+1) % N_AIOS == rumpuser_aio_tail) { - rumpuser_cv_wait(&rumpuser_aio_cv, &rumpuser_aio_mtx); - } - - rua = &rumpuser_aios[rumpuser_aio_head]; - KASSERT(rua->rua_bp == NULL); - rua->rua_fd = fd; - rua->rua_data = bp->b_data; - rua->rua_dlen = bp->b_bcount; - rua->rua_off = off; - rua->rua_bp = bp; - rua->rua_op = op; - - /* insert into queue & signal */ - rumpuser_aio_head = (rumpuser_aio_head+1) % N_AIOS; - rumpuser_cv_signal(&rumpuser_aio_cv); - rumpuser_mutex_exit(&rumpuser_aio_mtx); } else { - if (BUF_ISREAD(bp)) { - rumpuser_read_bio(rblk->rblk_fd, bp->b_data, - bp->b_bcount, off, rump_biodone, bp); - } else { - rumpuser_write_bio(rblk->rblk_fd, bp->b_data, - bp->b_bcount, off, rump_biodone, bp); - } + op = BUF_ISREAD(bp) ? RUMPUSER_BIO_READ : RUMPUSER_BIO_WRITE; if (BUF_ISWRITE(bp) && !async) - rumpuser_fsync(rblk->rblk_fd, &error); + op |= RUMPUSER_BIO_SYNC; + + rumpuser_bio(rblk->rblk_fd, op, bp->b_data, bp->b_bcount, off, + rump_biodone, bp); } } Added files: Index: src/lib/librumpuser/rumpuser_bio.c diff -u /dev/null src/lib/librumpuser/rumpuser_bio.c:1.1 --- /dev/null Mon Apr 29 12:56:04 2013 +++ src/lib/librumpuser/rumpuser_bio.c Mon Apr 29 12:56:04 2013 @@ -0,0 +1,173 @@ +/* $NetBSD: rumpuser_bio.c,v 1.1 2013/04/29 12:56:04 pooka Exp $ */ + +/*- + * Copyright (c) 2013 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, 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. + */ + +#include "rumpuser_port.h" + +#include <sys/types.h> + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <rump/rumpuser.h> + +#include "rumpuser_int.h" + +struct rumpuser_bio { + int bio_fd; + int bio_op; + void *bio_data; + size_t bio_dlen; + off_t bio_off; + + rump_biodone_fn bio_done; + void *bio_donearg; +}; + +#define N_BIOS 128 +static pthread_mutex_t biomtx = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t biocv = PTHREAD_COND_INITIALIZER; +static int bio_head, bio_tail; +static struct rumpuser_bio bios[N_BIOS]; + +static void +dobio(struct rumpuser_bio *biop) +{ + ssize_t rv; + int error, dummy; + + assert(biop->bio_donearg != NULL); + if (biop->bio_op & RUMPUSER_BIO_READ) { + error = 0; + rv = pread(biop->bio_fd, biop->bio_data, + biop->bio_dlen, biop->bio_off); + if (rv < 0) { + rv = 0; + error = errno; + } + } else { + error = 0; + rv = pwrite(biop->bio_fd, biop->bio_data, + biop->bio_dlen, biop->bio_off); + if (rv < 0) { + rv = 0; + error = errno; + } else if (biop->bio_op & RUMPUSER_BIO_SYNC) { +#ifdef __NetBSD__ + fsync_range(biop->bio_fd, FDATASYNC, + biop->bio_off, biop->bio_dlen); +#else + fsync(biop->bio_fd); +#endif + } + } + rumpuser__reschedule(0, NULL); + biop->bio_done(biop->bio_donearg, (size_t)rv, error); + rumpuser__unschedule(0, &dummy, NULL); + + /* paranoia */ + biop->bio_donearg = NULL; +} + +static void * +biothread(void *arg) +{ + struct rumpuser_bio *biop; + + NOFAIL_ERRNO(pthread_mutex_lock(&biomtx)); + for (;;) { + while (bio_head == bio_tail) + NOFAIL_ERRNO(pthread_cond_wait(&biocv, &biomtx)); + + biop = &bios[bio_tail]; + pthread_mutex_unlock(&biomtx); + + dobio(biop); + + NOFAIL_ERRNO(pthread_mutex_lock(&biomtx)); + bio_tail = (bio_tail+1) % N_BIOS; + pthread_cond_signal(&biocv); + } + + /* unreachable */ + abort(); +} + +void +rumpuser_bio(int fd, int op, void *data, size_t dlen, off_t doff, + rump_biodone_fn biodone, void *bioarg) +{ + struct rumpuser_bio bio; + static int inited = 0; + static int usethread = 0; + + if (!inited) { + pthread_mutex_lock(&biomtx); + if (!inited) { + char buf[16]; + pthread_t pt; + + /* + * duplicates policy of rump kernel. maybe a bit + * questionable, but since the setting is not + * used in normal circumstances, let's not care + */ + if (getenv_r("RUMP_THREADS", buf, sizeof(buf)) == 0) + usethread = *buf != '0'; + + pthread_create(&pt, NULL, biothread, NULL); + inited = 1; + } + pthread_mutex_unlock(&biomtx); + assert(inited); + } + + bio.bio_fd = fd; + bio.bio_op = op; + bio.bio_data = data; + bio.bio_dlen = dlen; + bio.bio_off = doff; + bio.bio_done = biodone; + bio.bio_donearg = bioarg; + + if (!usethread) { + dobio(&bio); + } else { + pthread_mutex_lock(&biomtx); + while ((bio_head+1) % N_BIOS == bio_tail) + pthread_cond_wait(&biocv, &biomtx); + + bios[bio_head] = bio; + bio_head = (bio_head+1) % N_BIOS; + + pthread_cond_signal(&biocv); + pthread_mutex_unlock(&biomtx); + } +}