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