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