From nobody Thu Dec 18 13:25:04 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1530282200865734.1547502705844; Fri, 29 Jun 2018 07:23:20 -0700 (PDT) Received: from localhost ([::1]:42521 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYuIx-0006Lr-Vo for importer@patchew.org; Fri, 29 Jun 2018 10:23:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49588) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYu6S-0003wA-Og for qemu-devel@nongnu.org; Fri, 29 Jun 2018 10:10:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYu6N-0003qK-Qe for qemu-devel@nongnu.org; Fri, 29 Jun 2018 10:10:24 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44844 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fYu6F-0003Zl-Jp; Fri, 29 Jun 2018 10:10:11 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4388FC12C9; Fri, 29 Jun 2018 14:10:11 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-232.ams2.redhat.com [10.36.116.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id 51B191102E29; Fri, 29 Jun 2018 14:10:10 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Fri, 29 Jun 2018 16:09:37 +0200 Message-Id: <20180629140959.6690-8-kwolf@redhat.com> In-Reply-To: <20180629140959.6690-1-kwolf@redhat.com> References: <20180629140959.6690-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 29 Jun 2018 14:10:11 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 29 Jun 2018 14:10:11 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 07/29] block: Convert .bdrv_truncate callback to coroutine_fn X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, peter.maydell@linaro.org, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Stefan Hajnoczi --- include/block/block.h | 4 +++ include/block/block_int.h | 4 +-- 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 ++-- 16 files changed, 162 insertions(+), 89 deletions(-) diff --git a/include/block/block.h b/include/block/block.h index b1d6fdb97a..42e59ff585 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -300,8 +300,12 @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *chil= d, 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 74646ed722..c653ee663a 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -289,8 +289,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 off= set, + PreallocMode prealloc, Error **er= rp); =20 int64_t (*bdrv_getlength)(BlockDriverState *bs); bool has_variable_length; diff --git a/block.c b/block.c index 1b8147c1b3..f761bc85d5 100644 --- a/block.c +++ b/block.c @@ -3788,8 +3788,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 =3D child->bs; BlockDriver *drv =3D bs->drv; @@ -3807,23 +3807,28 @@ int bdrv_truncate(BdrvChild *child, int64_t offset,= PreallocMode prealloc, return -EINVAL; } =20 - 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 =3D bdrv_co_truncate(bs->file, offset, prealloc, errp); + goto out; } error_setg(errp, "Image format driver does not support resize"); - return -ENOTSUP; + ret =3D -ENOTSUP; + goto out; } if (bs->read_only) { error_setg(errp, "Image is read-only"); - return -EACCES; + ret =3D -EACCES; + goto out; } =20 assert(!(bs->open_flags & BDRV_O_INACTIVE)); =20 - ret =3D drv->bdrv_truncate(bs, offset, prealloc, errp); + ret =3D drv->bdrv_co_truncate(bs, offset, prealloc, errp); if (ret < 0) { - return ret; + goto out; } ret =3D refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); if (ret < 0) { @@ -3834,9 +3839,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; } =20 +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 =3D opaque; + tco->ret =3D 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 =3D { + .child =3D child, + .offset =3D offset, + .prealloc =3D prealloc, + .errp =3D errp, + .ret =3D NOT_DONE, + }; + + if (qemu_in_coroutine()) { + /* Fast-path if already in coroutine context */ + bdrv_truncate_co_entry(&tco); + } else { + co =3D qemu_coroutine_create(bdrv_truncate_co_entry, &tco); + qemu_coroutine_enter(co); + BDRV_POLL_WHILE(child->bs, tco.ret =3D=3D 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 6a97208888..1dcdaeed69 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -80,10 +80,10 @@ static int64_t cor_getlength(BlockDriverState *bs) } =20 =20 -static int cor_truncate(BlockDriverState *bs, int64_t offset, - PreallocMode prealloc, Error **errp) +static int coroutine_fn cor_co_truncate(BlockDriverState *bs, int64_t offs= et, + PreallocMode prealloc, Error **err= p) { - return bdrv_truncate(bs->file, offset, prealloc, errp); + return bdrv_co_truncate(bs->file, offset, prealloc, errp); } =20 =20 @@ -147,7 +147,7 @@ BlockDriver bdrv_copy_on_read =3D { .bdrv_child_perm =3D cor_child_perm, =20 .bdrv_getlength =3D cor_getlength, - .bdrv_truncate =3D cor_truncate, + .bdrv_co_truncate =3D cor_co_truncate, =20 .bdrv_co_preadv =3D cor_co_preadv, .bdrv_co_pwritev =3D cor_co_pwritev, diff --git a/block/crypto.c b/block/crypto.c index aaa8fb7530..210c80d5c7 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -357,8 +357,9 @@ static int block_crypto_co_create_generic(BlockDriverSt= ate *bs, return ret; } =20 -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 =3D bs->opaque; uint64_t payload_offset =3D @@ -371,7 +372,7 @@ static int block_crypto_truncate(BlockDriverState *bs, = int64_t offset, =20 offset +=3D payload_offset; =20 - return bdrv_truncate(bs->file, offset, prealloc, errp); + return bdrv_co_truncate(bs->file, offset, prealloc, errp); } =20 static void block_crypto_close(BlockDriverState *bs) @@ -700,7 +701,7 @@ BlockDriver bdrv_crypto_luks =3D { .bdrv_child_perm =3D bdrv_format_default_perms, .bdrv_co_create =3D block_crypto_co_create_luks, .bdrv_co_create_opts =3D block_crypto_co_create_opts_luks, - .bdrv_truncate =3D block_crypto_truncate, + .bdrv_co_truncate =3D block_crypto_co_truncate, .create_opts =3D &block_crypto_create_opts_luks, =20 .bdrv_reopen_prepare =3D block_crypto_reopen_prepare, diff --git a/block/file-posix.c b/block/file-posix.c index 43b963b13e..53c5833659 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1878,8 +1878,8 @@ out: return result; } =20 -static int raw_truncate(BlockDriverState *bs, int64_t offset, - PreallocMode prealloc, Error **errp) +static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offs= et, + PreallocMode prealloc, Error **err= p) { BDRVRawState *s =3D bs->opaque; struct stat st; @@ -2625,7 +2625,7 @@ BlockDriver bdrv_file =3D { .bdrv_io_unplug =3D raw_aio_unplug, .bdrv_attach_aio_context =3D raw_aio_attach_aio_context, =20 - .bdrv_truncate =3D raw_truncate, + .bdrv_co_truncate =3D raw_co_truncate, .bdrv_getlength =3D raw_getlength, .bdrv_get_info =3D raw_get_info, .bdrv_get_allocated_file_size @@ -3105,7 +3105,7 @@ static BlockDriver bdrv_host_device =3D { .bdrv_io_plug =3D raw_aio_plug, .bdrv_io_unplug =3D raw_aio_unplug, =20 - .bdrv_truncate =3D raw_truncate, + .bdrv_co_truncate =3D raw_co_truncate, .bdrv_getlength =3D raw_getlength, .bdrv_get_info =3D raw_get_info, .bdrv_get_allocated_file_size @@ -3227,7 +3227,7 @@ static BlockDriver bdrv_host_cdrom =3D { .bdrv_io_plug =3D raw_aio_plug, .bdrv_io_unplug =3D raw_aio_unplug, =20 - .bdrv_truncate =3D raw_truncate, + .bdrv_co_truncate =3D raw_co_truncate, .bdrv_getlength =3D raw_getlength, .has_variable_length =3D true, .bdrv_get_allocated_file_size @@ -3357,7 +3357,7 @@ static BlockDriver bdrv_host_cdrom =3D { .bdrv_io_plug =3D raw_aio_plug, .bdrv_io_unplug =3D raw_aio_unplug, =20 - .bdrv_truncate =3D raw_truncate, + .bdrv_co_truncate =3D raw_co_truncate, .bdrv_getlength =3D raw_getlength, .has_variable_length =3D true, .bdrv_get_allocated_file_size diff --git a/block/file-win32.c b/block/file-win32.c index 3c67db4336..0411fe80fd 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -467,8 +467,8 @@ static void raw_close(BlockDriverState *bs) } } =20 -static int raw_truncate(BlockDriverState *bs, int64_t offset, - PreallocMode prealloc, Error **errp) +static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offs= et, + PreallocMode prealloc, Error **err= p) { BDRVRawState *s =3D bs->opaque; LONG low, high; @@ -640,7 +640,7 @@ BlockDriver bdrv_file =3D { .bdrv_aio_pwritev =3D raw_aio_pwritev, .bdrv_aio_flush =3D raw_aio_flush, =20 - .bdrv_truncate =3D raw_truncate, + .bdrv_co_truncate =3D raw_co_truncate, .bdrv_getlength =3D raw_getlength, .bdrv_get_allocated_file_size =3D raw_get_allocated_file_size, diff --git a/block/gluster.c b/block/gluster.c index b5fe7f3e87..a4e1c8ecd8 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1177,8 +1177,10 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriv= erState *bs, return acb.ret; } =20 -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 =3D bs->opaque; return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp); @@ -1499,7 +1501,7 @@ static BlockDriver bdrv_gluster =3D { .bdrv_co_create_opts =3D qemu_gluster_co_create_opts, .bdrv_getlength =3D qemu_gluster_getlength, .bdrv_get_allocated_file_size =3D qemu_gluster_allocated_file_size, - .bdrv_truncate =3D qemu_gluster_truncate, + .bdrv_co_truncate =3D qemu_gluster_co_truncate, .bdrv_co_readv =3D qemu_gluster_co_readv, .bdrv_co_writev =3D qemu_gluster_co_writev, .bdrv_co_flush_to_disk =3D qemu_gluster_co_flush_to_disk, @@ -1528,7 +1530,7 @@ static BlockDriver bdrv_gluster_tcp =3D { .bdrv_co_create_opts =3D qemu_gluster_co_create_opts, .bdrv_getlength =3D qemu_gluster_getlength, .bdrv_get_allocated_file_size =3D qemu_gluster_allocated_file_size, - .bdrv_truncate =3D qemu_gluster_truncate, + .bdrv_co_truncate =3D qemu_gluster_co_truncate, .bdrv_co_readv =3D qemu_gluster_co_readv, .bdrv_co_writev =3D qemu_gluster_co_writev, .bdrv_co_flush_to_disk =3D qemu_gluster_co_flush_to_disk, @@ -1557,7 +1559,7 @@ static BlockDriver bdrv_gluster_unix =3D { .bdrv_co_create_opts =3D qemu_gluster_co_create_opts, .bdrv_getlength =3D qemu_gluster_getlength, .bdrv_get_allocated_file_size =3D qemu_gluster_allocated_file_size, - .bdrv_truncate =3D qemu_gluster_truncate, + .bdrv_co_truncate =3D qemu_gluster_co_truncate, .bdrv_co_readv =3D qemu_gluster_co_readv, .bdrv_co_writev =3D qemu_gluster_co_writev, .bdrv_co_flush_to_disk =3D qemu_gluster_co_flush_to_disk, @@ -1592,7 +1594,7 @@ static BlockDriver bdrv_gluster_rdma =3D { .bdrv_co_create_opts =3D qemu_gluster_co_create_opts, .bdrv_getlength =3D qemu_gluster_getlength, .bdrv_get_allocated_file_size =3D qemu_gluster_allocated_file_size, - .bdrv_truncate =3D qemu_gluster_truncate, + .bdrv_co_truncate =3D qemu_gluster_co_truncate, .bdrv_co_readv =3D qemu_gluster_co_readv, .bdrv_co_writev =3D qemu_gluster_co_writev, .bdrv_co_flush_to_disk =3D qemu_gluster_co_flush_to_disk, diff --git a/block/iscsi.c b/block/iscsi.c index 9f00fb47a5..bc84b14e20 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2085,8 +2085,8 @@ static void iscsi_reopen_commit(BDRVReopenState *reop= en_state) } } =20 -static int iscsi_truncate(BlockDriverState *bs, int64_t offset, - PreallocMode prealloc, Error **errp) +static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t of= fset, + PreallocMode prealloc, Error **e= rrp) { IscsiLun *iscsilun =3D bs->opaque; Error *local_err =3D NULL; @@ -2431,7 +2431,7 @@ static BlockDriver bdrv_iscsi =3D { =20 .bdrv_getlength =3D iscsi_getlength, .bdrv_get_info =3D iscsi_get_info, - .bdrv_truncate =3D iscsi_truncate, + .bdrv_co_truncate =3D iscsi_co_truncate, .bdrv_refresh_limits =3D iscsi_refresh_limits, =20 .bdrv_co_block_status =3D iscsi_co_block_status, @@ -2468,7 +2468,7 @@ static BlockDriver bdrv_iser =3D { =20 .bdrv_getlength =3D iscsi_getlength, .bdrv_get_info =3D iscsi_get_info, - .bdrv_truncate =3D iscsi_truncate, + .bdrv_co_truncate =3D iscsi_co_truncate, .bdrv_refresh_limits =3D iscsi_refresh_limits, =20 .bdrv_co_block_status =3D iscsi_co_block_status, diff --git a/block/nfs.c b/block/nfs.c index 743ca0450e..eab1a2c408 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -743,8 +743,9 @@ static int64_t nfs_get_allocated_file_size(BlockDriverS= tate *bs) return (task.ret < 0 ? task.ret : st.st_blocks * 512); } =20 -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 =3D bs->opaque; int ret; @@ -873,7 +874,7 @@ static BlockDriver bdrv_nfs =3D { =20 .bdrv_has_zero_init =3D nfs_has_zero_init, .bdrv_get_allocated_file_size =3D nfs_get_allocated_file_size, - .bdrv_truncate =3D nfs_file_truncate, + .bdrv_co_truncate =3D nfs_file_co_truncate, =20 .bdrv_file_open =3D nfs_file_open, .bdrv_close =3D nfs_file_close, diff --git a/block/qcow2.c b/block/qcow2.c index 6b2e1e1058..9e0ccbbfaf 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2543,15 +2543,12 @@ static void coroutine_fn preallocate_co(void *opaqu= e) BlockDriverState *bs =3D params->bs; uint64_t offset =3D params->offset; uint64_t new_length =3D params->new_length; - BDRVQcow2State *s =3D bs->opaque; uint64_t bytes; uint64_t host_offset =3D 0; unsigned int cur_bytes; int ret; QCowL2Meta *meta; =20 - qemu_co_mutex_lock(&s->lock); - assert(offset <=3D new_length); bytes =3D new_length - offset; =20 @@ -2604,7 +2601,6 @@ static void coroutine_fn preallocate_co(void *opaque) ret =3D 0; =20 done: - qemu_co_mutex_unlock(&s->lock); params->ret =3D ret; } =20 @@ -3041,7 +3037,11 @@ qcow2_co_create(BlockdevCreateOptions *create_option= s, Error **errp) =20 /* And if we're supposed to preallocate metadata, do that now */ if (qcow2_opts->preallocation !=3D PREALLOC_MODE_OFF) { + BDRVQcow2State *s =3D blk_bs(blk)->opaque; + qemu_co_mutex_lock(&s->lock); ret =3D 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; @@ -3437,8 +3437,8 @@ fail: return ret; } =20 -static int qcow2_truncate(BlockDriverState *bs, int64_t offset, - PreallocMode prealloc, Error **errp) +static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t of= fset, + PreallocMode prealloc, Error **e= rrp) { BDRVQcow2State *s =3D bs->opaque; uint64_t old_length; @@ -3458,17 +3458,21 @@ static int qcow2_truncate(BlockDriverState *bs, int= 64_t offset, return -EINVAL; } =20 + 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 =3D -ENOTSUP; + goto fail; } =20 /* 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 =3D -ENOTSUP; + goto fail; } =20 old_length =3D bs->total_sectors * 512; @@ -3479,7 +3483,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64= _t offset, if (prealloc !=3D PREALLOC_MODE_OFF) { error_setg(errp, "Preallocation can't be used for shrinking an image= "); - return -EINVAL; + ret =3D -EINVAL; + goto fail; } =20 ret =3D qcow2_cluster_discard(bs, ROUND_UP(offset, s->cluster_size= ), @@ -3488,40 +3493,42 @@ static int qcow2_truncate(BlockDriverState *bs, int= 64_t offset, QCOW2_DISCARD_ALWAYS, true); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to discard cropped cluste= rs"); - return ret; + goto fail; } =20 ret =3D 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; } =20 ret =3D qcow2_shrink_reftable(bs); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to discard unused refblocks"); - return ret; + goto fail; } =20 old_file_size =3D 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 =3D old_file_size; + goto fail; } last_cluster =3D 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 =3D last_cluster; + goto fail; } if ((last_cluster + 1) * s->cluster_size < old_file_size) { Error *local_err =3D NULL; =20 - 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_siz= e, + PREALLOC_MODE_OFF, &local_err); if (local_err) { warn_reportf_err(local_err, "Failed to truncate the tail of the image= : "); @@ -3531,7 +3538,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64= _t offset, ret =3D 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; } } =20 @@ -3543,7 +3550,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64= _t offset, ret =3D preallocate(bs, old_length, offset); if (ret < 0) { error_setg_errno(errp, -ret, "Preallocation failed"); - return ret; + goto fail; } break; =20 @@ -3559,7 +3566,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 =3D old_file_size; + goto fail; } old_file_size =3D ROUND_UP(old_file_size, s->cluster_size); =20 @@ -3589,7 +3597,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 =3D allocation_start; + goto fail; } =20 clusters_allocated =3D qcow2_alloc_clusters_at(bs, allocation_star= t, @@ -3597,7 +3606,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 =3D clusters_allocated; + goto fail; } =20 assert(clusters_allocated =3D=3D nb_new_data_clusters); @@ -3605,13 +3615,13 @@ static int qcow2_truncate(BlockDriverState *bs, int= 64_t offset, /* Allocate the data area */ new_file_size =3D allocation_start + nb_new_data_clusters * s->cluster_size; - ret =3D bdrv_truncate(bs->file, new_file_size, prealloc, errp); + ret =3D 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; } =20 /* Create the necessary L2 entries */ @@ -3634,7 +3644,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; } =20 guest_offset +=3D nb_clusters * s->cluster_size; @@ -3650,11 +3660,11 @@ static int qcow2_truncate(BlockDriverState *bs, int= 64_t offset, =20 if (prealloc !=3D PREALLOC_MODE_OFF) { /* Flush metadata before actually changing the image size */ - ret =3D bdrv_flush(bs); + ret =3D qcow2_write_caches(bs); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to flush the preallocated area to dis= k"); - return ret; + goto fail; } } =20 @@ -3664,11 +3674,14 @@ static int qcow2_truncate(BlockDriverState *bs, int= 64_t offset, &offset, sizeof(uint64_t)); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to update the image size"); - return ret; + goto fail; } =20 s->l1_vm_state_index =3D new_l1_size; - return 0; + ret =3D 0; +fail: + qemu_co_mutex_unlock(&s->lock); + return ret; } =20 /* XXX: put compressed sectors first, then all the cluster aligned @@ -3692,7 +3705,8 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uin= t64_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_OF= F, + NULL); } =20 if (offset_into_cluster(s, offset)) { @@ -4696,7 +4710,7 @@ BlockDriver bdrv_qcow2 =3D { .bdrv_co_pdiscard =3D qcow2_co_pdiscard, .bdrv_co_copy_range_from =3D qcow2_co_copy_range_from, .bdrv_co_copy_range_to =3D qcow2_co_copy_range_to, - .bdrv_truncate =3D qcow2_truncate, + .bdrv_co_truncate =3D qcow2_co_truncate, .bdrv_co_pwritev_compressed =3D qcow2_co_pwritev_compressed, .bdrv_make_empty =3D qcow2_make_empty, =20 diff --git a/block/qed.c b/block/qed.c index 2363814538..689ea9d4d5 100644 --- a/block/qed.c +++ b/block/qed.c @@ -1467,8 +1467,10 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(Bl= ockDriverState *bs, QED_AIOCB_WRITE | QED_AIOCB_ZERO); } =20 -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 =3D bs->opaque; uint64_t old_image_size; @@ -1678,7 +1680,7 @@ static BlockDriver bdrv_qed =3D { .bdrv_co_readv =3D bdrv_qed_co_readv, .bdrv_co_writev =3D bdrv_qed_co_writev, .bdrv_co_pwrite_zeroes =3D bdrv_qed_co_pwrite_zeroes, - .bdrv_truncate =3D bdrv_qed_truncate, + .bdrv_co_truncate =3D bdrv_qed_co_truncate, .bdrv_getlength =3D bdrv_qed_getlength, .bdrv_get_info =3D bdrv_qed_get_info, .bdrv_refresh_limits =3D bdrv_qed_refresh_limits, diff --git a/block/raw-format.c b/block/raw-format.c index f2e468df6f..b78da564d4 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -366,8 +366,8 @@ static void raw_refresh_limits(BlockDriverState *bs, Er= ror **errp) } } =20 -static int raw_truncate(BlockDriverState *bs, int64_t offset, - PreallocMode prealloc, Error **errp) +static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offs= et, + PreallocMode prealloc, Error **err= p) { BDRVRawState *s =3D bs->opaque; =20 @@ -383,7 +383,7 @@ static int raw_truncate(BlockDriverState *bs, int64_t o= ffset, =20 s->size =3D offset; offset +=3D s->offset; - return bdrv_truncate(bs->file, offset, prealloc, errp); + return bdrv_co_truncate(bs->file, offset, prealloc, errp); } =20 static void raw_eject(BlockDriverState *bs, bool eject_flag) @@ -545,7 +545,7 @@ BlockDriver bdrv_raw =3D { .bdrv_co_block_status =3D &raw_co_block_status, .bdrv_co_copy_range_from =3D &raw_co_copy_range_from, .bdrv_co_copy_range_to =3D &raw_co_copy_range_to, - .bdrv_truncate =3D &raw_truncate, + .bdrv_co_truncate =3D &raw_co_truncate, .bdrv_getlength =3D &raw_getlength, .has_variable_length =3D true, .bdrv_measure =3D &raw_measure, diff --git a/block/rbd.c b/block/rbd.c index f2c6965418..ca8e5bbace 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -990,8 +990,10 @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs) return info.size; } =20 -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 =3D bs->opaque; int r; @@ -1184,7 +1186,7 @@ static BlockDriver bdrv_rbd =3D { .bdrv_get_info =3D qemu_rbd_getinfo, .create_opts =3D &qemu_rbd_create_opts, .bdrv_getlength =3D qemu_rbd_getlength, - .bdrv_truncate =3D qemu_rbd_truncate, + .bdrv_co_truncate =3D qemu_rbd_co_truncate, .protocol_name =3D "rbd", =20 .bdrv_aio_preadv =3D qemu_rbd_aio_preadv, diff --git a/block/sheepdog.c b/block/sheepdog.c index 665b1763eb..b229a664d9 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -2292,8 +2292,8 @@ static int64_t sd_getlength(BlockDriverState *bs) return s->inode.vdi_size; } =20 -static int sd_truncate(BlockDriverState *bs, int64_t offset, - PreallocMode prealloc, Error **errp) +static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offse= t, + PreallocMode prealloc, Error **errp) { BDRVSheepdogState *s =3D bs->opaque; int ret, fd; @@ -2609,7 +2609,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState= *bs, int64_t sector_num, =20 assert(!flags); if (offset > s->inode.vdi_size) { - ret =3D sd_truncate(bs, offset, PREALLOC_MODE_OFF, NULL); + ret =3D sd_co_truncate(bs, offset, PREALLOC_MODE_OFF, NULL); if (ret < 0) { return ret; } @@ -3231,7 +3231,7 @@ static BlockDriver bdrv_sheepdog =3D { .bdrv_has_zero_init =3D bdrv_has_zero_init_1, .bdrv_getlength =3D sd_getlength, .bdrv_get_allocated_file_size =3D sd_get_allocated_file_size, - .bdrv_truncate =3D sd_truncate, + .bdrv_co_truncate =3D sd_co_truncate, =20 .bdrv_co_readv =3D sd_co_readv, .bdrv_co_writev =3D sd_co_writev, @@ -3268,7 +3268,7 @@ static BlockDriver bdrv_sheepdog_tcp =3D { .bdrv_has_zero_init =3D bdrv_has_zero_init_1, .bdrv_getlength =3D sd_getlength, .bdrv_get_allocated_file_size =3D sd_get_allocated_file_size, - .bdrv_truncate =3D sd_truncate, + .bdrv_co_truncate =3D sd_co_truncate, =20 .bdrv_co_readv =3D sd_co_readv, .bdrv_co_writev =3D sd_co_writev, @@ -3305,7 +3305,7 @@ static BlockDriver bdrv_sheepdog_unix =3D { .bdrv_has_zero_init =3D bdrv_has_zero_init_1, .bdrv_getlength =3D sd_getlength, .bdrv_get_allocated_file_size =3D sd_get_allocated_file_size, - .bdrv_truncate =3D sd_truncate, + .bdrv_co_truncate =3D sd_co_truncate, =20 .bdrv_co_readv =3D sd_co_readv, .bdrv_co_writev =3D sd_co_writev, diff --git a/block/ssh.c b/block/ssh.c index da7bbf73e2..7fbc27abdf 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -1243,8 +1243,8 @@ static int64_t ssh_getlength(BlockDriverState *bs) return length; } =20 -static int ssh_truncate(BlockDriverState *bs, int64_t offset, - PreallocMode prealloc, Error **errp) +static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offs= et, + PreallocMode prealloc, Error **err= p) { BDRVSSHState *s =3D bs->opaque; =20 @@ -1279,7 +1279,7 @@ static BlockDriver bdrv_ssh =3D { .bdrv_co_readv =3D ssh_co_readv, .bdrv_co_writev =3D ssh_co_writev, .bdrv_getlength =3D ssh_getlength, - .bdrv_truncate =3D ssh_truncate, + .bdrv_co_truncate =3D ssh_co_truncate, .bdrv_co_flush_to_disk =3D ssh_co_flush, .create_opts =3D &ssh_create_opts, }; --=20 2.13.6