diff --git a/Makefile b/Makefile
index a8df278..916f071 100644
--- a/Makefile
+++ b/Makefile
@@ -139,7 +139,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-aio-posix.o
 endif
 
 ######################################################################
diff --git a/Makefile.target b/Makefile.target
index 75de753..773e81d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -485,7 +485,7 @@ OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o
 ifdef CONFIG_WIN32
 OBJS+=block-raw-win32.o
 else
-OBJS+=block-raw-posix.o
+OBJS+=block-raw-posix.o aio-posix.o aio-unix.o
 endif
 
 LIBS+=-lz
diff --git a/aio-posix.c b/aio-posix.c
new file mode 100644
index 0000000..d61eb9b
--- /dev/null
+++ b/aio-posix.c
@@ -0,0 +1,291 @@
+/*
+ * Block driver for RAW files (posix)
+ *
+ * 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"
+#ifndef QEMU_IMG
+#include "qemu-timer.h"
+#include "exec-all.h"
+#endif
+#include "block_int.h"
+#include "block-aio.h"
+#include "sysemu.h"
+#include <assert.h>
+#include <aio.h>
+
+#ifdef CONFIG_COCOA
+#include <paths.h>
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOMediaBSDClient.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+//#include <IOKit/storage/IOCDTypes.h>
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#ifdef __sun__
+#define _POSIX_PTHREAD_SEMANTICS 1
+#include <signal.h>
+#include <sys/dkio.h>
+#endif
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+#include <linux/fd.h>
+#endif
+#ifdef __FreeBSD__
+#include <sys/disk.h>
+#endif
+
+/***********************************************************/
+/* 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 */
+/* wait until at least one AIO was handled */
+static sigset_t wait_oset;
+
+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 void pa_poll(void *opaque)
+{
+    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: ;
+}
+
+
+static void pa_init(void)
+{
+    struct sigaction act;
+
+#ifndef QEMU_IMG
+    qemu_register_poll(pa_poll, NULL);
+#endif
+
+    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
+}
+
+static void pa_wait_start(void)
+{
+    sigset_t set;
+
+    sigemptyset(&set);
+    sigaddset(&set, aio_sig_num);
+    sigprocmask(SIG_BLOCK, &set, &wait_oset);
+}
+
+static void pa_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);
+    pa_poll(NULL);
+}
+
+static void pa_wait_end(void)
+{
+    sigprocmask(SIG_SETMASK, &wait_oset, NULL);
+}
+
+static void pa_flush(void)
+{
+    pa_wait_start();
+    pa_poll(NULL);
+    while (first_aio) {
+        pa_wait();
+    }
+    pa_wait_end();
+}
+
+static RawAIOCB *raw_aio_setup(BlockDriverState *bs, int fd,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *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;
+    if (nb_sectors < 0)
+        acb->aiocb.aio_nbytes = -nb_sectors;
+    else
+        acb->aiocb.aio_nbytes = nb_sectors * 512;
+    acb->aiocb.aio_offset = sector_num * 512;
+    acb->next = first_aio;
+    first_aio = acb;
+    return acb;
+}
+
+static BlockDriverAIOCB *pa_submit(BlockDriverState *bs,
+				   int fd, int64_t sector_num,
+				   void *buf, int nb_sectors, int write,
+				   BlockDriverCompletionFunc *cb,
+				   void *opaque)
+{
+    RawAIOCB *acb;
+    int err;
+
+    acb = raw_aio_setup(bs, fd, sector_num, buf, nb_sectors, cb, opaque);
+    if (!acb)
+        return NULL;
+
+    if (write) 
+	err = aio_write(&acb->aiocb);
+    else
+	err = aio_read(&acb->aiocb);
+
+    if (err < 0) {
+        qemu_aio_release(acb);
+        return NULL;
+    }
+    return &acb->common;
+}
+
+static void pa_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;
+    }
+}
+
+static AIODriver posix_aio_drv = {
+    .name = "posix",
+    .aiocb_size = sizeof(RawAIOCB),
+    .aio_init = pa_init,
+    .aio_wait_start = pa_wait_start,
+    .aio_wait = pa_wait,
+    .aio_wait_end = pa_wait_end,
+    .aio_flush = pa_flush,
+    .aio_submit = pa_submit,
+    .aio_cancel = pa_cancel,
+};
+
+int posix_aio_init(void)
+{
+    return qemu_register_aio(&posix_aio_drv);
+}
+	
diff --git a/aio-unix.c b/aio-unix.c
new file mode 100644
index 0000000..f2a1ef7
--- /dev/null
+++ b/aio-unix.c
@@ -0,0 +1,208 @@
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "block.h"
+#include "block_int.h"
+#include "block-aio.h"
+#include "sysemu.h"
+
+typedef struct UnixAIOCB {
+    BlockDriverAIOCB common;
+    int fd;
+    void *buffer;
+    off_t offset;
+    int write;
+    size_t size;
+    size_t completed;
+    struct UnixAIOCB *next;
+} UnixAIOCB;
+
+static UnixAIOCB *aio_table[1024];
+
+static void detach_aiocb(UnixAIOCB **list, UnixAIOCB *aio)
+{
+    for (; *list; list = &(*list)->next) {
+	if (*list == aio) {
+	    *list = aio->next;
+	    return;
+	}
+    }
+}
+
+static int try_complete(UnixAIOCB *aio)
+{
+    ssize_t len;
+    uint8_t *ptr;
+
+    if (aio == NULL)
+	return 0;
+
+    ptr = aio->buffer;
+
+    do {
+	if (aio->write)
+	    len = pwrite(aio->fd, ptr + aio->completed,
+			 aio->size - aio->completed,
+			 aio->offset + aio->completed);
+	else
+	    len = pread(aio->fd, ptr + aio->completed,
+			aio->size - aio->completed,
+			aio->offset + aio->completed);
+	if (len > 0)
+	    aio->completed += len;
+    } while ((len == -1 && errno == EINTR) || len > 0);
+
+    /* we still have more to complete but we'd block */
+    if (len == -1 && errno == EAGAIN)
+	return -EAGAIN;
+
+    /* we have an error in the request or we've succeeded,
+     * either way, complete the aio operation
+     */
+    if (len == -1) {
+	printf("io error %m!\n");
+	len = -errno;
+    } else 
+	len = 0;
+
+    if (len == 0 && aio->completed != aio->size) {
+	printf("wtf!\n");
+    }
+
+    detach_aiocb(&aio_table[aio->fd], aio);
+    aio->common.cb(aio->common.opaque, len);
+    qemu_aio_release(aio);
+
+    return 1;
+}
+
+static void do_try_complete(void *opaque)
+{
+    UnixAIOCB **pp = opaque;
+    int err, fd;
+
+    if (!*pp)
+	return;
+
+    fd = (*pp)->fd;
+
+    do {
+	err = try_complete(*pp);
+    } while (err > 0);
+
+    /* We could optimize this for the case we're already registered */
+
+    if (err == 0)
+	qemu_set_fd_handler2(fd, NULL, NULL, NULL, NULL);
+    else if ((*pp)->write)
+	qemu_set_fd_handler2(fd, NULL, NULL, do_try_complete, pp);
+    else
+	qemu_set_fd_handler2(fd, NULL, do_try_complete, NULL, pp);
+}
+
+static BlockDriverAIOCB *ua_submit(BlockDriverState *bs,
+				   int fd, int64_t sector_num,
+				   void *buf, int nb_sectors, int write,
+				   BlockDriverCompletionFunc *cb,
+				   void *opaque)
+{
+    UnixAIOCB *aiocb, **pp;
+    int need_register;
+
+    aiocb = qemu_aio_get(bs, cb, opaque);
+    if (!aiocb) {
+	printf("returning null??\n");
+	return NULL;
+    }
+
+    if (fd >= 1024) {
+	fprintf(stderr, "aio fd greater than 1024?\n");
+	return NULL;
+    }
+
+    need_register = !!(aio_table[fd] == NULL);
+
+    aiocb->fd = fd;
+    aiocb->buffer = buf;
+    aiocb->offset = sector_num * 512;
+    aiocb->size = nb_sectors * 512;
+    aiocb->completed = 0;
+    aiocb->write = write;
+    aiocb->next = NULL;
+
+    /* Put at end of queue */
+    for (pp = &aio_table[fd]; *pp; pp = &(*pp)->next);
+    *pp = aiocb;
+
+    /* If we're already waiting, don't bother trying to complete the IO
+       request */
+    if (need_register) {
+	int err;
+
+	do {
+	    err = try_complete(aio_table[fd]);
+	} while (err > 0);
+
+	/* if the current request would block, register a callback */
+	if (err == -EAGAIN) {
+	    if (aio_table[fd]->write)
+		qemu_set_fd_handler2(fd, NULL, NULL, do_try_complete,
+				     &aio_table[fd]);
+	    else
+		qemu_set_fd_handler2(fd, NULL, do_try_complete, NULL,
+				     &aio_table[fd]);
+	}
+    }
+
+    return &aiocb->common;
+}
+
+static void ua_wait(void)
+{
+    main_loop_wait(10);
+}
+
+static void ua_flush(void)
+{
+    int i;
+    int outstanding_requests;
+
+    do {
+	outstanding_requests = 0;
+
+	for (i = 0; i < 1024; i++) {
+	    if (aio_table[i]) {
+		outstanding_requests = 1;
+		break;
+	    }
+	}
+
+	if (outstanding_requests)
+	    ua_wait();
+    } while (outstanding_requests);
+}
+
+static void ua_cancel(BlockDriverAIOCB *baiocb)
+{
+    UnixAIOCB *aiocb = (void *)baiocb;
+
+    detach_aiocb(&aio_table[aiocb->fd], aiocb);
+
+    if (aio_table[aiocb->fd] == NULL)
+	qemu_set_fd_handler2(aiocb->fd, NULL, NULL, NULL, NULL);
+
+    qemu_aio_release(aiocb);
+}
+
+static AIODriver unix_aio_drv = {
+    .name = "unix",
+    .aiocb_size = sizeof(UnixAIOCB),
+    .aio_wait = ua_wait,
+    .aio_flush = ua_flush,
+    .aio_submit = ua_submit,
+    .aio_cancel = ua_cancel,
+};
+
+int unix_aio_init(void)
+{
+    return qemu_register_aio(&unix_aio_drv);
+}
diff --git a/block-aio.h b/block-aio.h
new file mode 100644
index 0000000..30c279a
--- /dev/null
+++ b/block-aio.h
@@ -0,0 +1,34 @@
+#ifndef QEMU_AIO_H
+#define QEMU_AIO_H
+
+#include "qemu-common.h"
+#include "block.h"
+
+typedef struct AIODriver
+{
+    const char *name;
+    size_t aiocb_size;
+    void (*aio_init)(void);
+    void (*aio_wait_start)(void);
+    void (*aio_wait)(void);
+    void (*aio_wait_end)(void);
+    void (*aio_flush)(void);
+    BlockDriverAIOCB *(*aio_submit)(BlockDriverState *bs, int fd,
+				    int64_t sector_num, void *buf,
+				    int sectors, int write,
+				    BlockDriverCompletionFunc *cb,
+				    void *opaque);
+    void (*aio_cancel)(BlockDriverAIOCB *aiocb);
+    struct AIODriver *next;
+} AIODriver;
+
+int qemu_register_aio(AIODriver *drv);
+
+int qemu_set_aio_driver(const char *name);
+
+extern AIODriver *aio_drv;
+
+int posix_aio_init(void);
+int unix_aio_init(void);
+
+#endif
diff --git a/block-raw-posix.c b/block-raw-posix.c
index 6b0009e..2b07f58 100644
--- a/block-raw-posix.c
+++ b/block-raw-posix.c
@@ -27,8 +27,8 @@
 #include "exec-all.h"
 #endif
 #include "block_int.h"
+#include "block-aio.h"
 #include <assert.h>
-#include <aio.h>
 
 #ifdef CONFIG_COCOA
 #include <paths.h>
@@ -111,6 +111,8 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
         open_flags |= O_DIRECT;
 #endif
 
+    open_flags |= O_NONBLOCK;
+
     s->type = FTYPE_FILE;
 
     fd = open(filename, open_flags, 0644);
@@ -230,230 +232,75 @@ label__raw_write__success:
     return ret;
 }
 
-/***********************************************************/
-/* 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
-}
+static int aio_initialized;
 
 void qemu_aio_init(void)
 {
-    struct sigaction act;
+    if (aio_initialized)
+	return;
 
     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: ;
+    bdrv_host_device.aiocb_size = aio_drv->aiocb_size;
+    bdrv_raw.aiocb_size = aio_drv->aiocb_size;
+    if (aio_drv->aio_init)
+	aio_drv->aio_init();
 }
 
 /* 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();
+    qemu_aio_init();
+    aio_drv->aio_flush();
 }
 
-/* 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);
+    qemu_aio_init();
+    if (aio_drv->aio_wait_start)
+	aio_drv->aio_wait_start();
 }
 
 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();
+    qemu_aio_init();
+    aio_drv->aio_wait();
 }
 
 void qemu_aio_wait_end(void)
 {
-    sigprocmask(SIG_SETMASK, &wait_oset, NULL);
+    if (aio_drv->aio_wait_end)
+	aio_drv->aio_wait_end();
 }
 
-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;
-    if (nb_sectors < 0)
-        acb->aiocb.aio_nbytes = -nb_sectors;
-    else
-        acb->aiocb.aio_nbytes = nb_sectors * 512;
-    acb->aiocb.aio_offset = sector_num * 512;
-    acb->next = first_aio;
-    first_aio = acb;
-    return acb;
-}
+	return NULL;
 
-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;
+    return aio_drv->aio_submit(bs, s->fd, sector_num, buf, nb_sectors, 0,
+			       cb, opaque);
 }
 
 static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
         int64_t sector_num, const uint8_t *buf, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
-    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);
-        return NULL;
-    }
-    return &acb->common;
+    BDRVRawState *s = bs->opaque;
+
+    if (fd_open(bs) < 0)
+	return NULL;
+
+    return aio_drv->aio_submit(bs, s->fd, sector_num, (void *)buf, nb_sectors,
+			       1, cb, opaque);
 }
 
 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;
-    }
+    aio_drv->aio_cancel(blockacb);
 }
 
 static void raw_close(BlockDriverState *bs)
@@ -559,7 +406,6 @@ BlockDriver bdrv_raw = {
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
     .bdrv_aio_cancel = raw_aio_cancel,
-    .aiocb_size = sizeof(RawAIOCB),
     .protocol_name = "file",
     .bdrv_pread = raw_pread,
     .bdrv_pwrite = raw_pwrite,
@@ -911,7 +757,6 @@ BlockDriver bdrv_host_device = {
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
     .bdrv_aio_cancel = raw_aio_cancel,
-    .aiocb_size = sizeof(RawAIOCB),
     .bdrv_pread = raw_pread,
     .bdrv_pwrite = raw_pwrite,
     .bdrv_getlength = raw_getlength,
diff --git a/block-raw-win32.c b/block-raw-win32.c
index 43d3f6c..6b40a27 100644
--- a/block-raw-win32.c
+++ b/block-raw-win32.c
@@ -350,10 +350,6 @@ void qemu_aio_init(void)
 {
 }
 
-void qemu_aio_poll(void)
-{
-}
-
 void qemu_aio_flush(void)
 {
 }
diff --git a/block.c b/block.c
index eb610e0..b6e4bd4 100644
--- a/block.c
+++ b/block.c
@@ -26,6 +26,7 @@
 #include "console.h"
 #endif
 #include "block_int.h"
+#include "block-aio.h"
 
 #ifdef _BSD
 #include <sys/types.h>
@@ -1347,6 +1348,10 @@ void bdrv_init(void)
     bdrv_register(&bdrv_vvfat);
     bdrv_register(&bdrv_qcow2);
     bdrv_register(&bdrv_parallels);
+#ifndef QEMU_IMG
+    unix_aio_init();
+#endif
+    posix_aio_init();
 }
 
 void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
@@ -1378,6 +1383,40 @@ void qemu_aio_release(void *p)
     drv->free_aiocb = acb;
 }
 
+static AIODriver *aio_driver_list;
+AIODriver *aio_drv;
+
+int qemu_register_aio(AIODriver *drv)
+{
+    drv->next = aio_driver_list;
+    aio_driver_list = drv;
+    aio_drv = aio_driver_list;
+
+    return 0;
+}
+
+int qemu_set_aio_driver(const char *name)
+{
+    AIODriver *drv;
+
+    if (!strcmp(name, "?")) {
+	printf("Available aio drivers:\n");
+	for (drv = aio_driver_list; drv; drv = drv->next) {
+	    printf("%s\n", drv->name);
+	}
+	exit(0);
+    }
+
+    for (drv = aio_driver_list; drv; drv = drv->next) {
+	if (!strcmp(name, drv->name))
+	    break;
+    }
+
+    aio_drv = drv;
+
+    return 0;
+}
+
 /**************************************************************/
 /* removable device support */
 
diff --git a/block.h b/block.h
index 9d30db2..ff19425 100644
--- a/block.h
+++ b/block.h
@@ -94,7 +94,6 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
 void bdrv_aio_cancel(BlockDriverAIOCB *acb);
 
 void qemu_aio_init(void);
-void qemu_aio_poll(void);
 void qemu_aio_flush(void);
 void qemu_aio_wait_start(void);
 void qemu_aio_wait(void);
diff --git a/sysemu.h b/sysemu.h
index 0078190..9931139 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -41,6 +41,8 @@ void qemu_system_powerdown(void);
 #endif
 void qemu_system_reset(void);
 
+void qemu_register_poll(IOHandler *poll, void *opaque);
+
 void cpu_save(QEMUFile *f, void *opaque);
 int cpu_load(QEMUFile *f, void *opaque, int version_id);
 
diff --git a/vl.c b/vl.c
index cc328b0..1f777dc 100644
--- a/vl.c
+++ b/vl.c
@@ -36,6 +36,7 @@
 #include "qemu-timer.h"
 #include "qemu-char.h"
 #include "block.h"
+#include "block-aio.h"
 #include "audio/audio.h"
 #include "balloon.h"
 
@@ -7372,6 +7373,33 @@ void qemu_bh_delete(QEMUBH *bh)
 }
 
 /***********************************************************/
+/* poll handlers */
+
+typedef struct PollHandler
+{
+    IOHandler *func;
+    void *opaque;
+    struct PollHandler *next;
+} PollHandler;
+
+static PollHandler *poll_handlers;
+
+void qemu_register_poll(IOHandler *poll, void *opaque)
+{
+    PollHandler *p;
+
+    p = qemu_mallocz(sizeof(*p));
+    if (p == NULL)
+	return;
+
+    p->func = poll;
+    p->opaque = opaque;
+    p->next = poll_handlers;
+
+    poll_handlers = p;
+}
+
+/***********************************************************/
 /* machine registration */
 
 QEMUMachine *first_machine = NULL;
@@ -7689,7 +7717,12 @@ void main_loop_wait(int timeout)
         slirp_select_poll(&rfds, &wfds, &xfds);
     }
 #endif
-    qemu_aio_poll();
+    if (poll_handlers) {
+	PollHandler *poll;
+
+	for (poll = poll_handlers; poll; poll = poll->next)
+	    poll->func(poll->opaque);
+    }
 
     if (vm_running) {
         qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
@@ -7928,6 +7961,8 @@ static void help(int exitcode)
            "-clock          force the use of the given methods for timer alarm.\n"
            "                To see what timers are available use -clock ?\n"
            "-startdate      select initial date of the clock\n"
+	   "-aio string     Force aio type `string'\n"
+	   "                Use -aio ? to see available aio types.\n"
            "\n"
            "During emulation, the following keys are useful:\n"
            "ctrl-alt-f      toggle full screen\n"
@@ -8031,6 +8066,7 @@ enum {
     QEMU_OPTION_old_param,
     QEMU_OPTION_clock,
     QEMU_OPTION_startdate,
+    QEMU_OPTION_aio,
 };
 
 typedef struct QEMUOption {
@@ -8142,6 +8178,7 @@ const QEMUOption qemu_options[] = {
 #endif
     { "clock", HAS_ARG, QEMU_OPTION_clock },
     { "startdate", HAS_ARG, QEMU_OPTION_startdate },
+    { "aio", HAS_ARG, QEMU_OPTION_aio },
     { NULL },
 };
 
@@ -8417,6 +8454,7 @@ int main(int argc, char **argv)
     int fds[2];
     const char *pid_file = NULL;
     VLANState *vlan;
+    const char *aio_opt = NULL;
 
     LIST_INIT (&vm_change_state_head);
 #ifndef _WIN32
@@ -8991,6 +9029,9 @@ int main(int argc, char **argv)
                     }
                 }
                 break;
+	    case QEMU_OPTION_aio:
+		aio_opt = optarg;
+		break;
             }
         }
     }
@@ -9075,7 +9116,6 @@ int main(int argc, char **argv)
 
     init_timers();
     init_timer_alarm();
-    qemu_aio_init();
 
 #ifdef _WIN32
     socket_init();
@@ -9146,6 +9186,9 @@ int main(int argc, char **argv)
 
     bdrv_init();
 
+    if (aio_opt)
+	qemu_set_aio_driver(aio_opt);
+
     /* we always create the cdrom drive, even if no disk is there */
 
     if (nb_drives_opt < MAX_DRIVES)
