Patchwork [2/3] Combine bdrv_aio_readv and bdrv_aio_writev into bdrv_aio_rw_vector

login
register
mail settings
Submitter Michael Tokarev
Date Feb. 28, 2012, 11:54 p.m.
Message ID <1330473276-8975-3-git-send-email-mjt@msgid.tls.msk.ru>
Download mbox | patch
Permalink /patch/143573/
State New
Headers show

Comments

Michael Tokarev - Feb. 28, 2012, 11:54 p.m.
iscsi block driver may receive some additional work.  For now, some
common code has been moved out of iscsi_aio_writev() and iscsi_aio_readv()
into iscsi_aio_rw_vector().  Leftovers there can be optimized further,
and consolidated into the rw_vector too.  Read and write callbacks are
consolidated as well, and once the XXX "todo" bounce-buffer change is
complete the only difference there should go away too.

Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
---
 block.c           |   39 ++-------------
 block.h           |    3 +
 block/blkdebug.c  |   24 ++--------
 block/blkverify.c |   74 +++++++++--------------------
 block/curl.c      |   19 +++++---
 block/iscsi.c     |  134 ++++++++++++++++++++--------------------------------
 block/qed.c       |   20 ++------
 block/raw-posix.c |   36 +++-----------
 block/rbd.c       |   46 ++++--------------
 block/vdi.c       |   39 ++++-----------
 block_int.h       |    7 +--
 trace-events      |    6 +--
 12 files changed, 140 insertions(+), 307 deletions(-)
Paolo Bonzini - Feb. 29, 2012, 3:54 p.m.
Il 29/02/2012 00:54, Michael Tokarev ha scritto:
> iscsi block driver may receive some additional work.  For now, some
> common code has been moved out of iscsi_aio_writev() and iscsi_aio_readv()
> into iscsi_aio_rw_vector().  Leftovers there can be optimized further,
> and consolidated into the rw_vector too.  Read and write callbacks are
> consolidated as well, and once the XXX "todo" bounce-buffer change is
> complete the only difference there should go away too.

What about flush, discard, etc.?

It seems to me that either we make a single entry point that takes some
kind of BlockRequest, or there is no reason to do partial unification.

Paolo
Michael Tokarev - Feb. 29, 2012, 4:16 p.m.
On 29.02.2012 19:54, Paolo Bonzini wrote:
> Il 29/02/2012 00:54, Michael Tokarev ha scritto:
>> iscsi block driver may receive some additional work.  For now, some
>> common code has been moved out of iscsi_aio_writev() and iscsi_aio_readv()
>> into iscsi_aio_rw_vector().  Leftovers there can be optimized further,
>> and consolidated into the rw_vector too.  Read and write callbacks are
>> consolidated as well, and once the XXX "todo" bounce-buffer change is
>> complete the only difference there should go away too.
> 
> What about flush, discard, etc.?
> 
> It seems to me that either we make a single entry point that takes some
> kind of BlockRequest, or there is no reason to do partial unification.

Flush and discard are quite special.  _All_ drivers provide reads and
writes (well, except of the case when the device is read-only by definition).
But very few provides discard, and discard is different from reads and
writes because it does not take any data.  Flush is of the same nature --
it is just request, no data.  So for these, separate methods exists
and are in use now -- only in these drivers where it is appropriate.

The only additional flag or operation which can be passed - which I can
think of, anyway - is WRITE_ZEROES.  But I think it is more of discard
variety than read/write.  So there, maybe it is discard method which
may be combined with write_zeroes, but not discard and flush combined
with reads and writes.

Thanks,

/mjt

Patch

diff --git a/block.c b/block.c
index 8869583..25ce28b 100644
--- a/block.c
+++ b/block.c
@@ -54,12 +54,6 @@  typedef enum {
 } BdrvRequestFlags;
 
 static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
-static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque);
-static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque);
 static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
                                          int64_t sector_num, int nb_sectors,
                                          QEMUIOVector *iov);
@@ -280,10 +274,9 @@  void bdrv_register(BlockDriver *bdrv)
         /* bdrv_co_readv_em()/brdv_co_writev_em() work in terms of aio, so if
          * the block driver lacks aio we need to emulate that too.
          */
-        if (!bdrv->bdrv_aio_readv) {
+        if (!bdrv->bdrv_aio_rw_vector) {
             /* add AIO emulation layer */
-            bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
-            bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
+            bdrv->bdrv_aio_rw_vector = bdrv_aio_rw_vector;
         }
     }
 
@@ -3180,13 +3173,13 @@  static void bdrv_aio_bh_cb(void *opaque)
     qemu_aio_release(acb);
 }
 
-static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
+BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
                                             int64_t sector_num,
                                             QEMUIOVector *qiov,
                                             int nb_sectors,
                                             BlockDriverCompletionFunc *cb,
                                             void *opaque,
-                                            int is_write)
+                                            bool is_write)
 
 {
     BlockDriverAIOCBSync *acb;
@@ -3207,21 +3200,6 @@  static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
     return &acb->common;
 }
 
-static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
-}
-
-static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
-}
-
-
 typedef struct BlockDriverAIOCBCoroutine {
     BlockDriverAIOCB common;
     BlockRequest req;
@@ -3404,13 +3382,8 @@  static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
     };
     BlockDriverAIOCB *acb;
 
-    if (is_write) {
-        acb = bs->drv->bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
-                                       bdrv_co_io_em_complete, &co);
-    } else {
-        acb = bs->drv->bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
-                                      bdrv_co_io_em_complete, &co);
-    }
+    acb = bs->drv->bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors,
+                                      bdrv_co_io_em_complete, &co, is_write);
 
     trace_bdrv_co_io_em(bs, sector_num, nb_sectors, is_write, acb);
     if (!acb) {
diff --git a/block.h b/block.h
index 49bca5a..f0f68e0 100644
--- a/block.h
+++ b/block.h
@@ -189,6 +189,9 @@  BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
 BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
                                   QEMUIOVector *iov, int nb_sectors,
                                   BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs, int64_t sector_num,
+                                     QEMUIOVector *iov, int nb_sectors,
+                                     BlockDriverCompletionFunc *cb, void *opaque, bool is_write);
 BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
                                  BlockDriverCompletionFunc *cb, void *opaque);
 BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
diff --git a/block/blkdebug.c b/block/blkdebug.c
index a251802..ae936eb 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -353,24 +353,9 @@  static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
     return &acb->common;
 }
 
-static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
+static BlockDriverAIOCB *blkdebug_aio_rw_vector(BlockDriverState *bs,
     int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-    BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BDRVBlkdebugState *s = bs->opaque;
-
-    if (s->vars.inject_errno) {
-        return inject_error(bs, cb, opaque);
-    }
-
-    BlockDriverAIOCB *acb =
-        bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
-    return acb;
-}
-
-static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
-    int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-    BlockDriverCompletionFunc *cb, void *opaque)
+    BlockDriverCompletionFunc *cb, void *opaque, bool is_write)
 {
     BDRVBlkdebugState *s = bs->opaque;
 
@@ -379,7 +364,7 @@  static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
     }
 
     BlockDriverAIOCB *acb =
-        bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
+        bdrv_aio_rw_vector(bs->file, sector_num, qiov, nb_sectors, cb, opaque, is_write);
     return acb;
 }
 
@@ -450,8 +435,7 @@  static BlockDriver bdrv_blkdebug = {
     .bdrv_file_open     = blkdebug_open,
     .bdrv_close         = blkdebug_close,
 
-    .bdrv_aio_readv     = blkdebug_aio_readv,
-    .bdrv_aio_writev    = blkdebug_aio_writev,
+    .bdrv_aio_rw_vector = blkdebug_aio_rw_vector,
     .bdrv_aio_flush     = blkdebug_aio_flush,
 
     .bdrv_debug_event   = blkdebug_debug_event,
diff --git a/block/blkverify.c b/block/blkverify.c
index 9d5f1ec..6877a23 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -227,27 +227,6 @@  static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src,
     }
 }
 
-static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
-                                         int64_t sector_num, QEMUIOVector *qiov,
-                                         int nb_sectors,
-                                         BlockDriverCompletionFunc *cb,
-                                         void *opaque)
-{
-    BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
-
-    acb->bh = NULL;
-    acb->is_write = is_write;
-    acb->sector_num = sector_num;
-    acb->nb_sectors = nb_sectors;
-    acb->ret = -EINPROGRESS;
-    acb->done = 0;
-    acb->qiov = qiov;
-    acb->buf = NULL;
-    acb->verify = NULL;
-    acb->finished = NULL;
-    return acb;
-}
-
 static void blkverify_aio_bh(void *opaque)
 {
     BlkverifyAIOCB *acb = opaque;
@@ -297,38 +276,34 @@  static void blkverify_verify_readv(BlkverifyAIOCB *acb)
     }
 }
 
-static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
+static BlockDriverAIOCB *blkverify_aio_rw_vector(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+        BlockDriverCompletionFunc *cb, void *opaque, bool is_write)
 {
     BDRVBlkverifyState *s = bs->opaque;
-    BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
-                                            nb_sectors, cb, opaque);
-
-    acb->verify = blkverify_verify_readv;
-    acb->buf = qemu_blockalign(bs->file, qiov->size);
-    qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
-    blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
-
-    bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
-                   blkverify_aio_cb, acb);
-    bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
-                   blkverify_aio_cb, acb);
-    return &acb->common;
-}
+    BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque);
 
-static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BDRVBlkverifyState *s = bs->opaque;
-    BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
-                                            nb_sectors, cb, opaque);
+    acb->bh = NULL;
+    acb->is_write = is_write;
+    acb->sector_num = sector_num;
+    acb->nb_sectors = nb_sectors;
+    acb->ret = -EINPROGRESS;
+    acb->done = 0;
+    acb->qiov = qiov;
+    acb->buf = NULL;
+    acb->verify = NULL;
+    acb->finished = NULL;
 
-    bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
-                    blkverify_aio_cb, acb);
-    bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
-                    blkverify_aio_cb, acb);
+    if (!is_write) {
+        acb->verify = blkverify_verify_readv;
+        acb->buf = qemu_blockalign(bs->file, qiov->size);
+        qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
+        blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
+    }
+    bdrv_aio_rw_vector(s->test_file, sector_num, qiov, nb_sectors,
+                       blkverify_aio_cb, acb, is_write);
+    bdrv_aio_rw_vector(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
+                       blkverify_aio_cb, acb, is_write);
     return &acb->common;
 }
 
@@ -353,8 +328,7 @@  static BlockDriver bdrv_blkverify = {
     .bdrv_file_open     = blkverify_open,
     .bdrv_close         = blkverify_close,
 
-    .bdrv_aio_readv     = blkverify_aio_readv,
-    .bdrv_aio_writev    = blkverify_aio_writev,
+    .bdrv_aio_rw_vector = blkverify_aio_rw_vector,
     .bdrv_aio_flush     = blkverify_aio_flush,
 };
 
diff --git a/block/curl.c b/block/curl.c
index e9102e3..ed58dd3 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -501,12 +501,17 @@  static void curl_readv_bh_cb(void *p)
 
 }
 
-static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
+static BlockDriverAIOCB *curl_aio_rw_vector(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+        BlockDriverCompletionFunc *cb, void *opaque, bool is_write)
 {
     CURLAIOCB *acb;
 
+    if (is_write) {
+        errno = EROFS;
+        return NULL;
+    }
+
     acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
 
     acb->qiov = qiov;
@@ -563,7 +568,7 @@  static BlockDriver bdrv_http = {
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
-    .bdrv_aio_readv  = curl_aio_readv,
+    .bdrv_aio_rw_vector = curl_aio_rw_vector,
 };
 
 static BlockDriver bdrv_https = {
@@ -575,7 +580,7 @@  static BlockDriver bdrv_https = {
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
-    .bdrv_aio_readv  = curl_aio_readv,
+    .bdrv_aio_rw_vector = curl_aio_rw_vector,
 };
 
 static BlockDriver bdrv_ftp = {
@@ -587,7 +592,7 @@  static BlockDriver bdrv_ftp = {
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
-    .bdrv_aio_readv  = curl_aio_readv,
+    .bdrv_aio_rw_vector = curl_aio_rw_vector,
 };
 
 static BlockDriver bdrv_ftps = {
@@ -599,7 +604,7 @@  static BlockDriver bdrv_ftps = {
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
-    .bdrv_aio_readv  = curl_aio_readv,
+    .bdrv_aio_rw_vector = curl_aio_rw_vector,
 };
 
 static BlockDriver bdrv_tftp = {
@@ -611,7 +616,7 @@  static BlockDriver bdrv_tftp = {
     .bdrv_close      = curl_close,
     .bdrv_getlength  = curl_getlength,
 
-    .bdrv_aio_readv  = curl_aio_readv,
+    .bdrv_aio_rw_vector = curl_aio_rw_vector,
 };
 
 static void curl_block_init(void)
diff --git a/block/iscsi.c b/block/iscsi.c
index bd3ca11..e780b5f 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -161,14 +161,16 @@  iscsi_readv_writev_bh_cb(void *p)
 
 
 static void
-iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
-                     void *command_data, void *opaque)
+iscsi_aio_rw10_cb(struct iscsi_context *iscsi, int status,
+                  void *command_data, void *opaque)
 {
     IscsiAIOCB *acb = opaque;
 
-    trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled);
+    trace_iscsi_aio_rw10_cb(iscsi, status, acb, acb->canceled);
 
-    g_free(acb->buf);
+    if (acb->buf) {
+        g_free(acb->buf);
+    }
 
     if (acb->canceled != 0) {
         qemu_aio_release(acb);
@@ -179,7 +181,7 @@  iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
 
     acb->status = 0;
     if (status < 0) {
-        error_report("Failed to write10 data to iSCSI lun. %s",
+        error_report("Failed to read/write10 data from/to iSCSI lun. %s",
                      iscsi_get_error(iscsi));
         acb->status = -EIO;
     }
@@ -194,15 +196,10 @@  static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
     return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
 }
 
-static BlockDriverAIOCB *
-iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
-                 QEMUIOVector *qiov, int nb_sectors,
-                 BlockDriverCompletionFunc *cb,
-                 void *opaque)
+static int
+iscsi_aio_writev(BlockDriverState *bs, IscsiAIOCB *acb, int64_t sector_num, int nb_sectors)
 {
-    IscsiLun *iscsilun = bs->opaque;
-    struct iscsi_context *iscsi = iscsilun->iscsi;
-    IscsiAIOCB *acb;
+    IscsiLun *iscsilun = acb->iscsilun;
     size_t size;
     int fua = 0;
 
@@ -211,86 +208,32 @@  iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
         fua = 1;
     }
 
-    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
-    trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
-
-    acb->iscsilun = iscsilun;
-    acb->qiov     = qiov;
-
-    acb->canceled   = 0;
-
     /* XXX we should pass the iovec to write10 to avoid the extra copy */
     /* this will allow us to get rid of 'buf' completely */
     size = nb_sectors * BDRV_SECTOR_SIZE;
     acb->buf = g_malloc(size);
     qemu_iovec_to_buffer(acb->qiov, acb->buf);
-    acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size,
+    acb->task = iscsi_write10_task(iscsilun->iscsi, iscsilun->lun, acb->buf, size,
                               sector_qemu2lun(sector_num, iscsilun),
                               fua, 0, iscsilun->block_size,
-                              iscsi_aio_write10_cb, acb);
+                              iscsi_aio_rw10_cb, acb);
     if (acb->task == NULL) {
-        error_report("iSCSI: Failed to send write10 command. %s",
-                     iscsi_get_error(iscsi));
         g_free(acb->buf);
-        qemu_aio_release(acb);
-        return NULL;
-    }
-
-    iscsi_set_events(iscsilun);
-
-    return &acb->common;
-}
-
-static void
-iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
-                    void *command_data, void *opaque)
-{
-    IscsiAIOCB *acb = opaque;
-
-    trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled);
-
-    if (acb->canceled != 0) {
-        qemu_aio_release(acb);
-        scsi_free_scsi_task(acb->task);
-        acb->task = NULL;
-        return;
-    }
-
-    acb->status = 0;
-    if (status != 0) {
-        error_report("Failed to read10 data from iSCSI lun. %s",
-                     iscsi_get_error(iscsi));
-        acb->status = -EIO;
+        return -1;
     }
-
-    iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
-    scsi_free_scsi_task(acb->task);
-    acb->task = NULL;
+    return 0;
 }
 
-static BlockDriverAIOCB *
-iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
-                QEMUIOVector *qiov, int nb_sectors,
-                BlockDriverCompletionFunc *cb,
-                void *opaque)
+static int
+iscsi_aio_readv(BlockDriverState *bs, IscsiAIOCB *acb, int64_t sector_num, int nb_sectors)
 {
-    IscsiLun *iscsilun = bs->opaque;
-    struct iscsi_context *iscsi = iscsilun->iscsi;
-    IscsiAIOCB *acb;
+    IscsiLun *iscsilun = acb->iscsilun;
     size_t qemu_read_size, lun_read_size;
     int i;
 
     qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
 
-    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
-    trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
-
-    acb->iscsilun = iscsilun;
-    acb->qiov     = qiov;
-
-    acb->canceled    = 0;
     acb->read_size   = qemu_read_size;
-    acb->buf         = NULL;
 
     /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
      * may be misaligned to the LUN, so we may need to read some extra
@@ -306,15 +249,12 @@  iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
     lun_read_size  = (qemu_read_size + iscsilun->block_size
                      + acb->read_offset - 1)
                      / iscsilun->block_size * iscsilun->block_size;
-    acb->task = iscsi_read10_task(iscsi, iscsilun->lun,
+    acb->task = iscsi_read10_task(iscsilun->iscsi, iscsilun->lun,
                              sector_qemu2lun(sector_num, iscsilun),
                              lun_read_size, iscsilun->block_size,
-                             iscsi_aio_read10_cb, acb);
+                             iscsi_aio_rw10_cb, acb);
     if (acb->task == NULL) {
-        error_report("iSCSI: Failed to send read10 command. %s",
-                     iscsi_get_error(iscsi));
-        qemu_aio_release(acb);
-        return NULL;
+        return -1;
     }
 
     for (i = 0; i < acb->qiov->niov; i++) {
@@ -323,6 +263,37 @@  iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
                 acb->qiov->iov[i].iov_base);
     }
 
+    return 0;
+}
+
+static BlockDriverAIOCB *
+iscsi_aio_rw_vector(BlockDriverState *bs, int64_t sector_num,
+                    QEMUIOVector *qiov, int nb_sectors,
+                    BlockDriverCompletionFunc *cb,
+                    void *opaque, bool is_write)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    IscsiAIOCB *acb;
+    int ret;
+
+    acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
+    trace_iscsi_aio_rw_vector(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb, is_write);
+
+    acb->iscsilun = iscsilun;
+    acb->qiov     = qiov;
+
+    acb->canceled    = 0;
+    acb->buf         = NULL;
+
+    ret = is_write ? iscsi_aio_writev(bs, acb, sector_num, nb_sectors)
+                   : iscsi_aio_readv(bs, acb, sector_num, nb_sectors);
+    if (ret != 0) {
+        error_report("iSCSI: Failed to send read10/write10 command. %s",
+                     iscsi_get_error(iscsilun->iscsi));
+        qemu_aio_release(acb);
+        return NULL;
+    }
+  
     iscsi_set_events(iscsilun);
 
     return &acb->common;
@@ -697,8 +668,7 @@  static BlockDriver bdrv_iscsi = {
 
     .bdrv_getlength  = iscsi_getlength,
 
-    .bdrv_aio_readv  = iscsi_aio_readv,
-    .bdrv_aio_writev = iscsi_aio_writev,
+    .bdrv_aio_rw_vector = iscsi_aio_rw_vector,
     .bdrv_aio_flush  = iscsi_aio_flush,
 };
 
diff --git a/block/qed.c b/block/qed.c
index a041d31..155fa59 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1331,23 +1331,14 @@  static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
     return &acb->common;
 }
 
-static BlockDriverAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
+static BlockDriverAIOCB *bdrv_qed_aio_rw_vector(BlockDriverState *bs,
                                             int64_t sector_num,
                                             QEMUIOVector *qiov, int nb_sectors,
                                             BlockDriverCompletionFunc *cb,
-                                            void *opaque)
-{
-    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
-}
-
-static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
-                                             int64_t sector_num,
-                                             QEMUIOVector *qiov, int nb_sectors,
-                                             BlockDriverCompletionFunc *cb,
-                                             void *opaque)
+                                            void *opaque, bool is_write)
 {
-    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb,
-                         opaque, QED_AIOCB_WRITE);
+  return
+     qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, is_write ? QED_AIOCB_WRITE : 0);
 }
 
 static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs,
@@ -1560,8 +1551,7 @@  static BlockDriver bdrv_qed = {
     .bdrv_create              = bdrv_qed_create,
     .bdrv_co_is_allocated     = bdrv_qed_co_is_allocated,
     .bdrv_make_empty          = bdrv_qed_make_empty,
-    .bdrv_aio_readv           = bdrv_qed_aio_readv,
-    .bdrv_aio_writev          = bdrv_qed_aio_writev,
+    .bdrv_aio_rw_vector       = bdrv_qed_aio_rw_vector,
     .bdrv_aio_flush           = bdrv_qed_aio_flush,
     .bdrv_co_write_zeroes     = bdrv_qed_co_write_zeroes,
     .bdrv_truncate            = bdrv_qed_truncate,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 2d1bc13..dc93911 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -312,11 +312,12 @@  static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
     return 1;
 }
 
-static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
+static BlockDriverAIOCB *raw_aio_rw_vector(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque, int type)
+        BlockDriverCompletionFunc *cb, void *opaque, bool is_write)
 {
     BDRVRawState *s = bs->opaque;
+    int type = is_write ? QEMU_AIO_WRITE : QEMU_AIO_READ;
 
     if (fd_open(bs) < 0)
         return NULL;
@@ -341,22 +342,6 @@  static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
                        cb, opaque, type);
 }
 
-static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
-                          cb, opaque, QEMU_AIO_READ);
-}
-
-static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
-                          cb, opaque, QEMU_AIO_WRITE);
-}
-
 static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
@@ -635,8 +620,7 @@  static BlockDriver bdrv_file = {
     .bdrv_create = raw_create,
     .bdrv_co_discard = raw_co_discard,
 
-    .bdrv_aio_readv = raw_aio_readv,
-    .bdrv_aio_writev = raw_aio_writev,
+    .bdrv_aio_rw_vector = raw_aio_rw_vector,
     .bdrv_aio_flush = raw_aio_flush,
 
     .bdrv_truncate = raw_truncate,
@@ -903,8 +887,7 @@  static BlockDriver bdrv_host_device = {
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
-    .bdrv_aio_readv	= raw_aio_readv,
-    .bdrv_aio_writev	= raw_aio_writev,
+    .bdrv_aio_rw_vector	= raw_aio_rw_vector,
     .bdrv_aio_flush	= raw_aio_flush,
 
     .bdrv_truncate      = raw_truncate,
@@ -1022,8 +1005,7 @@  static BlockDriver bdrv_host_floppy = {
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
-    .bdrv_aio_readv     = raw_aio_readv,
-    .bdrv_aio_writev    = raw_aio_writev,
+    .bdrv_aio_rw_vector = raw_aio_rw_vector,
     .bdrv_aio_flush	= raw_aio_flush,
 
     .bdrv_truncate      = raw_truncate,
@@ -1121,8 +1103,7 @@  static BlockDriver bdrv_host_cdrom = {
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
-    .bdrv_aio_readv     = raw_aio_readv,
-    .bdrv_aio_writev    = raw_aio_writev,
+    .bdrv_aio_rw_vector = raw_aio_rw_vector,
     .bdrv_aio_flush	= raw_aio_flush,
 
     .bdrv_truncate      = raw_truncate,
@@ -1240,8 +1221,7 @@  static BlockDriver bdrv_host_cdrom = {
     .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
-    .bdrv_aio_readv     = raw_aio_readv,
-    .bdrv_aio_writev    = raw_aio_writev,
+    .bdrv_aio_rw_vector = raw_aio_rw_vector,
     .bdrv_aio_flush	= raw_aio_flush,
 
     .bdrv_truncate      = raw_truncate,
diff --git a/block/rbd.c b/block/rbd.c
index 46a8579..5078b0d 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -617,12 +617,12 @@  static void rbd_aio_bh_cb(void *opaque)
     qemu_aio_release(acb);
 }
 
-static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
-                                           int64_t sector_num,
-                                           QEMUIOVector *qiov,
-                                           int nb_sectors,
-                                           BlockDriverCompletionFunc *cb,
-                                           void *opaque, int write)
+static BlockDriverAIOCB *qemu_rbd_aio_rw_vector(BlockDriverState *bs,
+                                               int64_t sector_num,
+                                               QEMUIOVector *qiov,
+                                               int nb_sectors,
+                                               BlockDriverCompletionFunc *cb,
+                                               void *opaque, bool is_write)
 {
     RBDAIOCB *acb;
     RADOSCB *rcb;
@@ -634,7 +634,7 @@  static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
     BDRVRBDState *s = bs->opaque;
 
     acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
-    acb->write = write;
+    acb->write = is_write;
     acb->qiov = qiov;
     acb->bounce = qemu_blockalign(bs, qiov->size);
     acb->ret = 0;
@@ -643,7 +643,7 @@  static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
     acb->cancelled = 0;
     acb->bh = NULL;
 
-    if (write) {
+    if (is_write) {
         qemu_iovec_to_buffer(acb->qiov, acb->bounce);
     }
 
@@ -665,11 +665,8 @@  static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
         goto failed;
     }
 
-    if (write) {
-        r = rbd_aio_write(s->image, off, size, buf, c);
-    } else {
-        r = rbd_aio_read(s->image, off, size, buf, c);
-    }
+    r = is_write ? rbd_aio_write(s->image, off, size, buf, c)
+                 : rbd_aio_read(s->image, off, size, buf, c);
 
     if (r < 0) {
         goto failed;
@@ -684,26 +681,6 @@  failed:
     return NULL;
 }
 
-static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
-                                            int64_t sector_num,
-                                            QEMUIOVector *qiov,
-                                            int nb_sectors,
-                                            BlockDriverCompletionFunc *cb,
-                                            void *opaque)
-{
-    return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
-}
-
-static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
-                                             int64_t sector_num,
-                                             QEMUIOVector *qiov,
-                                             int nb_sectors,
-                                             BlockDriverCompletionFunc *cb,
-                                             void *opaque)
-{
-    return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
-}
-
 static int qemu_rbd_co_flush(BlockDriverState *bs)
 {
 #if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
@@ -877,8 +854,7 @@  static BlockDriver bdrv_rbd = {
     .bdrv_truncate      = qemu_rbd_truncate,
     .protocol_name      = "rbd",
 
-    .bdrv_aio_readv         = qemu_rbd_aio_readv,
-    .bdrv_aio_writev        = qemu_rbd_aio_writev,
+    .bdrv_aio_rw_vector     = qemu_rbd_aio_rw_vector,
     .bdrv_co_flush_to_disk  = qemu_rbd_co_flush,
 
     .bdrv_snapshot_create   = qemu_rbd_snap_create,
diff --git a/block/vdi.c b/block/vdi.c
index 6a0011f..4fd56d7 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -642,15 +642,22 @@  done:
     qemu_aio_release(acb);
 }
 
-static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
+static BlockDriverAIOCB *vdi_aio_rw_vector(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+        BlockDriverCompletionFunc *cb, void *opaque, bool is_write)
 {
     VdiAIOCB *acb;
     int ret;
 
+#if !defined(CONFIG_VDI_WRITE)
+    if (is_write) {
+       errno = ENOSYS;
+       return NULL;
+    }
+#endif
+
     logout("\n");
-    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, is_write);
     ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
     if (ret < 0) {
         if (acb->qiov->niov > 1) {
@@ -796,27 +803,6 @@  done:
     qemu_aio_release(acb);
 }
 
-static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    VdiAIOCB *acb;
-    int ret;
-
-    logout("\n");
-    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
-    ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
-    if (ret < 0) {
-        if (acb->qiov->niov > 1) {
-            qemu_vfree(acb->orig_buf);
-        }
-        qemu_aio_release(acb);
-        return NULL;
-    }
-
-    return &acb->common;
-}
-
 static int vdi_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
@@ -973,10 +959,7 @@  static BlockDriver bdrv_vdi = {
     .bdrv_co_is_allocated = vdi_co_is_allocated,
     .bdrv_make_empty = vdi_make_empty,
 
-    .bdrv_aio_readv = vdi_aio_readv,
-#if defined(CONFIG_VDI_WRITE)
-    .bdrv_aio_writev = vdi_aio_writev,
-#endif
+    .bdrv_aio_rw_vector = vdi_aio_rw_vector,
 
     .bdrv_get_info = vdi_get_info,
 
diff --git a/block_int.h b/block_int.h
index f3930df..aeafa2e 100644
--- a/block_int.h
+++ b/block_int.h
@@ -113,12 +113,9 @@  struct BlockDriver {
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
     int (*bdrv_make_empty)(BlockDriverState *bs);
     /* aio */
-    BlockDriverAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs,
+    BlockDriverAIOCB *(*bdrv_aio_rw_vector)(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque);
-    BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque);
+        BlockDriverCompletionFunc *cb, void *opaque, bool is_write);
     BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque);
     BlockDriverAIOCB *(*bdrv_aio_discard)(BlockDriverState *bs,
diff --git a/trace-events b/trace-events
index e918ff6..e5d3c27 100644
--- a/trace-events
+++ b/trace-events
@@ -524,10 +524,8 @@  escc_kbd_command(int val) "Command %d"
 escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x"
 
 # block/iscsi.c
-iscsi_aio_write10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
-iscsi_aio_writev(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
-iscsi_aio_read10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
-iscsi_aio_readv(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
+iscsi_aio_rw10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
+iscsi_aio_rw_vector(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb, bool is_write) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p is_write %d"
 
 # hw/esp.c
 esp_raise_irq(void) "Raise IRQ"