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);
+	}
+}

Reply via email to