xref: /netbsd-src/lib/librumpuser/rumpuser_bio.c (revision 23dfcd7408ac64d59d92beb90663ee97670c6648)
1*23dfcd74Spooka /*	$NetBSD: rumpuser_bio.c,v 1.10 2014/11/04 19:05:17 pooka Exp $	*/
2262a3aafSpooka 
3262a3aafSpooka /*-
4262a3aafSpooka  * Copyright (c) 2013 Antti Kantee.  All Rights Reserved.
5262a3aafSpooka  *
6262a3aafSpooka  * Redistribution and use in source and binary forms, with or without
7262a3aafSpooka  * modification, are permitted provided that the following conditions
8262a3aafSpooka  * are met:
9262a3aafSpooka  * 1. Redistributions of source code must retain the above copyright
10262a3aafSpooka  *    notice, this list of conditions and the following disclaimer.
11262a3aafSpooka  * 2. Redistributions in binary form must reproduce the above copyright
12262a3aafSpooka  *    notice, this list of conditions and the following disclaimer in the
13262a3aafSpooka  *    documentation and/or other materials provided with the distribution.
14262a3aafSpooka  *
15262a3aafSpooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16262a3aafSpooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17262a3aafSpooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18262a3aafSpooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19262a3aafSpooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20262a3aafSpooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21262a3aafSpooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22262a3aafSpooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23262a3aafSpooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24262a3aafSpooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25262a3aafSpooka  * SUCH DAMAGE.
26262a3aafSpooka  */
27262a3aafSpooka 
28262a3aafSpooka #include "rumpuser_port.h"
29262a3aafSpooka 
3046b0c1cbSalnsn #if !defined(lint)
31*23dfcd74Spooka __RCSID("$NetBSD: rumpuser_bio.c,v 1.10 2014/11/04 19:05:17 pooka Exp $");
3246b0c1cbSalnsn #endif /* !lint */
3346b0c1cbSalnsn 
34262a3aafSpooka #include <sys/types.h>
35262a3aafSpooka 
36262a3aafSpooka #include <assert.h>
37262a3aafSpooka #include <errno.h>
38262a3aafSpooka #include <pthread.h>
39059f8df6Spooka #include <stdint.h>
40262a3aafSpooka #include <stdio.h>
41262a3aafSpooka #include <string.h>
42262a3aafSpooka #include <unistd.h>
43262a3aafSpooka 
44262a3aafSpooka #include <rump/rumpuser.h>
45262a3aafSpooka 
46262a3aafSpooka #include "rumpuser_int.h"
47262a3aafSpooka 
48262a3aafSpooka struct rumpuser_bio {
49262a3aafSpooka 	int bio_fd;
50262a3aafSpooka 	int bio_op;
51262a3aafSpooka 	void *bio_data;
52262a3aafSpooka 	size_t bio_dlen;
53262a3aafSpooka 	off_t bio_off;
54262a3aafSpooka 
55262a3aafSpooka 	rump_biodone_fn bio_done;
56262a3aafSpooka 	void *bio_donearg;
57262a3aafSpooka };
58262a3aafSpooka 
59262a3aafSpooka #define N_BIOS 128
60262a3aafSpooka static pthread_mutex_t biomtx = PTHREAD_MUTEX_INITIALIZER;
61262a3aafSpooka static pthread_cond_t biocv = PTHREAD_COND_INITIALIZER;
62262a3aafSpooka static int bio_head, bio_tail;
63262a3aafSpooka static struct rumpuser_bio bios[N_BIOS];
64262a3aafSpooka 
65262a3aafSpooka static void
dobio(struct rumpuser_bio * biop)66262a3aafSpooka dobio(struct rumpuser_bio *biop)
67262a3aafSpooka {
68262a3aafSpooka 	ssize_t rv;
69262a3aafSpooka 	int error, dummy;
70262a3aafSpooka 
71262a3aafSpooka 	assert(biop->bio_donearg != NULL);
72262a3aafSpooka 	if (biop->bio_op & RUMPUSER_BIO_READ) {
73262a3aafSpooka 		error = 0;
74262a3aafSpooka 		rv = pread(biop->bio_fd, biop->bio_data,
75262a3aafSpooka 		    biop->bio_dlen, biop->bio_off);
76262a3aafSpooka 		if (rv < 0) {
77262a3aafSpooka 			rv = 0;
78103543d4Sjustin 			error = rumpuser__errtrans(errno);
79262a3aafSpooka 		}
80262a3aafSpooka 	} else {
81262a3aafSpooka 		error = 0;
82262a3aafSpooka 		rv = pwrite(biop->bio_fd, biop->bio_data,
83262a3aafSpooka 		    biop->bio_dlen, biop->bio_off);
84262a3aafSpooka 		if (rv < 0) {
85262a3aafSpooka 			rv = 0;
86103543d4Sjustin 			error = rumpuser__errtrans(errno);
87262a3aafSpooka 		} else if (biop->bio_op & RUMPUSER_BIO_SYNC) {
88*23dfcd74Spooka #ifdef HAVE_FSYNC_RANGE
89262a3aafSpooka 			fsync_range(biop->bio_fd, FDATASYNC,
90262a3aafSpooka 			    biop->bio_off, biop->bio_dlen);
91262a3aafSpooka #else
92262a3aafSpooka 			fsync(biop->bio_fd);
93262a3aafSpooka #endif
94262a3aafSpooka 		}
95262a3aafSpooka 	}
965af3856aSpooka 	rumpkern_sched(0, NULL);
97262a3aafSpooka 	biop->bio_done(biop->bio_donearg, (size_t)rv, error);
985af3856aSpooka 	rumpkern_unsched(&dummy, NULL);
99262a3aafSpooka 
100262a3aafSpooka 	/* paranoia */
101262a3aafSpooka 	biop->bio_donearg = NULL;
102262a3aafSpooka }
103262a3aafSpooka 
104262a3aafSpooka static void *
biothread(void * arg)105262a3aafSpooka biothread(void *arg)
106262a3aafSpooka {
107262a3aafSpooka 	struct rumpuser_bio *biop;
108a15e0779Spooka 	int rv;
109262a3aafSpooka 
110a15e0779Spooka 	rumpuser__hyp.hyp_schedule();
111a15e0779Spooka 	rv = rumpuser__hyp.hyp_lwproc_newlwp(0);
112a15e0779Spooka 	assert(rv == 0);
113a15e0779Spooka 	rumpuser__hyp.hyp_unschedule();
114262a3aafSpooka 	NOFAIL_ERRNO(pthread_mutex_lock(&biomtx));
115262a3aafSpooka 	for (;;) {
116262a3aafSpooka 		while (bio_head == bio_tail)
117262a3aafSpooka 			NOFAIL_ERRNO(pthread_cond_wait(&biocv, &biomtx));
118262a3aafSpooka 
119262a3aafSpooka 		biop = &bios[bio_tail];
120262a3aafSpooka 		pthread_mutex_unlock(&biomtx);
121262a3aafSpooka 
122262a3aafSpooka 		dobio(biop);
123262a3aafSpooka 
124262a3aafSpooka 		NOFAIL_ERRNO(pthread_mutex_lock(&biomtx));
125262a3aafSpooka 		bio_tail = (bio_tail+1) % N_BIOS;
126262a3aafSpooka 		pthread_cond_signal(&biocv);
127262a3aafSpooka 	}
128262a3aafSpooka 
129262a3aafSpooka 	/* unreachable */
130262a3aafSpooka 	abort();
131262a3aafSpooka }
132262a3aafSpooka 
133262a3aafSpooka void
rumpuser_bio(int fd,int op,void * data,size_t dlen,int64_t doff,rump_biodone_fn biodone,void * bioarg)134601de6b0Spooka rumpuser_bio(int fd, int op, void *data, size_t dlen, int64_t doff,
135262a3aafSpooka 	rump_biodone_fn biodone, void *bioarg)
136262a3aafSpooka {
137262a3aafSpooka 	struct rumpuser_bio bio;
138262a3aafSpooka 	static int inited = 0;
139f134f096Spooka 	static int usethread = 1;
14017b3a6d0Spooka 	int nlocks;
14117b3a6d0Spooka 
1425af3856aSpooka 	rumpkern_unsched(&nlocks, NULL);
143262a3aafSpooka 
144262a3aafSpooka 	if (!inited) {
145262a3aafSpooka 		pthread_mutex_lock(&biomtx);
146262a3aafSpooka 		if (!inited) {
147262a3aafSpooka 			char buf[16];
148262a3aafSpooka 			pthread_t pt;
149262a3aafSpooka 
150262a3aafSpooka 			/*
151262a3aafSpooka 			 * duplicates policy of rump kernel.  maybe a bit
152262a3aafSpooka 			 * questionable, but since the setting is not
153262a3aafSpooka 			 * used in normal circumstances, let's not care
154262a3aafSpooka 			 */
155262a3aafSpooka 			if (getenv_r("RUMP_THREADS", buf, sizeof(buf)) == 0)
156262a3aafSpooka 				usethread = *buf != '0';
157262a3aafSpooka 
158f134f096Spooka 			if (usethread)
159262a3aafSpooka 				pthread_create(&pt, NULL, biothread, NULL);
160262a3aafSpooka 			inited = 1;
161262a3aafSpooka 		}
162262a3aafSpooka 		pthread_mutex_unlock(&biomtx);
163262a3aafSpooka 		assert(inited);
164262a3aafSpooka 	}
165262a3aafSpooka 
166262a3aafSpooka 	bio.bio_fd = fd;
167262a3aafSpooka 	bio.bio_op = op;
168262a3aafSpooka 	bio.bio_data = data;
169262a3aafSpooka 	bio.bio_dlen = dlen;
170601de6b0Spooka 	bio.bio_off = (off_t)doff;
171262a3aafSpooka 	bio.bio_done = biodone;
172262a3aafSpooka 	bio.bio_donearg = bioarg;
173262a3aafSpooka 
174262a3aafSpooka 	if (!usethread) {
175262a3aafSpooka 		dobio(&bio);
176262a3aafSpooka 	} else {
177262a3aafSpooka 		pthread_mutex_lock(&biomtx);
178262a3aafSpooka 		while ((bio_head+1) % N_BIOS == bio_tail)
179262a3aafSpooka 			pthread_cond_wait(&biocv, &biomtx);
180262a3aafSpooka 
181262a3aafSpooka 		bios[bio_head] = bio;
182262a3aafSpooka 		bio_head = (bio_head+1) % N_BIOS;
183262a3aafSpooka 
184262a3aafSpooka 		pthread_cond_signal(&biocv);
185262a3aafSpooka 		pthread_mutex_unlock(&biomtx);
186262a3aafSpooka 	}
18717b3a6d0Spooka 
1885af3856aSpooka 	rumpkern_sched(nlocks, NULL);
189262a3aafSpooka }
190