--- /dev/null
+From dc7588c1eb3008bda53dde1d6b890cd299758155 Mon Sep 17 00:00:00 2001
+From: Josh Durgin <josh.durgin@inktank.com>
+Date: Fri, 29 Mar 2013 13:03:23 -0700
+Subject: [PATCH] rbd: add an asynchronous flush
+
+The existing bdrv_co_flush_to_disk implementation uses rbd_flush(),
+which is sychronous and causes the main qemu thread to block until it
+is complete. This results in unresponsiveness and extra latency for
+the guest.
+
+Fix this by using an asynchronous version of flush. This was added to
+librbd with a special #define to indicate its presence, since it will
+be backported to stable versions. Thus, there is no need to check the
+version of librbd.
+
+Implement this as bdrv_aio_flush, since it matches other aio functions
+in the rbd block driver, and leave out bdrv_co_flush_to_disk when the
+asynchronous version is available.
+
+Reported-by: Oliver Francke <oliver@filoo.de>
+Signed-off-by: Josh Durgin <josh.durgin@inktank.com>
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+---
+ block/rbd.c | 37 +++++++++++++++++++++++++++++++++----
+ 1 files changed, 33 insertions(+), 4 deletions(-)
+
+diff --git a/block/rbd.c b/block/rbd.c
+index 1a8ea6d..141b488 100644
+--- a/block/rbd.c
++++ b/block/rbd.c
+@@ -63,7 +63,8 @@
+ typedef enum {
+ RBD_AIO_READ,
+ RBD_AIO_WRITE,
+- RBD_AIO_DISCARD
++ RBD_AIO_DISCARD,
++ RBD_AIO_FLUSH
+ } RBDAIOCmd;
+
+ typedef struct RBDAIOCB {
+@@ -379,8 +380,7 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
+
+ r = rcb->ret;
+
+- if (acb->cmd == RBD_AIO_WRITE ||
+- acb->cmd == RBD_AIO_DISCARD) {
++ if (acb->cmd != RBD_AIO_READ) {
+ if (r < 0) {
+ acb->ret = r;
+ acb->error = 1;
+@@ -659,6 +659,16 @@ static int rbd_aio_discard_wrapper(rbd_image_t image,
+ #endif
+ }
+
++static int rbd_aio_flush_wrapper(rbd_image_t image,
++ rbd_completion_t comp)
++{
++#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
++ return rbd_aio_flush(image, comp);
++#else
++ return -ENOTSUP;
++#endif
++}
++
+ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
+ int64_t sector_num,
+ QEMUIOVector *qiov,
+@@ -679,7 +689,7 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
+ acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque);
+ acb->cmd = cmd;
+ acb->qiov = qiov;
+- if (cmd == RBD_AIO_DISCARD) {
++ if (cmd == RBD_AIO_DISCARD || cmd == RBD_AIO_FLUSH) {
+ acb->bounce = NULL;
+ } else {
+ acb->bounce = qemu_blockalign(bs, qiov->size);
+@@ -723,6 +733,9 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
+ case RBD_AIO_DISCARD:
+ r = rbd_aio_discard_wrapper(s->image, off, size, c);
+ break;
++ case RBD_AIO_FLUSH:
++ r = rbd_aio_flush_wrapper(s->image, c);
++ break;
+ default:
+ r = -EINVAL;
+ }
+@@ -762,6 +775,16 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
+ RBD_AIO_WRITE);
+ }
+
++#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
++static BlockDriverAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
++ BlockDriverCompletionFunc *cb,
++ void *opaque)
++{
++ return rbd_start_aio(bs, 0, NULL, 0, cb, opaque, RBD_AIO_FLUSH);
++}
++
++#else
++
+ static int qemu_rbd_co_flush(BlockDriverState *bs)
+ {
+ #if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
+@@ -772,6 +795,7 @@ static int qemu_rbd_co_flush(BlockDriverState *bs)
+ return 0;
+ #endif
+ }
++#endif
+
+ static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
+ {
+@@ -949,7 +973,12 @@ static BlockDriver bdrv_rbd = {
+
+ .bdrv_aio_readv = qemu_rbd_aio_readv,
+ .bdrv_aio_writev = qemu_rbd_aio_writev,
++
++#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
++ .bdrv_aio_flush = qemu_rbd_aio_flush,
++#else
+ .bdrv_co_flush_to_disk = qemu_rbd_co_flush,
++#endif
+
+ #ifdef LIBRBD_SUPPORTS_DISCARD
+ .bdrv_aio_discard = qemu_rbd_aio_discard,
+--
+1.7.0.4
+