* 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();
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;
}
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)
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;
* 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,
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)
{
}
/**
- * 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.)
*/
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;
}
* 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();
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) {
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);
/**
* 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();
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;
}
* 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;
}
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;
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;
}
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)
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");
/**
* 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;
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;
}
}
/**
* 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);
}
}
* 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);
}
}
}
}
-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();
}
}
-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;
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)
.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,
.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,
return cod.ret;
}
-static void blkio_io_unplug(BlockDriverState *bs)
+static void coroutine_fn blkio_co_io_unplug(BlockDriverState *bs)
{
BDRVBlkioState *s = bs->opaque;
}
}
-static int64_t blkio_getlength(BlockDriverState *bs)
+static int64_t coroutine_fn blkio_co_getlength(BlockDriverState *bs)
{
BDRVBlkioState *s = bs->opaque;
uint64_t capacity;
return -ENOTSUP;
}
- current_length = blkio_getlength(bs);
+ current_length = blkio_co_getlength(bs);
if (offset > current_length) {
error_setg(errp, "Cannot grow device");
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;
}
.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, \
.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, \
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,
.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,
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.
.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,
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)
.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,
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;
}
if (!blk->allow_write_beyond_eof) {
- len = blk_getlength(blk);
+ len = bdrv_co_getlength(blk_bs(blk));
if (len < 0) {
return len;
}
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) {
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)
}
}
-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,
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)
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,
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);
}
}
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;
}
}
-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);
}
}
-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);
}
.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,
.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,
}
-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);
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;
}
.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,
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;
.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,
.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,
.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,
.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,
return -EIO;
}
-static int64_t raw_getlength(BlockDriverState *bs);
+static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs);
typedef struct RawPosixAIOData {
BlockDriverState *bs;
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
#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
}
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");
}
#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;
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;
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;
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;
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;
}
#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;
* 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);
#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;
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;
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;
.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,
.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,
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;
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;
}
}
-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;
.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,
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;
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;
.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__ */
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;
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);
.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,
};
.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)
}
-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);
}
}
-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);
}
.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,
.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,
}
#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;
}
}
-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;
* 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);
.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,
.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,
.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,
.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,
/**
* 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 {
}
}
-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 {
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
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);
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) {
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,
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:
trace_bdrv_co_preadv_part(bs, offset, bytes, flags);
- if (!bdrv_is_inserted(bs)) {
+ if (!bdrv_co_is_inserted(bs)) {
return -ENOMEDIUM;
}
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;
bytes_remaining -= num;
}
}
- bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
+ bdrv_co_debug_event(bs, BLKDBG_PWRITEV_DONE);
if (ret >= 0) {
ret = 0;
trace_bdrv_co_pwritev_part(child->bs, offset, bytes, flags);
- if (!bdrv_is_inserted(bs)) {
+ if (!bdrv_co_is_inserted(bs)) {
return -ENOMEDIUM;
}
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 {
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 {
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;
}
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;
}
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();
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);
}
}
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);
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);
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");
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:
#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;
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;
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;
.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,
.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,
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'
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;
*/
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;
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 {
return 0;
}
-static int64_t nbd_getlength(BlockDriverState *bs)
+static int64_t coroutine_fn nbd_co_getlength(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
.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,
.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,
.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,
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};
.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,
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;
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;
}
.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,
.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,
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;
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;
}
}
-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);
.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,
.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,
}
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;
}
}
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;
}
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;
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;
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;
.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,
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);
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;
}
/**
- * 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));
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;
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;
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)
}
}
-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);
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,
}
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");
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);
}
}
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;
.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,
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;
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;
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;
}
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;
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) {
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) {
.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,
}
/* 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;
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;
.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,
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;
}
.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,
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;
}
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)
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,
.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,
}
#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;
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;
.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",
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)
.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,
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;
.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,
}
-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,
.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,
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");
.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,
}
-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;
.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,
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;
}
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;
}
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,
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,
(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;
.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,
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;
.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,
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) {
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;
}
#include "qapi/error.h"
#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
* 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;
{
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--;
* - 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"
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);
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);
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 { \
*/
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,
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);
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,
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
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);
#include "io/channel-socket.h"
#include "crypto/tlscreds.h"
#include "qapi/error.h"
+#include "qemu/bswap.h"
extern const BlockExportDriver blk_exp_nbd;
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
* ....
* }
*/
+#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
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);
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,
'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'
} }
##
'*encryption-format': 'RbdImageEncryptionFormat'
} }
+##
+# @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:
{ 'struct': 'ImageInfoSpecificRbdWrapper',
'data': { 'data': 'ImageInfoSpecificRbd' } }
+##
+# @ImageInfoSpecificFileWrapper:
+#
+# Since: 8.0
+##
+{ 'struct': 'ImageInfoSpecificFileWrapper',
+ 'data': { 'data': 'ImageInfoSpecificFile' } }
+
##
# @ImageInfoSpecific:
#
'qcow2': 'ImageInfoSpecificQCow2Wrapper',
'vmdk': 'ImageInfoSpecificVmdkWrapper',
'luks': 'ImageInfoSpecificLUKSWrapper',
- 'rbd': 'ImageInfoSpecificRbdWrapper'
+ 'rbd': 'ImageInfoSpecificRbdWrapper',
+ 'file': 'ImageInfoSpecificFileWrapper'
} }
##
-# @ImageInfo:
+# @BlockNodeInfo:
#
# Information about a QEMU image file
#
#
# @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:
#
'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'] } }
blk = img_open_file(filename, NULL, fmt, flags, writethrough, quiet,
force_share);
}
+
+ if (blk) {
+ blk_set_force_allow_inactivate(blk);
+ }
+
return blk;
}
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) {
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);
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);
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) {
}
delim = true;
- bdrv_image_info_dump(elem->value);
+ dump_human_image_info(elem->value, 0, "/");
}
}
}
/**
- * 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;
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.",
}
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);
return head;
err:
- qapi_free_ImageInfoList(head);
+ qapi_free_BlockGraphInfoList(head);
g_hash_table_destroy(filenames);
return NULL;
}
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;
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;
}
QSIMPLEQ_HEAD(, ImgBitmapAction) actions;
ImgBitmapAction *act, *act_next;
const char *op;
+ int inactivate_ret;
QSIMPLEQ_INIT(&actions);
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);
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,
" -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");
}
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 {
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);
}
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)
{{
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},
s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
bdrv_poll_co(&s.poll_state);
- return s.ret;
+ {func.ret}
}}
}}"""
s.poll_state.co = qemu_coroutine_create({name}_entry, &s);
bdrv_poll_co(&s.poll_state);
- return s.ret;
+ {func.ret}
}}"""
typedef struct {struct_name} {{
BdrvPollCo poll_state;
- {func.return_type} ret;
+ {func.return_field}
{ func.gen_block(' {decl};') }
}} {struct_name};
{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;
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]
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
_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
$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:"
_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
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, \
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
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 ==='
_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
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" \
-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
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" \
-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
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:
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:
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')
--- /dev/null
+#!/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
+
--- /dev/null
+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
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);