Blame SOURCES/kvm-block-Convert-.bdrv_truncate-callback-to-coroutine_f.patch

26ba25
From 655e1605b0ec1e798482e36ccfcf43cfb983c26e Mon Sep 17 00:00:00 2001
26ba25
From: Kevin Wolf <kwolf@redhat.com>
26ba25
Date: Thu, 12 Jul 2018 14:42:54 +0200
26ba25
Subject: [PATCH 209/268] block: Convert .bdrv_truncate callback to
26ba25
 coroutine_fn
26ba25
26ba25
RH-Author: Kevin Wolf <kwolf@redhat.com>
26ba25
Message-id: <20180712144258.17303-3-kwolf@redhat.com>
26ba25
Patchwork-id: 81327
26ba25
O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/6] block: Convert .bdrv_truncate callback to coroutine_fn
26ba25
Bugzilla: 1595173
26ba25
RH-Acked-by: Max Reitz <mreitz@redhat.com>
26ba25
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
26ba25
RH-Acked-by: John Snow <jsnow@redhat.com>
26ba25
26ba25
bdrv_truncate() is an operation that can block (even for a quite long
26ba25
time, depending on the PreallocMode) in I/O paths that shouldn't block.
26ba25
Convert it to a coroutine_fn so that we have the infrastructure for
26ba25
drivers to make their .bdrv_co_truncate implementation asynchronous.
26ba25
26ba25
This change could potentially introduce new race conditions because
26ba25
bdrv_truncate() isn't necessarily executed atomically any more. Whether
26ba25
this is a problem needs to be evaluated for each block driver that
26ba25
supports truncate:
26ba25
26ba25
* file-posix/win32, gluster, iscsi, nfs, rbd, ssh, sheepdog: The
26ba25
  protocol drivers are trivially safe because they don't actually yield
26ba25
  yet, so there is no change in behaviour.
26ba25
26ba25
* copy-on-read, crypto, raw-format: Essentially just filter drivers that
26ba25
  pass the request to a child node, no problem.
26ba25
26ba25
* qcow2: The implementation modifies metadata, so it needs to hold
26ba25
  s->lock to be safe with concurrent I/O requests. In order to avoid
26ba25
  double locking, this requires pulling the locking out into
26ba25
  preallocate_co() and using qcow2_write_caches() instead of
26ba25
  bdrv_flush().
26ba25
26ba25
* qed: Does a single header update, this is fine without locking.
26ba25
26ba25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26ba25
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
26ba25
(cherry picked from commit 061ca8a368165fae300748c17971824a089f521f)
26ba25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26ba25
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
26ba25
---
26ba25
 block.c                   | 63 +++++++++++++++++++++++++++++++++++-----
26ba25
 block/copy-on-read.c      |  8 ++---
26ba25
 block/crypto.c            |  9 +++---
26ba25
 block/file-posix.c        | 12 ++++----
26ba25
 block/file-win32.c        |  6 ++--
26ba25
 block/gluster.c           | 14 +++++----
26ba25
 block/iscsi.c             |  8 ++---
26ba25
 block/nfs.c               |  7 +++--
26ba25
 block/qcow2.c             | 74 ++++++++++++++++++++++++++++-------------------
26ba25
 block/qed.c               |  8 +++--
26ba25
 block/raw-format.c        |  8 ++---
26ba25
 block/rbd.c               |  8 +++--
26ba25
 block/sheepdog.c          | 12 ++++----
26ba25
 block/ssh.c               |  6 ++--
26ba25
 include/block/block.h     |  4 +++
26ba25
 include/block/block_int.h |  4 +--
26ba25
 16 files changed, 162 insertions(+), 89 deletions(-)
26ba25
26ba25
diff --git a/block.c b/block.c
26ba25
index 0516284..0af08ca 100644
26ba25
--- a/block.c
26ba25
+++ b/block.c
26ba25
@@ -3738,8 +3738,8 @@ exit:
26ba25
 /**
26ba25
  * Truncate file to 'offset' bytes (needed only for file protocols)
26ba25
  */
26ba25
-int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
26ba25
-                  Error **errp)
26ba25
+int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
26ba25
+                                  PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     BlockDriverState *bs = child->bs;
26ba25
     BlockDriver *drv = bs->drv;
26ba25
@@ -3757,23 +3757,28 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
26ba25
         return -EINVAL;
26ba25
     }
26ba25
 
26ba25
-    if (!drv->bdrv_truncate) {
26ba25
+    bdrv_inc_in_flight(bs);
26ba25
+
26ba25
+    if (!drv->bdrv_co_truncate) {
26ba25
         if (bs->file && drv->is_filter) {
26ba25
-            return bdrv_truncate(bs->file, offset, prealloc, errp);
26ba25
+            ret = bdrv_co_truncate(bs->file, offset, prealloc, errp);
26ba25
+            goto out;
26ba25
         }
26ba25
         error_setg(errp, "Image format driver does not support resize");
26ba25
-        return -ENOTSUP;
26ba25
+        ret = -ENOTSUP;
26ba25
+        goto out;
26ba25
     }
26ba25
     if (bs->read_only) {
26ba25
         error_setg(errp, "Image is read-only");
26ba25
-        return -EACCES;
26ba25
+        ret = -EACCES;
26ba25
+        goto out;
26ba25
     }
26ba25
 
26ba25
     assert(!(bs->open_flags & BDRV_O_INACTIVE));
26ba25
 
26ba25
-    ret = drv->bdrv_truncate(bs, offset, prealloc, errp);
26ba25
+    ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp);
26ba25
     if (ret < 0) {
26ba25
-        return ret;
26ba25
+        goto out;
26ba25
     }
26ba25
     ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
26ba25
     if (ret < 0) {
26ba25
@@ -3784,9 +3789,51 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
26ba25
     bdrv_dirty_bitmap_truncate(bs, offset);
26ba25
     bdrv_parent_cb_resize(bs);
26ba25
     atomic_inc(&bs->write_gen);
26ba25
+
26ba25
+out:
26ba25
+    bdrv_dec_in_flight(bs);
26ba25
     return ret;
26ba25
 }
26ba25
 
26ba25
+typedef struct TruncateCo {
26ba25
+    BdrvChild *child;
26ba25
+    int64_t offset;
26ba25
+    PreallocMode prealloc;
26ba25
+    Error **errp;
26ba25
+    int ret;
26ba25
+} TruncateCo;
26ba25
+
26ba25
+static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
26ba25
+{
26ba25
+    TruncateCo *tco = opaque;
26ba25
+    tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc,
26ba25
+                                tco->errp);
26ba25
+}
26ba25
+
26ba25
+int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
26ba25
+                  Error **errp)
26ba25
+{
26ba25
+    Coroutine *co;
26ba25
+    TruncateCo tco = {
26ba25
+        .child      = child,
26ba25
+        .offset     = offset,
26ba25
+        .prealloc   = prealloc,
26ba25
+        .errp       = errp,
26ba25
+        .ret        = NOT_DONE,
26ba25
+    };
26ba25
+
26ba25
+    if (qemu_in_coroutine()) {
26ba25
+        /* Fast-path if already in coroutine context */
26ba25
+        bdrv_truncate_co_entry(&tco;;
26ba25
+    } else {
26ba25
+        co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco;;
26ba25
+        qemu_coroutine_enter(co);
26ba25
+        BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE);
26ba25
+    }
26ba25
+
26ba25
+    return tco.ret;
26ba25
+}
26ba25
+
26ba25
 /**
26ba25
  * Length of a allocated file in bytes. Sparse files are counted by actual
26ba25
  * allocated space. Return < 0 if error or unknown.
26ba25
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
26ba25
index 6a97208..1dcdaee 100644
26ba25
--- a/block/copy-on-read.c
26ba25
+++ b/block/copy-on-read.c
26ba25
@@ -80,10 +80,10 @@ static int64_t cor_getlength(BlockDriverState *bs)
26ba25
 }
26ba25
 
26ba25
 
26ba25
-static int cor_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                        PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn cor_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                                        PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
-    return bdrv_truncate(bs->file, offset, prealloc, errp);
26ba25
+    return bdrv_co_truncate(bs->file, offset, prealloc, errp);
26ba25
 }
26ba25
 
26ba25
 
26ba25
@@ -147,7 +147,7 @@ BlockDriver bdrv_copy_on_read = {
26ba25
     .bdrv_child_perm                    = cor_child_perm,
26ba25
 
26ba25
     .bdrv_getlength                     = cor_getlength,
26ba25
-    .bdrv_truncate                      = cor_truncate,
26ba25
+    .bdrv_co_truncate                   = cor_co_truncate,
26ba25
 
26ba25
     .bdrv_co_preadv                     = cor_co_preadv,
26ba25
     .bdrv_co_pwritev                    = cor_co_pwritev,
26ba25
diff --git a/block/crypto.c b/block/crypto.c
26ba25
index f5151f4..02f04f3 100644
26ba25
--- a/block/crypto.c
26ba25
+++ b/block/crypto.c
26ba25
@@ -357,8 +357,9 @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
26ba25
     return ret;
26ba25
 }
26ba25
 
26ba25
-static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                                 PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn
26ba25
+block_crypto_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                         PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     BlockCrypto *crypto = bs->opaque;
26ba25
     uint64_t payload_offset =
26ba25
@@ -371,7 +372,7 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
26ba25
 
26ba25
     offset += payload_offset;
26ba25
 
26ba25
-    return bdrv_truncate(bs->file, offset, prealloc, errp);
26ba25
+    return bdrv_co_truncate(bs->file, offset, prealloc, errp);
26ba25
 }
26ba25
 
26ba25
 static void block_crypto_close(BlockDriverState *bs)
26ba25
@@ -700,7 +701,7 @@ BlockDriver bdrv_crypto_luks = {
26ba25
     .bdrv_child_perm    = bdrv_format_default_perms,
26ba25
     .bdrv_co_create     = block_crypto_co_create_luks,
26ba25
     .bdrv_co_create_opts = block_crypto_co_create_opts_luks,
26ba25
-    .bdrv_truncate      = block_crypto_truncate,
26ba25
+    .bdrv_co_truncate   = block_crypto_co_truncate,
26ba25
     .create_opts        = &block_crypto_create_opts_luks,
26ba25
 
26ba25
     .bdrv_reopen_prepare = block_crypto_reopen_prepare,
26ba25
diff --git a/block/file-posix.c b/block/file-posix.c
26ba25
index cbf7c11..f8488ec 100644
26ba25
--- a/block/file-posix.c
26ba25
+++ b/block/file-posix.c
26ba25
@@ -1832,8 +1832,8 @@ out:
26ba25
     return result;
26ba25
 }
26ba25
 
26ba25
-static int raw_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                        PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                                        PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     BDRVRawState *s = bs->opaque;
26ba25
     struct stat st;
26ba25
@@ -2474,7 +2474,7 @@ BlockDriver bdrv_file = {
26ba25
     .bdrv_io_plug = raw_aio_plug,
26ba25
     .bdrv_io_unplug = raw_aio_unplug,
26ba25
 
26ba25
-    .bdrv_truncate = raw_truncate,
26ba25
+    .bdrv_co_truncate = raw_co_truncate,
26ba25
     .bdrv_getlength = raw_getlength,
26ba25
     .bdrv_get_info = raw_get_info,
26ba25
     .bdrv_get_allocated_file_size
26ba25
@@ -2953,7 +2953,7 @@ static BlockDriver bdrv_host_device = {
26ba25
     .bdrv_io_plug = raw_aio_plug,
26ba25
     .bdrv_io_unplug = raw_aio_unplug,
26ba25
 
26ba25
-    .bdrv_truncate      = raw_truncate,
26ba25
+    .bdrv_co_truncate       = raw_co_truncate,
26ba25
     .bdrv_getlength	= raw_getlength,
26ba25
     .bdrv_get_info = raw_get_info,
26ba25
     .bdrv_get_allocated_file_size
26ba25
@@ -3074,7 +3074,7 @@ static BlockDriver bdrv_host_cdrom = {
26ba25
     .bdrv_io_plug = raw_aio_plug,
26ba25
     .bdrv_io_unplug = raw_aio_unplug,
26ba25
 
26ba25
-    .bdrv_truncate      = raw_truncate,
26ba25
+    .bdrv_co_truncate    = raw_co_truncate,
26ba25
     .bdrv_getlength      = raw_getlength,
26ba25
     .has_variable_length = true,
26ba25
     .bdrv_get_allocated_file_size
26ba25
@@ -3204,7 +3204,7 @@ static BlockDriver bdrv_host_cdrom = {
26ba25
     .bdrv_io_plug = raw_aio_plug,
26ba25
     .bdrv_io_unplug = raw_aio_unplug,
26ba25
 
26ba25
-    .bdrv_truncate      = raw_truncate,
26ba25
+    .bdrv_co_truncate    = raw_co_truncate,
26ba25
     .bdrv_getlength      = raw_getlength,
26ba25
     .has_variable_length = true,
26ba25
     .bdrv_get_allocated_file_size
26ba25
diff --git a/block/file-win32.c b/block/file-win32.c
26ba25
index 2e2f746..6573338 100644
26ba25
--- a/block/file-win32.c
26ba25
+++ b/block/file-win32.c
26ba25
@@ -463,8 +463,8 @@ static void raw_close(BlockDriverState *bs)
26ba25
     }
26ba25
 }
26ba25
 
26ba25
-static int raw_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                        PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                                        PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     BDRVRawState *s = bs->opaque;
26ba25
     LONG low, high;
26ba25
@@ -636,7 +636,7 @@ BlockDriver bdrv_file = {
26ba25
     .bdrv_aio_writev    = raw_aio_writev,
26ba25
     .bdrv_aio_flush     = raw_aio_flush,
26ba25
 
26ba25
-    .bdrv_truncate	= raw_truncate,
26ba25
+    .bdrv_co_truncate   = raw_co_truncate,
26ba25
     .bdrv_getlength	= raw_getlength,
26ba25
     .bdrv_get_allocated_file_size
26ba25
                         = raw_get_allocated_file_size,
26ba25
diff --git a/block/gluster.c b/block/gluster.c
26ba25
index 418bb73..cecfe09 100644
26ba25
--- a/block/gluster.c
26ba25
+++ b/block/gluster.c
26ba25
@@ -1177,8 +1177,10 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
26ba25
     return acb.ret;
26ba25
 }
26ba25
 
26ba25
-static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                                 PreallocMode prealloc, Error **errp)
26ba25
+static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
26ba25
+                                                 int64_t offset,
26ba25
+                                                 PreallocMode prealloc,
26ba25
+                                                 Error **errp)
26ba25
 {
26ba25
     BDRVGlusterState *s = bs->opaque;
26ba25
     return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
26ba25
@@ -1497,7 +1499,7 @@ static BlockDriver bdrv_gluster = {
26ba25
     .bdrv_co_create_opts          = qemu_gluster_co_create_opts,
26ba25
     .bdrv_getlength               = qemu_gluster_getlength,
26ba25
     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
26ba25
-    .bdrv_truncate                = qemu_gluster_truncate,
26ba25
+    .bdrv_co_truncate             = qemu_gluster_co_truncate,
26ba25
     .bdrv_co_readv                = qemu_gluster_co_readv,
26ba25
     .bdrv_co_writev               = qemu_gluster_co_writev,
26ba25
     .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
26ba25
@@ -1526,7 +1528,7 @@ static BlockDriver bdrv_gluster_tcp = {
26ba25
     .bdrv_co_create_opts          = qemu_gluster_co_create_opts,
26ba25
     .bdrv_getlength               = qemu_gluster_getlength,
26ba25
     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
26ba25
-    .bdrv_truncate                = qemu_gluster_truncate,
26ba25
+    .bdrv_co_truncate             = qemu_gluster_co_truncate,
26ba25
     .bdrv_co_readv                = qemu_gluster_co_readv,
26ba25
     .bdrv_co_writev               = qemu_gluster_co_writev,
26ba25
     .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
26ba25
@@ -1555,7 +1557,7 @@ static BlockDriver bdrv_gluster_unix = {
26ba25
     .bdrv_co_create_opts          = qemu_gluster_co_create_opts,
26ba25
     .bdrv_getlength               = qemu_gluster_getlength,
26ba25
     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
26ba25
-    .bdrv_truncate                = qemu_gluster_truncate,
26ba25
+    .bdrv_co_truncate             = qemu_gluster_co_truncate,
26ba25
     .bdrv_co_readv                = qemu_gluster_co_readv,
26ba25
     .bdrv_co_writev               = qemu_gluster_co_writev,
26ba25
     .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
26ba25
@@ -1590,7 +1592,7 @@ static BlockDriver bdrv_gluster_rdma = {
26ba25
     .bdrv_co_create_opts          = qemu_gluster_co_create_opts,
26ba25
     .bdrv_getlength               = qemu_gluster_getlength,
26ba25
     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
26ba25
-    .bdrv_truncate                = qemu_gluster_truncate,
26ba25
+    .bdrv_co_truncate             = qemu_gluster_co_truncate,
26ba25
     .bdrv_co_readv                = qemu_gluster_co_readv,
26ba25
     .bdrv_co_writev               = qemu_gluster_co_writev,
26ba25
     .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
26ba25
diff --git a/block/iscsi.c b/block/iscsi.c
26ba25
index 751884d..5047e83 100644
26ba25
--- a/block/iscsi.c
26ba25
+++ b/block/iscsi.c
26ba25
@@ -2085,8 +2085,8 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
26ba25
     }
26ba25
 }
26ba25
 
26ba25
-static int iscsi_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                          PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                                          PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     IscsiLun *iscsilun = bs->opaque;
26ba25
     Error *local_err = NULL;
26ba25
@@ -2431,7 +2431,7 @@ static BlockDriver bdrv_iscsi = {
26ba25
 
26ba25
     .bdrv_getlength  = iscsi_getlength,
26ba25
     .bdrv_get_info   = iscsi_get_info,
26ba25
-    .bdrv_truncate   = iscsi_truncate,
26ba25
+    .bdrv_co_truncate    = iscsi_co_truncate,
26ba25
     .bdrv_refresh_limits = iscsi_refresh_limits,
26ba25
 
26ba25
     .bdrv_co_block_status  = iscsi_co_block_status,
26ba25
@@ -2468,7 +2468,7 @@ static BlockDriver bdrv_iser = {
26ba25
 
26ba25
     .bdrv_getlength  = iscsi_getlength,
26ba25
     .bdrv_get_info   = iscsi_get_info,
26ba25
-    .bdrv_truncate   = iscsi_truncate,
26ba25
+    .bdrv_co_truncate    = iscsi_co_truncate,
26ba25
     .bdrv_refresh_limits = iscsi_refresh_limits,
26ba25
 
26ba25
     .bdrv_co_block_status  = iscsi_co_block_status,
26ba25
diff --git a/block/nfs.c b/block/nfs.c
26ba25
index 743ca04..eab1a2c 100644
26ba25
--- a/block/nfs.c
26ba25
+++ b/block/nfs.c
26ba25
@@ -743,8 +743,9 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
26ba25
     return (task.ret < 0 ? task.ret : st.st_blocks * 512);
26ba25
 }
26ba25
 
26ba25
-static int nfs_file_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                             PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn
26ba25
+nfs_file_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                     PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     NFSClient *client = bs->opaque;
26ba25
     int ret;
26ba25
@@ -873,7 +874,7 @@ static BlockDriver bdrv_nfs = {
26ba25
 
26ba25
     .bdrv_has_zero_init             = nfs_has_zero_init,
26ba25
     .bdrv_get_allocated_file_size   = nfs_get_allocated_file_size,
26ba25
-    .bdrv_truncate                  = nfs_file_truncate,
26ba25
+    .bdrv_co_truncate               = nfs_file_co_truncate,
26ba25
 
26ba25
     .bdrv_file_open                 = nfs_file_open,
26ba25
     .bdrv_close                     = nfs_file_close,
26ba25
diff --git a/block/qcow2.c b/block/qcow2.c
26ba25
index dbd448c..c5c6ae9 100644
26ba25
--- a/block/qcow2.c
26ba25
+++ b/block/qcow2.c
26ba25
@@ -2539,15 +2539,12 @@ static void coroutine_fn preallocate_co(void *opaque)
26ba25
     BlockDriverState *bs = params->bs;
26ba25
     uint64_t offset = params->offset;
26ba25
     uint64_t new_length = params->new_length;
26ba25
-    BDRVQcow2State *s = bs->opaque;
26ba25
     uint64_t bytes;
26ba25
     uint64_t host_offset = 0;
26ba25
     unsigned int cur_bytes;
26ba25
     int ret;
26ba25
     QCowL2Meta *meta;
26ba25
 
26ba25
-    qemu_co_mutex_lock(&s->lock);
26ba25
-
26ba25
     assert(offset <= new_length);
26ba25
     bytes = new_length - offset;
26ba25
 
26ba25
@@ -2600,7 +2597,6 @@ static void coroutine_fn preallocate_co(void *opaque)
26ba25
     ret = 0;
26ba25
 
26ba25
 done:
26ba25
-    qemu_co_mutex_unlock(&s->lock);
26ba25
     params->ret = ret;
26ba25
 }
26ba25
 
26ba25
@@ -3037,7 +3033,11 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
26ba25
 
26ba25
     /* And if we're supposed to preallocate metadata, do that now */
26ba25
     if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) {
26ba25
+        BDRVQcow2State *s = blk_bs(blk)->opaque;
26ba25
+        qemu_co_mutex_lock(&s->lock);
26ba25
         ret = preallocate(blk_bs(blk), 0, qcow2_opts->size);
26ba25
+        qemu_co_mutex_unlock(&s->lock);
26ba25
+
26ba25
         if (ret < 0) {
26ba25
             error_setg_errno(errp, -ret, "Could not preallocate metadata");
26ba25
             goto out;
26ba25
@@ -3434,8 +3434,8 @@ fail:
26ba25
     return ret;
26ba25
 }
26ba25
 
26ba25
-static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                          PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                                          PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     BDRVQcow2State *s = bs->opaque;
26ba25
     uint64_t old_length;
26ba25
@@ -3455,17 +3455,21 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
         return -EINVAL;
26ba25
     }
26ba25
 
26ba25
+    qemu_co_mutex_lock(&s->lock);
26ba25
+
26ba25
     /* cannot proceed if image has snapshots */
26ba25
     if (s->nb_snapshots) {
26ba25
         error_setg(errp, "Can't resize an image which has snapshots");
26ba25
-        return -ENOTSUP;
26ba25
+        ret = -ENOTSUP;
26ba25
+        goto fail;
26ba25
     }
26ba25
 
26ba25
     /* cannot proceed if image has bitmaps */
26ba25
     if (s->nb_bitmaps) {
26ba25
         /* TODO: resize bitmaps in the image */
26ba25
         error_setg(errp, "Can't resize an image which has bitmaps");
26ba25
-        return -ENOTSUP;
26ba25
+        ret = -ENOTSUP;
26ba25
+        goto fail;
26ba25
     }
26ba25
 
26ba25
     old_length = bs->total_sectors * 512;
26ba25
@@ -3476,7 +3480,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
         if (prealloc != PREALLOC_MODE_OFF) {
26ba25
             error_setg(errp,
26ba25
                        "Preallocation can't be used for shrinking an image");
26ba25
-            return -EINVAL;
26ba25
+            ret = -EINVAL;
26ba25
+            goto fail;
26ba25
         }
26ba25
 
26ba25
         ret = qcow2_cluster_discard(bs, ROUND_UP(offset, s->cluster_size),
26ba25
@@ -3485,40 +3490,42 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
                                     QCOW2_DISCARD_ALWAYS, true);
26ba25
         if (ret < 0) {
26ba25
             error_setg_errno(errp, -ret, "Failed to discard cropped clusters");
26ba25
-            return ret;
26ba25
+            goto fail;
26ba25
         }
26ba25
 
26ba25
         ret = qcow2_shrink_l1_table(bs, new_l1_size);
26ba25
         if (ret < 0) {
26ba25
             error_setg_errno(errp, -ret,
26ba25
                              "Failed to reduce the number of L2 tables");
26ba25
-            return ret;
26ba25
+            goto fail;
26ba25
         }
26ba25
 
26ba25
         ret = qcow2_shrink_reftable(bs);
26ba25
         if (ret < 0) {
26ba25
             error_setg_errno(errp, -ret,
26ba25
                              "Failed to discard unused refblocks");
26ba25
-            return ret;
26ba25
+            goto fail;
26ba25
         }
26ba25
 
26ba25
         old_file_size = bdrv_getlength(bs->file->bs);
26ba25
         if (old_file_size < 0) {
26ba25
             error_setg_errno(errp, -old_file_size,
26ba25
                              "Failed to inquire current file length");
26ba25
-            return old_file_size;
26ba25
+            ret = old_file_size;
26ba25
+            goto fail;
26ba25
         }
26ba25
         last_cluster = qcow2_get_last_cluster(bs, old_file_size);
26ba25
         if (last_cluster < 0) {
26ba25
             error_setg_errno(errp, -last_cluster,
26ba25
                              "Failed to find the last cluster");
26ba25
-            return last_cluster;
26ba25
+            ret = last_cluster;
26ba25
+            goto fail;
26ba25
         }
26ba25
         if ((last_cluster + 1) * s->cluster_size < old_file_size) {
26ba25
             Error *local_err = NULL;
26ba25
 
26ba25
-            bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
26ba25
-                          PREALLOC_MODE_OFF, &local_err);
26ba25
+            bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
26ba25
+                             PREALLOC_MODE_OFF, &local_err);
26ba25
             if (local_err) {
26ba25
                 warn_reportf_err(local_err,
26ba25
                                  "Failed to truncate the tail of the image: ");
26ba25
@@ -3528,7 +3535,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
         ret = qcow2_grow_l1_table(bs, new_l1_size, true);
26ba25
         if (ret < 0) {
26ba25
             error_setg_errno(errp, -ret, "Failed to grow the L1 table");
26ba25
-            return ret;
26ba25
+            goto fail;
26ba25
         }
26ba25
     }
26ba25
 
26ba25
@@ -3540,7 +3547,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
         ret = preallocate(bs, old_length, offset);
26ba25
         if (ret < 0) {
26ba25
             error_setg_errno(errp, -ret, "Preallocation failed");
26ba25
-            return ret;
26ba25
+            goto fail;
26ba25
         }
26ba25
         break;
26ba25
 
26ba25
@@ -3556,7 +3563,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
         if (old_file_size < 0) {
26ba25
             error_setg_errno(errp, -old_file_size,
26ba25
                              "Failed to inquire current file length");
26ba25
-            return old_file_size;
26ba25
+            ret = old_file_size;
26ba25
+            goto fail;
26ba25
         }
26ba25
         old_file_size = ROUND_UP(old_file_size, s->cluster_size);
26ba25
 
26ba25
@@ -3586,7 +3594,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
         if (allocation_start < 0) {
26ba25
             error_setg_errno(errp, -allocation_start,
26ba25
                              "Failed to resize refcount structures");
26ba25
-            return allocation_start;
26ba25
+            ret = allocation_start;
26ba25
+            goto fail;
26ba25
         }
26ba25
 
26ba25
         clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start,
26ba25
@@ -3594,7 +3603,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
         if (clusters_allocated < 0) {
26ba25
             error_setg_errno(errp, -clusters_allocated,
26ba25
                              "Failed to allocate data clusters");
26ba25
-            return clusters_allocated;
26ba25
+            ret = clusters_allocated;
26ba25
+            goto fail;
26ba25
         }
26ba25
 
26ba25
         assert(clusters_allocated == nb_new_data_clusters);
26ba25
@@ -3602,13 +3612,13 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
         /* Allocate the data area */
26ba25
         new_file_size = allocation_start +
26ba25
                         nb_new_data_clusters * s->cluster_size;
26ba25
-        ret = bdrv_truncate(bs->file, new_file_size, prealloc, errp);
26ba25
+        ret = bdrv_co_truncate(bs->file, new_file_size, prealloc, errp);
26ba25
         if (ret < 0) {
26ba25
             error_prepend(errp, "Failed to resize underlying file: ");
26ba25
             qcow2_free_clusters(bs, allocation_start,
26ba25
                                 nb_new_data_clusters * s->cluster_size,
26ba25
                                 QCOW2_DISCARD_OTHER);
26ba25
-            return ret;
26ba25
+            goto fail;
26ba25
         }
26ba25
 
26ba25
         /* Create the necessary L2 entries */
26ba25
@@ -3631,7 +3641,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
                 qcow2_free_clusters(bs, host_offset,
26ba25
                                     nb_new_data_clusters * s->cluster_size,
26ba25
                                     QCOW2_DISCARD_OTHER);
26ba25
-                return ret;
26ba25
+                goto fail;
26ba25
             }
26ba25
 
26ba25
             guest_offset += nb_clusters * s->cluster_size;
26ba25
@@ -3647,11 +3657,11 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
 
26ba25
     if (prealloc != PREALLOC_MODE_OFF) {
26ba25
         /* Flush metadata before actually changing the image size */
26ba25
-        ret = bdrv_flush(bs);
26ba25
+        ret = qcow2_write_caches(bs);
26ba25
         if (ret < 0) {
26ba25
             error_setg_errno(errp, -ret,
26ba25
                              "Failed to flush the preallocated area to disk");
26ba25
-            return ret;
26ba25
+            goto fail;
26ba25
         }
26ba25
     }
26ba25
 
26ba25
@@ -3661,11 +3671,14 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
26ba25
                            &offset, sizeof(uint64_t));
26ba25
     if (ret < 0) {
26ba25
         error_setg_errno(errp, -ret, "Failed to update the image size");
26ba25
-        return ret;
26ba25
+        goto fail;
26ba25
     }
26ba25
 
26ba25
     s->l1_vm_state_index = new_l1_size;
26ba25
-    return 0;
26ba25
+    ret = 0;
26ba25
+fail:
26ba25
+    qemu_co_mutex_unlock(&s->lock);
26ba25
+    return ret;
26ba25
 }
26ba25
 
26ba25
 /* XXX: put compressed sectors first, then all the cluster aligned
26ba25
@@ -3689,7 +3702,8 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
26ba25
         if (cluster_offset < 0) {
26ba25
             return cluster_offset;
26ba25
         }
26ba25
-        return bdrv_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF, NULL);
26ba25
+        return bdrv_co_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF,
26ba25
+                                NULL);
26ba25
     }
26ba25
 
26ba25
     if (offset_into_cluster(s, offset)) {
26ba25
@@ -4694,7 +4708,7 @@ BlockDriver bdrv_qcow2 = {
26ba25
     .bdrv_co_pdiscard       = qcow2_co_pdiscard,
26ba25
     .bdrv_co_copy_range_from = qcow2_co_copy_range_from,
26ba25
     .bdrv_co_copy_range_to  = qcow2_co_copy_range_to,
26ba25
-    .bdrv_truncate          = qcow2_truncate,
26ba25
+    .bdrv_co_truncate       = qcow2_co_truncate,
26ba25
     .bdrv_co_pwritev_compressed = qcow2_co_pwritev_compressed,
26ba25
     .bdrv_make_empty        = qcow2_make_empty,
26ba25
 
26ba25
diff --git a/block/qed.c b/block/qed.c
26ba25
index 4c5d7e8..34cccea 100644
26ba25
--- a/block/qed.c
26ba25
+++ b/block/qed.c
26ba25
@@ -1466,8 +1466,10 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
26ba25
                           QED_AIOCB_WRITE | QED_AIOCB_ZERO);
26ba25
 }
26ba25
 
26ba25
-static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                             PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
26ba25
+                                             int64_t offset,
26ba25
+                                             PreallocMode prealloc,
26ba25
+                                             Error **errp)
26ba25
 {
26ba25
     BDRVQEDState *s = bs->opaque;
26ba25
     uint64_t old_image_size;
26ba25
@@ -1677,7 +1679,7 @@ static BlockDriver bdrv_qed = {
26ba25
     .bdrv_co_readv            = bdrv_qed_co_readv,
26ba25
     .bdrv_co_writev           = bdrv_qed_co_writev,
26ba25
     .bdrv_co_pwrite_zeroes    = bdrv_qed_co_pwrite_zeroes,
26ba25
-    .bdrv_truncate            = bdrv_qed_truncate,
26ba25
+    .bdrv_co_truncate         = bdrv_qed_co_truncate,
26ba25
     .bdrv_getlength           = bdrv_qed_getlength,
26ba25
     .bdrv_get_info            = bdrv_qed_get_info,
26ba25
     .bdrv_refresh_limits      = bdrv_qed_refresh_limits,
26ba25
diff --git a/block/raw-format.c b/block/raw-format.c
26ba25
index f2e468d..b78da56 100644
26ba25
--- a/block/raw-format.c
26ba25
+++ b/block/raw-format.c
26ba25
@@ -366,8 +366,8 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
26ba25
     }
26ba25
 }
26ba25
 
26ba25
-static int raw_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                        PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                                        PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     BDRVRawState *s = bs->opaque;
26ba25
 
26ba25
@@ -383,7 +383,7 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset,
26ba25
 
26ba25
     s->size = offset;
26ba25
     offset += s->offset;
26ba25
-    return bdrv_truncate(bs->file, offset, prealloc, errp);
26ba25
+    return bdrv_co_truncate(bs->file, offset, prealloc, errp);
26ba25
 }
26ba25
 
26ba25
 static void raw_eject(BlockDriverState *bs, bool eject_flag)
26ba25
@@ -545,7 +545,7 @@ BlockDriver bdrv_raw = {
26ba25
     .bdrv_co_block_status = &raw_co_block_status,
26ba25
     .bdrv_co_copy_range_from = &raw_co_copy_range_from,
26ba25
     .bdrv_co_copy_range_to  = &raw_co_copy_range_to,
26ba25
-    .bdrv_truncate        = &raw_truncate,
26ba25
+    .bdrv_co_truncate     = &raw_co_truncate,
26ba25
     .bdrv_getlength       = &raw_getlength,
26ba25
     .has_variable_length  = true,
26ba25
     .bdrv_measure         = &raw_measure,
26ba25
diff --git a/block/rbd.c b/block/rbd.c
26ba25
index 3242bcd..b93046b 100644
26ba25
--- a/block/rbd.c
26ba25
+++ b/block/rbd.c
26ba25
@@ -987,8 +987,10 @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs)
26ba25
     return info.size;
26ba25
 }
26ba25
 
26ba25
-static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                             PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
26ba25
+                                             int64_t offset,
26ba25
+                                             PreallocMode prealloc,
26ba25
+                                             Error **errp)
26ba25
 {
26ba25
     BDRVRBDState *s = bs->opaque;
26ba25
     int r;
26ba25
@@ -1180,7 +1182,7 @@ static BlockDriver bdrv_rbd = {
26ba25
     .bdrv_get_info          = qemu_rbd_getinfo,
26ba25
     .create_opts            = &qemu_rbd_create_opts,
26ba25
     .bdrv_getlength         = qemu_rbd_getlength,
26ba25
-    .bdrv_truncate          = qemu_rbd_truncate,
26ba25
+    .bdrv_co_truncate       = qemu_rbd_co_truncate,
26ba25
     .protocol_name          = "rbd",
26ba25
 
26ba25
     .bdrv_aio_readv         = qemu_rbd_aio_readv,
26ba25
diff --git a/block/sheepdog.c b/block/sheepdog.c
26ba25
index 933880c..14165d3 100644
26ba25
--- a/block/sheepdog.c
26ba25
+++ b/block/sheepdog.c
26ba25
@@ -2294,8 +2294,8 @@ static int64_t sd_getlength(BlockDriverState *bs)
26ba25
     return s->inode.vdi_size;
26ba25
 }
26ba25
 
26ba25
-static int sd_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                       PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                                       PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     BDRVSheepdogState *s = bs->opaque;
26ba25
     int ret, fd;
26ba25
@@ -2609,7 +2609,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
26ba25
     BDRVSheepdogState *s = bs->opaque;
26ba25
 
26ba25
     if (offset > s->inode.vdi_size) {
26ba25
-        ret = sd_truncate(bs, offset, PREALLOC_MODE_OFF, NULL);
26ba25
+        ret = sd_co_truncate(bs, offset, PREALLOC_MODE_OFF, NULL);
26ba25
         if (ret < 0) {
26ba25
             return ret;
26ba25
         }
26ba25
@@ -3229,7 +3229,7 @@ static BlockDriver bdrv_sheepdog = {
26ba25
     .bdrv_has_zero_init           = bdrv_has_zero_init_1,
26ba25
     .bdrv_getlength               = sd_getlength,
26ba25
     .bdrv_get_allocated_file_size = sd_get_allocated_file_size,
26ba25
-    .bdrv_truncate                = sd_truncate,
26ba25
+    .bdrv_co_truncate             = sd_co_truncate,
26ba25
 
26ba25
     .bdrv_co_readv                = sd_co_readv,
26ba25
     .bdrv_co_writev               = sd_co_writev,
26ba25
@@ -3266,7 +3266,7 @@ static BlockDriver bdrv_sheepdog_tcp = {
26ba25
     .bdrv_has_zero_init           = bdrv_has_zero_init_1,
26ba25
     .bdrv_getlength               = sd_getlength,
26ba25
     .bdrv_get_allocated_file_size = sd_get_allocated_file_size,
26ba25
-    .bdrv_truncate                = sd_truncate,
26ba25
+    .bdrv_co_truncate             = sd_co_truncate,
26ba25
 
26ba25
     .bdrv_co_readv                = sd_co_readv,
26ba25
     .bdrv_co_writev               = sd_co_writev,
26ba25
@@ -3303,7 +3303,7 @@ static BlockDriver bdrv_sheepdog_unix = {
26ba25
     .bdrv_has_zero_init           = bdrv_has_zero_init_1,
26ba25
     .bdrv_getlength               = sd_getlength,
26ba25
     .bdrv_get_allocated_file_size = sd_get_allocated_file_size,
26ba25
-    .bdrv_truncate                = sd_truncate,
26ba25
+    .bdrv_co_truncate             = sd_co_truncate,
26ba25
 
26ba25
     .bdrv_co_readv                = sd_co_readv,
26ba25
     .bdrv_co_writev               = sd_co_writev,
26ba25
diff --git a/block/ssh.c b/block/ssh.c
26ba25
index aab6996..6a55d82 100644
26ba25
--- a/block/ssh.c
26ba25
+++ b/block/ssh.c
26ba25
@@ -1241,8 +1241,8 @@ static int64_t ssh_getlength(BlockDriverState *bs)
26ba25
     return length;
26ba25
 }
26ba25
 
26ba25
-static int ssh_truncate(BlockDriverState *bs, int64_t offset,
26ba25
-                        PreallocMode prealloc, Error **errp)
26ba25
+static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
26ba25
+                                        PreallocMode prealloc, Error **errp)
26ba25
 {
26ba25
     BDRVSSHState *s = bs->opaque;
26ba25
 
26ba25
@@ -1277,7 +1277,7 @@ static BlockDriver bdrv_ssh = {
26ba25
     .bdrv_co_readv                = ssh_co_readv,
26ba25
     .bdrv_co_writev               = ssh_co_writev,
26ba25
     .bdrv_getlength               = ssh_getlength,
26ba25
-    .bdrv_truncate                = ssh_truncate,
26ba25
+    .bdrv_co_truncate             = ssh_co_truncate,
26ba25
     .bdrv_co_flush_to_disk        = ssh_co_flush,
26ba25
     .create_opts                  = &ssh_create_opts,
26ba25
 };
26ba25
diff --git a/include/block/block.h b/include/block/block.h
26ba25
index e677080..c3cfb40 100644
26ba25
--- a/include/block/block.h
26ba25
+++ b/include/block/block.h
26ba25
@@ -300,8 +300,12 @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
26ba25
 BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
26ba25
     const char *backing_file);
26ba25
 void bdrv_refresh_filename(BlockDriverState *bs);
26ba25
+
26ba25
+int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
26ba25
+                                  PreallocMode prealloc, Error **errp);
26ba25
 int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
26ba25
                   Error **errp);
26ba25
+
26ba25
 int64_t bdrv_nb_sectors(BlockDriverState *bs);
26ba25
 int64_t bdrv_getlength(BlockDriverState *bs);
26ba25
 int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
26ba25
diff --git a/include/block/block_int.h b/include/block/block_int.h
26ba25
index 3da86a7..46b2f87 100644
26ba25
--- a/include/block/block_int.h
26ba25
+++ b/include/block/block_int.h
26ba25
@@ -291,8 +291,8 @@ struct BlockDriver {
26ba25
      * bdrv_parse_filename.
26ba25
      */
26ba25
     const char *protocol_name;
26ba25
-    int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset,
26ba25
-                         PreallocMode prealloc, Error **errp);
26ba25
+    int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
26ba25
+                                         PreallocMode prealloc, Error **errp);
26ba25
 
26ba25
     int64_t (*bdrv_getlength)(BlockDriverState *bs);
26ba25
     bool has_variable_length;
26ba25
-- 
26ba25
1.8.3.1
26ba25