This patche moves raw AIO part from block-raw-posix.c to qemu-aio-raw.c to be able to use raw AIO from other files.
Laurent --- Makefile | 2 Makefile.target | 2 block-raw-posix.c | 205 ++------------------------------------------- qemu-aio-posix.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-aio-posix.h | 39 ++++++++ 5 files changed, 293 insertions(+), 196 deletions(-) Index: qemu/Makefile.target =================================================================== --- qemu.orig/Makefile.target 2008-01-23 09:18:17.000000000 +0100 +++ qemu/Makefile.target 2008-01-23 09:19:30.000000000 +0100 @@ -398,7 +398,7 @@ VL_OBJS=vl.o osdep.o monitor.o pci.o loa ifdef CONFIG_WIN32 VL_OBJS+=block-raw-win32.o else -VL_OBJS+=block-raw-posix.o +VL_OBJS+=block-raw-posix.o qemu-aio-posix.o endif ifdef CONFIG_ALSA Index: qemu/block-raw-posix.c =================================================================== --- qemu.orig/block-raw-posix.c 2008-01-23 09:19:16.000000000 +0100 +++ qemu/block-raw-posix.c 2008-01-23 09:19:30.000000000 +0100 @@ -28,7 +28,7 @@ #endif #include "block_int.h" #include <assert.h> -#include <aio.h> +#include "qemu-aio-posix.h" #ifdef CONFIG_COCOA #include <paths.h> @@ -75,7 +75,7 @@ #define FD_OPEN_TIMEOUT 1000 typedef struct BDRVRawState { - int fd; + int fd; /* must be the first field for qemu-aio-posix.c */ int type; unsigned int lseek_err_cnt; #if defined(__linux__) @@ -233,180 +233,18 @@ label__raw_write__success: /***********************************************************/ /* Unix AIO using POSIX AIO */ -typedef struct RawAIOCB { - BlockDriverAIOCB common; - struct aiocb aiocb; - struct RawAIOCB *next; -} RawAIOCB; - -static int aio_sig_num = SIGUSR2; -static RawAIOCB *first_aio; /* AIO issued */ -static int aio_initialized = 0; - -static void aio_signal_handler(int signum) -{ -#ifndef QEMU_IMG - CPUState *env = cpu_single_env; - if (env) { - /* stop the currently executing cpu because a timer occured */ - cpu_interrupt(env, CPU_INTERRUPT_EXIT); -#ifdef USE_KQEMU - if (env->kqemu_enabled) { - kqemu_cpu_interrupt(env); - } -#endif - } -#endif -} - -void qemu_aio_init(void) -{ - struct sigaction act; - - aio_initialized = 1; - - sigfillset(&act.sa_mask); - act.sa_flags = 0; /* do not restart syscalls to interrupt select() */ - act.sa_handler = aio_signal_handler; - sigaction(aio_sig_num, &act, NULL); - -#if defined(__GLIBC__) && defined(__linux__) - { - /* XXX: aio thread exit seems to hang on RedHat 9 and this init - seems to fix the problem. */ - struct aioinit ai; - memset(&ai, 0, sizeof(ai)); - ai.aio_threads = 1; - ai.aio_num = 1; - ai.aio_idle_time = 365 * 100000; - aio_init(&ai); - } -#endif -} - -void qemu_aio_poll(void) -{ - RawAIOCB *acb, **pacb; - int ret; - - for(;;) { - pacb = &first_aio; - for(;;) { - acb = *pacb; - if (!acb) - goto the_end; - ret = aio_error(&acb->aiocb); - if (ret == ECANCELED) { - /* remove the request */ - *pacb = acb->next; - qemu_aio_release(acb); - } else if (ret != EINPROGRESS) { - /* end of aio */ - if (ret == 0) { - ret = aio_return(&acb->aiocb); - if (ret == acb->aiocb.aio_nbytes) - ret = 0; - else - ret = -EINVAL; - } else { - ret = -ret; - } - /* remove the request */ - *pacb = acb->next; - /* call the callback */ - acb->common.cb(acb->common.opaque, ret); - qemu_aio_release(acb); - break; - } else { - pacb = &acb->next; - } - } - } - the_end: ; -} - -/* Wait for all IO requests to complete. */ -void qemu_aio_flush(void) -{ - qemu_aio_wait_start(); - qemu_aio_poll(); - while (first_aio) { - qemu_aio_wait(); - } - qemu_aio_wait_end(); -} - -/* wait until at least one AIO was handled */ -static sigset_t wait_oset; - -void qemu_aio_wait_start(void) -{ - sigset_t set; - - if (!aio_initialized) - qemu_aio_init(); - sigemptyset(&set); - sigaddset(&set, aio_sig_num); - sigprocmask(SIG_BLOCK, &set, &wait_oset); -} - -void qemu_aio_wait(void) -{ - sigset_t set; - int nb_sigs; - -#ifndef QEMU_IMG - if (qemu_bh_poll()) - return; -#endif - sigemptyset(&set); - sigaddset(&set, aio_sig_num); - sigwait(&set, &nb_sigs); - qemu_aio_poll(); -} - -void qemu_aio_wait_end(void) -{ - sigprocmask(SIG_SETMASK, &wait_oset, NULL); -} - -static RawAIOCB *raw_aio_setup(BlockDriverState *bs, +static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { - BDRVRawState *s = bs->opaque; RawAIOCB *acb; if (fd_open(bs) < 0) return NULL; - acb = qemu_aio_get(bs, cb, opaque); - if (!acb) - return NULL; - acb->aiocb.aio_fildes = s->fd; - acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num; - acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; - acb->aiocb.aio_buf = buf; - acb->aiocb.aio_nbytes = nb_sectors * 512; - acb->aiocb.aio_offset = sector_num * 512; - acb->next = first_aio; - first_aio = acb; - return acb; -} + acb = qemu_aio_read(bs, sector_num * 512, buf, nb_sectors * 512, + cb, opaque); -static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, - int64_t sector_num, uint8_t *buf, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) -{ - RawAIOCB *acb; - - acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque); - if (!acb) - return NULL; - if (aio_read(&acb->aiocb) < 0) { - qemu_aio_release(acb); - return NULL; - } return &acb->common; } @@ -416,41 +254,20 @@ static BlockDriverAIOCB *raw_aio_write(B { RawAIOCB *acb; - acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque); - if (!acb) - return NULL; - if (aio_write(&acb->aiocb) < 0) { - qemu_aio_release(acb); + if (fd_open(bs) < 0) return NULL; - } + + acb = qemu_aio_write(bs, sector_num * 512, buf, nb_sectors * 512, + cb, opaque); + return &acb->common; } static void raw_aio_cancel(BlockDriverAIOCB *blockacb) { - int ret; RawAIOCB *acb = (RawAIOCB *)blockacb; - RawAIOCB **pacb; - ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb); - if (ret == AIO_NOTCANCELED) { - /* fail safe: if the aio could not be canceled, we wait for - it */ - while (aio_error(&acb->aiocb) == EINPROGRESS); - } - - /* remove the callback from the queue */ - pacb = &first_aio; - for(;;) { - if (*pacb == NULL) { - break; - } else if (*pacb == acb) { - *pacb = acb->next; - qemu_aio_release(acb); - break; - } - pacb = &acb->next; - } + qemu_aio_cancel(acb); } static void raw_close(BlockDriverState *bs) Index: qemu/Makefile =================================================================== --- qemu.orig/Makefile 2008-01-23 09:18:17.000000000 +0100 +++ qemu/Makefile 2008-01-23 09:19:30.000000000 +0100 @@ -136,7 +136,7 @@ QEMU_IMG_BLOCK_OBJS = $(BLOCK_OBJS) ifdef CONFIG_WIN32 QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-win32.o else -QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-posix.o +QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-posix.o qemu-img-qemu-aio-posix.o endif ###################################################################### Index: qemu/qemu-aio-posix.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/qemu-aio-posix.c 2008-01-23 09:19:30.000000000 +0100 @@ -0,0 +1,241 @@ +/* + * QEMU Asynchronous I/O + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include <aio.h> +#ifndef QEMU_IMG +#include "qemu-timer.h" +#include "exec-all.h" +#endif +#include "block_int.h" +#include "qemu-aio-posix.h" + +static void aio_signal_handler(int signum) +{ +#ifndef QEMU_IMG + CPUState *env = cpu_single_env; + if (env) { + /* stop the currently executing cpu because a timer occured */ + cpu_interrupt(env, CPU_INTERRUPT_EXIT); +#ifdef USE_KQEMU + if (env->kqemu_enabled) { + kqemu_cpu_interrupt(env); + } +#endif + } +#endif +} + +static int aio_initialized = 0; +static int aio_sig_num = SIGUSR2; +static RawAIOCB *first_aio; /* AIO issued */ + +void qemu_aio_init(void) +{ + struct sigaction act; + + aio_initialized = 1; + + sigfillset(&act.sa_mask); + act.sa_flags = 0; /* do not restart syscalls to interrupt select() */ + act.sa_handler = aio_signal_handler; + sigaction(aio_sig_num, &act, NULL); + +#if defined(__GLIBC__) && defined(__linux__) + { + /* XXX: aio thread exit seems to hang on RedHat 9 and this init + seems to fix the problem. */ + struct aioinit ai; + memset(&ai, 0, sizeof(ai)); + ai.aio_threads = 1; + ai.aio_num = 1; + ai.aio_idle_time = 365 * 100000; + aio_init(&ai); + } +#endif +} + +void qemu_aio_poll(void) +{ + RawAIOCB *acb, **pacb; + int ret; + + for(;;) { + pacb = &first_aio; + for(;;) { + acb = *pacb; + if (!acb) + goto the_end; + ret = aio_error(&acb->aiocb); + if (ret == ECANCELED) { + /* remove the request */ + *pacb = acb->next; + qemu_aio_release(acb); + } else if (ret != EINPROGRESS) { + /* end of aio */ + if (ret == 0) { + ret = aio_return(&acb->aiocb); + if (ret == acb->aiocb.aio_nbytes) + ret = 0; + else + ret = -EINVAL; + } else { + ret = -ret; + } + /* remove the request */ + *pacb = acb->next; + /* call the callback */ + acb->common.cb(acb->common.opaque, ret); + qemu_aio_release(acb); + break; + } else { + pacb = &acb->next; + } + } + } + the_end: ; +} + +/* Wait for all IO requests to complete. */ +void qemu_aio_flush(void) +{ + qemu_aio_wait_start(); + qemu_aio_poll(); + while (first_aio) { + qemu_aio_wait(); + } + qemu_aio_wait_end(); +} + +/* wait until at least one AIO was handled */ +static sigset_t wait_oset; + +void qemu_aio_wait_start(void) +{ + sigset_t set; + + if (!aio_initialized) + qemu_aio_init(); + sigemptyset(&set); + sigaddset(&set, aio_sig_num); + sigprocmask(SIG_BLOCK, &set, &wait_oset); +} + +void qemu_aio_wait(void) +{ + sigset_t set; + int nb_sigs; + +#ifndef QEMU_IMG + if (qemu_bh_poll()) + return; +#endif + sigemptyset(&set); + sigaddset(&set, aio_sig_num); + sigwait(&set, &nb_sigs); + qemu_aio_poll(); +} + +void qemu_aio_wait_end(void) +{ + sigprocmask(SIG_SETMASK, &wait_oset, NULL); +} + +static RawAIOCB *qemu_aio_setup(BlockDriverState *bs, + int64_t offset, uint8_t *buf, int nb_bytes, + BlockDriverCompletionFunc *cb, void *opaque) +{ + int fd = *(int*)bs->opaque; + RawAIOCB *acb; + + acb = qemu_aio_get(bs, cb, opaque); + if (!acb) + return NULL; + acb->aiocb.aio_fildes = fd; + acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num; + acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + acb->aiocb.aio_buf = buf; + acb->aiocb.aio_nbytes = nb_bytes; + acb->aiocb.aio_offset = offset; + acb->next = first_aio; + first_aio = acb; + return acb; +} + +RawAIOCB *qemu_aio_read(BlockDriverState *bs, + int64_t offset, uint8_t *buf, int nb_bytes, + BlockDriverCompletionFunc *cb, void *opaque) +{ + RawAIOCB *acb; + + acb = qemu_aio_setup(bs, offset, buf, nb_bytes, cb, opaque); + if (!acb) + return NULL; + if (aio_read(&acb->aiocb) < 0) { + qemu_aio_release(acb); + return NULL; + } + return acb; +} + +RawAIOCB *qemu_aio_write(BlockDriverState *bs, + int64_t offset, const uint8_t *buf, int nb_bytes, + BlockDriverCompletionFunc *cb, void *opaque) +{ + RawAIOCB *acb; + + acb = qemu_aio_setup(bs, offset, (uint8_t*)buf, nb_bytes, cb, opaque); + if (!acb) + return NULL; + if (aio_write(&acb->aiocb) < 0) { + qemu_aio_release(acb); + return NULL; + } + return acb; +} + +void qemu_aio_cancel(RawAIOCB *acb) +{ + int ret; + RawAIOCB **pacb; + + ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb); + if (ret == AIO_NOTCANCELED) { + /* fail safe: if the aio could not be canceled, we wait for + it */ + while (aio_error(&acb->aiocb) == EINPROGRESS); + } + + /* remove the callback from the queue */ + pacb = &first_aio; + for(;;) { + if (*pacb == NULL) { + break; + } else if (*pacb == acb) { + *pacb = acb->next; + qemu_aio_release(acb); + break; + } + pacb = &acb->next; + } +} Index: qemu/qemu-aio-posix.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/qemu-aio-posix.h 2008-01-23 09:19:30.000000000 +0100 @@ -0,0 +1,39 @@ +/* + * QEMU Asynchronous I/O + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <aio.h> + +typedef struct RawAIOCB { + BlockDriverAIOCB common; + struct aiocb aiocb; + struct RawAIOCB *next; +} RawAIOCB; + +RawAIOCB *qemu_aio_read(BlockDriverState *bs, + int64_t offset, uint8_t *buf, int nb_bytes, + BlockDriverCompletionFunc *cb, void *opaque); +RawAIOCB *qemu_aio_write(BlockDriverState *bs, + int64_t offset, const uint8_t *buf, int nb_bytes, + BlockDriverCompletionFunc *cb, void *opaque); +void qemu_aio_cancel(RawAIOCB *acb);