Statistics
| Branch: | Revision:

root / posix-aio-compat.c @ 4b816985

History | View | Annotate | Download (10.1 kB)

1 3c529d93 aliguori
/*
2 3c529d93 aliguori
 * QEMU posix-aio emulation
3 3c529d93 aliguori
 *
4 3c529d93 aliguori
 * Copyright IBM, Corp. 2008
5 3c529d93 aliguori
 *
6 3c529d93 aliguori
 * Authors:
7 3c529d93 aliguori
 *  Anthony Liguori   <aliguori@us.ibm.com>
8 3c529d93 aliguori
 *
9 3c529d93 aliguori
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10 3c529d93 aliguori
 * the COPYING file in the top-level directory.
11 3c529d93 aliguori
 *
12 3c529d93 aliguori
 */
13 3c529d93 aliguori
14 221f715d aliguori
#include <sys/ioctl.h>
15 3c529d93 aliguori
#include <pthread.h>
16 3c529d93 aliguori
#include <unistd.h>
17 3c529d93 aliguori
#include <errno.h>
18 30525aff malc
#include <time.h>
19 8653c015 malc
#include <string.h>
20 8653c015 malc
#include <stdlib.h>
21 8653c015 malc
#include <stdio.h>
22 3c529d93 aliguori
#include "osdep.h"
23 f141eafe aliguori
#include "qemu-common.h"
24 3c529d93 aliguori
25 3c529d93 aliguori
#include "posix-aio-compat.h"
26 3c529d93 aliguori
27 3c529d93 aliguori
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
28 3c529d93 aliguori
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
29 3c529d93 aliguori
static pthread_t thread_id;
30 a8227a5a malc
static pthread_attr_t attr;
31 3c529d93 aliguori
static int max_threads = 64;
32 3c529d93 aliguori
static int cur_threads = 0;
33 3c529d93 aliguori
static int idle_threads = 0;
34 3c529d93 aliguori
static TAILQ_HEAD(, qemu_paiocb) request_list;
35 3c529d93 aliguori
36 ceb42de8 aliguori
#ifdef HAVE_PREADV
37 ceb42de8 aliguori
static int preadv_present = 1;
38 ceb42de8 aliguori
#else
39 ceb42de8 aliguori
static int preadv_present = 0;
40 ceb42de8 aliguori
#endif
41 ceb42de8 aliguori
42 8653c015 malc
static void die2(int err, const char *what)
43 8653c015 malc
{
44 8653c015 malc
    fprintf(stderr, "%s failed: %s\n", what, strerror(err));
45 8653c015 malc
    abort();
46 8653c015 malc
}
47 8653c015 malc
48 8653c015 malc
static void die(const char *what)
49 8653c015 malc
{
50 8653c015 malc
    die2(errno, what);
51 8653c015 malc
}
52 8653c015 malc
53 8653c015 malc
static void mutex_lock(pthread_mutex_t *mutex)
54 8653c015 malc
{
55 8653c015 malc
    int ret = pthread_mutex_lock(mutex);
56 8653c015 malc
    if (ret) die2(ret, "pthread_mutex_lock");
57 8653c015 malc
}
58 8653c015 malc
59 8653c015 malc
static void mutex_unlock(pthread_mutex_t *mutex)
60 8653c015 malc
{
61 8653c015 malc
    int ret = pthread_mutex_unlock(mutex);
62 8653c015 malc
    if (ret) die2(ret, "pthread_mutex_unlock");
63 8653c015 malc
}
64 8653c015 malc
65 8653c015 malc
static int cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
66 8653c015 malc
                           struct timespec *ts)
67 8653c015 malc
{
68 8653c015 malc
    int ret = pthread_cond_timedwait(cond, mutex, ts);
69 8653c015 malc
    if (ret && ret != ETIMEDOUT) die2(ret, "pthread_cond_timedwait");
70 8653c015 malc
    return ret;
71 8653c015 malc
}
72 8653c015 malc
73 5d47e372 malc
static void cond_signal(pthread_cond_t *cond)
74 8653c015 malc
{
75 5d47e372 malc
    int ret = pthread_cond_signal(cond);
76 5d47e372 malc
    if (ret) die2(ret, "pthread_cond_signal");
77 8653c015 malc
}
78 8653c015 malc
79 8653c015 malc
static void thread_create(pthread_t *thread, pthread_attr_t *attr,
80 8653c015 malc
                          void *(*start_routine)(void*), void *arg)
81 8653c015 malc
{
82 8653c015 malc
    int ret = pthread_create(thread, attr, start_routine, arg);
83 8653c015 malc
    if (ret) die2(ret, "pthread_create");
84 8653c015 malc
}
85 8653c015 malc
86 f141eafe aliguori
static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
87 f141eafe aliguori
{
88 f141eafe aliguori
        int ret;
89 f141eafe aliguori
90 f141eafe aliguori
        ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf);
91 f141eafe aliguori
        if (ret == -1)
92 f141eafe aliguori
                return -errno;
93 e7d54ae8 Christoph Hellwig
94 e7d54ae8 Christoph Hellwig
        /*
95 e7d54ae8 Christoph Hellwig
         * This looks weird, but the aio code only consideres a request
96 e7d54ae8 Christoph Hellwig
         * successfull if it has written the number full number of bytes.
97 e7d54ae8 Christoph Hellwig
         *
98 e7d54ae8 Christoph Hellwig
         * Now we overload aio_nbytes as aio_ioctl_cmd for the ioctl command,
99 e7d54ae8 Christoph Hellwig
         * so in fact we return the ioctl command here to make posix_aio_read()
100 e7d54ae8 Christoph Hellwig
         * happy..
101 e7d54ae8 Christoph Hellwig
         */
102 e7d54ae8 Christoph Hellwig
        return aiocb->aio_nbytes;
103 f141eafe aliguori
}
104 f141eafe aliguori
105 ceb42de8 aliguori
#ifdef HAVE_PREADV
106 ceb42de8 aliguori
107 ceb42de8 aliguori
static ssize_t
108 ceb42de8 aliguori
qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
109 ceb42de8 aliguori
{
110 ceb42de8 aliguori
    return preadv(fd, iov, nr_iov, offset);
111 ceb42de8 aliguori
}
112 ceb42de8 aliguori
113 ceb42de8 aliguori
static ssize_t
114 ceb42de8 aliguori
qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
115 ceb42de8 aliguori
{
116 ceb42de8 aliguori
    return pwritev(fd, iov, nr_iov, offset);
117 ceb42de8 aliguori
}
118 ceb42de8 aliguori
119 ceb42de8 aliguori
#else
120 ceb42de8 aliguori
121 ceb42de8 aliguori
static ssize_t
122 ceb42de8 aliguori
qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
123 ceb42de8 aliguori
{
124 ceb42de8 aliguori
    return -ENOSYS;
125 ceb42de8 aliguori
}
126 ceb42de8 aliguori
127 ceb42de8 aliguori
static ssize_t
128 ceb42de8 aliguori
qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
129 ceb42de8 aliguori
{
130 ceb42de8 aliguori
    return -ENOSYS;
131 ceb42de8 aliguori
}
132 ceb42de8 aliguori
133 ceb42de8 aliguori
#endif
134 ceb42de8 aliguori
135 f141eafe aliguori
/*
136 f141eafe aliguori
 * Check if we need to copy the data in the aiocb into a new
137 f141eafe aliguori
 * properly aligned buffer.
138 f141eafe aliguori
 */
139 f141eafe aliguori
static int aiocb_needs_copy(struct qemu_paiocb *aiocb)
140 f141eafe aliguori
{
141 f141eafe aliguori
    if (aiocb->aio_flags & QEMU_AIO_SECTOR_ALIGNED) {
142 f141eafe aliguori
        int i;
143 f141eafe aliguori
144 f141eafe aliguori
        for (i = 0; i < aiocb->aio_niov; i++)
145 f141eafe aliguori
            if ((uintptr_t) aiocb->aio_iov[i].iov_base % 512)
146 f141eafe aliguori
                return 1;
147 f141eafe aliguori
    }
148 f141eafe aliguori
149 f141eafe aliguori
    return 0;
150 f141eafe aliguori
}
151 f141eafe aliguori
152 ceb42de8 aliguori
static size_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
153 ceb42de8 aliguori
{
154 ceb42de8 aliguori
    size_t offset = 0;
155 ceb42de8 aliguori
    ssize_t len;
156 ceb42de8 aliguori
157 ceb42de8 aliguori
    do {
158 ceb42de8 aliguori
        if (aiocb->aio_type == QEMU_PAIO_WRITE)
159 ceb42de8 aliguori
            len = qemu_pwritev(aiocb->aio_fildes,
160 ceb42de8 aliguori
                               aiocb->aio_iov,
161 ceb42de8 aliguori
                               aiocb->aio_niov,
162 ceb42de8 aliguori
                               aiocb->aio_offset + offset);
163 ceb42de8 aliguori
         else
164 ceb42de8 aliguori
            len = qemu_preadv(aiocb->aio_fildes,
165 ceb42de8 aliguori
                              aiocb->aio_iov,
166 ceb42de8 aliguori
                              aiocb->aio_niov,
167 ceb42de8 aliguori
                              aiocb->aio_offset + offset);
168 ceb42de8 aliguori
    } while (len == -1 && errno == EINTR);
169 ceb42de8 aliguori
170 ceb42de8 aliguori
    if (len == -1)
171 ceb42de8 aliguori
        return -errno;
172 ceb42de8 aliguori
    return len;
173 ceb42de8 aliguori
}
174 ceb42de8 aliguori
175 f141eafe aliguori
static size_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
176 221f715d aliguori
{
177 221f715d aliguori
    size_t offset = 0;
178 f141eafe aliguori
    size_t len;
179 221f715d aliguori
180 221f715d aliguori
    while (offset < aiocb->aio_nbytes) {
181 f141eafe aliguori
         if (aiocb->aio_type == QEMU_PAIO_WRITE)
182 f141eafe aliguori
             len = pwrite(aiocb->aio_fildes,
183 f141eafe aliguori
                          (const char *)buf + offset,
184 f141eafe aliguori
                          aiocb->aio_nbytes - offset,
185 f141eafe aliguori
                          aiocb->aio_offset + offset);
186 f141eafe aliguori
         else
187 f141eafe aliguori
             len = pread(aiocb->aio_fildes,
188 f141eafe aliguori
                         buf + offset,
189 221f715d aliguori
                         aiocb->aio_nbytes - offset,
190 221f715d aliguori
                         aiocb->aio_offset + offset);
191 221f715d aliguori
192 f141eafe aliguori
         if (len == -1 && errno == EINTR)
193 f141eafe aliguori
             continue;
194 f141eafe aliguori
         else if (len == -1) {
195 f141eafe aliguori
             offset = -errno;
196 f141eafe aliguori
             break;
197 f141eafe aliguori
         } else if (len == 0)
198 f141eafe aliguori
             break;
199 f141eafe aliguori
200 f141eafe aliguori
         offset += len;
201 221f715d aliguori
    }
202 221f715d aliguori
203 221f715d aliguori
    return offset;
204 221f715d aliguori
}
205 221f715d aliguori
206 f141eafe aliguori
static size_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
207 221f715d aliguori
{
208 f141eafe aliguori
    size_t nbytes;
209 f141eafe aliguori
    char *buf;
210 f141eafe aliguori
211 ceb42de8 aliguori
    if (!aiocb_needs_copy(aiocb)) {
212 f141eafe aliguori
        /*
213 f141eafe aliguori
         * If there is just a single buffer, and it is properly aligned
214 f141eafe aliguori
         * we can just use plain pread/pwrite without any problems.
215 f141eafe aliguori
         */
216 ceb42de8 aliguori
        if (aiocb->aio_niov == 1)
217 ceb42de8 aliguori
             return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
218 ceb42de8 aliguori
219 ceb42de8 aliguori
        /*
220 ceb42de8 aliguori
         * We have more than one iovec, and all are properly aligned.
221 ceb42de8 aliguori
         *
222 ceb42de8 aliguori
         * Try preadv/pwritev first and fall back to linearizing the
223 ceb42de8 aliguori
         * buffer if it's not supported.
224 ceb42de8 aliguori
         */
225 ceb42de8 aliguori
        if (preadv_present) {
226 ceb42de8 aliguori
            nbytes = handle_aiocb_rw_vector(aiocb);
227 ceb42de8 aliguori
            if (nbytes == aiocb->aio_nbytes)
228 ceb42de8 aliguori
                return nbytes;
229 ceb42de8 aliguori
            if (nbytes < 0 && nbytes != -ENOSYS)
230 ceb42de8 aliguori
                return nbytes;
231 ceb42de8 aliguori
            preadv_present = 0;
232 ceb42de8 aliguori
        }
233 ceb42de8 aliguori
234 ceb42de8 aliguori
        /*
235 ceb42de8 aliguori
         * XXX(hch): short read/write.  no easy way to handle the reminder
236 ceb42de8 aliguori
         * using these interfaces.  For now retry using plain
237 ceb42de8 aliguori
         * pread/pwrite?
238 ceb42de8 aliguori
         */
239 f141eafe aliguori
    }
240 221f715d aliguori
241 f141eafe aliguori
    /*
242 f141eafe aliguori
     * Ok, we have to do it the hard way, copy all segments into
243 f141eafe aliguori
     * a single aligned buffer.
244 f141eafe aliguori
     */
245 f141eafe aliguori
    buf = qemu_memalign(512, aiocb->aio_nbytes);
246 f141eafe aliguori
    if (aiocb->aio_type == QEMU_PAIO_WRITE) {
247 f141eafe aliguori
        char *p = buf;
248 f141eafe aliguori
        int i;
249 f141eafe aliguori
250 f141eafe aliguori
        for (i = 0; i < aiocb->aio_niov; ++i) {
251 f141eafe aliguori
            memcpy(p, aiocb->aio_iov[i].iov_base, aiocb->aio_iov[i].iov_len);
252 f141eafe aliguori
            p += aiocb->aio_iov[i].iov_len;
253 f141eafe aliguori
        }
254 f141eafe aliguori
    }
255 f141eafe aliguori
256 f141eafe aliguori
    nbytes = handle_aiocb_rw_linear(aiocb, buf);
257 f141eafe aliguori
    if (aiocb->aio_type != QEMU_PAIO_WRITE) {
258 f141eafe aliguori
        char *p = buf;
259 f141eafe aliguori
        size_t count = aiocb->aio_nbytes, copy;
260 f141eafe aliguori
        int i;
261 f141eafe aliguori
262 f141eafe aliguori
        for (i = 0; i < aiocb->aio_niov && count; ++i) {
263 f141eafe aliguori
            copy = count;
264 f141eafe aliguori
            if (copy > aiocb->aio_iov[i].iov_len)
265 f141eafe aliguori
                copy = aiocb->aio_iov[i].iov_len;
266 f141eafe aliguori
            memcpy(aiocb->aio_iov[i].iov_base, p, copy);
267 f141eafe aliguori
            p     += copy;
268 f141eafe aliguori
            count -= copy;
269 f141eafe aliguori
        }
270 f141eafe aliguori
    }
271 f141eafe aliguori
    qemu_vfree(buf);
272 f141eafe aliguori
273 f141eafe aliguori
    return nbytes;
274 221f715d aliguori
}
275 221f715d aliguori
276 3c529d93 aliguori
static void *aio_thread(void *unused)
277 3c529d93 aliguori
{
278 a8227a5a malc
    pid_t pid;
279 3c529d93 aliguori
    sigset_t set;
280 3c529d93 aliguori
281 a8227a5a malc
    pid = getpid();
282 a8227a5a malc
283 3c529d93 aliguori
    /* block all signals */
284 8653c015 malc
    if (sigfillset(&set)) die("sigfillset");
285 8653c015 malc
    if (sigprocmask(SIG_BLOCK, &set, NULL)) die("sigprocmask");
286 3c529d93 aliguori
287 3c529d93 aliguori
    while (1) {
288 3c529d93 aliguori
        struct qemu_paiocb *aiocb;
289 221f715d aliguori
        size_t ret = 0;
290 30525aff malc
        qemu_timeval tv;
291 30525aff malc
        struct timespec ts;
292 30525aff malc
293 30525aff malc
        qemu_gettimeofday(&tv);
294 30525aff malc
        ts.tv_sec = tv.tv_sec + 10;
295 30525aff malc
        ts.tv_nsec = 0;
296 3c529d93 aliguori
297 8653c015 malc
        mutex_lock(&lock);
298 3c529d93 aliguori
299 3c529d93 aliguori
        while (TAILQ_EMPTY(&request_list) &&
300 3c529d93 aliguori
               !(ret == ETIMEDOUT)) {
301 8653c015 malc
            ret = cond_timedwait(&cond, &lock, &ts);
302 3c529d93 aliguori
        }
303 3c529d93 aliguori
304 514f7a27 malc
        if (TAILQ_EMPTY(&request_list))
305 3c529d93 aliguori
            break;
306 3c529d93 aliguori
307 3c529d93 aliguori
        aiocb = TAILQ_FIRST(&request_list);
308 3c529d93 aliguori
        TAILQ_REMOVE(&request_list, aiocb, node);
309 3c529d93 aliguori
        aiocb->active = 1;
310 3c529d93 aliguori
        idle_threads--;
311 8653c015 malc
        mutex_unlock(&lock);
312 3c529d93 aliguori
313 221f715d aliguori
        switch (aiocb->aio_type) {
314 221f715d aliguori
        case QEMU_PAIO_READ:
315 221f715d aliguori
        case QEMU_PAIO_WRITE:
316 f141eafe aliguori
                ret = handle_aiocb_rw(aiocb);
317 221f715d aliguori
                break;
318 221f715d aliguori
        case QEMU_PAIO_IOCTL:
319 221f715d aliguori
                ret = handle_aiocb_ioctl(aiocb);
320 221f715d aliguori
                break;
321 221f715d aliguori
        default:
322 221f715d aliguori
                fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
323 221f715d aliguori
                ret = -EINVAL;
324 221f715d aliguori
                break;
325 221f715d aliguori
        }
326 3c529d93 aliguori
327 8653c015 malc
        mutex_lock(&lock);
328 221f715d aliguori
        aiocb->ret = ret;
329 3c529d93 aliguori
        idle_threads++;
330 8653c015 malc
        mutex_unlock(&lock);
331 3c529d93 aliguori
332 a8227a5a malc
        if (kill(pid, aiocb->ev_signo)) die("kill failed");
333 3c529d93 aliguori
    }
334 3c529d93 aliguori
335 3c529d93 aliguori
    idle_threads--;
336 3c529d93 aliguori
    cur_threads--;
337 8653c015 malc
    mutex_unlock(&lock);
338 3c529d93 aliguori
339 3c529d93 aliguori
    return NULL;
340 3c529d93 aliguori
}
341 3c529d93 aliguori
342 8653c015 malc
static void spawn_thread(void)
343 3c529d93 aliguori
{
344 3c529d93 aliguori
    cur_threads++;
345 3c529d93 aliguori
    idle_threads++;
346 8653c015 malc
    thread_create(&thread_id, &attr, aio_thread, NULL);
347 3c529d93 aliguori
}
348 3c529d93 aliguori
349 3c529d93 aliguori
int qemu_paio_init(struct qemu_paioinit *aioinit)
350 3c529d93 aliguori
{
351 a8227a5a malc
    int ret;
352 a8227a5a malc
353 a8227a5a malc
    ret = pthread_attr_init(&attr);
354 a8227a5a malc
    if (ret) die2(ret, "pthread_attr_init");
355 a8227a5a malc
356 a8227a5a malc
    ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
357 a8227a5a malc
    if (ret) die2(ret, "pthread_attr_setdetachstate");
358 a8227a5a malc
359 3c529d93 aliguori
    TAILQ_INIT(&request_list);
360 3c529d93 aliguori
361 3c529d93 aliguori
    return 0;
362 3c529d93 aliguori
}
363 3c529d93 aliguori
364 221f715d aliguori
static int qemu_paio_submit(struct qemu_paiocb *aiocb, int type)
365 3c529d93 aliguori
{
366 221f715d aliguori
    aiocb->aio_type = type;
367 3c529d93 aliguori
    aiocb->ret = -EINPROGRESS;
368 3c529d93 aliguori
    aiocb->active = 0;
369 8653c015 malc
    mutex_lock(&lock);
370 3c529d93 aliguori
    if (idle_threads == 0 && cur_threads < max_threads)
371 3c529d93 aliguori
        spawn_thread();
372 3c529d93 aliguori
    TAILQ_INSERT_TAIL(&request_list, aiocb, node);
373 8653c015 malc
    mutex_unlock(&lock);
374 5d47e372 malc
    cond_signal(&cond);
375 3c529d93 aliguori
376 3c529d93 aliguori
    return 0;
377 3c529d93 aliguori
}
378 3c529d93 aliguori
379 3c529d93 aliguori
int qemu_paio_read(struct qemu_paiocb *aiocb)
380 3c529d93 aliguori
{
381 221f715d aliguori
    return qemu_paio_submit(aiocb, QEMU_PAIO_READ);
382 3c529d93 aliguori
}
383 3c529d93 aliguori
384 3c529d93 aliguori
int qemu_paio_write(struct qemu_paiocb *aiocb)
385 3c529d93 aliguori
{
386 221f715d aliguori
    return qemu_paio_submit(aiocb, QEMU_PAIO_WRITE);
387 221f715d aliguori
}
388 221f715d aliguori
389 221f715d aliguori
int qemu_paio_ioctl(struct qemu_paiocb *aiocb)
390 221f715d aliguori
{
391 221f715d aliguori
    return qemu_paio_submit(aiocb, QEMU_PAIO_IOCTL);
392 3c529d93 aliguori
}
393 3c529d93 aliguori
394 3c529d93 aliguori
ssize_t qemu_paio_return(struct qemu_paiocb *aiocb)
395 3c529d93 aliguori
{
396 3c529d93 aliguori
    ssize_t ret;
397 3c529d93 aliguori
398 8653c015 malc
    mutex_lock(&lock);
399 3c529d93 aliguori
    ret = aiocb->ret;
400 8653c015 malc
    mutex_unlock(&lock);
401 3c529d93 aliguori
402 3c529d93 aliguori
    return ret;
403 3c529d93 aliguori
}
404 3c529d93 aliguori
405 3c529d93 aliguori
int qemu_paio_error(struct qemu_paiocb *aiocb)
406 3c529d93 aliguori
{
407 3c529d93 aliguori
    ssize_t ret = qemu_paio_return(aiocb);
408 3c529d93 aliguori
409 3c529d93 aliguori
    if (ret < 0)
410 3c529d93 aliguori
        ret = -ret;
411 3c529d93 aliguori
    else
412 3c529d93 aliguori
        ret = 0;
413 3c529d93 aliguori
414 3c529d93 aliguori
    return ret;
415 3c529d93 aliguori
}
416 3c529d93 aliguori
417 3c529d93 aliguori
int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb)
418 3c529d93 aliguori
{
419 3c529d93 aliguori
    int ret;
420 3c529d93 aliguori
421 8653c015 malc
    mutex_lock(&lock);
422 3c529d93 aliguori
    if (!aiocb->active) {
423 3c529d93 aliguori
        TAILQ_REMOVE(&request_list, aiocb, node);
424 3c529d93 aliguori
        aiocb->ret = -ECANCELED;
425 3c529d93 aliguori
        ret = QEMU_PAIO_CANCELED;
426 3c529d93 aliguori
    } else if (aiocb->ret == -EINPROGRESS)
427 3c529d93 aliguori
        ret = QEMU_PAIO_NOTCANCELED;
428 3c529d93 aliguori
    else
429 3c529d93 aliguori
        ret = QEMU_PAIO_ALLDONE;
430 8653c015 malc
    mutex_unlock(&lock);
431 3c529d93 aliguori
432 3c529d93 aliguori
    return ret;
433 3c529d93 aliguori
}