diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/io.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/block/io.c b/block/io.c index 5817bb9405..4c7a7ac7b1 100644 --- a/block/io.c +++ b/block/io.c @@ -1236,7 +1236,7 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, * modifying the image file. This is critical for zero-copy guest I/O * where anything might happen inside guest memory. */ - void *bounce_buffer; + void *bounce_buffer = NULL; BlockDriver *drv = bs->drv; int64_t cluster_offset; @@ -1271,14 +1271,6 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, trace_bdrv_co_do_copy_on_readv(bs, offset, bytes, cluster_offset, cluster_bytes); - bounce_buffer = qemu_try_blockalign(bs, - MIN(MIN(max_transfer, cluster_bytes), - MAX_BOUNCE_BUFFER)); - if (bounce_buffer == NULL) { - ret = -ENOMEM; - goto err; - } - while (cluster_bytes) { int64_t pnum; @@ -1305,6 +1297,17 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, /* Must copy-on-read; use the bounce buffer */ pnum = MIN(pnum, MAX_BOUNCE_BUFFER); + if (!bounce_buffer) { + int64_t max_we_need = MAX(pnum, cluster_bytes - pnum); + int64_t max_allowed = MIN(max_transfer, MAX_BOUNCE_BUFFER); + int64_t bounce_buffer_len = MIN(max_we_need, max_allowed); + + bounce_buffer = qemu_try_blockalign(bs, bounce_buffer_len); + if (!bounce_buffer) { + ret = -ENOMEM; + goto err; + } + } qemu_iovec_init_buf(&local_qiov, bounce_buffer, pnum); ret = bdrv_driver_preadv(bs, cluster_offset, pnum, |