}
-static int qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset,
- uint8_t *buf, size_t buflen,
- void *opaque, Error **errp)
+static int GRAPH_RDLOCK
+qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset,
+ uint8_t *buf, size_t buflen,
+ void *opaque, Error **errp)
{
BlockDriverState *bs = opaque;
BDRVQcow2State *s = bs->opaque;
}
-static int qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen,
- void *opaque, Error **errp)
+static int coroutine_fn GRAPH_RDLOCK
+qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, void *opaque,
+ Error **errp)
{
BlockDriverState *bs = opaque;
BDRVQcow2State *s = bs->opaque;
*/
clusterlen = size_to_clusters(s, headerlen) * s->cluster_size;
assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen, false) == 0);
- ret = bdrv_pwrite_zeroes(bs->file,
- ret,
- clusterlen, 0);
+ ret = bdrv_co_pwrite_zeroes(bs->file, ret, clusterlen, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not zero fill encryption header");
return -1;
}
-static int qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
- const uint8_t *buf, size_t buflen,
- void *opaque, Error **errp)
+/* The graph lock must be held when called in coroutine context */
+static int coroutine_mixed_fn GRAPH_RDLOCK
+qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
+ const uint8_t *buf, size_t buflen,
+ void *opaque, Error **errp)
{
BlockDriverState *bs = opaque;
BDRVQcow2State *s = bs->opaque;
* function when there are no pending requests, it does not guard against
* concurrent requests dirtying the image.
*/
-static int qcow2_mark_clean(BlockDriverState *bs)
+static int GRAPH_RDLOCK qcow2_mark_clean(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
* Marks the image as consistent, i.e., unsets the corrupt bit, and flushes
* before if necessary.
*/
-int qcow2_mark_consistent(BlockDriverState *bs)
+static int coroutine_fn GRAPH_RDLOCK
+qcow2_mark_consistent(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
QCOW2_OPT_DISCARD_REQUEST,
QCOW2_OPT_DISCARD_SNAPSHOT,
QCOW2_OPT_DISCARD_OTHER,
+ QCOW2_OPT_DISCARD_NO_UNREF,
QCOW2_OPT_OVERLAP,
QCOW2_OPT_OVERLAP_TEMPLATE,
QCOW2_OPT_OVERLAP_MAIN_HEADER,
.type = QEMU_OPT_BOOL,
.help = "Generate discard requests when other clusters are freed",
},
+ {
+ .name = QCOW2_OPT_DISCARD_NO_UNREF,
+ .type = QEMU_OPT_BOOL,
+ .help = "Do not unreference discarded clusters",
+ },
{
.name = QCOW2_OPT_OVERLAP,
.type = QEMU_OPT_STRING,
bool use_lazy_refcounts;
int overlap_check;
bool discard_passthrough[QCOW2_DISCARD_MAX];
+ bool discard_no_unref;
uint64_t cache_clean_interval;
QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */
} Qcow2ReopenState;
-static int qcow2_update_options_prepare(BlockDriverState *bs,
- Qcow2ReopenState *r,
- QDict *options, int flags,
- Error **errp)
+static int GRAPH_RDLOCK
+qcow2_update_options_prepare(BlockDriverState *bs, Qcow2ReopenState *r,
+ QDict *options, int flags, Error **errp)
{
BDRVQcow2State *s = bs->opaque;
QemuOpts *opts = NULL;
r->discard_passthrough[QCOW2_DISCARD_OTHER] =
qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
+ r->discard_no_unref = qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_NO_UNREF,
+ false);
+ if (r->discard_no_unref && s->qcow_version < 3) {
+ error_setg(errp,
+ "discard-no-unref is only supported since qcow2 version 3");
+ ret = -EINVAL;
+ goto fail;
+ }
+
switch (s->crypt_method_header) {
case QCOW_CRYPT_NONE:
if (encryptfmt) {
s->discard_passthrough[i] = r->discard_passthrough[i];
}
+ s->discard_no_unref = r->discard_no_unref;
+
if (s->cache_clean_interval != r->cache_clean_interval) {
cache_clean_timer_del(bs);
s->cache_clean_interval = r->cache_clean_interval;
qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
}
-static int coroutine_fn
+static int coroutine_fn GRAPH_RDLOCK
qcow2_update_options(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
if (open_data_file) {
/* Open external data file */
+ bdrv_graph_co_rdunlock();
s->data_file = bdrv_co_open_child(NULL, options, "data-file", bs,
&child_of_bds, BDRV_CHILD_DATA,
true, errp);
+ bdrv_graph_co_rdlock();
if (*errp) {
ret = -EINVAL;
goto fail;
if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
if (!s->data_file && s->image_data_file) {
+ bdrv_graph_co_rdunlock();
s->data_file = bdrv_co_open_child(s->image_data_file, options,
"data-file", bs,
&child_of_bds,
BDRV_CHILD_DATA, false, errp);
+ bdrv_graph_co_rdlock();
if (!s->data_file) {
ret = -EINVAL;
goto fail;
fail:
g_free(s->image_data_file);
if (open_data_file && has_data_file(bs)) {
- bdrv_unref_child(bs, s->data_file);
+ bdrv_graph_co_rdunlock();
+ bdrv_co_unref_child(bs, s->data_file);
+ bdrv_graph_co_rdlock();
s->data_file = NULL;
}
g_free(s->unknown_header_fields);
QCow2OpenCo *qoc = opaque;
BDRVQcow2State *s = qoc->bs->opaque;
- assume_graph_lock(); /* FIXME */
+ GRAPH_RDLOCK_GUARD();
qemu_co_mutex_lock(&s->lock);
qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, true,
qoc->errp);
qemu_co_mutex_unlock(&s->lock);
+
+ aio_wait_kick();
}
static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
/* Initialise locks */
qemu_co_mutex_init(&s->lock);
- if (qemu_in_coroutine()) {
- /* From bdrv_co_create. */
- qcow2_open_entry(&qoc);
- } else {
- assert(qemu_get_current_aio_context() == qemu_get_aio_context());
- qemu_coroutine_enter(qemu_coroutine_create(qcow2_open_entry, &qoc));
- BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
- }
+ assert(!qemu_in_coroutine());
+ assert(qemu_get_current_aio_context() == qemu_get_aio_context());
+
+ aio_co_enter(bdrv_get_aio_context(bs),
+ qemu_coroutine_create(qcow2_open_entry, &qoc));
+ AIO_WAIT_WHILE_UNLOCKED(NULL, qoc.ret == -EINPROGRESS);
+
return qoc.ret;
}
bs->bl.pdiscard_alignment = s->cluster_size;
}
-static int qcow2_reopen_prepare(BDRVReopenState *state,
- BlockReopenQueue *queue, Error **errp)
+static int GRAPH_UNLOCKED
+qcow2_reopen_prepare(BDRVReopenState *state,BlockReopenQueue *queue,
+ Error **errp)
{
BDRVQcow2State *s = state->bs->opaque;
Qcow2ReopenState *r;
int ret;
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
r = g_new0(Qcow2ReopenState, 1);
state->opaque = r;
{
BDRVQcow2State *s = state->bs->opaque;
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
qcow2_update_options_commit(state->bs, state->opaque);
if (!s->data_file) {
/*
static void qcow2_reopen_commit_post(BDRVReopenState *state)
{
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
if (state->flags & BDRV_O_RDWR) {
Error *local_err = NULL;
{
BDRVQcow2State *s = state->bs->opaque;
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
if (!s->data_file) {
/*
* If we don't have an external data file, s->data_file was cleared by
}
}
-static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
- bool want_zero,
- int64_t offset, int64_t count,
- int64_t *pnum, int64_t *map,
- BlockDriverState **file)
+static int coroutine_fn GRAPH_RDLOCK
+qcow2_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset,
+ int64_t count, int64_t *pnum, int64_t *map,
+ BlockDriverState **file)
{
BDRVQcow2State *s = bs->opaque;
uint64_t host_offset;
{
status |= BDRV_BLOCK_RECURSE;
}
+ if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
+ status |= BDRV_BLOCK_COMPRESSED;
+ }
return status;
}
return -ENOMEM;
}
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
ret = bdrv_co_pread(s->data_file, host_offset, bytes, buf, 0);
if (ret < 0) {
goto fail;
case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
assert(bs->backing); /* otherwise handled in qcow2_co_preadv_part */
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
return bdrv_co_preadv_part(bs->backing, offset, bytes,
qiov, qiov_offset, 0);
offset, bytes, qiov, qiov_offset);
}
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
return bdrv_co_preadv_part(s->data_file, host_offset,
bytes, qiov, qiov_offset, 0);
return ret;
}
- BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_SPACE);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_SPACE);
ret = bdrv_co_pwrite_zeroes(s->data_file, start_offset, nb_bytes,
BDRV_REQ_NO_FALLBACK);
if (ret < 0) {
* guest data now.
*/
if (!merge_cow(offset, bytes, qiov, qiov_offset, l2meta)) {
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
trace_qcow2_writev_data(qemu_coroutine_self(), host_offset);
ret = bdrv_co_pwritev_part(s->data_file, host_offset,
bytes, qiov, qiov_offset, 0);
return ret;
}
-static int qcow2_inactivate(BlockDriverState *bs)
+static int GRAPH_RDLOCK qcow2_inactivate(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
int ret, result = 0;
return result;
}
-static void qcow2_do_close(BlockDriverState *bs, bool close_data_file)
+static void coroutine_mixed_fn GRAPH_RDLOCK
+qcow2_do_close(BlockDriverState *bs, bool close_data_file)
{
BDRVQcow2State *s = bs->opaque;
qemu_vfree(s->l1_table);
g_free(s->image_backing_format);
if (close_data_file && has_data_file(bs)) {
+ GLOBAL_STATE_CODE();
+ bdrv_graph_rdunlock_main_loop();
+ bdrv_graph_wrlock();
bdrv_unref_child(bs, s->data_file);
+ bdrv_graph_wrunlock();
s->data_file = NULL;
+ bdrv_graph_rdlock_main_loop();
}
qcow2_refcount_close(bs);
qcow2_free_snapshots(bs);
}
-static void qcow2_close(BlockDriverState *bs)
+static void GRAPH_UNLOCKED qcow2_close(BlockDriverState *bs)
{
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
qcow2_do_close(bs, true);
}
return ret;
}
-static int qcow2_change_backing_file(BlockDriverState *bs,
- const char *backing_file, const char *backing_fmt)
+static int coroutine_fn GRAPH_RDLOCK
+qcow2_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
+ const char *backing_fmt)
{
BDRVQcow2State *s = bs->opaque;
return qcow2_update_header(bs);
}
-static int qcow2_set_up_encryption(BlockDriverState *bs,
- QCryptoBlockCreateOptions *cryptoopts,
- Error **errp)
+static int coroutine_fn GRAPH_RDLOCK
+qcow2_set_up_encryption(BlockDriverState *bs,
+ QCryptoBlockCreateOptions *cryptoopts,
+ Error **errp)
{
BDRVQcow2State *s = bs->opaque;
QCryptoBlock *crypto = NULL;
* all of the allocated clusters (otherwise we get failing reads after
* EOF). Extend the image to the last allocated sector.
*/
- file_length = bdrv_getlength(s->data_file->bs);
+ file_length = bdrv_co_getlength(s->data_file->bs);
if (file_length < 0) {
error_setg_errno(errp, -file_length, "Could not get file size");
ret = file_length;
return refcount_bits;
}
-static int coroutine_fn
+static int coroutine_fn GRAPH_UNLOCKED
qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
{
BlockdevCreateOptionsQcow2 *qcow2_opts;
goto out;
}
- blk_unref(blk);
+ blk_co_unref(blk);
blk = NULL;
/*
goto out;
}
+ bdrv_graph_co_rdlock();
ret = qcow2_alloc_clusters(blk_bs(blk), 3 * cluster_size);
if (ret < 0) {
+ bdrv_graph_co_rdunlock();
error_setg_errno(errp, -ret, "Could not allocate clusters for qcow2 "
"header and refcount table");
goto out;
/* Create a full header (including things like feature table) */
ret = qcow2_update_header(blk_bs(blk));
+ bdrv_graph_co_rdunlock();
+
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not update qcow2 header");
goto out;
backing_format = BlockdevDriver_str(qcow2_opts->backing_fmt);
}
- ret = bdrv_change_backing_file(blk_bs(blk), qcow2_opts->backing_file,
- backing_format, false);
+ bdrv_graph_co_rdlock();
+ ret = bdrv_co_change_backing_file(blk_bs(blk), qcow2_opts->backing_file,
+ backing_format, false);
+ bdrv_graph_co_rdunlock();
+
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not assign backing file '%s' "
"with format '%s'", qcow2_opts->backing_file,
/* Want encryption? There you go. */
if (qcow2_opts->encrypt) {
+ bdrv_graph_co_rdlock();
ret = qcow2_set_up_encryption(blk_bs(blk), qcow2_opts->encrypt, errp);
+ bdrv_graph_co_rdunlock();
+
if (ret < 0) {
goto out;
}
}
- blk_unref(blk);
+ blk_co_unref(blk);
blk = NULL;
/* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning.
ret = 0;
out:
- blk_unref(blk);
- bdrv_unref(bs);
- bdrv_unref(data_bs);
+ blk_co_unref(blk);
+ bdrv_co_unref(bs);
+ bdrv_co_unref(data_bs);
return ret;
}
-static int coroutine_fn GRAPH_RDLOCK
+static int coroutine_fn GRAPH_UNLOCKED
qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
Error **errp)
{
ret = qcow2_co_create(create_options, errp);
finish:
if (ret < 0) {
+ bdrv_graph_co_rdlock();
bdrv_co_delete_file_noerr(bs);
bdrv_co_delete_file_noerr(data_bs);
+ bdrv_graph_co_rdunlock();
} else {
ret = 0;
}
qobject_unref(qdict);
- bdrv_unref(bs);
- bdrv_unref(data_bs);
+ bdrv_co_unref(bs);
+ bdrv_co_unref(data_bs);
qapi_free_BlockdevCreateOptions(create_options);
return ret;
}
-static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
+static bool coroutine_fn GRAPH_RDLOCK
+is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
{
int64_t nr;
int res;
* backing file. So, we need a loop.
*/
do {
- res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
+ res = bdrv_co_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
offset += nr;
bytes -= nr;
} while (res >= 0 && (res & BDRV_BLOCK_ZERO) && nr && bytes);
return ret;
}
-static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
- int64_t offset, int64_t bytes)
+static int coroutine_fn GRAPH_RDLOCK
+qcow2_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
{
int ret;
BDRVQcow2State *s = bs->opaque;
case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
if (bs->backing && bs->backing->bs) {
- int64_t backing_length = bdrv_getlength(bs->backing->bs);
+ int64_t backing_length = bdrv_co_getlength(bs->backing->bs);
if (src_offset >= backing_length) {
cur_write_flags |= BDRV_REQ_ZERO_WRITE;
} else {
goto fail;
}
- old_file_size = bdrv_getlength(bs->file->bs);
+ old_file_size = bdrv_co_getlength(bs->file->bs);
if (old_file_size < 0) {
error_setg_errno(errp, -old_file_size,
"Failed to inquire current file length");
break;
}
- old_file_size = bdrv_getlength(bs->file->bs);
+ old_file_size = bdrv_co_getlength(bs->file->bs);
if (old_file_size < 0) {
error_setg_errno(errp, -old_file_size,
"Failed to inquire current file length");
goto fail;
}
- BLKDBG_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED);
+ BLKDBG_CO_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED);
ret = bdrv_co_pwrite(s->data_file, cluster_offset, out_len, out_buf, 0);
if (ret < 0) {
goto fail;
* align end of file to a sector boundary to ease reading with
* sector based I/Os
*/
- int64_t len = bdrv_getlength(bs->file->bs);
+ int64_t len = bdrv_co_getlength(bs->file->bs);
if (len < 0) {
return len;
}
out_buf = qemu_blockalign(bs, s->cluster_size);
- BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_co_pread(bs->file, coffset, csize, buf, 0);
if (ret < 0) {
goto fail;
return ret;
}
-static int make_completely_empty(BlockDriverState *bs)
+static int GRAPH_RDLOCK make_completely_empty(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
Error *local_err = NULL;
return ret;
}
-static int qcow2_make_empty(BlockDriverState *bs)
+static int GRAPH_RDLOCK qcow2_make_empty(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
uint64_t offset, end_offset;
return ret;
}
-static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
+static coroutine_fn GRAPH_RDLOCK int qcow2_co_flush_to_os(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
int ret;
{
BDRVQcow2State *s = bs->opaque;
bdi->cluster_size = s->cluster_size;
+ bdi->subcluster_size = s->subcluster_size;
bdi->vm_state_offset = qcow2_vm_state_offset(s);
bdi->is_dirty = s->incompatible_features & QCOW2_INCOMPAT_DIRTY;
return 0;
}
-static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
- Error **errp)
+static ImageInfoSpecific * GRAPH_RDLOCK
+qcow2_get_specific_info(BlockDriverState *bs, Error **errp)
{
BDRVQcow2State *s = bs->opaque;
ImageInfoSpecific *spec_info;
return spec_info;
}
-static int qcow2_has_zero_init(BlockDriverState *bs)
+static int coroutine_mixed_fn GRAPH_RDLOCK
+qcow2_has_zero_init(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
bool preallocated;
return offset;
}
- BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0);
}
return offset;
}
- BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
}
-static int qcow2_has_compressed_clusters(BlockDriverState *bs)
+static int GRAPH_RDLOCK qcow2_has_compressed_clusters(BlockDriverState *bs)
{
int64_t offset = 0;
int64_t bytes = bdrv_getlength(bs);
* Downgrades an image's version. To achieve this, any incompatible features
* have to be removed.
*/
-static int qcow2_downgrade(BlockDriverState *bs, int target_version,
- BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
- Error **errp)
+static int GRAPH_RDLOCK
+qcow2_downgrade(BlockDriverState *bs, int target_version,
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
+ Error **errp)
{
BDRVQcow2State *s = bs->opaque;
int current_version = s->qcow_version;
* features of older versions, some things may have to be presented
* differently.
*/
-static int qcow2_upgrade(BlockDriverState *bs, int target_version,
- BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
- Error **errp)
+static int GRAPH_RDLOCK
+qcow2_upgrade(BlockDriverState *bs, int target_version,
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
+ Error **errp)
{
BDRVQcow2State *s = bs->opaque;
bool need_snapshot_update;
info->original_cb_opaque);
}
-static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
- BlockDriverAmendStatusCB *status_cb,
- void *cb_opaque,
- bool force,
- Error **errp)
+static int GRAPH_RDLOCK
+qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
+ bool force, Error **errp)
{
BDRVQcow2State *s = bs->opaque;
int old_version = s->qcow_version, new_version = old_version;
};
BlockDriver bdrv_qcow2 = {
- .format_name = "qcow2",
- .instance_size = sizeof(BDRVQcow2State),
- .bdrv_probe = qcow2_probe,
- .bdrv_open = qcow2_open,
- .bdrv_close = qcow2_close,
- .bdrv_reopen_prepare = qcow2_reopen_prepare,
- .bdrv_reopen_commit = qcow2_reopen_commit,
- .bdrv_reopen_commit_post = qcow2_reopen_commit_post,
- .bdrv_reopen_abort = qcow2_reopen_abort,
- .bdrv_join_options = qcow2_join_options,
- .bdrv_child_perm = bdrv_default_perms,
- .bdrv_co_create_opts = qcow2_co_create_opts,
- .bdrv_co_create = qcow2_co_create,
- .bdrv_has_zero_init = qcow2_has_zero_init,
- .bdrv_co_block_status = qcow2_co_block_status,
-
- .bdrv_co_preadv_part = qcow2_co_preadv_part,
- .bdrv_co_pwritev_part = qcow2_co_pwritev_part,
- .bdrv_co_flush_to_os = qcow2_co_flush_to_os,
-
- .bdrv_co_pwrite_zeroes = qcow2_co_pwrite_zeroes,
- .bdrv_co_pdiscard = qcow2_co_pdiscard,
- .bdrv_co_copy_range_from = qcow2_co_copy_range_from,
- .bdrv_co_copy_range_to = qcow2_co_copy_range_to,
- .bdrv_co_truncate = qcow2_co_truncate,
- .bdrv_co_pwritev_compressed_part = qcow2_co_pwritev_compressed_part,
- .bdrv_make_empty = qcow2_make_empty,
-
- .bdrv_snapshot_create = qcow2_snapshot_create,
- .bdrv_snapshot_goto = qcow2_snapshot_goto,
- .bdrv_snapshot_delete = qcow2_snapshot_delete,
- .bdrv_snapshot_list = qcow2_snapshot_list,
- .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp,
- .bdrv_measure = qcow2_measure,
- .bdrv_co_get_info = qcow2_co_get_info,
- .bdrv_get_specific_info = qcow2_get_specific_info,
-
- .bdrv_co_save_vmstate = qcow2_co_save_vmstate,
- .bdrv_co_load_vmstate = qcow2_co_load_vmstate,
-
- .is_format = true,
- .supports_backing = true,
- .bdrv_change_backing_file = qcow2_change_backing_file,
-
- .bdrv_refresh_limits = qcow2_refresh_limits,
- .bdrv_co_invalidate_cache = qcow2_co_invalidate_cache,
- .bdrv_inactivate = qcow2_inactivate,
-
- .create_opts = &qcow2_create_opts,
- .amend_opts = &qcow2_amend_opts,
- .strong_runtime_opts = qcow2_strong_runtime_opts,
- .mutable_opts = mutable_opts,
- .bdrv_co_check = qcow2_co_check,
- .bdrv_amend_options = qcow2_amend_options,
- .bdrv_co_amend = qcow2_co_amend,
-
- .bdrv_detach_aio_context = qcow2_detach_aio_context,
- .bdrv_attach_aio_context = qcow2_attach_aio_context,
+ .format_name = "qcow2",
+ .instance_size = sizeof(BDRVQcow2State),
+ .bdrv_probe = qcow2_probe,
+ .bdrv_open = qcow2_open,
+ .bdrv_close = qcow2_close,
+ .bdrv_reopen_prepare = qcow2_reopen_prepare,
+ .bdrv_reopen_commit = qcow2_reopen_commit,
+ .bdrv_reopen_commit_post = qcow2_reopen_commit_post,
+ .bdrv_reopen_abort = qcow2_reopen_abort,
+ .bdrv_join_options = qcow2_join_options,
+ .bdrv_child_perm = bdrv_default_perms,
+ .bdrv_co_create_opts = qcow2_co_create_opts,
+ .bdrv_co_create = qcow2_co_create,
+ .bdrv_has_zero_init = qcow2_has_zero_init,
+ .bdrv_co_block_status = qcow2_co_block_status,
+
+ .bdrv_co_preadv_part = qcow2_co_preadv_part,
+ .bdrv_co_pwritev_part = qcow2_co_pwritev_part,
+ .bdrv_co_flush_to_os = qcow2_co_flush_to_os,
+
+ .bdrv_co_pwrite_zeroes = qcow2_co_pwrite_zeroes,
+ .bdrv_co_pdiscard = qcow2_co_pdiscard,
+ .bdrv_co_copy_range_from = qcow2_co_copy_range_from,
+ .bdrv_co_copy_range_to = qcow2_co_copy_range_to,
+ .bdrv_co_truncate = qcow2_co_truncate,
+ .bdrv_co_pwritev_compressed_part = qcow2_co_pwritev_compressed_part,
+ .bdrv_make_empty = qcow2_make_empty,
+
+ .bdrv_snapshot_create = qcow2_snapshot_create,
+ .bdrv_snapshot_goto = qcow2_snapshot_goto,
+ .bdrv_snapshot_delete = qcow2_snapshot_delete,
+ .bdrv_snapshot_list = qcow2_snapshot_list,
+ .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp,
+ .bdrv_measure = qcow2_measure,
+ .bdrv_co_get_info = qcow2_co_get_info,
+ .bdrv_get_specific_info = qcow2_get_specific_info,
+
+ .bdrv_co_save_vmstate = qcow2_co_save_vmstate,
+ .bdrv_co_load_vmstate = qcow2_co_load_vmstate,
+
+ .is_format = true,
+ .supports_backing = true,
+ .bdrv_co_change_backing_file = qcow2_co_change_backing_file,
+
+ .bdrv_refresh_limits = qcow2_refresh_limits,
+ .bdrv_co_invalidate_cache = qcow2_co_invalidate_cache,
+ .bdrv_inactivate = qcow2_inactivate,
+
+ .create_opts = &qcow2_create_opts,
+ .amend_opts = &qcow2_amend_opts,
+ .strong_runtime_opts = qcow2_strong_runtime_opts,
+ .mutable_opts = mutable_opts,
+ .bdrv_co_check = qcow2_co_check,
+ .bdrv_amend_options = qcow2_amend_options,
+ .bdrv_co_amend = qcow2_co_amend,
+
+ .bdrv_detach_aio_context = qcow2_detach_aio_context,
+ .bdrv_attach_aio_context = qcow2_attach_aio_context,
.bdrv_supports_persistent_dirty_bitmap =
qcow2_supports_persistent_dirty_bitmap,