diff options
69 files changed, 1209 insertions, 552 deletions
@@ -1035,7 +1035,8 @@ static int find_image_format(BlockBackend *file, const char *filename, * Set the current 'total_sectors' value * Return 0 on success, -errno on error. */ -int refresh_total_sectors(BlockDriverState *bs, int64_t hint) +int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs, + int64_t hint) { BlockDriver *drv = bs->drv; IO_CODE(); @@ -1044,13 +1045,13 @@ int refresh_total_sectors(BlockDriverState *bs, int64_t hint) return -ENOMEDIUM; } - /* Do not attempt drv->bdrv_getlength() on scsi-generic devices */ + /* Do not attempt drv->bdrv_co_getlength() on scsi-generic devices */ if (bdrv_is_sg(bs)) return 0; /* query actual device if possible, otherwise just trust the hint */ - if (drv->bdrv_getlength) { - int64_t length = drv->bdrv_getlength(bs); + if (drv->bdrv_co_getlength) { + int64_t length = drv->bdrv_co_getlength(bs); if (length < 0) { return length; } @@ -1601,6 +1602,11 @@ out: g_free(gen_node_name); } +/* + * The caller must always hold @bs AioContext lock, because this function calls + * bdrv_refresh_total_sectors() which polls when called from non-coroutine + * context. + */ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name, QDict *options, int open_flags, Error **errp) @@ -1652,7 +1658,7 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, bs->supported_read_flags |= BDRV_REQ_REGISTERED_BUF; bs->supported_write_flags |= BDRV_REQ_REGISTERED_BUF; - ret = refresh_total_sectors(bs, bs->total_sectors); + ret = bdrv_refresh_total_sectors(bs, bs->total_sectors); if (ret < 0) { error_setg_errno(errp, -ret, "Could not refresh total sector count"); return ret; @@ -3796,6 +3802,10 @@ out: * The reference parameter may be used to specify an existing block device which * should be opened. If specified, neither options nor a filename may be given, * nor can an existing BDS be reused (that is, *pbs has to be NULL). + * + * The caller must always hold @filename AioContext lock, because this + * function eventually calls bdrv_refresh_total_sectors() which polls + * when called from non-coroutine context. */ static BlockDriverState *bdrv_open_inherit(const char *filename, const char *reference, @@ -4084,6 +4094,11 @@ close_and_fail: return NULL; } +/* + * The caller must always hold @filename AioContext lock, because this + * function eventually calls bdrv_refresh_total_sectors() which polls + * when called from non-coroutine context. + */ BlockDriverState *bdrv_open(const char *filename, const char *reference, QDict *options, int flags, Error **errp) { @@ -5705,7 +5720,7 @@ exit: } /** - * Implementation of BlockDriver.bdrv_get_allocated_file_size() that + * Implementation of BlockDriver.bdrv_co_get_allocated_file_size() that * sums the size of all data-bearing children. (This excludes backing * children.) */ @@ -5718,7 +5733,7 @@ static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs) if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | BDRV_CHILD_FILTERED)) { - child_size = bdrv_get_allocated_file_size(child->bs); + child_size = bdrv_co_get_allocated_file_size(child->bs); if (child_size < 0) { return child_size; } @@ -5733,7 +5748,7 @@ static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs) * Length of a allocated file in bytes. Sparse files are counted by actual * allocated space. Return < 0 if error or unknown. */ -int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) +int64_t coroutine_fn bdrv_co_get_allocated_file_size(BlockDriverState *bs) { BlockDriver *drv = bs->drv; IO_CODE(); @@ -5741,8 +5756,8 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) if (!drv) { return -ENOMEDIUM; } - if (drv->bdrv_get_allocated_file_size) { - return drv->bdrv_get_allocated_file_size(bs); + if (drv->bdrv_co_get_allocated_file_size) { + return drv->bdrv_co_get_allocated_file_size(bs); } if (drv->bdrv_file_open) { @@ -5754,7 +5769,7 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs) return -ENOTSUP; } else if (drv->is_filter) { /* Filter drivers default to the size of their filtered child */ - return bdrv_get_allocated_file_size(bdrv_filter_bs(bs)); + return bdrv_co_get_allocated_file_size(bdrv_filter_bs(bs)); } else { /* Other drivers default to summing their children's sizes */ return bdrv_sum_allocated_file_size(bs); @@ -5800,7 +5815,7 @@ BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, /** * Return number of sectors on success, -errno on error. */ -int64_t bdrv_nb_sectors(BlockDriverState *bs) +int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs) { BlockDriver *drv = bs->drv; IO_CODE(); @@ -5809,7 +5824,7 @@ int64_t bdrv_nb_sectors(BlockDriverState *bs) return -ENOMEDIUM; if (drv->has_variable_length) { - int ret = refresh_total_sectors(bs, bs->total_sectors); + int ret = bdrv_co_refresh_total_sectors(bs, bs->total_sectors); if (ret < 0) { return ret; } @@ -5821,11 +5836,12 @@ int64_t bdrv_nb_sectors(BlockDriverState *bs) * Return length in bytes on success, -errno on error. * The length is always a multiple of BDRV_SECTOR_SIZE. */ -int64_t bdrv_getlength(BlockDriverState *bs) +int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs) { - int64_t ret = bdrv_nb_sectors(bs); + int64_t ret; IO_CODE(); + ret = bdrv_co_nb_sectors(bs); if (ret < 0) { return ret; } @@ -6285,7 +6301,7 @@ void bdrv_get_backing_filename(BlockDriverState *bs, pstrcpy(filename, filename_size, bs->backing_file); } -int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +int coroutine_fn bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { int ret; BlockDriver *drv = bs->drv; @@ -6294,15 +6310,15 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) if (!drv) { return -ENOMEDIUM; } - if (!drv->bdrv_get_info) { + if (!drv->bdrv_co_get_info) { BlockDriverState *filtered = bdrv_filter_bs(bs); if (filtered) { - return bdrv_get_info(filtered, bdi); + return bdrv_co_get_info(filtered, bdi); } return -ENOTSUP; } memset(bdi, 0, sizeof(*bdi)); - ret = drv->bdrv_get_info(bs, bdi); + ret = drv->bdrv_co_get_info(bs, bdi); if (ret < 0) { return ret; } @@ -6335,14 +6351,14 @@ BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs) return drv->bdrv_get_specific_stats(bs); } -void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event) +void coroutine_fn bdrv_co_debug_event(BlockDriverState *bs, BlkdebugEvent event) { IO_CODE(); - if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) { + if (!bs || !bs->drv || !bs->drv->bdrv_co_debug_event) { return; } - bs->drv->bdrv_debug_event(bs, event); + bs->drv->bdrv_co_debug_event(bs, event); } static BlockDriverState *bdrv_find_debug_node(BlockDriverState *bs) @@ -6591,7 +6607,7 @@ int bdrv_activate(BlockDriverState *bs, Error **errp) bdrv_dirty_bitmap_skip_store(bm, false); } - ret = refresh_total_sectors(bs, bs->total_sectors); + ret = bdrv_refresh_total_sectors(bs, bs->total_sectors); if (ret < 0) { bs->open_flags |= BDRV_O_INACTIVE; error_setg_errno(errp, -ret, "Could not refresh total sector count"); @@ -6782,7 +6798,7 @@ out: /** * Return TRUE if the media is present */ -bool bdrv_is_inserted(BlockDriverState *bs) +bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs) { BlockDriver *drv = bs->drv; BdrvChild *child; @@ -6791,11 +6807,11 @@ bool bdrv_is_inserted(BlockDriverState *bs) if (!drv) { return false; } - if (drv->bdrv_is_inserted) { - return drv->bdrv_is_inserted(bs); + if (drv->bdrv_co_is_inserted) { + return drv->bdrv_co_is_inserted(bs); } QLIST_FOREACH(child, &bs->children, next) { - if (!bdrv_is_inserted(child->bs)) { + if (!bdrv_co_is_inserted(child->bs)) { return false; } } @@ -6805,13 +6821,13 @@ bool bdrv_is_inserted(BlockDriverState *bs) /** * If eject_flag is TRUE, eject the media. Otherwise, close the tray */ -void bdrv_eject(BlockDriverState *bs, bool eject_flag) +void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag) { BlockDriver *drv = bs->drv; IO_CODE(); - if (drv && drv->bdrv_eject) { - drv->bdrv_eject(bs, eject_flag); + if (drv && drv->bdrv_co_eject) { + drv->bdrv_co_eject(bs, eject_flag); } } @@ -6819,14 +6835,14 @@ void bdrv_eject(BlockDriverState *bs, bool eject_flag) * Lock or unlock the media (if it is locked, the user won't be able * to eject it manually). */ -void bdrv_lock_medium(BlockDriverState *bs, bool locked) +void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked) { BlockDriver *drv = bs->drv; IO_CODE(); trace_bdrv_lock_medium(bs, locked); - if (drv && drv->bdrv_lock_medium) { - drv->bdrv_lock_medium(bs, locked); + if (drv && drv->bdrv_co_lock_medium) { + drv->bdrv_co_lock_medium(bs, locked); } } @@ -7178,12 +7194,6 @@ void coroutine_fn bdrv_co_unlock(BlockDriverState *bs) } } -void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co) -{ - IO_CODE(); - aio_co_enter(bdrv_get_aio_context(bs), co); -} - static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban) { GLOBAL_STATE_CODE(); diff --git a/block/blkdebug.c b/block/blkdebug.c index fa38c1cf7d..28772be73f 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -836,7 +836,8 @@ static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, } } -static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) +static void coroutine_fn +blkdebug_co_debug_event(BlockDriverState *bs, BlkdebugEvent event) { BDRVBlkdebugState *s = bs->opaque; struct BlkdebugRule *rule, *next; @@ -966,9 +967,9 @@ static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) return false; } -static int64_t blkdebug_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blkdebug_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } static void blkdebug_refresh_filename(BlockDriverState *bs) @@ -1075,7 +1076,7 @@ static BlockDriver bdrv_blkdebug = { .bdrv_reopen_prepare = blkdebug_reopen_prepare, .bdrv_child_perm = blkdebug_child_perm, - .bdrv_getlength = blkdebug_getlength, + .bdrv_co_getlength = blkdebug_co_getlength, .bdrv_refresh_filename = blkdebug_refresh_filename, .bdrv_refresh_limits = blkdebug_refresh_limits, @@ -1086,7 +1087,7 @@ static BlockDriver bdrv_blkdebug = { .bdrv_co_pdiscard = blkdebug_co_pdiscard, .bdrv_co_block_status = blkdebug_co_block_status, - .bdrv_debug_event = blkdebug_debug_event, + .bdrv_co_debug_event = blkdebug_co_debug_event, .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, .bdrv_debug_remove_breakpoint = blkdebug_debug_remove_breakpoint, diff --git a/block/blkio.c b/block/blkio.c index 6ad86b23d1..0cdc99a729 100644 --- a/block/blkio.c +++ b/block/blkio.c @@ -479,7 +479,7 @@ static int coroutine_fn blkio_co_pwrite_zeroes(BlockDriverState *bs, return cod.ret; } -static void blkio_io_unplug(BlockDriverState *bs) +static void coroutine_fn blkio_co_io_unplug(BlockDriverState *bs) { BDRVBlkioState *s = bs->opaque; @@ -839,7 +839,7 @@ static void blkio_close(BlockDriverState *bs) } } -static int64_t blkio_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blkio_co_getlength(BlockDriverState *bs) { BDRVBlkioState *s = bs->opaque; uint64_t capacity; @@ -867,7 +867,7 @@ static int coroutine_fn blkio_truncate(BlockDriverState *bs, int64_t offset, return -ENOTSUP; } - current_length = blkio_getlength(bs); + current_length = blkio_co_getlength(bs); if (offset > current_length) { error_setg(errp, "Cannot grow device"); @@ -880,7 +880,8 @@ static int coroutine_fn blkio_truncate(BlockDriverState *bs, int64_t offset, return 0; } -static int blkio_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +blkio_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { return 0; } @@ -998,9 +999,9 @@ static void blkio_refresh_limits(BlockDriverState *bs, Error **errp) .instance_size = sizeof(BDRVBlkioState), \ .bdrv_file_open = blkio_file_open, \ .bdrv_close = blkio_close, \ - .bdrv_getlength = blkio_getlength, \ + .bdrv_co_getlength = blkio_co_getlength, \ .bdrv_co_truncate = blkio_truncate, \ - .bdrv_get_info = blkio_get_info, \ + .bdrv_co_get_info = blkio_co_get_info, \ .bdrv_attach_aio_context = blkio_attach_aio_context, \ .bdrv_detach_aio_context = blkio_detach_aio_context, \ .bdrv_co_pdiscard = blkio_co_pdiscard, \ @@ -1008,7 +1009,7 @@ static void blkio_refresh_limits(BlockDriverState *bs, Error **errp) .bdrv_co_pwritev = blkio_co_pwritev, \ .bdrv_co_flush_to_disk = blkio_co_flush, \ .bdrv_co_pwrite_zeroes = blkio_co_pwrite_zeroes, \ - .bdrv_io_unplug = blkio_io_unplug, \ + .bdrv_co_io_unplug = blkio_co_io_unplug, \ .bdrv_refresh_limits = blkio_refresh_limits, \ .bdrv_register_buf = blkio_register_buf, \ .bdrv_unregister_buf = blkio_unregister_buf, \ diff --git a/block/blklogwrites.c b/block/blklogwrites.c index a5bf767184..b00b8a6dd0 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -267,9 +267,9 @@ static void blk_log_writes_close(BlockDriverState *bs) s->log_file = NULL; } -static int64_t blk_log_writes_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blk_log_writes_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, @@ -498,7 +498,7 @@ static BlockDriver bdrv_blk_log_writes = { .bdrv_open = blk_log_writes_open, .bdrv_close = blk_log_writes_close, - .bdrv_getlength = blk_log_writes_getlength, + .bdrv_co_getlength = blk_log_writes_co_getlength, .bdrv_child_perm = blk_log_writes_child_perm, .bdrv_refresh_limits = blk_log_writes_refresh_limits, diff --git a/block/blkreplay.c b/block/blkreplay.c index e3b6a3efb2..16543f585a 100644 --- a/block/blkreplay.c +++ b/block/blkreplay.c @@ -40,9 +40,9 @@ fail: return ret; } -static int64_t blkreplay_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blkreplay_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } /* This bh is used for synchronization of return from coroutines. @@ -136,7 +136,7 @@ static BlockDriver bdrv_blkreplay = { .bdrv_open = blkreplay_open, .bdrv_child_perm = bdrv_default_perms, - .bdrv_getlength = blkreplay_getlength, + .bdrv_co_getlength = blkreplay_co_getlength, .bdrv_co_preadv = blkreplay_co_preadv, .bdrv_co_pwritev = blkreplay_co_pwritev, diff --git a/block/blkverify.c b/block/blkverify.c index 0e78bc9dd6..edf1a550f2 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -155,11 +155,11 @@ static void blkverify_close(BlockDriverState *bs) s->test_file = NULL; } -static int64_t blkverify_getlength(BlockDriverState *bs) +static int64_t coroutine_fn blkverify_co_getlength(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; - return bdrv_getlength(s->test_file->bs); + return bdrv_co_getlength(s->test_file->bs); } static void coroutine_fn blkverify_do_test_req(void *opaque) @@ -314,7 +314,7 @@ static BlockDriver bdrv_blkverify = { .bdrv_file_open = blkverify_open, .bdrv_close = blkverify_close, .bdrv_child_perm = bdrv_default_perms, - .bdrv_getlength = blkverify_getlength, + .bdrv_co_getlength = blkverify_co_getlength, .bdrv_refresh_filename = blkverify_refresh_filename, .bdrv_dirname = blkverify_dirname, diff --git a/block/block-backend.c b/block/block-backend.c index ba7bf1d6bc..ef512f7c48 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1235,8 +1235,8 @@ void blk_set_disable_request_queuing(BlockBackend *blk, bool disable) blk->disable_request_queuing = disable; } -static int blk_check_byte_request(BlockBackend *blk, int64_t offset, - int64_t bytes) +static coroutine_fn int blk_check_byte_request(BlockBackend *blk, + int64_t offset, int64_t bytes) { int64_t len; @@ -1253,7 +1253,7 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset, } if (!blk->allow_write_beyond_eof) { - len = blk_getlength(blk); + len = bdrv_co_getlength(blk_bs(blk)); if (len < 0) { return len; } @@ -1555,7 +1555,7 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, acb->has_returned = false; co = qemu_coroutine_create(co_entry, acb); - bdrv_coroutine_enter(blk_bs(blk), co); + aio_co_enter(blk_get_aio_context(blk), co); acb->has_returned = true; if (acb->rwco.ret != NOT_DONE) { @@ -1599,14 +1599,15 @@ BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, flags | BDRV_REQ_ZERO_WRITE, cb, opaque); } -int64_t blk_getlength(BlockBackend *blk) +int64_t coroutine_fn blk_co_getlength(BlockBackend *blk) { IO_CODE(); + if (!blk_is_available(blk)) { return -ENOMEDIUM; } - return bdrv_getlength(blk_bs(blk)); + return bdrv_co_getlength(blk_bs(blk)); } void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) @@ -1619,14 +1620,15 @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) } } -int64_t blk_nb_sectors(BlockBackend *blk) +int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk) { IO_CODE(); + if (!blk_is_available(blk)) { return -ENOMEDIUM; } - return bdrv_nb_sectors(blk_bs(blk)); + return bdrv_co_nb_sectors(blk_bs(blk)); } BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset, @@ -1983,12 +1985,12 @@ void blk_activate(BlockBackend *blk, Error **errp) bdrv_activate(bs, errp); } -bool blk_is_inserted(BlockBackend *blk) +bool coroutine_fn blk_co_is_inserted(BlockBackend *blk) { BlockDriverState *bs = blk_bs(blk); IO_CODE(); - return bs && bdrv_is_inserted(bs); + return bs && bdrv_co_is_inserted(bs); } bool blk_is_available(BlockBackend *blk) @@ -1997,24 +1999,24 @@ bool blk_is_available(BlockBackend *blk) return blk_is_inserted(blk) && !blk_dev_is_tray_open(blk); } -void blk_lock_medium(BlockBackend *blk, bool locked) +void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked) { BlockDriverState *bs = blk_bs(blk); IO_CODE(); if (bs) { - bdrv_lock_medium(bs, locked); + bdrv_co_lock_medium(bs, locked); } } -void blk_eject(BlockBackend *blk, bool eject_flag) +void coroutine_fn blk_co_eject(BlockBackend *blk, bool eject_flag) { BlockDriverState *bs = blk_bs(blk); char *id; IO_CODE(); if (bs) { - bdrv_eject(bs, eject_flag); + bdrv_co_eject(bs, eject_flag); } /* Whether or not we ejected on the backend, @@ -2315,23 +2317,23 @@ void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify) notifier_list_add(&blk->insert_bs_notifiers, notify); } -void blk_io_plug(BlockBackend *blk) +void coroutine_fn blk_co_io_plug(BlockBackend *blk) { BlockDriverState *bs = blk_bs(blk); IO_CODE(); if (bs) { - bdrv_io_plug(bs); + bdrv_co_io_plug(bs); } } -void blk_io_unplug(BlockBackend *blk) +void coroutine_fn blk_co_io_unplug(BlockBackend *blk) { BlockDriverState *bs = blk_bs(blk); IO_CODE(); if (bs) { - bdrv_io_unplug(bs); + bdrv_co_io_unplug(bs); } } diff --git a/block/commit.c b/block/commit.c index b346341767..41e3599281 100644 --- a/block/commit.c +++ b/block/commit.c @@ -123,13 +123,13 @@ static int coroutine_fn commit_run(Job *job, Error **errp) QEMU_AUTO_VFREE void *buf = NULL; int64_t len, base_len; - len = blk_getlength(s->top); + len = blk_co_getlength(s->top); if (len < 0) { return len; } job_progress_set_remaining(&s->common.job, len); - base_len = blk_getlength(s->base); + base_len = blk_co_getlength(s->base); if (base_len < 0) { return base_len; } diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 13ed4150a6..3280eb2feb 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -121,9 +121,9 @@ static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, } -static int64_t cor_getlength(BlockDriverState *bs) +static int64_t coroutine_fn cor_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } @@ -217,15 +217,15 @@ static int coroutine_fn cor_co_pwritev_compressed(BlockDriverState *bs, } -static void cor_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn cor_co_eject(BlockDriverState *bs, bool eject_flag) { - bdrv_eject(bs->file->bs, eject_flag); + bdrv_co_eject(bs->file->bs, eject_flag); } -static void cor_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn cor_co_lock_medium(BlockDriverState *bs, bool locked) { - bdrv_lock_medium(bs->file->bs, locked); + bdrv_co_lock_medium(bs->file->bs, locked); } @@ -250,7 +250,7 @@ static BlockDriver bdrv_copy_on_read = { .bdrv_close = cor_close, .bdrv_child_perm = cor_child_perm, - .bdrv_getlength = cor_getlength, + .bdrv_co_getlength = cor_co_getlength, .bdrv_co_preadv_part = cor_co_preadv_part, .bdrv_co_pwritev_part = cor_co_pwritev_part, @@ -258,8 +258,8 @@ static BlockDriver bdrv_copy_on_read = { .bdrv_co_pdiscard = cor_co_pdiscard, .bdrv_co_pwritev_compressed = cor_co_pwritev_compressed, - .bdrv_eject = cor_eject, - .bdrv_lock_medium = cor_lock_medium, + .bdrv_co_eject = cor_co_eject, + .bdrv_co_lock_medium = cor_co_lock_medium, .has_variable_length = true, .is_filter = true, diff --git a/block/crypto.c b/block/crypto.c index bbeb9f437c..b70cec97c7 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -531,10 +531,10 @@ static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp) } -static int64_t block_crypto_getlength(BlockDriverState *bs) +static int64_t coroutine_fn block_crypto_co_getlength(BlockDriverState *bs) { BlockCrypto *crypto = bs->opaque; - int64_t len = bdrv_getlength(bs->file->bs); + int64_t len = bdrv_co_getlength(bs->file->bs); uint64_t offset = qcrypto_block_get_payload_offset(crypto->block); assert(offset < INT64_MAX); @@ -737,13 +737,13 @@ fail: return ret; } -static int block_crypto_get_info_luks(BlockDriverState *bs, - BlockDriverInfo *bdi) +static int coroutine_fn +block_crypto_co_get_info_luks(BlockDriverState *bs, BlockDriverInfo *bdi) { BlockDriverInfo subbdi; int ret; - ret = bdrv_get_info(bs->file->bs, &subbdi); + ret = bdrv_co_get_info(bs->file->bs, &subbdi); if (ret != 0) { return ret; } @@ -953,9 +953,9 @@ static BlockDriver bdrv_crypto_luks = { .bdrv_refresh_limits = block_crypto_refresh_limits, .bdrv_co_preadv = block_crypto_co_preadv, .bdrv_co_pwritev = block_crypto_co_pwritev, - .bdrv_getlength = block_crypto_getlength, + .bdrv_co_getlength = block_crypto_co_getlength, .bdrv_measure = block_crypto_measure, - .bdrv_get_info = block_crypto_get_info_luks, + .bdrv_co_get_info = block_crypto_co_get_info_luks, .bdrv_get_specific_info = block_crypto_get_specific_info_luks, .bdrv_amend_options = block_crypto_amend_options_luks, .bdrv_co_amend = block_crypto_co_amend_luks, diff --git a/block/curl.c b/block/curl.c index bf45fa3244..cbada22e9e 100644 --- a/block/curl.c +++ b/block/curl.c @@ -958,7 +958,7 @@ static void curl_close(BlockDriverState *bs) g_free(s->proxypassword); } -static int64_t curl_getlength(BlockDriverState *bs) +static int64_t coroutine_fn curl_co_getlength(BlockDriverState *bs) { BDRVCURLState *s = bs->opaque; return s->len; @@ -1002,7 +1002,7 @@ static BlockDriver bdrv_http = { .bdrv_parse_filename = curl_parse_filename, .bdrv_file_open = curl_open, .bdrv_close = curl_close, - .bdrv_getlength = curl_getlength, + .bdrv_co_getlength = curl_co_getlength, .bdrv_co_preadv = curl_co_preadv, @@ -1021,7 +1021,7 @@ static BlockDriver bdrv_https = { .bdrv_parse_filename = curl_parse_filename, .bdrv_file_open = curl_open, .bdrv_close = curl_close, - .bdrv_getlength = curl_getlength, + .bdrv_co_getlength = curl_co_getlength, .bdrv_co_preadv = curl_co_preadv, @@ -1040,7 +1040,7 @@ static BlockDriver bdrv_ftp = { .bdrv_parse_filename = curl_parse_filename, .bdrv_file_open = curl_open, .bdrv_close = curl_close, - .bdrv_getlength = curl_getlength, + .bdrv_co_getlength = curl_co_getlength, .bdrv_co_preadv = curl_co_preadv, @@ -1059,7 +1059,7 @@ static BlockDriver bdrv_ftps = { .bdrv_parse_filename = curl_parse_filename, .bdrv_file_open = curl_open, .bdrv_close = curl_close, - .bdrv_getlength = curl_getlength, + .bdrv_co_getlength = curl_co_getlength, .bdrv_co_preadv = curl_co_preadv, diff --git a/block/file-posix.c b/block/file-posix.c index fa227d9d14..d3073a7caa 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -189,7 +189,7 @@ static int fd_open(BlockDriverState *bs) return -EIO; } -static int64_t raw_getlength(BlockDriverState *bs); +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs); typedef struct RawPosixAIOData { BlockDriverState *bs; @@ -2132,7 +2132,7 @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset, return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_WRITE); } -static void raw_aio_plug(BlockDriverState *bs) +static void coroutine_fn raw_co_io_plug(BlockDriverState *bs) { BDRVRawState __attribute__((unused)) *s = bs->opaque; #ifdef CONFIG_LINUX_AIO @@ -2149,7 +2149,7 @@ static void raw_aio_plug(BlockDriverState *bs) #endif } -static void raw_aio_unplug(BlockDriverState *bs) +static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs) { BDRVRawState __attribute__((unused)) *s = bs->opaque; #ifdef CONFIG_LINUX_AIO @@ -2280,7 +2280,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, } if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { - int64_t cur_length = raw_getlength(bs); + int64_t cur_length = raw_co_getlength(bs); if (offset != cur_length && exact) { error_setg(errp, "Cannot resize device files"); @@ -2298,7 +2298,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, } #ifdef __OpenBSD__ -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int fd = s->fd; @@ -2317,7 +2317,7 @@ static int64_t raw_getlength(BlockDriverState *bs) return st.st_size; } #elif defined(__NetBSD__) -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int fd = s->fd; @@ -2342,7 +2342,7 @@ static int64_t raw_getlength(BlockDriverState *bs) return st.st_size; } #elif defined(__sun__) -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; struct dk_minfo minfo; @@ -2373,7 +2373,7 @@ static int64_t raw_getlength(BlockDriverState *bs) return size; } #elif defined(CONFIG_BSD) -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int fd = s->fd; @@ -2445,7 +2445,7 @@ again: return size; } #else -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int ret; @@ -2464,7 +2464,7 @@ static int64_t raw_getlength(BlockDriverState *bs) } #endif -static int64_t raw_get_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_get_allocated_file_size(BlockDriverState *bs) { struct stat st; BDRVRawState *s = bs->opaque; @@ -2830,7 +2830,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, * round up if necessary. */ if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) { - int64_t file_length = raw_getlength(bs); + int64_t file_length = raw_co_getlength(bs); if (file_length > 0) { /* Ignore errors, this is just a safeguard */ assert(hole == file_length); @@ -2852,7 +2852,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, #if defined(__linux__) /* Verify that the file is not in the page cache */ -static void check_cache_dropped(BlockDriverState *bs, Error **errp) +static void coroutine_fn check_cache_dropped(BlockDriverState *bs, Error **errp) { const size_t window_size = 128 * 1024 * 1024; BDRVRawState *s = bs->opaque; @@ -2867,7 +2867,7 @@ static void check_cache_dropped(BlockDriverState *bs, Error **errp) page_size = sysconf(_SC_PAGESIZE); vec = g_malloc(DIV_ROUND_UP(window_size, page_size)); - end = raw_getlength(bs); + end = raw_co_getlength(bs); for (offset = 0; offset < end; offset += window_size) { void *new_window; @@ -3086,11 +3086,40 @@ static int coroutine_fn raw_co_pwrite_zeroes( return raw_do_pwrite_zeroes(bs, offset, bytes, flags, false); } -static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +raw_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { return 0; } +static ImageInfoSpecific *raw_get_specific_info(BlockDriverState *bs, + Error **errp) +{ + ImageInfoSpecificFile *file_info = g_new0(ImageInfoSpecificFile, 1); + ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1); + + *spec_info = (ImageInfoSpecific){ + .type = IMAGE_INFO_SPECIFIC_KIND_FILE, + .u.file.data = file_info, + }; + +#ifdef FS_IOC_FSGETXATTR + { + BDRVRawState *s = bs->opaque; + struct fsxattr attr; + int ret; + + ret = ioctl(s->fd, FS_IOC_FSGETXATTR, &attr); + if (!ret && attr.fsx_extsize != 0) { + file_info->has_extent_size_hint = true; + file_info->extent_size_hint = attr.fsx_extsize; + } + } +#endif + + return spec_info; +} + static BlockStatsSpecificFile get_blockstats_specific_file(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -3317,15 +3346,15 @@ BlockDriver bdrv_file = { .bdrv_co_copy_range_from = raw_co_copy_range_from, .bdrv_co_copy_range_to = raw_co_copy_range_to, .bdrv_refresh_limits = raw_refresh_limits, - .bdrv_io_plug = raw_aio_plug, - .bdrv_io_unplug = raw_aio_unplug, + .bdrv_co_io_plug = raw_co_io_plug, + .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, - .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, - .bdrv_get_info = raw_get_info, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_truncate = raw_co_truncate, + .bdrv_co_getlength = raw_co_getlength, + .bdrv_co_get_info = raw_co_get_info, + .bdrv_get_specific_info = raw_get_specific_info, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, .bdrv_get_specific_stats = raw_get_specific_stats, .bdrv_check_perm = raw_check_perm, .bdrv_set_perm = raw_set_perm, @@ -3689,15 +3718,15 @@ static BlockDriver bdrv_host_device = { .bdrv_co_copy_range_from = raw_co_copy_range_from, .bdrv_co_copy_range_to = raw_co_copy_range_to, .bdrv_refresh_limits = raw_refresh_limits, - .bdrv_io_plug = raw_aio_plug, - .bdrv_io_unplug = raw_aio_unplug, + .bdrv_co_io_plug = raw_co_io_plug, + .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, - .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, - .bdrv_get_info = raw_get_info, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_truncate = raw_co_truncate, + .bdrv_co_getlength = raw_co_getlength, + .bdrv_co_get_info = raw_co_get_info, + .bdrv_get_specific_info = raw_get_specific_info, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, .bdrv_get_specific_stats = hdev_get_specific_stats, .bdrv_check_perm = raw_check_perm, .bdrv_set_perm = raw_set_perm, @@ -3757,7 +3786,7 @@ out: return prio; } -static bool cdrom_is_inserted(BlockDriverState *bs) +static bool coroutine_fn cdrom_co_is_inserted(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int ret; @@ -3766,7 +3795,7 @@ static bool cdrom_is_inserted(BlockDriverState *bs) return ret == CDS_DISC_OK; } -static void cdrom_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn cdrom_co_eject(BlockDriverState *bs, bool eject_flag) { BDRVRawState *s = bs->opaque; @@ -3779,7 +3808,7 @@ static void cdrom_eject(BlockDriverState *bs, bool eject_flag) } } -static void cdrom_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn cdrom_co_lock_medium(BlockDriverState *bs, bool locked) { BDRVRawState *s = bs->opaque; @@ -3813,20 +3842,19 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_pwritev = raw_co_pwritev, .bdrv_co_flush_to_disk = raw_co_flush_to_disk, .bdrv_refresh_limits = raw_refresh_limits, - .bdrv_io_plug = raw_aio_plug, - .bdrv_io_unplug = raw_aio_unplug, + .bdrv_co_io_plug = raw_co_io_plug, + .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, - .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, - .has_variable_length = true, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_truncate = raw_co_truncate, + .bdrv_co_getlength = raw_co_getlength, + .has_variable_length = true, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, /* removable device support */ - .bdrv_is_inserted = cdrom_is_inserted, - .bdrv_eject = cdrom_eject, - .bdrv_lock_medium = cdrom_lock_medium, + .bdrv_co_is_inserted = cdrom_co_is_inserted, + .bdrv_co_eject = cdrom_co_eject, + .bdrv_co_lock_medium = cdrom_co_lock_medium, /* generic scsi device */ .bdrv_co_ioctl = hdev_co_ioctl, @@ -3883,12 +3911,12 @@ static int cdrom_reopen(BlockDriverState *bs) return 0; } -static bool cdrom_is_inserted(BlockDriverState *bs) +static bool coroutine_fn cdrom_co_is_inserted(BlockDriverState *bs) { - return raw_getlength(bs) > 0; + return raw_co_getlength(bs) > 0; } -static void cdrom_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn cdrom_co_eject(BlockDriverState *bs, bool eject_flag) { BDRVRawState *s = bs->opaque; @@ -3908,7 +3936,7 @@ static void cdrom_eject(BlockDriverState *bs, bool eject_flag) cdrom_reopen(bs); } -static void cdrom_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn cdrom_co_lock_medium(BlockDriverState *bs, bool locked) { BDRVRawState *s = bs->opaque; @@ -3943,20 +3971,19 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_co_pwritev = raw_co_pwritev, .bdrv_co_flush_to_disk = raw_co_flush_to_disk, .bdrv_refresh_limits = raw_refresh_limits, - .bdrv_io_plug = raw_aio_plug, - .bdrv_io_unplug = raw_aio_unplug, + .bdrv_co_io_plug = raw_co_io_plug, + .bdrv_co_io_unplug = raw_co_io_unplug, .bdrv_attach_aio_context = raw_aio_attach_aio_context, - .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, - .has_variable_length = true, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_truncate = raw_co_truncate, + .bdrv_co_getlength = raw_co_getlength, + .has_variable_length = true, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, /* removable device support */ - .bdrv_is_inserted = cdrom_is_inserted, - .bdrv_eject = cdrom_eject, - .bdrv_lock_medium = cdrom_lock_medium, + .bdrv_co_is_inserted = cdrom_co_is_inserted, + .bdrv_co_eject = cdrom_co_eject, + .bdrv_co_lock_medium = cdrom_co_lock_medium, }; #endif /* __FreeBSD__ */ diff --git a/block/file-win32.c b/block/file-win32.c index 12be9c3d0f..200d244116 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -526,7 +526,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, return 0; } -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; LARGE_INTEGER l; @@ -559,7 +559,7 @@ static int64_t raw_getlength(BlockDriverState *bs) return l.QuadPart; } -static int64_t raw_get_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_get_allocated_file_size(BlockDriverState *bs) { typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD * high); @@ -764,9 +764,9 @@ BlockDriver bdrv_file = { .bdrv_aio_flush = raw_aio_flush, .bdrv_co_truncate = raw_co_truncate, - .bdrv_getlength = raw_getlength, - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_getlength = raw_co_getlength, + .bdrv_co_get_allocated_file_size + = raw_co_get_allocated_file_size, .create_opts = &raw_create_opts, }; @@ -933,11 +933,9 @@ static BlockDriver bdrv_host_device = { .bdrv_detach_aio_context = raw_detach_aio_context, .bdrv_attach_aio_context = raw_attach_aio_context, - .bdrv_getlength = raw_getlength, - .has_variable_length = true, - - .bdrv_get_allocated_file_size - = raw_get_allocated_file_size, + .bdrv_co_getlength = raw_co_getlength, + .has_variable_length = true, + .bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size, }; static void bdrv_file_init(void) diff --git a/block/filter-compress.c b/block/filter-compress.c index 0ff8d28661..2e2a65966c 100644 --- a/block/filter-compress.c +++ b/block/filter-compress.c @@ -55,9 +55,9 @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags, } -static int64_t compress_getlength(BlockDriverState *bs) +static int64_t coroutine_fn compress_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } @@ -117,15 +117,17 @@ static void compress_refresh_limits(BlockDriverState *bs, Error **errp) } -static void compress_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn +compress_co_eject(BlockDriverState *bs, bool eject_flag) { - bdrv_eject(bs->file->bs, eject_flag); + bdrv_co_eject(bs->file->bs, eject_flag); } -static void compress_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn +compress_co_lock_medium(BlockDriverState *bs, bool locked) { - bdrv_lock_medium(bs->file->bs, locked); + bdrv_co_lock_medium(bs->file->bs, locked); } @@ -135,7 +137,7 @@ static BlockDriver bdrv_compress = { .bdrv_open = compress_open, .bdrv_child_perm = bdrv_default_perms, - .bdrv_getlength = compress_getlength, + .bdrv_co_getlength = compress_co_getlength, .bdrv_co_preadv_part = compress_co_preadv_part, .bdrv_co_pwritev_part = compress_co_pwritev_part, @@ -143,8 +145,8 @@ static BlockDriver bdrv_compress = { .bdrv_co_pdiscard = compress_co_pdiscard, .bdrv_refresh_limits = compress_refresh_limits, - .bdrv_eject = compress_eject, - .bdrv_lock_medium = compress_lock_medium, + .bdrv_co_eject = compress_co_eject, + .bdrv_co_lock_medium = compress_co_lock_medium, .has_variable_length = true, .is_filter = true, diff --git a/block/gluster.c b/block/gluster.c index 1ad19ae915..185a83e5e5 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1318,7 +1318,7 @@ static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs, } #endif -static int64_t qemu_gluster_getlength(BlockDriverState *bs) +static int64_t coroutine_fn qemu_gluster_co_getlength(BlockDriverState *bs) { BDRVGlusterState *s = bs->opaque; int64_t ret; @@ -1331,7 +1331,8 @@ static int64_t qemu_gluster_getlength(BlockDriverState *bs) } } -static int64_t qemu_gluster_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn +qemu_gluster_co_get_allocated_file_size(BlockDriverState *bs) { BDRVGlusterState *s = bs->opaque; struct stat st; @@ -1510,7 +1511,7 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs, * round up if necessary. */ if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) { - int64_t file_length = qemu_gluster_getlength(bs); + int64_t file_length = qemu_gluster_co_getlength(bs); if (file_length > 0) { /* Ignore errors, this is just a safeguard */ assert(hole == file_length); @@ -1559,8 +1560,8 @@ static BlockDriver bdrv_gluster = { .bdrv_close = qemu_gluster_close, .bdrv_co_create = qemu_gluster_co_create, .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_co_getlength = qemu_gluster_co_getlength, + .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, @@ -1588,8 +1589,8 @@ static BlockDriver bdrv_gluster_tcp = { .bdrv_close = qemu_gluster_close, .bdrv_co_create = qemu_gluster_co_create, .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_co_getlength = qemu_gluster_co_getlength, + .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, @@ -1617,8 +1618,8 @@ static BlockDriver bdrv_gluster_unix = { .bdrv_close = qemu_gluster_close, .bdrv_co_create = qemu_gluster_co_create, .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_co_getlength = qemu_gluster_co_getlength, + .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, @@ -1652,8 +1653,8 @@ static BlockDriver bdrv_gluster_rdma = { .bdrv_close = qemu_gluster_close, .bdrv_co_create = qemu_gluster_co_create, .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_co_getlength = qemu_gluster_co_getlength, + .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size, .bdrv_co_truncate = qemu_gluster_co_truncate, .bdrv_co_readv = qemu_gluster_co_readv, .bdrv_co_writev = qemu_gluster_co_writev, diff --git a/block/io.c b/block/io.c index a09a19f7a7..2dc0c13e41 100644 --- a/block/io.c +++ b/block/io.c @@ -722,14 +722,14 @@ BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs) /** * Round a region to cluster boundaries */ -void bdrv_round_to_clusters(BlockDriverState *bs, +void coroutine_fn bdrv_round_to_clusters(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *cluster_offset, int64_t *cluster_bytes) { BlockDriverInfo bdi; IO_CODE(); - if (bdrv_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) { + if (bdrv_co_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) { *cluster_offset = offset; *cluster_bytes = bytes; } else { @@ -739,12 +739,12 @@ void bdrv_round_to_clusters(BlockDriverState *bs, } } -static int bdrv_get_cluster_size(BlockDriverState *bs) +static coroutine_fn int bdrv_get_cluster_size(BlockDriverState *bs) { BlockDriverInfo bdi; int ret; - ret = bdrv_get_info(bs, &bdi); + ret = bdrv_co_get_info(bs, &bdi); if (ret < 0 || bdi.cluster_size == 0) { return bs->bl.request_alignment; } else { @@ -1251,7 +1251,7 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, goto err; } - bdrv_debug_event(bs, BLKDBG_COR_WRITE); + bdrv_co_debug_event(bs, BLKDBG_COR_WRITE); if (drv->bdrv_co_pwrite_zeroes && buffer_is_zero(bounce_buffer, pnum)) { /* FIXME: Should we (perhaps conditionally) be setting @@ -1496,10 +1496,10 @@ static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, qemu_iovec_init_buf(&local_qiov, pad->buf, bytes); if (pad->head) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD); } if (pad->merge_reads && pad->tail) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); } ret = bdrv_aligned_preadv(child, req, req->overlap_offset, bytes, align, &local_qiov, 0, 0); @@ -1507,10 +1507,10 @@ static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, return ret; } if (pad->head) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); } if (pad->merge_reads && pad->tail) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); } if (pad->merge_reads) { @@ -1521,7 +1521,7 @@ static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, if (pad->tail) { qemu_iovec_init_buf(&local_qiov, pad->tail_buf, align); - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL); ret = bdrv_aligned_preadv( child, req, req->overlap_offset + req->overlap_bytes - align, @@ -1529,7 +1529,7 @@ static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, if (ret < 0) { return ret; } - bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); } zero_mem: @@ -1622,7 +1622,7 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, trace_bdrv_co_preadv_part(bs, offset, bytes, flags); - if (!bdrv_is_inserted(bs)) { + if (!bdrv_co_is_inserted(bs)) { return -ENOMEDIUM; } @@ -1931,16 +1931,16 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, if (ret < 0) { /* Do nothing, write notifier decided to fail this request */ } else if (flags & BDRV_REQ_ZERO_WRITE) { - bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_ZERO); ret = bdrv_co_do_pwrite_zeroes(bs, offset, bytes, flags); } else if (flags & BDRV_REQ_WRITE_COMPRESSED) { ret = bdrv_driver_pwritev_compressed(bs, offset, bytes, qiov, qiov_offset); } else if (bytes <= max_transfer) { - bdrv_debug_event(bs, BLKDBG_PWRITEV); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV); ret = bdrv_driver_pwritev(bs, offset, bytes, qiov, qiov_offset, flags); } else { - bdrv_debug_event(bs, BLKDBG_PWRITEV); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV); while (bytes_remaining) { int num = MIN(bytes_remaining, max_transfer); int local_flags = flags; @@ -1963,7 +1963,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, bytes_remaining -= num; } } - bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE); + bdrv_co_debug_event(bs, BLKDBG_PWRITEV_DONE); if (ret >= 0) { ret = 0; @@ -2067,7 +2067,7 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, trace_bdrv_co_pwritev_part(child->bs, offset, bytes, flags); - if (!bdrv_is_inserted(bs)) { + if (!bdrv_co_is_inserted(bs)) { return -ENOMEDIUM; } @@ -2720,8 +2720,8 @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) bdrv_inc_in_flight(bs); - if (drv->bdrv_load_vmstate) { - ret = drv->bdrv_load_vmstate(bs, qiov, pos); + if (drv->bdrv_co_load_vmstate) { + ret = drv->bdrv_co_load_vmstate(bs, qiov, pos); } else if (child_bs) { ret = bdrv_co_readv_vmstate(child_bs, qiov, pos); } else { @@ -2753,8 +2753,8 @@ bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) bdrv_inc_in_flight(bs); - if (drv->bdrv_save_vmstate) { - ret = drv->bdrv_save_vmstate(bs, qiov, pos); + if (drv->bdrv_co_save_vmstate) { + ret = drv->bdrv_co_save_vmstate(bs, qiov, pos); } else if (child_bs) { ret = bdrv_co_writev_vmstate(child_bs, qiov, pos); } else { @@ -2835,7 +2835,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) bdrv_inc_in_flight(bs); - if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs) || + if (!bdrv_co_is_inserted(bs) || bdrv_is_read_only(bs) || bdrv_is_sg(bs)) { goto early_exit; } @@ -2959,7 +2959,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, BlockDriverState *bs = child->bs; IO_CODE(); - if (!bs || !bs->drv || !bdrv_is_inserted(bs)) { + if (!bs || !bs->drv || !bdrv_co_is_inserted(bs)) { return -ENOMEDIUM; } @@ -3137,24 +3137,24 @@ void *qemu_try_blockalign0(BlockDriverState *bs, size_t size) return mem; } -void bdrv_io_plug(BlockDriverState *bs) +void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs) { BdrvChild *child; IO_CODE(); QLIST_FOREACH(child, &bs->children, next) { - bdrv_io_plug(child->bs); + bdrv_co_io_plug(child->bs); } if (qatomic_fetch_inc(&bs->io_plugged) == 0) { BlockDriver *drv = bs->drv; - if (drv && drv->bdrv_io_plug) { - drv->bdrv_io_plug(bs); + if (drv && drv->bdrv_co_io_plug) { + drv->bdrv_co_io_plug(bs); } } } -void bdrv_io_unplug(BlockDriverState *bs) +void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs) { BdrvChild *child; IO_CODE(); @@ -3162,13 +3162,13 @@ void bdrv_io_unplug(BlockDriverState *bs) assert(bs->io_plugged); if (qatomic_fetch_dec(&bs->io_plugged) == 1) { BlockDriver *drv = bs->drv; - if (drv && drv->bdrv_io_unplug) { - drv->bdrv_io_unplug(bs); + if (drv && drv->bdrv_co_io_unplug) { + drv->bdrv_co_io_unplug(bs); } } QLIST_FOREACH(child, &bs->children, next) { - bdrv_io_unplug(child->bs); + bdrv_co_io_unplug(child->bs); } } @@ -3241,7 +3241,7 @@ static int coroutine_fn bdrv_co_copy_range_internal( assert(!(read_flags & BDRV_REQ_NO_WAIT)); assert(!(write_flags & BDRV_REQ_NO_WAIT)); - if (!dst || !dst->bs || !bdrv_is_inserted(dst->bs)) { + if (!dst || !dst->bs || !bdrv_co_is_inserted(dst->bs)) { return -ENOMEDIUM; } ret = bdrv_check_request32(dst_offset, bytes, NULL, 0); @@ -3252,7 +3252,7 @@ static int coroutine_fn bdrv_co_copy_range_internal( return bdrv_co_pwrite_zeroes(dst, dst_offset, bytes, write_flags); } - if (!src || !src->bs || !bdrv_is_inserted(src->bs)) { + if (!src || !src->bs || !bdrv_co_is_inserted(src->bs)) { return -ENOMEDIUM; } ret = bdrv_check_request32(src_offset, bytes, NULL, 0); @@ -3444,7 +3444,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, if (new_bytes && backing) { int64_t backing_len; - backing_len = bdrv_getlength(backing->bs); + backing_len = bdrv_co_getlength(backing->bs); if (backing_len < 0) { ret = backing_len; error_setg_errno(errp, -ret, "Could not get backing file size"); @@ -3474,15 +3474,17 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, goto out; } - ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); + ret = bdrv_co_refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); if (ret < 0) { error_setg_errno(errp, -ret, "Could not refresh total sector count"); } else { offset = bs->total_sectors * BDRV_SECTOR_SIZE; } - /* It's possible that truncation succeeded but refresh_total_sectors + /* + * It's possible that truncation succeeded but bdrv_refresh_total_sectors * failed, but the latter doesn't affect how we should finish the request. - * Pass 0 as the last parameter so that dirty bitmaps etc. are handled. */ + * Pass 0 as the last parameter so that dirty bitmaps etc. are handled. + */ bdrv_co_write_req_finish(child, offset - new_bytes, new_bytes, &req, 0); out: diff --git a/block/iscsi.c b/block/iscsi.c index c16c592042..b3e10f40b6 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1127,8 +1127,8 @@ static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs, #endif -static int64_t -iscsi_getlength(BlockDriverState *bs) +static int64_t coroutine_fn +iscsi_co_getlength(BlockDriverState *bs) { IscsiLun *iscsilun = bs->opaque; int64_t len; @@ -2155,7 +2155,7 @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, return -EIO; } - cur_length = iscsi_getlength(bs); + cur_length = iscsi_co_getlength(bs); if (offset != cur_length && exact) { error_setg(errp, "Cannot resize iSCSI devices"); return -ENOTSUP; @@ -2171,7 +2171,8 @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, return 0; } -static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +iscsi_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { IscsiLun *iscsilun = bs->opaque; bdi->cluster_size = iscsilun->cluster_size; @@ -2434,8 +2435,8 @@ static BlockDriver bdrv_iscsi = { .bdrv_reopen_commit = iscsi_reopen_commit, .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, - .bdrv_getlength = iscsi_getlength, - .bdrv_get_info = iscsi_get_info, + .bdrv_co_getlength = iscsi_co_getlength, + .bdrv_co_get_info = iscsi_co_get_info, .bdrv_co_truncate = iscsi_co_truncate, .bdrv_refresh_limits = iscsi_refresh_limits, @@ -2473,8 +2474,8 @@ static BlockDriver bdrv_iser = { .bdrv_reopen_commit = iscsi_reopen_commit, .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, - .bdrv_getlength = iscsi_getlength, - .bdrv_get_info = iscsi_get_info, + .bdrv_co_getlength = iscsi_co_getlength, + .bdrv_co_get_info = iscsi_co_get_info, .bdrv_co_truncate = iscsi_co_truncate, .bdrv_refresh_limits = iscsi_refresh_limits, diff --git a/block/meson.build b/block/meson.build index 90011a2805..3662852dc2 100644 --- a/block/meson.build +++ b/block/meson.build @@ -139,6 +139,7 @@ block_gen_c = custom_target('block-gen.c', input: files( '../include/block/block-io.h', '../include/block/dirty-bitmap.h', + '../include/block/block_int-io.h', '../include/block/block-global-state.h', '../include/sysemu/block-backend-io.h', 'coroutines.h' diff --git a/block/mirror.c b/block/mirror.c index 634815d78d..ab326b67c9 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -910,13 +910,13 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) goto immediate_exit; } - s->bdev_length = bdrv_getlength(bs); + s->bdev_length = bdrv_co_getlength(bs); if (s->bdev_length < 0) { ret = s->bdev_length; goto immediate_exit; } - target_length = blk_getlength(s->target); + target_length = blk_co_getlength(s->target); if (target_length < 0) { ret = target_length; goto immediate_exit; @@ -957,7 +957,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) */ bdrv_get_backing_filename(target_bs, backing_filename, sizeof(backing_filename)); - if (!bdrv_get_info(target_bs, &bdi) && bdi.cluster_size) { + if (!bdrv_co_get_info(target_bs, &bdi) && bdi.cluster_size) { s->target_cluster_size = bdi.cluster_size; } else { s->target_cluster_size = BDRV_SECTOR_SIZE; diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index 0ff7c84039..4dc07f71d4 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -725,7 +725,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, monitor_printf(mon, "\nImages:\n"); image_info = inserted->image; while (1) { - bdrv_image_info_dump(image_info); + bdrv_node_info_dump(qapi_ImageInfo_base(image_info), 0, false); if (image_info->backing_image) { image_info = image_info->backing_image; } else { diff --git a/block/nbd.c b/block/nbd.c index 7d485c86d2..bf2894ad5c 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1992,7 +1992,7 @@ static int coroutine_fn nbd_co_truncate(BlockDriverState *bs, int64_t offset, return 0; } -static int64_t nbd_getlength(BlockDriverState *bs) +static int64_t coroutine_fn nbd_co_getlength(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; @@ -2124,7 +2124,7 @@ static BlockDriver bdrv_nbd = { .bdrv_co_pdiscard = nbd_client_co_pdiscard, .bdrv_refresh_limits = nbd_refresh_limits, .bdrv_co_truncate = nbd_co_truncate, - .bdrv_getlength = nbd_getlength, + .bdrv_co_getlength = nbd_co_getlength, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, .bdrv_dirname = nbd_dirname, @@ -2152,7 +2152,7 @@ static BlockDriver bdrv_nbd_tcp = { .bdrv_co_pdiscard = nbd_client_co_pdiscard, .bdrv_refresh_limits = nbd_refresh_limits, .bdrv_co_truncate = nbd_co_truncate, - .bdrv_getlength = nbd_getlength, + .bdrv_co_getlength = nbd_co_getlength, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, .bdrv_dirname = nbd_dirname, @@ -2180,7 +2180,7 @@ static BlockDriver bdrv_nbd_unix = { .bdrv_co_pdiscard = nbd_client_co_pdiscard, .bdrv_refresh_limits = nbd_refresh_limits, .bdrv_co_truncate = nbd_co_truncate, - .bdrv_getlength = nbd_getlength, + .bdrv_co_getlength = nbd_co_getlength, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, .bdrv_dirname = nbd_dirname, diff --git a/block/nfs.c b/block/nfs.c index 5e288dfc83..351dc6ec8d 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -732,7 +732,7 @@ nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data, bdrv_wakeup(task->bs); } -static int64_t nfs_get_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn nfs_co_get_allocated_file_size(BlockDriverState *bs) { NFSClient *client = bs->opaque; NFSRPC task = {0}; @@ -885,7 +885,7 @@ static BlockDriver bdrv_nfs = { .bdrv_has_zero_init = nfs_has_zero_init, /* libnfs does not provide the allocated filesize of a file on win32. */ #if !defined(_WIN32) - .bdrv_get_allocated_file_size = nfs_get_allocated_file_size, + .bdrv_co_get_allocated_file_size = nfs_co_get_allocated_file_size, #endif .bdrv_co_truncate = nfs_file_co_truncate, diff --git a/block/null.c b/block/null.c index 306e605fa1..4808704ffd 100644 --- a/block/null.c +++ b/block/null.c @@ -100,7 +100,7 @@ static int null_file_open(BlockDriverState *bs, QDict *options, int flags, return ret; } -static int64_t null_getlength(BlockDriverState *bs) +static int64_t coroutine_fn null_co_getlength(BlockDriverState *bs) { BDRVNullState *s = bs->opaque; return s->length; @@ -265,7 +265,8 @@ static void null_refresh_filename(BlockDriverState *bs) bs->drv->format_name); } -static int64_t null_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn +null_co_get_allocated_file_size(BlockDriverState *bs) { return 0; } @@ -284,8 +285,8 @@ static BlockDriver bdrv_null_co = { .bdrv_file_open = null_file_open, .bdrv_parse_filename = null_co_parse_filename, - .bdrv_getlength = null_getlength, - .bdrv_get_allocated_file_size = null_allocated_file_size, + .bdrv_co_getlength = null_co_getlength, + .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size, .bdrv_co_preadv = null_co_preadv, .bdrv_co_pwritev = null_co_pwritev, @@ -305,8 +306,8 @@ static BlockDriver bdrv_null_aio = { .bdrv_file_open = null_file_open, .bdrv_parse_filename = null_aio_parse_filename, - .bdrv_getlength = null_getlength, - .bdrv_get_allocated_file_size = null_allocated_file_size, + .bdrv_co_getlength = null_co_getlength, + .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size, .bdrv_aio_preadv = null_aio_preadv, .bdrv_aio_pwritev = null_aio_pwritev, diff --git a/block/nvme.c b/block/nvme.c index 1f1367640a..5b744c2bda 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -1002,7 +1002,7 @@ fail: return ret; } -static int64_t nvme_getlength(BlockDriverState *bs) +static int64_t coroutine_fn nvme_co_getlength(BlockDriverState *bs) { BDRVNVMeState *s = bs->opaque; return s->nsze << s->blkshift; @@ -1486,7 +1486,7 @@ static int coroutine_fn nvme_co_truncate(BlockDriverState *bs, int64_t offset, return -ENOTSUP; } - cur_length = nvme_getlength(bs); + cur_length = nvme_co_getlength(bs); if (offset != cur_length && exact) { error_setg(errp, "Cannot resize NVMe devices"); return -ENOTSUP; @@ -1567,14 +1567,14 @@ static void nvme_attach_aio_context(BlockDriverState *bs, } } -static void nvme_aio_plug(BlockDriverState *bs) +static void coroutine_fn nvme_co_io_plug(BlockDriverState *bs) { BDRVNVMeState *s = bs->opaque; assert(!s->plugged); s->plugged = true; } -static void nvme_aio_unplug(BlockDriverState *bs) +static void coroutine_fn nvme_co_io_unplug(BlockDriverState *bs) { BDRVNVMeState *s = bs->opaque; assert(s->plugged); @@ -1643,7 +1643,7 @@ static BlockDriver bdrv_nvme = { .bdrv_parse_filename = nvme_parse_filename, .bdrv_file_open = nvme_file_open, .bdrv_close = nvme_close, - .bdrv_getlength = nvme_getlength, + .bdrv_co_getlength = nvme_co_getlength, .bdrv_probe_blocksizes = nvme_probe_blocksizes, .bdrv_co_truncate = nvme_co_truncate, @@ -1664,8 +1664,8 @@ static BlockDriver bdrv_nvme = { .bdrv_detach_aio_context = nvme_detach_aio_context, .bdrv_attach_aio_context = nvme_attach_aio_context, - .bdrv_io_plug = nvme_aio_plug, - .bdrv_io_unplug = nvme_aio_unplug, + .bdrv_co_io_plug = nvme_co_io_plug, + .bdrv_co_io_unplug = nvme_co_io_unplug, .bdrv_register_buf = nvme_register_buf, .bdrv_unregister_buf = nvme_unregister_buf, diff --git a/block/preallocate.c b/block/preallocate.c index a51fc08515..c0dcf8c346 100644 --- a/block/preallocate.c +++ b/block/preallocate.c @@ -287,7 +287,7 @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset, } if (s->data_end < 0) { - s->data_end = bdrv_getlength(bs->file->bs); + s->data_end = bdrv_co_getlength(bs->file->bs); if (s->data_end < 0) { return false; } @@ -309,7 +309,7 @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset, } if (s->file_end < 0) { - s->file_end = bdrv_getlength(bs->file->bs); + s->file_end = bdrv_co_getlength(bs->file->bs); if (s->file_end < 0) { return false; } @@ -381,7 +381,7 @@ preallocate_co_truncate(BlockDriverState *bs, int64_t offset, if (s->data_end >= 0 && offset > s->data_end) { if (s->file_end < 0) { - s->file_end = bdrv_getlength(bs->file->bs); + s->file_end = bdrv_co_getlength(bs->file->bs); if (s->file_end < 0) { error_setg(errp, "failed to get file length"); return s->file_end; @@ -442,7 +442,7 @@ static int coroutine_fn preallocate_co_flush(BlockDriverState *bs) return bdrv_co_flush(bs->file->bs); } -static int64_t preallocate_getlength(BlockDriverState *bs) +static int64_t coroutine_fn preallocate_co_getlength(BlockDriverState *bs) { int64_t ret; BDRVPreallocateState *s = bs->opaque; @@ -451,7 +451,7 @@ static int64_t preallocate_getlength(BlockDriverState *bs) return s->data_end; } - ret = bdrv_getlength(bs->file->bs); + ret = bdrv_co_getlength(bs->file->bs); if (has_prealloc_perms(bs)) { s->file_end = s->zero_start = s->data_end = ret; @@ -537,9 +537,9 @@ BlockDriver bdrv_preallocate_filter = { .format_name = "preallocate", .instance_size = sizeof(BDRVPreallocateState), - .bdrv_getlength = preallocate_getlength, - .bdrv_open = preallocate_open, - .bdrv_close = preallocate_close, + .bdrv_co_getlength = preallocate_co_getlength, + .bdrv_open = preallocate_open, + .bdrv_close = preallocate_close, .bdrv_reopen_prepare = preallocate_reopen_prepare, .bdrv_reopen_commit = preallocate_reopen_commit, diff --git a/block/qapi.c b/block/qapi.c index 9b4da12966..d52f1ab614 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -48,8 +48,10 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, Error **errp) { ImageInfo **p_image_info; + ImageInfo *backing_info; BlockDriverState *bs0, *backing; BlockDeviceInfo *info; + ERRP_GUARD(); if (!bs->drv) { error_setg(errp, "Block device %s is ejected", bs->node_name); @@ -147,37 +149,21 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, bs0 = bs; p_image_info = &info->image; info->backing_file_depth = 0; - while (1) { - Error *local_err = NULL; - bdrv_query_image_info(bs0, p_image_info, &local_err); - if (local_err) { - error_propagate(errp, local_err); - qapi_free_BlockDeviceInfo(info); - return NULL; - } - /* stop gathering data for flat output */ - if (flat) { - break; - } - - if (bs0->drv && bdrv_filter_or_cow_child(bs0)) { - /* - * Put any filtered child here (for backwards compatibility to when - * we put bs0->backing here, which might be any filtered child). - */ - info->backing_file_depth++; - bs0 = bdrv_filter_or_cow_bs(bs0); - p_image_info = &((*p_image_info)->backing_image); - } else { - break; - } + /* + * Skip automatically inserted nodes that the user isn't aware of for + * query-block (blk != NULL), but not for query-named-block-nodes + */ + bdrv_query_image_info(bs0, p_image_info, flat, blk != NULL, errp); + if (*errp) { + qapi_free_BlockDeviceInfo(info); + return NULL; + } - /* Skip automatically inserted nodes that the user isn't aware of for - * query-block (blk != NULL), but not for query-named-block-nodes */ - if (blk) { - bs0 = bdrv_skip_implicit_filters(bs0); - } + backing_info = info->image->backing_image; + while (backing_info) { + info->backing_file_depth++; + backing_info = backing_info->backing_image; } return info; @@ -238,30 +224,18 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs, } /** - * bdrv_query_image_info: - * @bs: block device to examine - * @p_info: location to store image information - * @errp: location to store error information - * - * Store "flat" image information in @p_info. - * - * "Flat" means it does *not* query backing image information, - * i.e. (*pinfo)->has_backing_image will be set to false and - * (*pinfo)->backing_image to NULL even when the image does in fact have - * a backing image. - * - * @p_info will be set only on success. On error, store error in @errp. + * Helper function for other query info functions. Store information about @bs + * in @info, setting @errp on error. */ -void bdrv_query_image_info(BlockDriverState *bs, - ImageInfo **p_info, - Error **errp) +static void bdrv_do_query_node_info(BlockDriverState *bs, + BlockNodeInfo *info, + Error **errp) { int64_t size; const char *backing_filename; BlockDriverInfo bdi; int ret; Error *err = NULL; - ImageInfo *info; aio_context_acquire(bdrv_get_aio_context(bs)); @@ -274,7 +248,6 @@ void bdrv_query_image_info(BlockDriverState *bs, bdrv_refresh_filename(bs); - info = g_new0(ImageInfo, 1); info->filename = g_strdup(bs->filename); info->format = g_strdup(bdrv_get_format_name(bs)); info->virtual_size = size; @@ -295,7 +268,6 @@ void bdrv_query_image_info(BlockDriverState *bs, info->format_specific = bdrv_get_specific_info(bs, &err); if (err) { error_propagate(errp, err); - qapi_free_ImageInfo(info); goto out; } backing_filename = bs->backing_file; @@ -331,16 +303,154 @@ void bdrv_query_image_info(BlockDriverState *bs, break; default: error_propagate(errp, err); - qapi_free_ImageInfo(info); goto out; } - *p_info = info; - out: aio_context_release(bdrv_get_aio_context(bs)); } +/** + * bdrv_query_block_node_info: + * @bs: block node to examine + * @p_info: location to store node information + * @errp: location to store error information + * + * Store image information about @bs in @p_info. + * + * @p_info will be set only on success. On error, store error in @errp. + */ +void bdrv_query_block_node_info(BlockDriverState *bs, + BlockNodeInfo **p_info, + Error **errp) +{ + BlockNodeInfo *info; + ERRP_GUARD(); + + info = g_new0(BlockNodeInfo, 1); + bdrv_do_query_node_info(bs, info, errp); + if (*errp) { + qapi_free_BlockNodeInfo(info); + return; + } + + *p_info = info; +} + +/** + * bdrv_query_image_info: + * @bs: block node to examine + * @p_info: location to store image information + * @flat: skip backing node information + * @skip_implicit_filters: skip implicit filters in the backing chain + * @errp: location to store error information + * + * Store image information in @p_info, potentially recursively covering the + * backing chain. + * + * If @flat is true, do not query backing image information, i.e. + * (*p_info)->has_backing_image will be set to false and + * (*p_info)->backing_image to NULL even when the image does in fact have a + * backing image. + * + * If @skip_implicit_filters is true, implicit filter nodes in the backing chain + * will be skipped when querying backing image information. + * (@skip_implicit_filters is ignored when @flat is true.) + * + * @p_info will be set only on success. On error, store error in @errp. + */ +void bdrv_query_image_info(BlockDriverState *bs, + ImageInfo **p_info, + bool flat, + bool skip_implicit_filters, + Error **errp) +{ + ImageInfo *info; + ERRP_GUARD(); + + info = g_new0(ImageInfo, 1); + bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), errp); + if (*errp) { + goto fail; + } + + if (!flat) { + BlockDriverState *backing; + + /* + * Use any filtered child here (for backwards compatibility to when + * we always took bs->backing, which might be any filtered child). + */ + backing = bdrv_filter_or_cow_bs(bs); + if (skip_implicit_filters) { + backing = bdrv_skip_implicit_filters(backing); + } + + if (backing) { + bdrv_query_image_info(backing, &info->backing_image, false, + skip_implicit_filters, errp); + if (*errp) { + goto fail; + } + } + } + + *p_info = info; + return; + +fail: + assert(*errp); + qapi_free_ImageInfo(info); +} + +/** + * bdrv_query_block_graph_info: + * @bs: root node to start from + * @p_info: location to store image information + * @errp: location to store error information + * + * Store image information about the graph starting from @bs in @p_info. + * + * @p_info will be set only on success. On error, store error in @errp. + */ +void bdrv_query_block_graph_info(BlockDriverState *bs, + BlockGraphInfo **p_info, + Error **errp) +{ + BlockGraphInfo *info; + BlockChildInfoList **children_list_tail; + BdrvChild *c; + ERRP_GUARD(); + + info = g_new0(BlockGraphInfo, 1); + bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), errp); + if (*errp) { + goto fail; + } + + children_list_tail = &info->children; + + QLIST_FOREACH(c, &bs->children, next) { + BlockChildInfo *c_info; + + c_info = g_new0(BlockChildInfo, 1); + QAPI_LIST_APPEND(children_list_tail, c_info); + + c_info->name = g_strdup(c->name); + bdrv_query_block_graph_info(c->bs, &c_info->info, errp); + if (*errp) { + goto fail; + } + } + + *p_info = info; + return; + +fail: + assert(*errp != NULL); + qapi_free_BlockGraphInfo(info); +} + /* @p_info will be set only on success. */ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, Error **errp) @@ -760,7 +870,36 @@ static void dump_qdict(int indentation, QDict *dict) } } -void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec) +/* + * Return whether dumping the given QObject with dump_qobject() would + * yield an empty dump, i.e. not print anything. + */ +static bool qobject_is_empty_dump(const QObject *obj) +{ + switch (qobject_type(obj)) { + case QTYPE_QNUM: + case QTYPE_QSTRING: + case QTYPE_QBOOL: + return false; + + case QTYPE_QDICT: + return qdict_size(qobject_to(QDict, obj)) == 0; + + case QTYPE_QLIST: + return qlist_empty(qobject_to(QList, obj)); + + default: + abort(); + } +} + +/** + * Dumps the given ImageInfoSpecific object in a human-readable form, + * prepending an optional prefix if the dump is not empty. + */ +void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, + const char *prefix, + int indentation) { QObject *obj, *data; Visitor *v = qobject_output_visitor_new(&obj); @@ -768,45 +907,78 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec) visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort); visit_complete(v, &obj); data = qdict_get(qobject_to(QDict, obj), "data"); - dump_qobject(1, data); + if (!qobject_is_empty_dump(data)) { + if (prefix) { + qemu_printf("%*s%s", indentation * 4, "", prefix); + } + dump_qobject(indentation + 1, data); + } qobject_unref(obj); visit_free(v); } -void bdrv_image_info_dump(ImageInfo *info) +/** + * Print the given @info object in human-readable form. Every field is indented + * using the given @indentation (four spaces per indentation level). + * + * When using this to print a whole block graph, @protocol can be set to true to + * signify that the given information is associated with a protocol node, i.e. + * just data storage for an image, such that the data it presents is not really + * a full VM disk. If so, several fields change name: For example, "virtual + * size" is printed as "file length". + * (Consider a qcow2 image, which is represented by a qcow2 node and a file + * node. Printing a "virtual size" for the file node does not make sense, + * because without the qcow2 node, it is not really a guest disk, so it does not + * have a "virtual size". Therefore, we call it "file length" instead.) + * + * @protocol is ignored when @indentation is 0, because we take that to mean + * that the associated node is the root node in the queried block graph, and + * thus is always to be interpreted as a standalone guest disk. + */ +void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol) { char *size_buf, *dsize_buf; + g_autofree char *ind_s = g_strdup_printf("%*s", indentation * 4, ""); + + if (indentation == 0) { + /* Top level, consider this a normal image */ + protocol = false; + } + if (!info->has_actual_size) { dsize_buf = g_strdup("unavailable"); } else { dsize_buf = size_to_str(info->actual_size); } size_buf = size_to_str(info->virtual_size); - qemu_printf("image: %s\n" - "file format: %s\n" - "virtual size: %s (%" PRId64 " bytes)\n" - "disk size: %s\n", - info->filename, info->format, size_buf, - info->virtual_size, - dsize_buf); + qemu_printf("%s%s: %s\n" + "%s%s: %s\n" + "%s%s: %s (%" PRId64 " bytes)\n" + "%sdisk size: %s\n", + ind_s, protocol ? "filename" : "image", info->filename, + ind_s, protocol ? "protocol type" : "file format", + info->format, + ind_s, protocol ? "file length" : "virtual size", + size_buf, info->virtual_size, + ind_s, dsize_buf); g_free(size_buf); g_free(dsize_buf); if (info->has_encrypted && info->encrypted) { - qemu_printf("encrypted: yes\n"); + qemu_printf("%sencrypted: yes\n", ind_s); } if (info->has_cluster_size) { - qemu_printf("cluster_size: %" PRId64 "\n", - info->cluster_size); + qemu_printf("%scluster_size: %" PRId64 "\n", + ind_s, info->cluster_size); } if (info->has_dirty_flag && info->dirty_flag) { - qemu_printf("cleanly shut down: no\n"); + qemu_printf("%scleanly shut down: no\n", ind_s); } if (info->backing_filename) { - qemu_printf("backing file: %s", info->backing_filename); + qemu_printf("%sbacking file: %s", ind_s, info->backing_filename); if (!info->full_backing_filename) { qemu_printf(" (cannot determine actual path)"); } else if (strcmp(info->backing_filename, @@ -815,15 +987,16 @@ void bdrv_image_info_dump(ImageInfo *info) } qemu_printf("\n"); if (info->backing_filename_format) { - qemu_printf("backing file format: %s\n", - info->backing_filename_format); + qemu_printf("%sbacking file format: %s\n", + ind_s, info->backing_filename_format); } } if (info->has_snapshots) { SnapshotInfoList *elem; - qemu_printf("Snapshot list:\n"); + qemu_printf("%sSnapshot list:\n", ind_s); + qemu_printf("%s", ind_s); bdrv_snapshot_dump(NULL); qemu_printf("\n"); @@ -843,13 +1016,15 @@ void bdrv_image_info_dump(ImageInfo *info) pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id); pstrcpy(sn.name, sizeof(sn.name), elem->value->name); + qemu_printf("%s", ind_s); bdrv_snapshot_dump(&sn); qemu_printf("\n"); } } if (info->format_specific) { - qemu_printf("Format specific information:\n"); - bdrv_image_info_specific_dump(info->format_specific); + bdrv_image_info_specific_dump(info->format_specific, + "Format specific information:\n", + indentation); } } diff --git a/block/qcow.c b/block/qcow.c index 5d99f00411..5f0801f545 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -1129,7 +1129,8 @@ fail: return ret; } -static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +qcow_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQcowState *s = bs->opaque; bdi->cluster_size = s->cluster_size; @@ -1198,7 +1199,7 @@ static BlockDriver bdrv_qcow = { .bdrv_make_empty = qcow_make_empty, .bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed, - .bdrv_get_info = qcow_get_info, + .bdrv_co_get_info = qcow_co_get_info, .create_opts = &qcow_create_opts, .strong_runtime_opts = qcow_strong_runtime_opts, diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 385260a1b5..5f456a2785 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -117,7 +117,7 @@ static int update_header_sync(BlockDriverState *bs) return bdrv_flush(bs->file->bs); } -static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size) +static inline void bitmap_table_bswap_be(uint64_t *bitmap_table, size_t size) { size_t i; @@ -1403,9 +1403,10 @@ static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) goto fail; } - bitmap_table_to_be(tb, tb_size); + bitmap_table_bswap_be(tb, tb_size); ret = bdrv_pwrite(bs->file, tb_offset, tb_size * sizeof(tb[0]), tb, 0); if (ret < 0) { + bitmap_table_bswap_be(tb, tb_size); error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file", bm_name); goto fail; diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 5ffbefee2e..b092f89da9 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -3720,7 +3720,7 @@ int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs) return file_length; } - real_allocation = bdrv_get_allocated_file_size(bs->file->bs); + real_allocation = bdrv_co_get_allocated_file_size(bs->file->bs); if (real_allocation < 0) { return real_allocation; } diff --git a/block/qcow2.c b/block/qcow2.c index 2e9c57e269..21aa4c6b7a 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5143,7 +5143,8 @@ err: return NULL; } -static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +qcow2_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQcow2State *s = bs->opaque; bdi->cluster_size = s->cluster_size; @@ -5286,8 +5287,8 @@ static int64_t qcow2_check_vmstate_request(BlockDriverState *bs, return pos; } -static coroutine_fn int qcow2_save_vmstate(BlockDriverState *bs, - QEMUIOVector *qiov, int64_t pos) +static coroutine_fn int qcow2_co_save_vmstate(BlockDriverState *bs, + QEMUIOVector *qiov, int64_t pos) { int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); if (offset < 0) { @@ -5298,8 +5299,8 @@ static coroutine_fn int qcow2_save_vmstate(BlockDriverState *bs, return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0); } -static coroutine_fn int qcow2_load_vmstate(BlockDriverState *bs, - QEMUIOVector *qiov, int64_t pos) +static coroutine_fn int qcow2_co_load_vmstate(BlockDriverState *bs, + QEMUIOVector *qiov, int64_t pos) { int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); if (offset < 0) { @@ -6077,11 +6078,11 @@ BlockDriver bdrv_qcow2 = { .bdrv_snapshot_list = qcow2_snapshot_list, .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp, .bdrv_measure = qcow2_measure, - .bdrv_get_info = qcow2_get_info, + .bdrv_co_get_info = qcow2_co_get_info, .bdrv_get_specific_info = qcow2_get_specific_info, - .bdrv_save_vmstate = qcow2_save_vmstate, - .bdrv_load_vmstate = qcow2_load_vmstate, + .bdrv_co_save_vmstate = qcow2_co_save_vmstate, + .bdrv_co_load_vmstate = qcow2_co_load_vmstate, .is_format = true, .supports_backing = true, diff --git a/block/qed.c b/block/qed.c index faa606618e..4473465bba 100644 --- a/block/qed.c +++ b/block/qed.c @@ -424,7 +424,7 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, } /* Round down file size to the last cluster */ - file_size = bdrv_getlength(bs->file->bs); + file_size = bdrv_co_getlength(bs->file->bs); if (file_size < 0) { error_setg(errp, "Failed to get file length"); return file_size; @@ -1480,13 +1480,14 @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs, return ret; } -static int64_t bdrv_qed_getlength(BlockDriverState *bs) +static int64_t coroutine_fn bdrv_qed_co_getlength(BlockDriverState *bs) { BDRVQEDState *s = bs->opaque; return s->header.image_size; } -static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +bdrv_qed_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQEDState *s = bs->opaque; @@ -1653,8 +1654,8 @@ static BlockDriver bdrv_qed = { .bdrv_co_writev = bdrv_qed_co_writev, .bdrv_co_pwrite_zeroes = bdrv_qed_co_pwrite_zeroes, .bdrv_co_truncate = bdrv_qed_co_truncate, - .bdrv_getlength = bdrv_qed_getlength, - .bdrv_get_info = bdrv_qed_get_info, + .bdrv_co_getlength = bdrv_qed_co_getlength, + .bdrv_co_get_info = bdrv_qed_co_get_info, .bdrv_refresh_limits = bdrv_qed_refresh_limits, .bdrv_change_backing_file = bdrv_qed_change_backing_file, .bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache, diff --git a/block/quorum.c b/block/quorum.c index 7f21c03f1f..d1dcf2eaba 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -754,19 +754,19 @@ static int coroutine_fn quorum_co_pwrite_zeroes(BlockDriverState *bs, flags | BDRV_REQ_ZERO_WRITE); } -static int64_t quorum_getlength(BlockDriverState *bs) +static int64_t coroutine_fn quorum_co_getlength(BlockDriverState *bs) { BDRVQuorumState *s = bs->opaque; int64_t result; int i; /* check that all file have the same length */ - result = bdrv_getlength(s->children[0]->bs); + result = bdrv_co_getlength(s->children[0]->bs); if (result < 0) { return result; } for (i = 1; i < s->num_children; i++) { - int64_t value = bdrv_getlength(s->children[i]->bs); + int64_t value = bdrv_co_getlength(s->children[i]->bs); if (value < 0) { return value; } @@ -1283,7 +1283,7 @@ static BlockDriver bdrv_quorum = { .bdrv_co_flush = quorum_co_flush, - .bdrv_getlength = quorum_getlength, + .bdrv_co_getlength = quorum_co_getlength, .bdrv_co_preadv = quorum_co_preadv, .bdrv_co_pwritev = quorum_co_pwritev, diff --git a/block/raw-format.c b/block/raw-format.c index b6a0ce58f4..0dc469b629 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -317,14 +317,14 @@ static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs, return bdrv_co_pdiscard(bs->file, offset, bytes); } -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) { int64_t len; BDRVRawState *s = bs->opaque; /* Update size. It should not change unless the file was externally * modified. */ - len = bdrv_getlength(bs->file->bs); + len = bdrv_co_getlength(bs->file->bs); if (len < 0) { return len; } @@ -368,9 +368,10 @@ static BlockMeasureInfo *raw_measure(QemuOpts *opts, BlockDriverState *in_bs, return info; } -static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +raw_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { - return bdrv_get_info(bs->file->bs, bdi); + return bdrv_co_get_info(bs->file->bs, bdi); } static void raw_refresh_limits(BlockDriverState *bs, Error **errp) @@ -404,14 +405,14 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp); } -static void raw_eject(BlockDriverState *bs, bool eject_flag) +static void coroutine_fn raw_co_eject(BlockDriverState *bs, bool eject_flag) { - bdrv_eject(bs->file->bs, eject_flag); + bdrv_co_eject(bs->file->bs, eject_flag); } -static void raw_lock_medium(BlockDriverState *bs, bool locked) +static void coroutine_fn raw_co_lock_medium(BlockDriverState *bs, bool locked) { - bdrv_lock_medium(bs->file->bs, locked); + bdrv_co_lock_medium(bs->file->bs, locked); } static int coroutine_fn raw_co_ioctl(BlockDriverState *bs, @@ -622,16 +623,16 @@ BlockDriver bdrv_raw = { .bdrv_co_copy_range_from = &raw_co_copy_range_from, .bdrv_co_copy_range_to = &raw_co_copy_range_to, .bdrv_co_truncate = &raw_co_truncate, - .bdrv_getlength = &raw_getlength, + .bdrv_co_getlength = &raw_co_getlength, .is_format = true, .has_variable_length = true, .bdrv_measure = &raw_measure, - .bdrv_get_info = &raw_get_info, + .bdrv_co_get_info = &raw_co_get_info, .bdrv_refresh_limits = &raw_refresh_limits, .bdrv_probe_blocksizes = &raw_probe_blocksizes, .bdrv_probe_geometry = &raw_probe_geometry, - .bdrv_eject = &raw_eject, - .bdrv_lock_medium = &raw_lock_medium, + .bdrv_co_eject = &raw_co_eject, + .bdrv_co_lock_medium = &raw_co_lock_medium, .bdrv_co_ioctl = &raw_co_ioctl, .create_opts = &raw_create_opts, .bdrv_has_zero_init = &raw_has_zero_init, diff --git a/block/rbd.c b/block/rbd.c index 6167c5e424..5e102fea0d 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1240,7 +1240,8 @@ coroutine_fn qemu_rbd_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, } #endif -static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +qemu_rbd_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVRBDState *s = bs->opaque; bdi->cluster_size = s->object_size; @@ -1430,7 +1431,7 @@ static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs, return status; } -static int64_t qemu_rbd_getlength(BlockDriverState *bs) +static int64_t coroutine_fn qemu_rbd_co_getlength(BlockDriverState *bs) { BDRVRBDState *s = bs->opaque; int r; @@ -1651,10 +1652,10 @@ static BlockDriver bdrv_rbd = { .bdrv_co_create = qemu_rbd_co_create, .bdrv_co_create_opts = qemu_rbd_co_create_opts, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_get_info = qemu_rbd_getinfo, + .bdrv_co_get_info = qemu_rbd_co_get_info, .bdrv_get_specific_info = qemu_rbd_get_specific_info, .create_opts = &qemu_rbd_create_opts, - .bdrv_getlength = qemu_rbd_getlength, + .bdrv_co_getlength = qemu_rbd_co_getlength, .bdrv_co_truncate = qemu_rbd_co_truncate, .protocol_name = "rbd", diff --git a/block/replication.c b/block/replication.c index c62f48a874..a27417d310 100644 --- a/block/replication.c +++ b/block/replication.c @@ -179,9 +179,9 @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, return; } -static int64_t replication_getlength(BlockDriverState *bs) +static int64_t coroutine_fn replication_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } static int replication_get_io_status(BDRVReplicationState *s) @@ -758,7 +758,7 @@ static BlockDriver bdrv_replication = { .bdrv_close = replication_close, .bdrv_child_perm = replication_child_perm, - .bdrv_getlength = replication_getlength, + .bdrv_co_getlength = replication_co_getlength, .bdrv_co_readv = replication_co_readv, .bdrv_co_writev = replication_co_writev, diff --git a/block/ssh.c b/block/ssh.c index 8bd2a134c1..b3b3352075 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -1253,7 +1253,7 @@ static coroutine_fn int ssh_co_flush(BlockDriverState *bs) return ret; } -static int64_t ssh_getlength(BlockDriverState *bs) +static int64_t coroutine_fn ssh_co_getlength(BlockDriverState *bs) { BDRVSSHState *s = bs->opaque; int64_t length; @@ -1364,7 +1364,7 @@ static BlockDriver bdrv_ssh = { .bdrv_has_zero_init = ssh_has_zero_init, .bdrv_co_readv = ssh_co_readv, .bdrv_co_writev = ssh_co_writev, - .bdrv_getlength = ssh_getlength, + .bdrv_co_getlength = ssh_co_getlength, .bdrv_co_truncate = ssh_co_truncate, .bdrv_co_flush_to_disk = ssh_co_flush, .bdrv_refresh_filename = ssh_refresh_filename, diff --git a/block/throttle.c b/block/throttle.c index 00cb46d0e5..64fa0f5acc 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -106,9 +106,9 @@ static void throttle_close(BlockDriverState *bs) } -static int64_t throttle_getlength(BlockDriverState *bs) +static int64_t coroutine_fn throttle_co_getlength(BlockDriverState *bs) { - return bdrv_getlength(bs->file->bs); + return bdrv_co_getlength(bs->file->bs); } static int coroutine_fn throttle_co_preadv(BlockDriverState *bs, @@ -247,7 +247,7 @@ static BlockDriver bdrv_throttle = { .bdrv_child_perm = bdrv_default_perms, - .bdrv_getlength = throttle_getlength, + .bdrv_co_getlength = throttle_co_getlength, .bdrv_co_preadv = throttle_co_preadv, .bdrv_co_pwritev = throttle_co_pwritev, diff --git a/block/vdi.c b/block/vdi.c index 479bcfe820..9c8736b26f 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -327,9 +327,10 @@ static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res, return 0; } -static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +vdi_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { - /* TODO: vdi_get_info would be needed for machine snapshots. + /* TODO: vdi_co_get_info would be needed for machine snapshots. vm_state_offset is still missing. */ BDRVVdiState *s = (BDRVVdiState *)bs->opaque; logout("\n"); @@ -1049,7 +1050,7 @@ static BlockDriver bdrv_vdi = { .bdrv_co_pwritev = vdi_co_pwritev, #endif - .bdrv_get_info = vdi_get_info, + .bdrv_co_get_info = vdi_co_get_info, .is_format = true, .create_opts = &vdi_create_opts, diff --git a/block/vhdx.c b/block/vhdx.c index 4c929800fe..ef1f65d917 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1161,7 +1161,8 @@ static void vhdx_block_translate(BDRVVHDXState *s, int64_t sector_num, } -static int vhdx_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +vhdx_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVVHDXState *s = bs->opaque; @@ -2245,7 +2246,7 @@ static BlockDriver bdrv_vhdx = { .bdrv_co_writev = vhdx_co_writev, .bdrv_co_create = vhdx_co_create, .bdrv_co_create_opts = vhdx_co_create_opts, - .bdrv_get_info = vhdx_get_info, + .bdrv_co_get_info = vhdx_co_get_info, .bdrv_co_check = vhdx_co_check, .bdrv_has_zero_init = vhdx_has_zero_init, diff --git a/block/vmdk.c b/block/vmdk.c index 8894dac2d4..5b0eae877e 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2856,14 +2856,15 @@ static void vmdk_close(BlockDriverState *bs) error_free(s->migration_blocker); } -static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) +static int64_t coroutine_fn +vmdk_co_get_allocated_file_size(BlockDriverState *bs) { int i; int64_t ret = 0; int64_t r; BDRVVmdkState *s = bs->opaque; - ret = bdrv_get_allocated_file_size(bs->file->bs); + ret = bdrv_co_get_allocated_file_size(bs->file->bs); if (ret < 0) { return ret; } @@ -2871,7 +2872,7 @@ static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) if (s->extents[i].file == bs->file) { continue; } - r = bdrv_get_allocated_file_size(s->extents[i].file->bs); + r = bdrv_co_get_allocated_file_size(s->extents[i].file->bs); if (r < 0) { return r; } @@ -2897,12 +2898,12 @@ static int vmdk_has_zero_init(BlockDriverState *bs) return 1; } -static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) +static VmdkExtentInfo *vmdk_get_extent_info(VmdkExtent *extent) { - ImageInfo *info = g_new0(ImageInfo, 1); + VmdkExtentInfo *info = g_new0(VmdkExtentInfo, 1); bdrv_refresh_filename(extent->file->bs); - *info = (ImageInfo){ + *info = (VmdkExtentInfo){ .filename = g_strdup(extent->file->bs->filename), .format = g_strdup(extent->type), .virtual_size = extent->sectors * BDRV_SECTOR_SIZE, @@ -2981,7 +2982,7 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs, int i; BDRVVmdkState *s = bs->opaque; ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1); - ImageInfoList **tail; + VmdkExtentInfoList **tail; *spec_info = (ImageInfoSpecific){ .type = IMAGE_INFO_SPECIFIC_KIND_VMDK, @@ -3011,7 +3012,8 @@ static bool vmdk_extents_type_eq(const VmdkExtent *a, const VmdkExtent *b) (a->flat || a->cluster_sectors == b->cluster_sectors); } -static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +vmdk_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { int i; BDRVVmdkState *s = bs->opaque; @@ -3124,11 +3126,11 @@ static BlockDriver bdrv_vmdk = { .bdrv_co_create_opts = vmdk_co_create_opts, .bdrv_co_create = vmdk_co_create, .bdrv_co_block_status = vmdk_co_block_status, - .bdrv_get_allocated_file_size = vmdk_get_allocated_file_size, + .bdrv_co_get_allocated_file_size = vmdk_co_get_allocated_file_size, .bdrv_has_zero_init = vmdk_has_zero_init, .bdrv_get_specific_info = vmdk_get_specific_info, .bdrv_refresh_limits = vmdk_refresh_limits, - .bdrv_get_info = vmdk_get_info, + .bdrv_co_get_info = vmdk_co_get_info, .bdrv_gather_child_options = vmdk_gather_child_options, .is_format = true, diff --git a/block/vpc.c b/block/vpc.c index 6ee95dcb96..cfdea7db80 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -598,7 +598,8 @@ fail: return ret; } -static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +static int coroutine_fn +vpc_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVVPCState *s = (BDRVVPCState *)bs->opaque; @@ -1240,7 +1241,7 @@ static BlockDriver bdrv_vpc = { .bdrv_co_pwritev = vpc_co_pwritev, .bdrv_co_block_status = vpc_co_block_status, - .bdrv_get_info = vpc_get_info, + .bdrv_co_get_info = vpc_co_get_info, .is_format = true, .create_opts = &vpc_create_opts, diff --git a/blockdev.c b/blockdev.c index fe9d8d89c0..d7b5c18f0a 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1024,6 +1024,7 @@ fail: static BlockDriverState *qmp_get_root_bs(const char *name, Error **errp) { BlockDriverState *bs; + AioContext *aio_context; bs = bdrv_lookup_bs(name, name, errp); if (bs == NULL) { @@ -1035,11 +1036,16 @@ static BlockDriverState *qmp_get_root_bs(const char *name, Error **errp) return NULL; } + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + if (!bdrv_is_inserted(bs)) { error_setg(errp, "Device has no medium"); - return NULL; + bs = NULL; } + aio_context_release(aio_context); + return bs; } diff --git a/hw/block/block.c b/hw/block/block.c index ddcef71f80..af0710e477 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -16,6 +16,40 @@ #include "qapi/qapi-types-block.h" /* + * Read the non-zeroes parts of @blk into @buf + * Reading all of the @blk is expensive if the zeroes parts of @blk + * is large enough. Therefore check the block status and only write + * the non-zeroes block into @buf. + * + * Return 0 on success, non-zero on error. + */ +static int blk_pread_nonzeroes(BlockBackend *blk, hwaddr size, void *buf) +{ + int ret; + int64_t bytes, offset = 0; + BlockDriverState *bs = blk_bs(blk); + + for (;;) { + bytes = MIN(size - offset, BDRV_REQUEST_MAX_SECTORS); + if (bytes <= 0) { + return 0; + } + ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL); + if (ret < 0) { + return ret; + } + if (!(ret & BDRV_BLOCK_ZERO)) { + ret = bdrv_pread(bs->file, offset, bytes, + (uint8_t *) buf + offset, 0); + if (ret < 0) { + return ret; + } + } + offset += bytes; + } +} + +/* * Read the entire contents of @blk into @buf. * @blk's contents must be @size bytes, and @size must be at most * BDRV_REQUEST_MAX_BYTES. @@ -54,7 +88,7 @@ bool blk_check_size_and_read_all(BlockBackend *blk, void *buf, hwaddr size, * block device and read only on demand. */ assert(size <= BDRV_REQUEST_MAX_BYTES); - ret = blk_pread(blk, 0, size, buf, 0); + ret = blk_pread_nonzeroes(blk, size, buf); if (ret < 0) { error_setg_errno(errp, -ret, "can't read block backend"); return false; diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index e493c28814..d4e360850f 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2332,10 +2332,15 @@ static void scsi_disk_reset(DeviceState *dev) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev); uint64_t nb_sectors; + AioContext *ctx; scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET)); + ctx = blk_get_aio_context(s->qdev.conf.blk); + aio_context_acquire(ctx); blk_get_geometry(s->qdev.conf.blk, &nb_sectors); + aio_context_release(ctx); + nb_sectors /= s->qdev.blocksize / BDRV_SECTOR_SIZE; if (nb_sectors) { nb_sectors--; diff --git a/include/block/block-common.h b/include/block/block-common.h index 41686810de..469300fe8d 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -45,11 +45,14 @@ * - co_wrapper_mixed_bdrv_rdlock are co_wrapper_mixed functions but * automatically take and release the graph rdlock when creating a new * coroutine. + * + * These functions should not be called from a coroutine_fn; instead, + * call the wrapped function directly. */ -#define co_wrapper -#define co_wrapper_mixed -#define co_wrapper_bdrv_rdlock -#define co_wrapper_mixed_bdrv_rdlock +#define co_wrapper no_coroutine_fn +#define co_wrapper_mixed no_coroutine_fn coroutine_mixed_fn +#define co_wrapper_bdrv_rdlock no_coroutine_fn +#define co_wrapper_mixed_bdrv_rdlock no_coroutine_fn coroutine_mixed_fn #include "block/blockjob.h" diff --git a/include/block/block-io.h b/include/block/block-io.h index 3398351596..614cbd7eda 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -76,9 +76,15 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); -int64_t bdrv_nb_sectors(BlockDriverState *bs); -int64_t bdrv_getlength(BlockDriverState *bs); -int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); +int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs); +int64_t co_wrapper_mixed bdrv_nb_sectors(BlockDriverState *bs); + +int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs); +int64_t co_wrapper_mixed bdrv_getlength(BlockDriverState *bs); + +int64_t coroutine_fn bdrv_co_get_allocated_file_size(BlockDriverState *bs); +int64_t co_wrapper bdrv_get_allocated_file_size(BlockDriverState *bs); + BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, BlockDriverState *in_bs, Error **errp); void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); @@ -136,16 +142,23 @@ bool bdrv_is_read_only(BlockDriverState *bs); bool bdrv_is_writable(BlockDriverState *bs); bool bdrv_is_sg(BlockDriverState *bs); int bdrv_get_flags(BlockDriverState *bs); -bool bdrv_is_inserted(BlockDriverState *bs); -void bdrv_lock_medium(BlockDriverState *bs, bool locked); -void bdrv_eject(BlockDriverState *bs, bool eject_flag); + +bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs); +bool co_wrapper bdrv_is_inserted(BlockDriverState *bs); + +void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked); +void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag); + const char *bdrv_get_format_name(BlockDriverState *bs); bool bdrv_supports_compressed_writes(BlockDriverState *bs); const char *bdrv_get_node_name(const BlockDriverState *bs); const char *bdrv_get_device_name(const BlockDriverState *bs); const char *bdrv_get_device_or_node_name(const BlockDriverState *bs); -int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); + +int coroutine_fn bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); +int co_wrapper_mixed bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); + ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, Error **errp); BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs); @@ -178,7 +191,10 @@ void *qemu_try_blockalign0(BlockDriverState *bs, size_t size); void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); -void bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event); +void coroutine_fn bdrv_co_debug_event(BlockDriverState *bs, + BlkdebugEvent event); +void co_wrapper_mixed bdrv_debug_event(BlockDriverState *bs, + BlkdebugEvent event); #define BLKDBG_EVENT(child, evt) \ do { \ @@ -213,15 +229,10 @@ AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs); */ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx); -/** - * Transfer control to @co in the aio context of @bs - */ -void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co); - AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); -void bdrv_io_plug(BlockDriverState *bs); -void bdrv_io_unplug(BlockDriverState *bs); +void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs); +void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs); bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 887ace7dbd..ba2e0fce25 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -680,8 +680,10 @@ struct BlockDriver { int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, bool exact, PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); - int64_t (*bdrv_getlength)(BlockDriverState *bs); - int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs); + int64_t coroutine_fn (*bdrv_co_getlength)(BlockDriverState *bs); + int64_t coroutine_fn (*bdrv_co_get_allocated_file_size)( + BlockDriverState *bs); + BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs, Error **errp); @@ -691,22 +693,23 @@ struct BlockDriver { int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset); - int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); + int coroutine_fn (*bdrv_co_get_info)(BlockDriverState *bs, + BlockDriverInfo *bdi); ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs, Error **errp); BlockStatsSpecific *(*bdrv_get_specific_stats)(BlockDriverState *bs); - int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_save_vmstate)( + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_save_vmstate)( BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); - int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_load_vmstate)( + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_load_vmstate)( BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); /* removable device specific */ - bool (*bdrv_is_inserted)(BlockDriverState *bs); - void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag); - void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); + bool coroutine_fn (*bdrv_co_is_inserted)(BlockDriverState *bs); + void coroutine_fn (*bdrv_co_eject)(BlockDriverState *bs, bool eject_flag); + void coroutine_fn (*bdrv_co_lock_medium)(BlockDriverState *bs, bool locked); /* to control generic scsi devices */ BlockAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs, @@ -722,11 +725,12 @@ struct BlockDriver { int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_check)( BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix); - void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); + void coroutine_fn (*bdrv_co_debug_event)(BlockDriverState *bs, + BlkdebugEvent event); /* io queue for linux-aio */ - void (*bdrv_io_plug)(BlockDriverState *bs); - void (*bdrv_io_unplug)(BlockDriverState *bs); + void coroutine_fn (*bdrv_co_io_plug)(BlockDriverState *bs); + void coroutine_fn (*bdrv_co_io_unplug)(BlockDriverState *bs); /** * bdrv_drain_begin is called if implemented in the beginning of a diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h index 44367219f4..4430bf4c4a 100644 --- a/include/block/block_int-io.h +++ b/include/block/block_int-io.h @@ -122,7 +122,10 @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, BdrvRequestFlags read_flags, BdrvRequestFlags write_flags); -int refresh_total_sectors(BlockDriverState *bs, int64_t hint); +int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs, + int64_t hint); +int co_wrapper_mixed +bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint); BdrvChild *bdrv_cow_child(BlockDriverState *bs); BdrvChild *bdrv_filter_child(BlockDriverState *bs); diff --git a/include/block/nbd.h b/include/block/nbd.h index 4ede3b2bd0..a4c98169c3 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -24,6 +24,7 @@ #include "io/channel-socket.h" #include "crypto/tlscreds.h" #include "qapi/error.h" +#include "qemu/bswap.h" extern const BlockExportDriver blk_exp_nbd; diff --git a/include/block/qapi.h b/include/block/qapi.h index 865fb974d4..8773b9b191 100644 --- a/include/block/qapi.h +++ b/include/block/qapi.h @@ -35,11 +35,21 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, int bdrv_query_snapshot_info_list(BlockDriverState *bs, SnapshotInfoList **p_list, Error **errp); +void bdrv_query_block_node_info(BlockDriverState *bs, + BlockNodeInfo **p_info, + Error **errp); void bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, + bool flat, + bool skip_implicit_filters, Error **errp); +void bdrv_query_block_graph_info(BlockDriverState *bs, + BlockGraphInfo **p_info, + Error **errp); void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); -void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec); -void bdrv_image_info_dump(ImageInfo *info); +void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, + const char *prefix, + int indentation); +void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol); #endif diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index c850001408..88c9facbf2 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -171,7 +171,51 @@ extern "C" { * .... * } */ +#ifdef __clang__ +#define coroutine_fn __attribute__((__annotate__("coroutine_fn"))) +#else #define coroutine_fn +#endif + +/** + * Mark a function that can suspend when executed in coroutine context, + * but can handle running in non-coroutine context too. + */ +#ifdef __clang__ +#define coroutine_mixed_fn __attribute__((__annotate__("coroutine_mixed_fn"))) +#else +#define coroutine_mixed_fn +#endif + +/** + * Mark a function that should not be called from a coroutine context. + * Usually there will be an analogous, coroutine_fn function that should + * be used instead. + * + * When the function is also marked as coroutine_mixed_fn, the function should + * only be called if the caller does not know whether it is in coroutine + * context. + * + * Functions that are only no_coroutine_fn, on the other hand, should not + * be called from within coroutines at all. This for example includes + * functions that block. + * + * In the future it would be nice to enable compiler or static checker + * support for catching such errors. This annotation is the first step + * towards this, and in the meantime it serves as documentation. + * + * For example: + * + * static void no_coroutine_fn foo(void) { + * .... + * } + */ +#ifdef __clang__ +#define no_coroutine_fn __attribute__((__annotate__("no_coroutine_fn"))) +#else +#define no_coroutine_fn +#endif + /* * For mingw, as of v6.0.0, the function implementing the assert macro is diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h index 031a27ba10..b1196ab93c 100644 --- a/include/sysemu/block-backend-io.h +++ b/include/sysemu/block-backend-io.h @@ -54,13 +54,26 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, void blk_inc_in_flight(BlockBackend *blk); void blk_dec_in_flight(BlockBackend *blk); -bool blk_is_inserted(BlockBackend *blk); + +bool coroutine_fn blk_co_is_inserted(BlockBackend *blk); +bool co_wrapper_mixed blk_is_inserted(BlockBackend *blk); + bool blk_is_available(BlockBackend *blk); -void blk_lock_medium(BlockBackend *blk, bool locked); -void blk_eject(BlockBackend *blk, bool eject_flag); -int64_t blk_getlength(BlockBackend *blk); + +void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked); +void co_wrapper blk_lock_medium(BlockBackend *blk, bool locked); + +void coroutine_fn blk_co_eject(BlockBackend *blk, bool eject_flag); +void co_wrapper blk_eject(BlockBackend *blk, bool eject_flag); + +int64_t coroutine_fn blk_co_getlength(BlockBackend *blk); +int64_t co_wrapper_mixed blk_getlength(BlockBackend *blk); + void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr); -int64_t blk_nb_sectors(BlockBackend *blk); + +int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk); +int64_t co_wrapper_mixed blk_nb_sectors(BlockBackend *blk); + void *blk_try_blockalign(BlockBackend *blk, size_t size); void *blk_blockalign(BlockBackend *blk, size_t size); bool blk_is_writable(BlockBackend *blk); @@ -74,8 +87,12 @@ void blk_iostatus_set_err(BlockBackend *blk, int error); int blk_get_max_iov(BlockBackend *blk); int blk_get_max_hw_iov(BlockBackend *blk); -void blk_io_plug(BlockBackend *blk); -void blk_io_unplug(BlockBackend *blk); +void coroutine_fn blk_co_io_plug(BlockBackend *blk); +void co_wrapper blk_io_plug(BlockBackend *blk); + +void coroutine_fn blk_co_io_unplug(BlockBackend *blk); +void co_wrapper blk_io_unplug(BlockBackend *blk); + AioContext *blk_get_aio_context(BlockBackend *blk); BlockAcctStats *blk_get_stats(BlockBackend *blk); void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk, diff --git a/qapi/block-core.json b/qapi/block-core.json index 95ac4fa634..7f331eb8ea 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -124,7 +124,33 @@ 'create-type': 'str', 'cid': 'int', 'parent-cid': 'int', - 'extents': ['ImageInfo'] + 'extents': ['VmdkExtentInfo'] + } } + +## +# @VmdkExtentInfo: +# +# Information about a VMDK extent file +# +# @filename: Name of the extent file +# +# @format: Extent type (e.g. FLAT or SPARSE) +# +# @virtual-size: Number of bytes covered by this extent +# +# @cluster-size: Cluster size in bytes (for non-flat extents) +# +# @compressed: Whether this extent contains compressed data +# +# Since: 8.0 +## +{ 'struct': 'VmdkExtentInfo', + 'data': { + 'filename': 'str', + 'format': 'str', + 'virtual-size': 'int', + '*cluster-size': 'int', + '*compressed': 'bool' } } ## @@ -140,15 +166,28 @@ } } ## +# @ImageInfoSpecificFile: +# +# @extent-size-hint: Extent size hint (if available) +# +# Since: 8.0 +## +{ 'struct': 'ImageInfoSpecificFile', + 'data': { + '*extent-size-hint': 'size' + } } + +## # @ImageInfoSpecificKind: # # @luks: Since 2.7 # @rbd: Since 6.1 +# @file: Since 8.0 # # Since: 1.7 ## { 'enum': 'ImageInfoSpecificKind', - 'data': [ 'qcow2', 'vmdk', 'luks', 'rbd' ] } + 'data': [ 'qcow2', 'vmdk', 'luks', 'rbd', 'file' ] } ## # @ImageInfoSpecificQCow2Wrapper: @@ -186,6 +225,14 @@ 'data': { 'data': 'ImageInfoSpecificRbd' } } ## +# @ImageInfoSpecificFileWrapper: +# +# Since: 8.0 +## +{ 'struct': 'ImageInfoSpecificFileWrapper', + 'data': { 'data': 'ImageInfoSpecificFile' } } + +## # @ImageInfoSpecific: # # A discriminated record of image format specific information structures. @@ -199,11 +246,12 @@ 'qcow2': 'ImageInfoSpecificQCow2Wrapper', 'vmdk': 'ImageInfoSpecificVmdkWrapper', 'luks': 'ImageInfoSpecificLUKSWrapper', - 'rbd': 'ImageInfoSpecificRbdWrapper' + 'rbd': 'ImageInfoSpecificRbdWrapper', + 'file': 'ImageInfoSpecificFileWrapper' } } ## -# @ImageInfo: +# @BlockNodeInfo: # # Information about a QEMU image file # @@ -231,23 +279,70 @@ # # @snapshots: list of VM snapshots # -# @backing-image: info of the backing image (since 1.6) -# # @format-specific: structure supplying additional format-specific # information (since 1.7) # -# Since: 1.3 +# Since: 8.0 ## -{ 'struct': 'ImageInfo', +{ 'struct': 'BlockNodeInfo', 'data': {'filename': 'str', 'format': 'str', '*dirty-flag': 'bool', '*actual-size': 'int', 'virtual-size': 'int', '*cluster-size': 'int', '*encrypted': 'bool', '*compressed': 'bool', '*backing-filename': 'str', '*full-backing-filename': 'str', '*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'], - '*backing-image': 'ImageInfo', '*format-specific': 'ImageInfoSpecific' } } ## +# @ImageInfo: +# +# Information about a QEMU image file, and potentially its backing image +# +# @backing-image: info of the backing image +# +# Since: 1.3 +## +{ 'struct': 'ImageInfo', + 'base': 'BlockNodeInfo', + 'data': { + '*backing-image': 'ImageInfo' + } } + +## +# @BlockChildInfo: +# +# Information about all nodes in the block graph starting at some node, +# annotated with information about that node in relation to its parent. +# +# @name: Child name of the root node in the BlockGraphInfo struct, in its role +# as the child of some undescribed parent node +# +# @info: Block graph information starting at this node +# +# Since: 8.0 +## +{ 'struct': 'BlockChildInfo', + 'data': { + 'name': 'str', + 'info': 'BlockGraphInfo' + } } + +## +# @BlockGraphInfo: +# +# Information about all nodes in a block (sub)graph in the form of BlockNodeInfo +# data. +# The base BlockNodeInfo struct contains the information for the (sub)graph's +# root node. +# +# @children: Array of links to this node's child nodes' information +# +# Since: 8.0 +## +{ 'struct': 'BlockGraphInfo', + 'base': 'BlockNodeInfo', + 'data': { 'children': ['BlockChildInfo'] } } + +## # @ImageCheck: # # Information about a QEMU image file check @@ -5732,3 +5827,13 @@ 'data': { 'device': 'str', '*id': 'str', '*name': 'str'}, 'returns': 'SnapshotInfo', 'allow-preconfig': true } + +## +# @DummyBlockCoreForceArrays: +# +# Not used by QMP; hack to let us use BlockGraphInfoList internally +# +# Since: 8.0 +## +{ 'struct': 'DummyBlockCoreForceArrays', + 'data': { 'unused-block-graph-info': ['BlockGraphInfo'] } } diff --git a/qemu-img.c b/qemu-img.c index 7e73c5c1da..7c05931866 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -450,6 +450,11 @@ static BlockBackend *img_open(bool image_opts, blk = img_open_file(filename, NULL, fmt, flags, writethrough, quiet, force_share); } + + if (blk) { + blk_set_force_allow_inactivate(blk); + } + return blk; } @@ -1120,6 +1125,14 @@ unref_backing: done: qemu_progress_end(); + /* + * Manually inactivate the image first because this way we can know whether + * an error occurred. blk_unref() doesn't tell us about failures. + */ + ret = bdrv_inactivate_all(); + if (ret < 0 && !local_err) { + error_setg_errno(&local_err, -ret, "Error while closing the image"); + } blk_unref(blk); if (local_err) { @@ -2804,13 +2817,13 @@ static void dump_snapshots(BlockDriverState *bs) g_free(sn_tab); } -static void dump_json_image_info_list(ImageInfoList *list) +static void dump_json_block_graph_info_list(BlockGraphInfoList *list) { GString *str; QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); - visit_type_ImageInfoList(v, NULL, &list, &error_abort); + visit_type_BlockGraphInfoList(v, NULL, &list, &error_abort); visit_complete(v, &obj); str = qobject_to_json_pretty(obj, true); assert(str != NULL); @@ -2820,13 +2833,13 @@ static void dump_json_image_info_list(ImageInfoList *list) g_string_free(str, true); } -static void dump_json_image_info(ImageInfo *info) +static void dump_json_block_graph_info(BlockGraphInfo *info) { GString *str; QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); - visit_type_ImageInfo(v, NULL, &info, &error_abort); + visit_type_BlockGraphInfo(v, NULL, &info, &error_abort); visit_complete(v, &obj); str = qobject_to_json_pretty(obj, true); assert(str != NULL); @@ -2836,9 +2849,30 @@ static void dump_json_image_info(ImageInfo *info) g_string_free(str, true); } -static void dump_human_image_info_list(ImageInfoList *list) +static void dump_human_image_info(BlockGraphInfo *info, int indentation, + const char *path) +{ + BlockChildInfoList *children_list; + + bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation, + info->children == NULL); + + for (children_list = info->children; children_list; + children_list = children_list->next) + { + BlockChildInfo *child = children_list->value; + g_autofree char *child_path = NULL; + + printf("%*sChild node '%s%s':\n", + indentation * 4, "", path, child->name); + child_path = g_strdup_printf("%s%s/", path, child->name); + dump_human_image_info(child->info, indentation + 1, child_path); + } +} + +static void dump_human_image_info_list(BlockGraphInfoList *list) { - ImageInfoList *elem; + BlockGraphInfoList *elem; bool delim = false; for (elem = list; elem; elem = elem->next) { @@ -2847,7 +2881,7 @@ static void dump_human_image_info_list(ImageInfoList *list) } delim = true; - bdrv_image_info_dump(elem->value); + dump_human_image_info(elem->value, 0, "/"); } } @@ -2857,24 +2891,24 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) } /** - * Open an image file chain and return an ImageInfoList + * Open an image file chain and return an BlockGraphInfoList * * @filename: topmost image filename * @fmt: topmost image format (may be NULL to autodetect) * @chain: true - enumerate entire backing file chain * false - only topmost image file * - * Returns a list of ImageInfo objects or NULL if there was an error opening an - * image file. If there was an error a message will have been printed to - * stderr. + * Returns a list of BlockNodeInfo objects or NULL if there was an error + * opening an image file. If there was an error a message will have been + * printed to stderr. */ -static ImageInfoList *collect_image_info_list(bool image_opts, - const char *filename, - const char *fmt, - bool chain, bool force_share) +static BlockGraphInfoList *collect_image_info_list(bool image_opts, + const char *filename, + const char *fmt, + bool chain, bool force_share) { - ImageInfoList *head = NULL; - ImageInfoList **tail = &head; + BlockGraphInfoList *head = NULL; + BlockGraphInfoList **tail = &head; GHashTable *filenames; Error *err = NULL; @@ -2883,7 +2917,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, while (filename) { BlockBackend *blk; BlockDriverState *bs; - ImageInfo *info; + BlockGraphInfo *info; if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) { error_report("Backing file '%s' creates an infinite loop.", @@ -2900,7 +2934,14 @@ static ImageInfoList *collect_image_info_list(bool image_opts, } bs = blk_bs(blk); - bdrv_query_image_info(bs, &info, &err); + /* + * Note that the returned BlockGraphInfo object will not have + * information about this image's backing node, because we have opened + * it with BDRV_O_NO_BACKING. Printing this object will therefore not + * duplicate the backing chain information that we obtain by walking + * the chain manually here. + */ + bdrv_query_block_graph_info(bs, &info, &err); if (err) { error_report_err(err); blk_unref(blk); @@ -2933,7 +2974,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, return head; err: - qapi_free_ImageInfoList(head); + qapi_free_BlockGraphInfoList(head); g_hash_table_destroy(filenames); return NULL; } @@ -2944,7 +2985,7 @@ static int img_info(int argc, char **argv) OutputFormat output_format = OFORMAT_HUMAN; bool chain = false; const char *filename, *fmt, *output; - ImageInfoList *list; + BlockGraphInfoList *list; bool image_opts = false; bool force_share = false; @@ -3023,14 +3064,14 @@ static int img_info(int argc, char **argv) break; case OFORMAT_JSON: if (chain) { - dump_json_image_info_list(list); + dump_json_block_graph_info_list(list); } else { - dump_json_image_info(list->value); + dump_json_block_graph_info(list->value); } break; } - qapi_free_ImageInfoList(list); + qapi_free_BlockGraphInfoList(list); return 0; } @@ -4633,6 +4674,7 @@ static int img_bitmap(int argc, char **argv) QSIMPLEQ_HEAD(, ImgBitmapAction) actions; ImgBitmapAction *act, *act_next; const char *op; + int inactivate_ret; QSIMPLEQ_INIT(&actions); @@ -4817,6 +4859,16 @@ static int img_bitmap(int argc, char **argv) ret = 0; out: + /* + * Manually inactivate the images first because this way we can know whether + * an error occurred. blk_unref() doesn't tell us about failures. + */ + inactivate_ret = bdrv_inactivate_all(); + if (inactivate_ret < 0) { + error_report("Error while closing the image: %s", strerror(-inactivate_ret)); + ret = 1; + } + blk_unref(src); blk_unref(blk); qemu_opts_del(opts); diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 952dc940f1..a061031615 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -572,54 +572,17 @@ static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, return 1; } -typedef struct { - BlockBackend *blk; - int64_t offset; - int64_t bytes; - int64_t *total; - int flags; - int ret; - bool done; -} CoWriteZeroes; - -static void coroutine_fn co_pwrite_zeroes_entry(void *opaque) -{ - CoWriteZeroes *data = opaque; - - data->ret = blk_co_pwrite_zeroes(data->blk, data->offset, data->bytes, - data->flags); - data->done = true; - if (data->ret < 0) { - *data->total = data->ret; - return; - } - - *data->total = data->bytes; -} - -static int do_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, +static int do_pwrite_zeroes(BlockBackend *blk, int64_t offset, int64_t bytes, int flags, int64_t *total) { - Coroutine *co; - CoWriteZeroes data = { - .blk = blk, - .offset = offset, - .bytes = bytes, - .total = total, - .flags = flags, - .done = false, - }; - - co = qemu_coroutine_create(co_pwrite_zeroes_entry, &data); - bdrv_coroutine_enter(blk_bs(blk), co); - while (!data.done) { - aio_poll(blk_get_aio_context(blk), true); - } - if (data.ret < 0) { - return data.ret; - } else { - return 1; + int ret = blk_pwrite_zeroes(blk, offset, bytes, + flags | BDRV_REQ_ZERO_WRITE); + + if (ret < 0) { + return ret; } + *total = bytes; + return 1; } static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset, @@ -1042,7 +1005,7 @@ static void write_help(void) " -C, -- report statistics in a machine parsable format\n" " -q, -- quiet mode, do not show I/O statistics\n" " -u, -- with -z, allow unmapping\n" -" -z, -- write zeroes using blk_co_pwrite_zeroes\n" +" -z, -- write zeroes using blk_pwrite_zeroes\n" "\n"); } @@ -1199,7 +1162,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv) if (bflag) { ret = do_save_vmstate(blk, buf, offset, count, &total); } else if (zflag) { - ret = do_co_pwrite_zeroes(blk, offset, count, flags, &total); + ret = do_pwrite_zeroes(blk, offset, count, flags, &total); } else if (cflag) { ret = do_write_compressed(blk, buf, offset, count, &total); } else { @@ -1825,8 +1788,9 @@ static int info_f(BlockBackend *blk, int argc, char **argv) return -EIO; } if (spec_info) { - printf("Format specific information:\n"); - bdrv_image_info_specific_dump(spec_info); + bdrv_image_info_specific_dump(spec_info, + "Format specific information:\n", + 0); qapi_free_ImageInfoSpecific(spec_info); } diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py index dff3af49f5..e82b648127 100644 --- a/scripts/block-coroutine-wrapper.py +++ b/scripts/block-coroutine-wrapper.py @@ -86,6 +86,16 @@ class FuncDecl: ctx = 'qemu_get_aio_context()' self.ctx = ctx + self.get_result = 's->ret = ' + self.ret = 'return s.ret;' + self.co_ret = 'return ' + self.return_field = self.return_type + " ret;" + if self.return_type == 'void': + self.get_result = '' + self.ret = '' + self.co_ret = '' + self.return_field = '' + def gen_list(self, format: str) -> str: return ', '.join(format.format_map(arg.__dict__) for arg in self.args) @@ -132,7 +142,7 @@ def create_mixed_wrapper(func: FuncDecl) -> str: {{ if (qemu_in_coroutine()) {{ {graph_assume_lock} - return {name}({ func.gen_list('{name}') }); + {func.co_ret}{name}({ func.gen_list('{name}') }); }} else {{ {struct_name} s = {{ .poll_state.ctx = {func.ctx}, @@ -144,7 +154,7 @@ def create_mixed_wrapper(func: FuncDecl) -> str: s.poll_state.co = qemu_coroutine_create({name}_entry, &s); bdrv_poll_co(&s.poll_state); - return s.ret; + {func.ret} }} }}""" @@ -169,7 +179,7 @@ def create_co_wrapper(func: FuncDecl) -> str: s.poll_state.co = qemu_coroutine_create({name}_entry, &s); bdrv_poll_co(&s.poll_state); - return s.ret; + {func.ret} }}""" @@ -196,7 +206,7 @@ def gen_wrapper(func: FuncDecl) -> str: typedef struct {struct_name} {{ BdrvPollCo poll_state; - {func.return_type} ret; + {func.return_field} { func.gen_block(' {decl};') } }} {struct_name}; @@ -205,7 +215,7 @@ static void coroutine_fn {name}_entry(void *opaque) {struct_name} *s = opaque; {graph_lock} - s->ret = {name}({ func.gen_list('s->{name}') }); + {func.get_result}{name}({ func.gen_list('s->{name}') }); {graph_unlock} s->poll_state.in_progress = false; diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065 index b724c89c7c..b76701c71e 100755 --- a/tests/qemu-iotests/065 +++ b/tests/qemu-iotests/065 @@ -56,7 +56,7 @@ class TestQemuImgInfo(TestImageInfoSpecific): def test_human(self): data = qemu_img('info', '--output=human', test_img).stdout.split('\n') data = data[(data.index('Format specific information:') + 1) - :data.index('')] + :data.index("Child node '/file':")] for field in data: self.assertTrue(re.match('^ {4}[^ ]', field) is not None) data = [line.strip() for line in data] diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 index 9d6adb542d..ae0fc46691 100755 --- a/tests/qemu-iotests/106 +++ b/tests/qemu-iotests/106 @@ -66,7 +66,7 @@ for create_mode in off falloc full; do expected_size=$((expected_size + $GROWTH_SIZE)) fi - actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size') + actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size' | head -n 1) actual_size=$(echo "$actual_size" | sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/') # The actual size may exceed the expected size, depending on the file @@ -105,7 +105,7 @@ for growth_mode in falloc full; do _make_test_img -o "extent_size_hint=0" 2G $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K - actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size') + actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size' | head -n 1) actual_size=$(echo "$actual_size" | sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/') if [ $actual_size -lt $GROWTH_SIZE ]; then diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214 index c66e246ba2..55ffcd7f44 100755 --- a/tests/qemu-iotests/214 +++ b/tests/qemu-iotests/214 @@ -102,7 +102,8 @@ let data_size="8 * $cluster_size" $QEMU_IO -c "write -P 0xaa 0 $data_size" "$TEST_IMG" \ 2>&1 | _filter_qemu_io | _filter_testdir sizeA=$($QEMU_IMG info --output=json "$TEST_IMG" | - sed -n '/"actual-size":/ s/[^0-9]//gp') + sed -n '/"actual-size":/ s/[^0-9]//gp' | + head -n 1) _make_test_img 2M -o cluster_size=$cluster_size echo "Write compressed data:" @@ -124,7 +125,8 @@ $QEMU_IO -c "write -P 0xcc $offset $data_size" "json:{\ _filter_qemu_io | _filter_testdir sizeB=$($QEMU_IMG info --output=json "$TEST_IMG" | - sed -n '/"actual-size":/ s/[^0-9]//gp') + sed -n '/"actual-size":/ s/[^0-9]//gp' | + head -n 1) if [ $sizeA -lt $sizeB ] then diff --git a/tests/qemu-iotests/262 b/tests/qemu-iotests/262 index 2294fd5ecb..a4a92de45a 100755 --- a/tests/qemu-iotests/262 +++ b/tests/qemu-iotests/262 @@ -25,7 +25,8 @@ import iotests import os iotests.script_initialize(supported_fmts=['qcow2'], - supported_platforms=['linux']) + supported_platforms=['linux'], + required_fmts=['blkverify']) with iotests.FilePath('img') as img_path, \ iotests.FilePath('mig_fifo') as fifo, \ diff --git a/tests/qemu-iotests/302.out b/tests/qemu-iotests/302.out index 3e7c281b91..7b5014cdd8 100644 --- a/tests/qemu-iotests/302.out +++ b/tests/qemu-iotests/302.out @@ -4,6 +4,11 @@ image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock file format: raw virtual size: 448 KiB (458752 bytes) disk size: unavailable +Child node '/file': + filename: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock + protocol type: nbd + file length: 448 KiB (458752 bytes) + disk size: unavailable === Converted image info === image: TEST_IMG diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 index bde4aac2fa..09275e9a10 100755 --- a/tests/qemu-iotests/308 +++ b/tests/qemu-iotests/308 @@ -217,12 +217,12 @@ echo echo '=== Remove export ===' # Double-check that $EXT_MP appears as a non-empty file (the raw image) -$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' +$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' | head -n 1 fuse_export_del 'export-mp' # See that the file appears empty again -$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' +$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' | head -n 1 echo echo '=== Writable export ===' diff --git a/tests/qemu-iotests/312 b/tests/qemu-iotests/312 index 4139745f0e..0d9ea09a31 100755 --- a/tests/qemu-iotests/312 +++ b/tests/qemu-iotests/312 @@ -52,6 +52,7 @@ _supported_fmt qcow2 _supported_proto file _supported_os Linux _unsupported_imgopts cluster_size data_file +_require_drivers quorum echo echo '### Create all images' # three source (quorum), one destination diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index cc9f1a5891..6b32c7fbfa 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -223,6 +223,7 @@ _filter_img_info() discard=0 regex_json_spec_start='^ *"format-specific": \{' + regex_json_child_start='^ *"children": \[' gsed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ -e "s#$TEST_DIR#TEST_DIR#g" \ @@ -251,20 +252,25 @@ _filter_img_info() -e 's/\(compression type: \)\(zlib\|zstd\)/\1COMPRESSION_TYPE/' \ -e "s/uuid: [-a-f0-9]\\+/uuid: 00000000-0000-0000-0000-000000000000/" | \ while IFS='' read -r line; do - if [[ $format_specific == 1 ]]; then - discard=0 - elif [[ $line == "Format specific information:" ]]; then - discard=1 - elif [[ $line =~ $regex_json_spec_start ]]; then - discard=2 - regex_json_spec_end="^${line%%[^ ]*}\\},? *$" + if [[ $discard == 0 ]]; then + if [[ $format_specific == 0 && $line == "Format specific information:" ]]; then + discard=1 + elif [[ $line =~ "Child node '/" ]]; then + discard=1 + elif [[ $line =~ $regex_json_spec_start ]]; then + discard=2 + regex_json_end="^${line%%[^ ]*}\\},? *$" + elif [[ $line =~ $regex_json_child_start ]]; then + discard=2 + regex_json_end="^${line%%[^ ]*}\\],? *$" + fi fi if [[ $discard == 0 ]]; then echo "$line" elif [[ $discard == 1 && ! $line ]]; then echo discard=0 - elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then + elif [[ $discard == 2 && $line =~ $regex_json_end ]]; then discard=0 fi done diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index db757025cb..f4476b62f7 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -711,6 +711,7 @@ _img_info() discard=0 regex_json_spec_start='^ *"format-specific": \{' + regex_json_child_start='^ *"children": \[' $QEMU_IMG info $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1 | \ sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ @@ -721,20 +722,25 @@ _img_info() -e "/^disk size:/ D" \ -e "/actual-size/ D" | \ while IFS='' read -r line; do - if [[ $format_specific == 1 ]]; then - discard=0 - elif [[ $line == "Format specific information:" ]]; then - discard=1 - elif [[ $line =~ $regex_json_spec_start ]]; then - discard=2 - regex_json_spec_end="^${line%%[^ ]*}\\},? *$" + if [[ $discard == 0 ]]; then + if [[ $format_specific == 0 && $line == "Format specific information:" ]]; then + discard=1 + elif [[ $line =~ "Child node '/" ]]; then + discard=1 + elif [[ $format_specific == 0 && $line =~ $regex_json_spec_start ]]; then + discard=2 + regex_json_end="^${line%%[^ ]*}\\},? *$" + elif [[ $line =~ $regex_json_child_start ]]; then + discard=2 + regex_json_end="^${line%%[^ ]*}\\],? *$" + fi fi if [[ $discard == 0 ]]; then echo "$line" elif [[ $discard == 1 && ! $line ]]; then echo discard=0 - elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then + elif [[ $discard == 2 && $line =~ $regex_json_end ]]; then discard=0 fi done diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index da7d6637e1..94aeb3f3b2 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -329,7 +329,7 @@ def qemu_img_log(*args: str, check: bool = True def img_info_log(filename: str, filter_path: Optional[str] = None, use_image_opts: bool = False, extra_args: Sequence[str] = (), - check: bool = True, + check: bool = True, drop_child_info: bool = True, ) -> None: args = ['info'] if use_image_opts: @@ -342,7 +342,7 @@ def img_info_log(filename: str, filter_path: Optional[str] = None, output = qemu_img(*args, check=check).stdout if not filter_path: filter_path = filename - log(filter_img_info(output, filter_path)) + log(filter_img_info(output, filter_path, drop_child_info)) def qemu_io_wrap_args(args: Sequence[str]) -> List[str]: if '-f' in args or '--image-opts' in args: @@ -642,11 +642,23 @@ def filter_qmp_virtio_scsi(qmsg): def filter_generated_node_ids(msg): return re.sub("#block[0-9]+", "NODE_NAME", msg) -def filter_img_info(output, filename): +def filter_img_info(output: str, filename: str, + drop_child_info: bool = True) -> str: lines = [] + drop_indented = False for line in output.split('\n'): if 'disk size' in line or 'actual-size' in line: continue + + # Drop child node info + if drop_indented: + if line.startswith(' '): + continue + drop_indented = False + if drop_child_info and "Child node '/" in line: + drop_indented = True + continue + line = line.replace(filename, 'TEST_IMG') line = filter_testfiles(line) line = line.replace(imgfmt, 'IMGFMT') diff --git a/tests/qemu-iotests/tests/qemu-img-close-errors b/tests/qemu-iotests/tests/qemu-img-close-errors new file mode 100755 index 0000000000..50bfb6cfa2 --- /dev/null +++ b/tests/qemu-iotests/tests/qemu-img-close-errors @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +# group: rw auto quick +# +# Check that errors while closing the image, in particular writing back dirty +# bitmaps, is correctly reported with a failing qemu-img exit code. +# +# Copyright (C) 2023 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +cd .. +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +size=1G + +# The error we are going to use is ENOSPC. Depending on how many bitmaps we +# create in the backing file (and therefore increase the used up space), we get +# failures in different places. With a low number, only merging the bitmap +# fails, whereas with a higher number, already 'qemu-img commit' fails. +for max_bitmap in 6 7; do + echo + echo "=== Test with $max_bitmap bitmaps ===" + + TEST_IMG="$TEST_IMG.base" _make_test_img -q $size + for i in $(seq 1 $max_bitmap); do + $QEMU_IMG bitmap --add "$TEST_IMG.base" "stale-bitmap-$i" + done + + # Simulate a block device of 128 MB by resizing the image file accordingly + # and then enforcing the size with the raw driver + $QEMU_IO -f raw -c "truncate 128M" "$TEST_IMG.base" + BASE_JSON='json:{ + "driver": "qcow2", + "file": { + "driver": "raw", + "size": 134217728, + "file": { + "driver": "file", + "filename":"'"$TEST_IMG.base"'" + } + } + }' + + _make_test_img -q -b "$BASE_JSON" -F $IMGFMT + $QEMU_IMG bitmap --add "$TEST_IMG" "good-bitmap" + + $QEMU_IO -c 'write 0 126m' "$TEST_IMG" | _filter_qemu_io + + $QEMU_IMG commit -d "$TEST_IMG" 2>&1 | _filter_generated_node_ids + echo "qemu-img commit exit code: ${PIPESTATUS[0]}" + + $QEMU_IMG bitmap --add "$BASE_JSON" "good-bitmap" + echo "qemu-img bitmap --add exit code: $?" + + $QEMU_IMG bitmap --merge "good-bitmap" -b "$TEST_IMG" "$BASE_JSON" \ + "good-bitmap" 2>&1 | _filter_generated_node_ids + echo "qemu-img bitmap --merge exit code: ${PIPESTATUS[0]}" +done + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 + diff --git a/tests/qemu-iotests/tests/qemu-img-close-errors.out b/tests/qemu-iotests/tests/qemu-img-close-errors.out new file mode 100644 index 0000000000..1bfe88f176 --- /dev/null +++ b/tests/qemu-iotests/tests/qemu-img-close-errors.out @@ -0,0 +1,23 @@ +QA output created by qemu-img-close-errors + +=== Test with 6 bitmaps === +wrote 132120576/132120576 bytes at offset 0 +126 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Image committed. +qemu-img commit exit code: 0 +qemu-img bitmap --add exit code: 0 +qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'good-bitmap' to file: No space left on device +qemu-img: Error while closing the image: Invalid argument +qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'good-bitmap' to file: No space left on device +qemu-img bitmap --merge exit code: 1 + +=== Test with 7 bitmaps === +wrote 132120576/132120576 bytes at offset 0 +126 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'stale-bitmap-7' to file: No space left on device +qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'stale-bitmap-7' to file: No space left on device +qemu-img: Error while closing the image: Invalid argument +qemu-img commit exit code: 1 +qemu-img bitmap --add exit code: 0 +qemu-img bitmap --merge exit code: 0 +*** done diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index ff5147f619..6dfac6468a 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -832,7 +832,10 @@ static void test_attach_second_node(void) qdict_put_str(options, "driver", "raw"); qdict_put_str(options, "file", "base"); + aio_context_acquire(ctx); filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort); + aio_context_release(ctx); + g_assert(blk_get_aio_context(blk) == ctx); g_assert(bdrv_get_aio_context(bs) == ctx); g_assert(bdrv_get_aio_context(filter) == ctx); |