diff options
Diffstat (limited to 'block/io.c')
-rw-r--r-- | block/io.c | 238 |
1 files changed, 128 insertions, 110 deletions
diff --git a/block/io.c b/block/io.c index 7cf3645ade..708690898f 100644 --- a/block/io.c +++ b/block/io.c @@ -33,7 +33,7 @@ #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ -static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, +static BlockAIOCB *bdrv_co_aio_rw_vector(BdrvChild *child, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, @@ -67,6 +67,17 @@ static void bdrv_parent_drained_end(BlockDriverState *bs) } } +static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src) +{ + dst->opt_transfer = MAX(dst->opt_transfer, src->opt_transfer); + dst->max_transfer = MIN_NON_ZERO(dst->max_transfer, src->max_transfer); + dst->opt_mem_alignment = MAX(dst->opt_mem_alignment, + src->opt_mem_alignment); + dst->min_mem_alignment = MAX(dst->min_mem_alignment, + src->min_mem_alignment); + dst->max_iov = MIN_NON_ZERO(dst->max_iov, src->max_iov); +} + void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) { BlockDriver *drv = bs->drv; @@ -78,6 +89,9 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) return; } + /* Default alignment based on whether driver has byte interface */ + bs->bl.request_alignment = drv->bdrv_co_preadv ? 1 : 512; + /* Take some limits from the children as a default */ if (bs->file) { bdrv_refresh_limits(bs->file->bs, &local_err); @@ -85,11 +99,7 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) error_propagate(errp, local_err); return; } - bs->bl.opt_transfer_length = bs->file->bs->bl.opt_transfer_length; - bs->bl.max_transfer_length = bs->file->bs->bl.max_transfer_length; - bs->bl.min_mem_alignment = bs->file->bs->bl.min_mem_alignment; - bs->bl.opt_mem_alignment = bs->file->bs->bl.opt_mem_alignment; - bs->bl.max_iov = bs->file->bs->bl.max_iov; + bdrv_merge_limits(&bs->bl, &bs->file->bs->bl); } else { bs->bl.min_mem_alignment = 512; bs->bl.opt_mem_alignment = getpagesize(); @@ -104,21 +114,7 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) error_propagate(errp, local_err); return; } - bs->bl.opt_transfer_length = - MAX(bs->bl.opt_transfer_length, - bs->backing->bs->bl.opt_transfer_length); - bs->bl.max_transfer_length = - MIN_NON_ZERO(bs->bl.max_transfer_length, - bs->backing->bs->bl.max_transfer_length); - bs->bl.opt_mem_alignment = - MAX(bs->bl.opt_mem_alignment, - bs->backing->bs->bl.opt_mem_alignment); - bs->bl.min_mem_alignment = - MAX(bs->bl.min_mem_alignment, - bs->backing->bs->bl.min_mem_alignment); - bs->bl.max_iov = - MIN(bs->bl.max_iov, - bs->backing->bs->bl.max_iov); + bdrv_merge_limits(&bs->bl, &bs->backing->bs->bl); } /* Then let the driver override it */ @@ -463,7 +459,7 @@ static int bdrv_get_cluster_size(BlockDriverState *bs) ret = bdrv_get_info(bs, &bdi); if (ret < 0 || bdi.cluster_size == 0) { - return bs->request_alignment; + return bs->bl.request_alignment; } else { return bdi.cluster_size; } @@ -557,7 +553,7 @@ static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num, } typedef struct RwCo { - BlockDriverState *bs; + BdrvChild *child; int64_t offset; QEMUIOVector *qiov; bool is_write; @@ -570,11 +566,11 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque) RwCo *rwco = opaque; if (!rwco->is_write) { - rwco->ret = bdrv_co_preadv(rwco->bs, rwco->offset, + rwco->ret = bdrv_co_preadv(rwco->child, rwco->offset, rwco->qiov->size, rwco->qiov, rwco->flags); } else { - rwco->ret = bdrv_co_pwritev(rwco->bs, rwco->offset, + rwco->ret = bdrv_co_pwritev(rwco->child, rwco->offset, rwco->qiov->size, rwco->qiov, rwco->flags); } @@ -583,13 +579,13 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque) /* * Process a vectored synchronous request using coroutines */ -static int bdrv_prwv_co(BlockDriverState *bs, int64_t offset, +static int bdrv_prwv_co(BdrvChild *child, int64_t offset, QEMUIOVector *qiov, bool is_write, BdrvRequestFlags flags) { Coroutine *co; RwCo rwco = { - .bs = bs, + .child = child, .offset = offset, .qiov = qiov, .is_write = is_write, @@ -601,7 +597,7 @@ static int bdrv_prwv_co(BlockDriverState *bs, int64_t offset, /* Fast-path if already in coroutine context */ bdrv_rw_co_entry(&rwco); } else { - AioContext *aio_context = bdrv_get_aio_context(bs); + AioContext *aio_context = bdrv_get_aio_context(child->bs); co = qemu_coroutine_create(bdrv_rw_co_entry); qemu_coroutine_enter(co, &rwco); @@ -615,7 +611,7 @@ static int bdrv_prwv_co(BlockDriverState *bs, int64_t offset, /* * Process a synchronous request using coroutines */ -static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, +static int bdrv_rw_co(BdrvChild *child, int64_t sector_num, uint8_t *buf, int nb_sectors, bool is_write, BdrvRequestFlags flags) { QEMUIOVector qiov; @@ -629,15 +625,15 @@ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, } qemu_iovec_init_external(&qiov, &iov, 1); - return bdrv_prwv_co(bs, sector_num << BDRV_SECTOR_BITS, + return bdrv_prwv_co(child, sector_num << BDRV_SECTOR_BITS, &qiov, is_write, flags); } /* return < 0 if error. See bdrv_write() for the return codes */ -int bdrv_read(BlockDriverState *bs, int64_t sector_num, +int bdrv_read(BdrvChild *child, int64_t sector_num, uint8_t *buf, int nb_sectors) { - return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false, 0); + return bdrv_rw_co(child, sector_num, buf, nb_sectors, false, 0); } /* Return < 0 if error. Important errors are: @@ -646,13 +642,13 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, -EINVAL Invalid sector number or nb_sectors -EACCES Trying to write a read-only device */ -int bdrv_write(BlockDriverState *bs, int64_t sector_num, +int bdrv_write(BdrvChild *child, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true, 0); + return bdrv_rw_co(child, sector_num, (uint8_t *)buf, nb_sectors, true, 0); } -int bdrv_pwrite_zeroes(BlockDriverState *bs, int64_t offset, +int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, int count, BdrvRequestFlags flags) { QEMUIOVector qiov; @@ -662,7 +658,7 @@ int bdrv_pwrite_zeroes(BlockDriverState *bs, int64_t offset, }; qemu_iovec_init_external(&qiov, &iov, 1); - return bdrv_prwv_co(bs, offset, &qiov, true, + return bdrv_prwv_co(child, offset, &qiov, true, BDRV_REQ_ZERO_WRITE | flags); } @@ -675,9 +671,10 @@ int bdrv_pwrite_zeroes(BlockDriverState *bs, int64_t offset, * * Returns < 0 on error, 0 on success. For error codes see bdrv_write(). */ -int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags) +int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) { int64_t target_sectors, ret, nb_sectors, sector_num = 0; + BlockDriverState *bs = child->bs; BlockDriverState *file; int n; @@ -701,7 +698,7 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags) sector_num += n; continue; } - ret = bdrv_pwrite_zeroes(bs, sector_num << BDRV_SECTOR_BITS, + ret = bdrv_pwrite_zeroes(child, sector_num << BDRV_SECTOR_BITS, n << BDRV_SECTOR_BITS, flags); if (ret < 0) { error_report("error writing zeroes at sector %" PRId64 ": %s", @@ -712,11 +709,11 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags) } } -int bdrv_preadv(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov) +int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov) { int ret; - ret = bdrv_prwv_co(bs, offset, qiov, false, 0); + ret = bdrv_prwv_co(child, offset, qiov, false, 0); if (ret < 0) { return ret; } @@ -724,7 +721,7 @@ int bdrv_preadv(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov) return qiov->size; } -int bdrv_pread(BlockDriverState *bs, int64_t offset, void *buf, int bytes) +int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes) { QEMUIOVector qiov; struct iovec iov = { @@ -737,14 +734,14 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, void *buf, int bytes) } qemu_iovec_init_external(&qiov, &iov, 1); - return bdrv_preadv(bs, offset, &qiov); + return bdrv_preadv(child, offset, &qiov); } -int bdrv_pwritev(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov) +int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov) { int ret; - ret = bdrv_prwv_co(bs, offset, qiov, true, 0); + ret = bdrv_prwv_co(child, offset, qiov, true, 0); if (ret < 0) { return ret; } @@ -752,8 +749,7 @@ int bdrv_pwritev(BlockDriverState *bs, int64_t offset, QEMUIOVector *qiov) return qiov->size; } -int bdrv_pwrite(BlockDriverState *bs, int64_t offset, - const void *buf, int bytes) +int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes) { QEMUIOVector qiov; struct iovec iov = { @@ -766,7 +762,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, } qemu_iovec_init_external(&qiov, &iov, 1); - return bdrv_pwritev(bs, offset, &qiov); + return bdrv_pwritev(child, offset, &qiov); } /* @@ -775,17 +771,17 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, * * Returns 0 on success, -errno in error cases. */ -int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset, - const void *buf, int count) +int bdrv_pwrite_sync(BdrvChild *child, int64_t offset, + const void *buf, int count) { int ret; - ret = bdrv_pwrite(bs, offset, buf, count); + ret = bdrv_pwrite(child, offset, buf, count); if (ret < 0) { return ret; } - ret = bdrv_flush(bs); + ret = bdrv_flush(child->bs); if (ret < 0) { return ret; } @@ -945,6 +941,9 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs, if (drv->bdrv_co_pwrite_zeroes && buffer_is_zero(bounce_buffer, iov.iov_len)) { + /* FIXME: Should we (perhaps conditionally) be setting + * BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy + * that still correctly reads as zero? */ ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, cluster_bytes, 0); } else { /* This does not change the data on the disk, it is not necessary @@ -987,7 +986,12 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs, assert((bytes & (align - 1)) == 0); assert(!qiov || bytes == qiov->size); assert((bs->open_flags & BDRV_O_NO_IO) == 0); - assert(!(flags & ~BDRV_REQ_MASK)); + + /* TODO: We would need a per-BDS .supported_read_flags and + * potential fallback support, if we ever implement any read flags + * to pass through to drivers. For now, there aren't any + * passthrough flags. */ + assert(!(flags & ~(BDRV_REQ_NO_SERIALISING | BDRV_REQ_COPY_ON_READ))); /* Handle Copy on Read and associated serialisation */ if (flags & BDRV_REQ_COPY_ON_READ) { @@ -1028,7 +1032,7 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs, } max_bytes = ROUND_UP(MAX(0, total_bytes - offset), align); - if (bytes < max_bytes) { + if (bytes <= max_bytes) { ret = bdrv_driver_preadv(bs, offset, bytes, qiov, 0); } else if (max_bytes > 0) { QEMUIOVector local_qiov; @@ -1057,14 +1061,15 @@ out: /* * Handle a read request in coroutine context */ -int coroutine_fn bdrv_co_preadv(BlockDriverState *bs, +int coroutine_fn bdrv_co_preadv(BdrvChild *child, int64_t offset, unsigned int bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) { + BlockDriverState *bs = child->bs; BlockDriver *drv = bs->drv; BdrvTrackedRequest req; - uint64_t align = bs->request_alignment; + uint64_t align = bs->bl.request_alignment; uint8_t *head_buf = NULL; uint8_t *tail_buf = NULL; QEMUIOVector local_qiov; @@ -1125,7 +1130,7 @@ int coroutine_fn bdrv_co_preadv(BlockDriverState *bs, return ret; } -static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, +static int coroutine_fn bdrv_co_do_readv(BdrvChild *child, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, BdrvRequestFlags flags) { @@ -1133,19 +1138,20 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, return -EINVAL; } - return bdrv_co_preadv(bs, sector_num << BDRV_SECTOR_BITS, + return bdrv_co_preadv(child, sector_num << BDRV_SECTOR_BITS, nb_sectors << BDRV_SECTOR_BITS, qiov, flags); } -int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, QEMUIOVector *qiov) +int coroutine_fn bdrv_co_readv(BdrvChild *child, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov) { - trace_bdrv_co_readv(bs, sector_num, nb_sectors); + trace_bdrv_co_readv(child->bs, sector_num, nb_sectors); - return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, 0); + return bdrv_co_do_readv(child, sector_num, nb_sectors, qiov, 0); } -#define MAX_WRITE_ZEROES_BOUNCE_BUFFER 32768 +/* Maximum buffer for write zeroes fallback, in bytes */ +#define MAX_WRITE_ZEROES_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS) static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int count, BdrvRequestFlags flags) @@ -1159,8 +1165,8 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int tail = 0; int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX); - int alignment = MAX(bs->bl.pwrite_zeroes_alignment ?: 1, - bs->request_alignment); + int alignment = MAX(bs->bl.pwrite_zeroes_alignment, + bs->bl.request_alignment); assert(is_power_of_2(alignment)); head = offset & (alignment - 1); @@ -1203,7 +1209,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, if (ret == -ENOTSUP) { /* Fall back to bounce buffer if write zeroes is unsupported */ - int max_xfer_len = MIN_NON_ZERO(bs->bl.max_transfer_length, + int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_WRITE_ZEROES_BOUNCE_BUFFER); BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE; @@ -1214,7 +1220,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, write_flags &= ~BDRV_REQ_FUA; need_flush = true; } - num = MIN(num, max_xfer_len << BDRV_SECTOR_BITS); + num = MIN(num, max_transfer); iov.iov_len = num; if (iov.iov_base == NULL) { iov.iov_base = qemu_try_blockalign(bs, num); @@ -1231,7 +1237,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, /* Keep bounce buffer around if it is big enough for all * all future requests. */ - if (num < max_xfer_len << BDRV_SECTOR_BITS) { + if (num < max_transfer) { qemu_vfree(iov.iov_base); iov.iov_base = NULL; } @@ -1254,7 +1260,7 @@ fail: */ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs, BdrvTrackedRequest *req, int64_t offset, unsigned int bytes, - QEMUIOVector *qiov, int flags) + int64_t align, QEMUIOVector *qiov, int flags) { BlockDriver *drv = bs->drv; bool waited; @@ -1263,6 +1269,9 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs, int64_t start_sector = offset >> BDRV_SECTOR_BITS; int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE); + assert(is_power_of_2(align)); + assert((offset & (align - 1)) == 0); + assert((bytes & (align - 1)) == 0); assert(!qiov || bytes == qiov->size); assert((bs->open_flags & BDRV_O_NO_IO) == 0); assert(!(flags & ~BDRV_REQ_MASK)); @@ -1316,7 +1325,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs, uint8_t *buf = NULL; QEMUIOVector local_qiov; struct iovec iov; - uint64_t align = bs->request_alignment; + uint64_t align = bs->bl.request_alignment; unsigned int head_padding_bytes, tail_padding_bytes; int ret = 0; @@ -1349,7 +1358,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs, memset(buf + head_padding_bytes, 0, zero_bytes); ret = bdrv_aligned_pwritev(bs, req, offset & ~(align - 1), align, - &local_qiov, + align, &local_qiov, flags & ~BDRV_REQ_ZERO_WRITE); if (ret < 0) { goto fail; @@ -1362,7 +1371,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs, if (bytes >= align) { /* Write the aligned part in the middle. */ uint64_t aligned_bytes = bytes & ~(align - 1); - ret = bdrv_aligned_pwritev(bs, req, offset, aligned_bytes, + ret = bdrv_aligned_pwritev(bs, req, offset, aligned_bytes, align, NULL, flags); if (ret < 0) { goto fail; @@ -1386,7 +1395,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs, bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); memset(buf, 0, bytes); - ret = bdrv_aligned_pwritev(bs, req, offset, align, + ret = bdrv_aligned_pwritev(bs, req, offset, align, align, &local_qiov, flags & ~BDRV_REQ_ZERO_WRITE); } fail: @@ -1398,12 +1407,13 @@ fail: /* * Handle a write request in coroutine context */ -int coroutine_fn bdrv_co_pwritev(BlockDriverState *bs, +int coroutine_fn bdrv_co_pwritev(BdrvChild *child, int64_t offset, unsigned int bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) { + BlockDriverState *bs = child->bs; BdrvTrackedRequest req; - uint64_t align = bs->request_alignment; + uint64_t align = bs->bl.request_alignment; uint8_t *head_buf = NULL; uint8_t *tail_buf = NULL; QEMUIOVector local_qiov; @@ -1511,7 +1521,7 @@ int coroutine_fn bdrv_co_pwritev(BlockDriverState *bs, bytes = ROUND_UP(bytes, align); } - ret = bdrv_aligned_pwritev(bs, &req, offset, bytes, + ret = bdrv_aligned_pwritev(bs, &req, offset, bytes, align, use_local_qiov ? &local_qiov : qiov, flags); @@ -1527,7 +1537,7 @@ out: return ret; } -static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs, +static int coroutine_fn bdrv_co_do_writev(BdrvChild *child, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, BdrvRequestFlags flags) { @@ -1535,29 +1545,28 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs, return -EINVAL; } - return bdrv_co_pwritev(bs, sector_num << BDRV_SECTOR_BITS, + return bdrv_co_pwritev(child, sector_num << BDRV_SECTOR_BITS, nb_sectors << BDRV_SECTOR_BITS, qiov, flags); } -int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num, +int coroutine_fn bdrv_co_writev(BdrvChild *child, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) { - trace_bdrv_co_writev(bs, sector_num, nb_sectors); + trace_bdrv_co_writev(child->bs, sector_num, nb_sectors); - return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov, 0); + return bdrv_co_do_writev(child, sector_num, nb_sectors, qiov, 0); } -int coroutine_fn bdrv_co_pwrite_zeroes(BlockDriverState *bs, - int64_t offset, int count, - BdrvRequestFlags flags) +int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, + int count, BdrvRequestFlags flags) { - trace_bdrv_co_pwrite_zeroes(bs, offset, count, flags); + trace_bdrv_co_pwrite_zeroes(child->bs, offset, count, flags); - if (!(bs->open_flags & BDRV_O_UNMAP)) { + if (!(child->bs->open_flags & BDRV_O_UNMAP)) { flags &= ~BDRV_REQ_MAY_UNMAP; } - return bdrv_co_pwritev(bs, offset, count, NULL, + return bdrv_co_pwritev(child, offset, count, NULL, BDRV_REQ_ZERO_WRITE | flags); } @@ -1954,23 +1963,23 @@ int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) /**************************************************************/ /* async I/Os */ -BlockAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, +BlockAIOCB *bdrv_aio_readv(BdrvChild *child, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockCompletionFunc *cb, void *opaque) { - trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque); + trace_bdrv_aio_readv(child->bs, sector_num, nb_sectors, opaque); - return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0, + return bdrv_co_aio_rw_vector(child, sector_num, qiov, nb_sectors, 0, cb, opaque, false); } -BlockAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, +BlockAIOCB *bdrv_aio_writev(BdrvChild *child, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockCompletionFunc *cb, void *opaque) { - trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque); + trace_bdrv_aio_writev(child->bs, sector_num, nb_sectors, opaque); - return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0, + return bdrv_co_aio_rw_vector(child, sector_num, qiov, nb_sectors, 0, cb, opaque, true); } @@ -2026,6 +2035,7 @@ typedef struct BlockRequest { typedef struct BlockAIOCBCoroutine { BlockAIOCB common; + BdrvChild *child; BlockRequest req; bool is_write; bool need_bh; @@ -2069,20 +2079,19 @@ static void bdrv_co_maybe_schedule_bh(BlockAIOCBCoroutine *acb) static void coroutine_fn bdrv_co_do_rw(void *opaque) { BlockAIOCBCoroutine *acb = opaque; - BlockDriverState *bs = acb->common.bs; if (!acb->is_write) { - acb->req.error = bdrv_co_do_readv(bs, acb->req.sector, + acb->req.error = bdrv_co_do_readv(acb->child, acb->req.sector, acb->req.nb_sectors, acb->req.qiov, acb->req.flags); } else { - acb->req.error = bdrv_co_do_writev(bs, acb->req.sector, + acb->req.error = bdrv_co_do_writev(acb->child, acb->req.sector, acb->req.nb_sectors, acb->req.qiov, acb->req.flags); } bdrv_co_complete(acb); } -static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, +static BlockAIOCB *bdrv_co_aio_rw_vector(BdrvChild *child, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, @@ -2094,7 +2103,8 @@ static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, Coroutine *co; BlockAIOCBCoroutine *acb; - acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque); + acb = qemu_aio_get(&bdrv_em_co_aiocb_info, child->bs, cb, opaque); + acb->child = child; acb->need_bh = true; acb->req.error = -EINPROGRESS; acb->req.sector = sector_num; @@ -2200,9 +2210,15 @@ void qemu_aio_unref(void *p) /**************************************************************/ /* Coroutine block device emulation */ +typedef struct FlushCo { + BlockDriverState *bs; + int ret; +} FlushCo; + + static void coroutine_fn bdrv_flush_co_entry(void *opaque) { - RwCo *rwco = opaque; + FlushCo *rwco = opaque; rwco->ret = bdrv_co_flush(rwco->bs); } @@ -2286,25 +2302,25 @@ out: int bdrv_flush(BlockDriverState *bs) { Coroutine *co; - RwCo rwco = { + FlushCo flush_co = { .bs = bs, .ret = NOT_DONE, }; if (qemu_in_coroutine()) { /* Fast-path if already in coroutine context */ - bdrv_flush_co_entry(&rwco); + bdrv_flush_co_entry(&flush_co); } else { AioContext *aio_context = bdrv_get_aio_context(bs); co = qemu_coroutine_create(bdrv_flush_co_entry); - qemu_coroutine_enter(co, &rwco); - while (rwco.ret == NOT_DONE) { + qemu_coroutine_enter(co, &flush_co); + while (flush_co.ret == NOT_DONE) { aio_poll(aio_context, true); } } - return rwco.ret; + return flush_co.ret; } typedef struct DiscardCo { @@ -2355,19 +2371,21 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, goto out; } - max_discard = MIN_NON_ZERO(bs->bl.max_discard, BDRV_REQUEST_MAX_SECTORS); + max_discard = MIN_NON_ZERO(bs->bl.max_pdiscard >> BDRV_SECTOR_BITS, + BDRV_REQUEST_MAX_SECTORS); while (nb_sectors > 0) { int ret; int num = nb_sectors; + int discard_alignment = bs->bl.pdiscard_alignment >> BDRV_SECTOR_BITS; /* align request */ - if (bs->bl.discard_alignment && - num >= bs->bl.discard_alignment && - sector_num % bs->bl.discard_alignment) { - if (num > bs->bl.discard_alignment) { - num = bs->bl.discard_alignment; + if (discard_alignment && + num >= discard_alignment && + sector_num % discard_alignment) { + if (num > discard_alignment) { + num = discard_alignment; } - num -= sector_num % bs->bl.discard_alignment; + num -= sector_num % discard_alignment; } /* limit request size */ |