if ((buf = qemu_opt_get(opts, "format")) != NULL) {
if (is_help_option(buf)) {
error_printf("Supported formats:");
- bdrv_iterate_format(bdrv_format_print, NULL);
+ bdrv_iterate_format(bdrv_format_print, NULL, false);
+ error_printf("\nSupported formats (read-only):");
+ bdrv_iterate_format(bdrv_format_print, NULL, true);
error_printf("\n");
goto early_err;
}
blk = blockdev_init(filename, bs_opts, &local_err);
bs_opts = NULL;
if (!blk) {
- if (local_err) {
- error_propagate(errp, local_err);
- }
+ error_propagate(errp, local_err);
goto fail;
} else {
assert(!local_err);
const BlkActionOps *ops;
JobTxn *block_job_txn;
TransactionProperties *txn_props;
- QSIMPLEQ_ENTRY(BlkActionState) entry;
+ QTAILQ_ENTRY(BlkActionState) entry;
};
/* internal snapshot private data */
error_setg_errno(errp, -size, "bdrv_getlength failed");
goto out;
}
+ bdrv_refresh_filename(state->old_bs);
bdrv_img_create(new_image_file, format,
state->old_bs->filename,
state->old_bs->drv->format_name,
}
options = qdict_new();
- if (s->has_snapshot_node_name) {
+ if (snapshot_node_name) {
qdict_put_str(options, "node-name", snapshot_node_name);
}
qdict_put_str(options, "driver", format);
* bdrv_reopen_multiple() across all the entries at once, because we
* don't want to abort all of them if one of them fails the reopen */
if (!atomic_read(&state->old_bs->copy_on_read)) {
- bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR,
- NULL);
+ bdrv_reopen_set_read_only(state->old_bs, true, NULL);
}
aio_context_release(aio_context);
action->has_granularity, action->granularity,
action->has_persistent, action->persistent,
action->has_autoload, action->autoload,
- action->has_x_disabled, action->x_disabled,
+ action->has_disabled, action->disabled,
&local_err);
if (!local_err) {
return;
}
- action = common->action->u.x_block_dirty_bitmap_enable.data;
+ action = common->action->u.block_dirty_bitmap_enable.data;
state->bitmap = block_dirty_bitmap_lookup(action->node,
action->name,
NULL,
return;
}
- action = common->action->u.x_block_dirty_bitmap_disable.data;
+ action = common->action->u.block_dirty_bitmap_disable.data;
state->bitmap = block_dirty_bitmap_lookup(action->node,
action->name,
NULL,
}
}
+static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node,
+ const char *target,
+ strList *bitmaps,
+ HBitmap **backup,
+ Error **errp);
+
static void block_dirty_bitmap_merge_prepare(BlkActionState *common,
Error **errp)
{
BlockDirtyBitmapMerge *action;
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
common, common);
- BdrvDirtyBitmap *merge_source;
if (action_check_completion_mode(common, errp) < 0) {
return;
}
- action = common->action->u.x_block_dirty_bitmap_merge.data;
- state->bitmap = block_dirty_bitmap_lookup(action->node,
- action->dst_name,
- &state->bs,
- errp);
- if (!state->bitmap) {
- return;
- }
-
- merge_source = bdrv_find_dirty_bitmap(state->bs, action->src_name);
- if (!merge_source) {
- return;
- }
+ action = common->action->u.block_dirty_bitmap_merge.data;
- bdrv_merge_dirty_bitmap(state->bitmap, merge_source, &state->backup, errp);
+ state->bitmap = do_block_dirty_bitmap_merge(action->node, action->target,
+ action->bitmaps, &state->backup,
+ errp);
}
static void abort_prepare(BlkActionState *common, Error **errp)
.commit = block_dirty_bitmap_free_backup,
.abort = block_dirty_bitmap_restore,
},
- [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_ENABLE] = {
+ [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ENABLE] = {
.instance_size = sizeof(BlockDirtyBitmapState),
.prepare = block_dirty_bitmap_enable_prepare,
.abort = block_dirty_bitmap_enable_abort,
},
- [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_DISABLE] = {
+ [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_DISABLE] = {
.instance_size = sizeof(BlockDirtyBitmapState),
.prepare = block_dirty_bitmap_disable_prepare,
.abort = block_dirty_bitmap_disable_abort,
},
- [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_MERGE] = {
+ [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_MERGE] = {
.instance_size = sizeof(BlockDirtyBitmapState),
.prepare = block_dirty_bitmap_merge_prepare,
.commit = block_dirty_bitmap_free_backup,
BlkActionState *state, *next;
Error *local_err = NULL;
- QSIMPLEQ_HEAD(snap_bdrv_states, BlkActionState) snap_bdrv_states;
- QSIMPLEQ_INIT(&snap_bdrv_states);
+ QTAILQ_HEAD(, BlkActionState) snap_bdrv_states;
+ QTAILQ_INIT(&snap_bdrv_states);
/* Does this transaction get canceled as a group on failure?
* If not, we don't really need to make a JobTxn.
state->action = dev_info;
state->block_job_txn = block_job_txn;
state->txn_props = props;
- QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
+ QTAILQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
state->ops->prepare(state, &local_err);
if (local_err) {
}
}
- QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {
+ QTAILQ_FOREACH(state, &snap_bdrv_states, entry) {
if (state->ops->commit) {
state->ops->commit(state);
}
delete_and_fail:
/* failure, and it is all-or-none; roll back all operations */
- QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {
+ QTAILQ_FOREACH_REVERSE(state, &snap_bdrv_states, entry) {
if (state->ops->abort) {
state->ops->abort(state);
}
}
exit:
- QSIMPLEQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) {
+ QTAILQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) {
if (state->ops->clean) {
state->ops->clean(state);
}
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
+ AioContext *aio_context = NULL;
if (!name || name[0] == '\0') {
error_setg(errp, "Bitmap name cannot be empty");
disabled = false;
}
- if (persistent &&
- !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
- {
- return;
+ if (persistent) {
+ aio_context = bdrv_get_aio_context(bs);
+ aio_context_acquire(aio_context);
+ if (!bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) {
+ goto out;
+ }
}
bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
if (bitmap == NULL) {
- return;
+ goto out;
}
if (disabled) {
}
bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
+ out:
+ if (aio_context) {
+ aio_context_release(aio_context);
+ }
}
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
Error *local_err = NULL;
+ AioContext *aio_context = NULL;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap || !bs) {
}
if (bdrv_dirty_bitmap_get_persistance(bitmap)) {
+ aio_context = bdrv_get_aio_context(bs);
+ aio_context_acquire(aio_context);
bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
- return;
+ goto out;
}
}
bdrv_release_dirty_bitmap(bs, bitmap);
+ out:
+ if (aio_context) {
+ aio_context_release(aio_context);
+ }
}
/**
bdrv_clear_dirty_bitmap(bitmap, NULL);
}
-void qmp_x_block_dirty_bitmap_enable(const char *node, const char *name,
+void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
Error **errp)
{
BlockDriverState *bs;
bdrv_enable_dirty_bitmap(bitmap);
}
-void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name,
+void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
Error **errp)
{
BlockDriverState *bs;
bdrv_disable_dirty_bitmap(bitmap);
}
-void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name,
- const char *src_name, Error **errp)
+static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node,
+ const char *target,
+ strList *bitmaps,
+ HBitmap **backup,
+ Error **errp)
{
BlockDriverState *bs;
- BdrvDirtyBitmap *dst, *src;
+ BdrvDirtyBitmap *dst, *src, *anon;
+ strList *lst;
+ Error *local_err = NULL;
- dst = block_dirty_bitmap_lookup(node, dst_name, &bs, errp);
+ dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
if (!dst) {
- return;
+ return NULL;
}
- src = bdrv_find_dirty_bitmap(bs, src_name);
- if (!src) {
- error_setg(errp, "Dirty bitmap '%s' not found", src_name);
- return;
+ anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst),
+ NULL, errp);
+ if (!anon) {
+ return NULL;
+ }
+
+ for (lst = bitmaps; lst; lst = lst->next) {
+ src = bdrv_find_dirty_bitmap(bs, lst->value);
+ if (!src) {
+ error_setg(errp, "Dirty bitmap '%s' not found", lst->value);
+ dst = NULL;
+ goto out;
+ }
+
+ bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ dst = NULL;
+ goto out;
+ }
}
- bdrv_merge_dirty_bitmap(dst, src, NULL, errp);
+ /* Merge into dst; dst is unchanged on failure. */
+ bdrv_merge_dirty_bitmap(dst, anon, backup, errp);
+
+ out:
+ bdrv_release_dirty_bitmap(bs, anon);
+ return dst;
+}
+
+void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
+ strList *bitmaps, Error **errp)
+{
+ do_block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
}
BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
goto out;
}
assert(bdrv_get_aio_context(base_bs) == aio_context);
+ bdrv_refresh_filename(base_bs);
base_name = base_bs->filename;
}
goto out;
}
} else if (has_top && top) {
+ /* This strcmp() is just a shortcut, there is no need to
+ * refresh @bs's filename. If it mismatches,
+ * bdrv_find_backing_image() will do the refresh and may still
+ * return @bs. */
if (strcmp(bs->filename, top) != 0) {
top_bs = bdrv_find_backing_image(bs, top);
}
if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
assert(backup->format);
if (source) {
+ bdrv_refresh_filename(source);
bdrv_img_create(backup->target, backup->format, source->filename,
source->drv->format_name, NULL,
size, flags, false, &local_err);
return bdrv_named_nodes_list(errp);
}
+XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp)
+{
+ return bdrv_get_xdbg_block_graph(errp);
+}
+
BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
Error **errp)
{
break;
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
/* create new image with backing file */
+ bdrv_refresh_filename(source);
bdrv_img_create(arg->target, format,
source->filename,
source->drv->format_name,
BlockDriverState *image_bs = NULL;
Error *local_err = NULL;
bool ro;
- int open_flags;
int ret;
bs = qmp_get_root_bs(device, errp);
}
/* if not r/w, reopen to make r/w */
- open_flags = image_bs->open_flags;
ro = bdrv_is_read_only(image_bs);
if (ro) {
- bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (bdrv_reopen_set_read_only(image_bs, false, errp) != 0) {
goto out;
}
}
}
if (ro) {
- bdrv_reopen(image_bs, open_flags, &local_err);
+ bdrv_reopen_set_read_only(image_bs, true, &local_err);
error_propagate(errp, local_err);
}
goto out;
}
- if (!bs->monitor_list.tqe_prev) {
+ if (!QTAILQ_IN_USE(bs, monitor_list)) {
error_setg(errp, "Node %s is not owned by the monitor",
bs->node_name);
goto out;