rename blockdev-group-snapshot-sync

We will add other kinds of operation.  Prepare for this by adjusting
the schema.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Paolo Bonzini 2012-03-06 18:55:57 +01:00 committed by Kevin Wolf
parent dc8fb6df5a
commit 52e7c241ac
3 changed files with 96 additions and 76 deletions

View File

@ -719,31 +719,24 @@ void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
/* New and old BlockDriverState structs for group snapshots */ /* New and old BlockDriverState structs for group snapshots */
typedef struct BlkGroupSnapshotStates { typedef struct BlkTransactionStates {
BlockDriverState *old_bs; BlockDriverState *old_bs;
BlockDriverState *new_bs; BlockDriverState *new_bs;
QSIMPLEQ_ENTRY(BlkGroupSnapshotStates) entry; QSIMPLEQ_ENTRY(BlkTransactionStates) entry;
} BlkGroupSnapshotStates; } BlkTransactionStates;
/* /*
* 'Atomic' group snapshots. The snapshots are taken as a set, and if any fail * '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 * then we do not pivot any of the devices in the group, and abandon the
* snapshots * snapshots
*/ */
void qmp_blockdev_group_snapshot_sync(SnapshotDevList *dev_list, void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
Error **errp)
{ {
int ret = 0; int ret = 0;
SnapshotDevList *dev_entry = dev_list; BlockdevActionList *dev_entry = dev_list;
SnapshotDev *dev_info = NULL; BlkTransactionStates *states, *next;
BlkGroupSnapshotStates *states, *next;
BlockDriver *proto_drv;
BlockDriver *drv;
int flags;
const char *format;
const char *snapshot_file;
QSIMPLEQ_HEAD(snap_bdrv_states, BlkGroupSnapshotStates) snap_bdrv_states; QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionStates) snap_bdrv_states;
QSIMPLEQ_INIT(&snap_bdrv_states); QSIMPLEQ_INIT(&snap_bdrv_states);
/* drain all i/o before any snapshots */ /* drain all i/o before any snapshots */
@ -751,21 +744,46 @@ void qmp_blockdev_group_snapshot_sync(SnapshotDevList *dev_list,
/* We don't do anything in this loop that commits us to the snapshot */ /* We don't do anything in this loop that commits us to the snapshot */
while (NULL != dev_entry) { while (NULL != dev_entry) {
BlockdevAction *dev_info = NULL;
BlockDriver *proto_drv;
BlockDriver *drv;
int flags;
const char *device;
const char *format = "qcow2";
const char *new_image_file = NULL;
dev_info = dev_entry->value; dev_info = dev_entry->value;
dev_entry = dev_entry->next; dev_entry = dev_entry->next;
states = g_malloc0(sizeof(BlkGroupSnapshotStates)); states = g_malloc0(sizeof(BlkTransactionStates));
QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, states, entry); QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, states, entry);
states->old_bs = bdrv_find(dev_info->device); switch (dev_info->kind) {
case BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC:
device = dev_info->blockdev_snapshot_sync->device;
if (dev_info->blockdev_snapshot_sync->has_format) {
format = dev_info->blockdev_snapshot_sync->format;
}
new_image_file = dev_info->blockdev_snapshot_sync->snapshot_file;
break;
default:
abort();
}
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) { 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; goto delete_and_fail;
} }
if (bdrv_in_use(states->old_bs)) { 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; goto delete_and_fail;
} }
@ -778,44 +796,30 @@ void qmp_blockdev_group_snapshot_sync(SnapshotDevList *dev_list,
} }
} }
snapshot_file = dev_info->snapshot_file;
flags = states->old_bs->open_flags; flags = states->old_bs->open_flags;
if (!dev_info->has_format) { proto_drv = bdrv_find_protocol(new_image_file);
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);
if (!proto_drv) { if (!proto_drv) {
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
goto delete_and_fail; goto delete_and_fail;
} }
/* create new image w/backing file */ /* 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->filename,
states->old_bs->drv->format_name, states->old_bs->drv->format_name,
NULL, -1, flags); NULL, -1, flags);
if (ret) { 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; goto delete_and_fail;
} }
/* We will manually add the backing_hd field to the bs later */ /* We will manually add the backing_hd field to the bs later */
states->new_bs = bdrv_new(""); 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); flags | BDRV_O_NO_BACKING, drv);
if (ret != 0) { 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; goto delete_and_fail;
} }
} }

View File

@ -1118,7 +1118,7 @@
{ 'command': 'block_resize', 'data': { 'device': 'str', 'size': 'int' }} { 'command': 'block_resize', 'data': { 'device': 'str', 'size': 'int' }}
## ##
# @SnapshotDev # @BlockdevSnapshot
# #
# @device: the name of the device to generate the snapshot from. # @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'. # @format: #optional the format of the snapshot image, default is 'qcow2'.
## ##
{ 'type': 'SnapshotDev', { 'type': 'BlockdevSnapshot',
'data': {'device': 'str', 'snapshot-file': 'str', '*format': 'str' } } 'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str' } }
## ##
# @blockdev-group-snapshot-sync # @BlockdevAction
# #
# Generates a synchronous snapshot of a group of one or more block devices, # A discriminated record of operations that can be performed with
# as atomically as possible. If the snapshot of any device in the group # @transaction.
# fails, then the entire group snapshot will be abandoned and the ##
# appropriate error returned. { 'union': 'BlockdevAction',
'data': {
'blockdev-snapshot-sync': 'BlockdevSnapshot',
} }
##
# @transaction
#
# 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 blockdev-snapshot-sync.
# #
# List of: # List of:
# @SnapshotDev: information needed for the device snapshot # @BlockdevAction: information needed for the device snapshot
# #
# Returns: nothing on success # Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound # If @device is not a valid block device, DeviceNotFound
@ -1147,13 +1158,14 @@
# If @snapshot-file can't be opened, OpenFileFailed # If @snapshot-file can't be opened, OpenFileFailed
# If @format is invalid, InvalidBlockFormat # If @format is invalid, InvalidBlockFormat
# #
# Note: The group snapshot attempt returns failure on the first snapshot # Note: The transaction aborts on the first failure. Therefore, there will
# device failure. Therefore, there will be only one device or snapshot file # be only one device or snapshot file returned in an error condition, and
# returned in an error condition, and subsequent devices will not have been # subsequent actions will not have been attempted.
# attempted. #
# Since 1.1
## ##
{ 'command': 'blockdev-group-snapshot-sync', { 'command': 'transaction',
'data': { 'devlist': [ 'SnapshotDev' ] } } 'data': { 'actions': [ 'BlockdevAction' ] } }
## ##
# @blockdev-snapshot-sync # @blockdev-snapshot-sync

View File

@ -687,41 +687,45 @@ EQMP
.mhandler.cmd_new = qmp_marshal_input_block_job_cancel, .mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
}, },
{ {
.name = "blockdev-group-snapshot-sync", .name = "transaction",
.args_type = "devlist:O", .args_type = "actions:O",
.params = "device:B,snapshot-file:s,format:s?", .mhandler.cmd_new = qmp_marshal_input_transaction,
.mhandler.cmd_new = qmp_marshal_input_blockdev_group_snapshot_sync,
}, },
SQMP SQMP
blockdev-group-snapshot-sync transaction
---------------------- -----------
Synchronous snapshot of one or more block devices. A list array input Atomically operate on one or more block devices. The only supported
is accepted, that contains the device and snapshot file information for operation for now is snapshotting. If there is any failure performing
each device in group. The default format, if not specified, is qcow2. any of the operations, all snapshots for the group are abandoned, and
the original disks pre-snapshot attempt are used.
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.
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: Arguments:
devlist array: actions array:
- "device": device name to snapshot (json-string) - "type": the operation to perform. The only supported
- "snapshot-file": name of new image file (json-string) value is "blockdev-snapshot-sync". (json-string)
- "format": format of new image (json-string, optional) - "data": a dictionary. The contents depend on the value
of "type". When "type" is "blockdev-snapshot-sync":
- "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: Example:
-> { "execute": "blockdev-group-snapshot-sync", "arguments": -> { "execute": "transaction",
{ "devlist": [{ "device": "ide-hd0", "arguments": { "actions": [
"snapshot-file": "/some/place/my-image", { 'type': 'blockdev-snapshot-sync', 'data' : { "device": "ide-hd0",
"format": "qcow2" }, "snapshot-file": "/some/place/my-image",
{ "device": "ide-hd1", "format": "qcow2" } },
"snapshot-file": "/some/place/my-image2", { 'type': 'blockdev-snapshot-sync', 'data' : { "device": "ide-hd1",
"format": "qcow2" }] } } "snapshot-file": "/some/place/my-image2",
"format": "qcow2" } } ] } }
<- { "return": {} } <- { "return": {} }
EQMP EQMP