Commit 9a665b2b made bdrv_truncate() call bdrv_drain_all(), but this breaks QCOW images, as well other future image formats (such as VHDX) that may call bdrv_truncate(bs->file) from within a read/write operation. For example, QCOW will cause an assert, due to tracked_requests not being empty (since the read/write that called bdrv_truncate() is still in progress).
This modifies the check to only force the bdrv_drain_all() call if the BDS to be truncated is not growable, or if we are shrinking the BDS. Otherwise, if we are just growing the file, allow it to happen without forcing a call to bdrv_drain_all(). Signed-off-by: Jeff Cody <jc...@redhat.com> --- block.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index 124a9eb..dce844c 100644 --- a/block.c +++ b/block.c @@ -2450,8 +2450,14 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset) if (bdrv_in_use(bs)) return -EBUSY; - /* There better not be any in-flight IOs when we truncate the device. */ - bdrv_drain_all(); + /* Don't force a drain if we are just growing the file - otherwise, + * using bdrv_truncate() from within a block driver in a read/write + * operation will cause an assert, because bdrv_drain_all() will assert if + * a tracked_request is still in progress. */ + if (!bs->growable || offset < bdrv_getlength(bs)) { + /* There better not be any in-flight IOs when we truncate the device. */ + bdrv_drain_all(); + } ret = drv->bdrv_truncate(bs, offset); if (ret == 0) { -- 1.8.1.4