We will add other kinds of operation. Prepare for this by adjusting the schema and renaming some types/variables.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- blockdev.c | 73 +++++++++++++++++++++++++++++------------------------ qapi-schema.json | 33 ++++++++++++++++-------- qmp-commands.hx | 51 ++++++++++++++++++++----------------- 3 files changed, 90 insertions(+), 67 deletions(-) diff --git a/blockdev.c b/blockdev.c index 96a893b..3c35553 100644 --- a/blockdev.c +++ b/blockdev.c @@ -716,31 +716,32 @@ void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file, /* New and old BlockDriverState structs for group snapshots */ -typedef struct BlkGroupSnapshotStates { +typedef struct BlkTransactionStates { BlockDriverState *old_bs; BlockDriverState *new_bs; - QSIMPLEQ_ENTRY(BlkGroupSnapshotStates) entry; -} BlkGroupSnapshotStates; + QSIMPLEQ_ENTRY(BlkTransactionStates) entry; +} BlkTransactionStates; /* * 'Atomic' group snapshots. The snapshots are taken as a set, and if any fail * then we do not pivot any of the devices in the group, and abandon the * snapshots */ -void qmp_blockdev_group_snapshot_sync(SnapshotDevList *dev_list, - Error **errp) +void qmp_blockdev_transaction(BlockdevActionList *dev_list, + Error **errp) { int ret = 0; - SnapshotDevList *dev_entry = dev_list; - SnapshotDev *dev_info = NULL; - BlkGroupSnapshotStates *states; + BlockdevActionList *dev_entry = dev_list; + BlockdevAction *dev_info = NULL; + BlkTransactionStates *states; BlockDriver *proto_drv; BlockDriver *drv; int flags; + const char *device; const char *format; - const char *snapshot_file; + const char *new_image_file = NULL; - QSIMPLEQ_HEAD(snap_bdrv_states, BlkGroupSnapshotStates) snap_bdrv_states; + QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionStates) snap_bdrv_states; QSIMPLEQ_INIT(&snap_bdrv_states); /* drain all i/o before any snapshots */ @@ -751,18 +752,38 @@ void qmp_blockdev_group_snapshot_sync(SnapshotDevList *dev_list, dev_info = dev_entry->value; dev_entry = dev_entry->next; - states = g_malloc0(sizeof(BlkGroupSnapshotStates)); + states = g_malloc0(sizeof(BlkTransactionStates)); QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, states, entry); - states->old_bs = bdrv_find(dev_info->device); + switch (dev_info->kind) { + case BLOCKDEV_ACTION_KIND_SNAPSHOT: + device = dev_info->snapshot->device; + new_image_file = dev_info->snapshot->snapshot_file; + format = dev_info->snapshot->format; + assert(!(dev_info->snapshot->has_format && format)); + break; + default: + abort(); + } + if (!format) { + format = "qcow2"; + } + + drv = bdrv_find_format(format); + if (!drv) { + error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); + goto delete_and_fail; + } + + states->old_bs = bdrv_find(device); if (!states->old_bs) { - error_set(errp, QERR_DEVICE_NOT_FOUND, dev_info->device); + error_set(errp, QERR_DEVICE_NOT_FOUND, device); goto delete_and_fail; } if (bdrv_in_use(states->old_bs)) { - error_set(errp, QERR_DEVICE_IN_USE, dev_info->device); + error_set(errp, QERR_DEVICE_IN_USE, device); goto delete_and_fail; } @@ -775,44 +796,30 @@ void qmp_blockdev_group_snapshot_sync(SnapshotDevList *dev_list, } } - snapshot_file = dev_info->snapshot_file; - flags = states->old_bs->open_flags; - if (!dev_info->has_format) { - format = "qcow2"; - } else { - format = dev_info->format; - } - - drv = bdrv_find_format(format); - if (!drv) { - error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); - goto delete_and_fail; - } - - proto_drv = bdrv_find_protocol(snapshot_file); + proto_drv = bdrv_find_protocol(new_image_file); if (!proto_drv) { error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); goto delete_and_fail; } /* create new image w/backing file */ - ret = bdrv_img_create(snapshot_file, format, + ret = bdrv_img_create(new_image_file, format, states->old_bs->filename, states->old_bs->drv->format_name, NULL, -1, flags); if (ret) { - error_set(errp, QERR_OPEN_FILE_FAILED, snapshot_file); + error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file); goto delete_and_fail; } /* We will manually add the backing_hd field to the bs later */ states->new_bs = bdrv_new(""); - ret = bdrv_open(states->new_bs, snapshot_file, + ret = bdrv_open(states->new_bs, new_image_file, flags | BDRV_O_NO_BACKING, drv); if (ret != 0) { - error_set(errp, QERR_OPEN_FILE_FAILED, snapshot_file); + error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file); goto delete_and_fail; } } diff --git a/qapi-schema.json b/qapi-schema.json index 5f293c4..d2fbee3 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1118,7 +1118,7 @@ { 'command': 'block_resize', 'data': { 'device': 'str', 'size': 'int' }} ## -# @SnapshotDev +# @BlockdevSnapshot # # @device: the name of the device to generate the snapshot from. # @@ -1126,19 +1126,30 @@ # # @format: #optional the format of the snapshot image, default is 'qcow2'. ## -{ 'type': 'SnapshotDev', - 'data': {'device': 'str', 'snapshot-file': 'str', '*format': 'str' } } +{ 'type': 'BlockdevSnapshot', + 'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str' } } + +## +# @BlockdevAction +# +# A discriminated record of operations that can be performed with +# @blockdev-transaction. +## +{ 'union': 'BlockdevAction', + 'data': { + 'snapshot': 'BlockdevSnapshot' + } } ## -# @blockdev-group-snapshot-sync +# @blockdev-transaction # -# Generates a synchronous snapshot of a group of one or more block devices, -# as atomically as possible. If the snapshot of any device in the group -# fails, then the entire group snapshot will be abandoned and the -# appropriate error returned. +# Atomically operate on a group of one or more block devices. If +# any operation fails, then the entire set of actions will be +# abandoned and the appropriate error returned. The only operation +# supported is currently snapshot. # # List of: -# @SnapshotDev: information needed for the device snapshot +# @BlockdevAction: information needed for the device snapshot # # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound @@ -1152,8 +1163,8 @@ # returned in an error condition, and subsequent devices will not have been # attempted. ## -{ 'command': 'blockdev-group-snapshot-sync', - 'data': { 'devlist': [ 'SnapshotDev' ] } } +{ 'command': 'blockdev-transaction', + 'data': { 'actions': [ 'BlockdevAction' ] } } ## # @blockdev-snapshot-sync diff --git a/qmp-commands.hx b/qmp-commands.hx index 0c9bfac..ee05ec2 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -687,41 +687,46 @@ EQMP .mhandler.cmd_new = qmp_marshal_input_block_job_cancel, }, { - .name = "blockdev-group-snapshot-sync", - .args_type = "devlist:O", - .params = "device:B,snapshot-file:s,format:s?", - .mhandler.cmd_new = qmp_marshal_input_blockdev_group_snapshot_sync, + .name = "blockdev-transaction", + .args_type = "actions:O", + .mhandler.cmd_new = qmp_marshal_input_blockdev_transaction, }, SQMP -blockdev-group-snapshot-sync +blockdev-transaction ---------------------- -Synchronous snapshot of one or more block devices. A list array input -is accepted, that contains the device and snapshot file information for -each device in group. The default format, if not specified, is qcow2. - -If there is any failure creating or opening a new snapshot, all snapshots -for the group are abandoned, and the original disks pre-snapshot attempt -are used. +Atomically operate on one or more block devices. The only supported +operation for now is snapshotting. If there is any failure performing +any of the operations, all snapshots for the group are abandoned, and +the original disks pre-snapshot attempt are used. +A list of dictionaries is accepted, that contains the actions to be performed. +For snapshots this is the device, the file to use for the new snapshot, +and the format. The default format, if not specified, is qcow2. Arguments: -devlist array: - - "device": device name to snapshot (json-string) - - "snapshot-file": name of new image file (json-string) - - "format": format of new image (json-string, optional) +actions array: + - "type": the operation to perform. The only supported + value is "snapshot". (json-string) + - "data": a dictionary. The contents depend on the value + of "type". When "type" is "snapshot": + - "device": device name to snapshot (json-string) + - "snapshot-file": name of new image file (json-string) + - "format": format of new image (json-string, optional) Example: --> { "execute": "blockdev-group-snapshot-sync", "arguments": - { "devlist": [{ "device": "ide-hd0", - "snapshot-file": "/some/place/my-image", - "format": "qcow2" }, - { "device": "ide-hd1", - "snapshot-file": "/some/place/my-image2", - "format": "qcow2" }] } } +-> { "execute": "blockdev-transaction", + "arguments": { "actions": [ + { 'type': 'snapshot, 'data' : { "device": "ide-hd0", + "snapshot-file": "/some/place/my-image", + "format": "qcow2" } }, + { 'type': 'snapshot, 'data' : { "device": "ide-hd1", + "snapshot-file": "/some/place/my-image2", + "format": "qcow2", + "op": "snapshot" } } ] } } <- { "return": {} } EQMP -- 1.7.7.6