qmp: convert blockdev-snapshot-sync to a wrapper around transactions

Simplify the blockdev-snapshot-sync code and gain failsafe operation
by turning it into a wrapper around the new transaction command.  A new
option is also added matching "mode".

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:59 +01:00 committed by Kevin Wolf
parent bc8b094feb
commit 6cc2a4157b
5 changed files with 44 additions and 73 deletions

View File

@ -649,72 +649,33 @@ void do_commit(Monitor *mon, const QDict *qdict)
} }
} }
static void blockdev_do_action(int kind, void *data, Error **errp)
{
BlockdevAction action;
BlockdevActionList list;
action.kind = kind;
action.data = data;
list.value = &action;
list.next = NULL;
qmp_transaction(&list, errp);
}
void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file, void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
bool has_format, const char *format, bool has_format, const char *format,
bool has_mode, enum NewImageMode mode,
Error **errp) Error **errp)
{ {
BlockDriverState *bs; BlockdevSnapshot snapshot = {
BlockDriver *drv, *old_drv, *proto_drv; .device = (char *) device,
int ret = 0; .snapshot_file = (char *) snapshot_file,
int flags; .has_format = has_format,
char old_filename[1024]; .format = (char *) format,
.has_mode = has_mode,
bs = bdrv_find(device); .mode = mode,
if (!bs) { };
error_set(errp, QERR_DEVICE_NOT_FOUND, device); blockdev_do_action(BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC, &snapshot,
return; errp);
}
if (bdrv_in_use(bs)) {
error_set(errp, QERR_DEVICE_IN_USE, device);
return;
}
pstrcpy(old_filename, sizeof(old_filename), bs->filename);
old_drv = bs->drv;
flags = bs->open_flags;
if (!has_format) {
format = "qcow2";
}
drv = bdrv_find_format(format);
if (!drv) {
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
return;
}
proto_drv = bdrv_find_protocol(snapshot_file);
if (!proto_drv) {
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
return;
}
ret = bdrv_img_create(snapshot_file, format, bs->filename,
bs->drv->format_name, NULL, -1, flags);
if (ret) {
error_set(errp, QERR_UNDEFINED_ERROR);
return;
}
bdrv_drain_all();
bdrv_flush(bs);
bdrv_close(bs);
ret = bdrv_open(bs, snapshot_file, flags, drv);
/*
* If reopening the image file we just created fails, fall back
* and try to re-open the original image. If that fails too, we
* are in serious trouble.
*/
if (ret != 0) {
ret = bdrv_open(bs, old_filename, flags, old_drv);
if (ret != 0) {
error_set(errp, QERR_OPEN_FILE_FAILED, old_filename);
} else {
error_set(errp, QERR_OPEN_FILE_FAILED, snapshot_file);
}
}
} }

View File

@ -882,14 +882,17 @@ ETEXI
{ {
.name = "snapshot_blkdev", .name = "snapshot_blkdev",
.args_type = "device:B,snapshot-file:s?,format:s?", .args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?",
.params = "device [new-image-file] [format]", .params = "[-n] device [new-image-file] [format]",
.help = "initiates a live snapshot\n\t\t\t" .help = "initiates a live snapshot\n\t\t\t"
"of device. If a new image file is specified, the\n\t\t\t" "of device. If a new image file is specified, the\n\t\t\t"
"new image file will become the new root image.\n\t\t\t" "new image file will become the new root image.\n\t\t\t"
"If format is specified, the snapshot file will\n\t\t\t" "If format is specified, the snapshot file will\n\t\t\t"
"be created in that format. Otherwise the\n\t\t\t" "be created in that format. Otherwise the\n\t\t\t"
"snapshot will be internal! (currently unsupported)", "snapshot will be internal! (currently unsupported).\n\t\t\t"
"The default format is qcow2. The -n flag requests QEMU\n\t\t\t"
"to reuse the image found in new-image-file, instead of\n\t\t\t"
"recreating it from scratch.",
.mhandler.cmd = hmp_snapshot_blkdev, .mhandler.cmd = hmp_snapshot_blkdev,
}, },

6
hmp.c
View File

@ -692,6 +692,8 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
const char *device = qdict_get_str(qdict, "device"); const char *device = qdict_get_str(qdict, "device");
const char *filename = qdict_get_try_str(qdict, "snapshot-file"); const char *filename = qdict_get_try_str(qdict, "snapshot-file");
const char *format = qdict_get_try_str(qdict, "format"); const char *format = qdict_get_try_str(qdict, "format");
int reuse = qdict_get_try_bool(qdict, "reuse", 0);
enum NewImageMode mode;
Error *errp = NULL; Error *errp = NULL;
if (!filename) { if (!filename) {
@ -702,7 +704,9 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
return; return;
} }
qmp_blockdev_snapshot_sync(device, filename, !!format, format, &errp); mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
qmp_blockdev_snapshot_sync(device, filename, !!format, format,
true, mode, &errp);
hmp_handle_error(mon, &errp); hmp_handle_error(mon, &errp);
} }

View File

@ -1141,6 +1141,9 @@
# @snapshot-file: the target of the new image. A new file will be created. # @snapshot-file: the target of the new image. A new file will be created.
# #
# @format: #optional the format of the snapshot image, default is 'qcow2'. # @format: #optional the format of the snapshot image, default is 'qcow2'.
#
# @mode: #optional whether and how QEMU should create a new image, default is
# 'absolute-paths'.
## ##
{ 'type': 'BlockdevSnapshot', { 'type': 'BlockdevSnapshot',
'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str', 'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str',
@ -1197,21 +1200,19 @@
# #
# @format: #optional the format of the snapshot image, default is 'qcow2'. # @format: #optional the format of the snapshot image, default is 'qcow2'.
# #
# @mode: #optional whether and how QEMU should create a new image, default is
# 'absolute-paths'.
#
# 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
# 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
# #
# Notes: One of the last steps taken by this command is to close the current
# image being used by @device and open the @snapshot-file one. If that
# fails, the command will try to reopen the original image file. If
# that also fails OpenFileFailed will be returned and the guest may get
# unexpected errors.
#
# Since 0.14.0 # Since 0.14.0
## ##
{ 'command': 'blockdev-snapshot-sync', { 'command': 'blockdev-snapshot-sync',
'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str' } } 'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str',
'*mode': 'NewImageMode'} }
## ##
# @human-monitor-command: # @human-monitor-command:

View File

@ -760,6 +760,8 @@ Arguments:
- "device": device name to snapshot (json-string) - "device": device name to snapshot (json-string)
- "snapshot-file": name of new image file (json-string) - "snapshot-file": name of new image file (json-string)
- "mode": whether and how QEMU should create the snapshot file
(NewImageMode, optional, default "absolute-paths")
- "format": format of new image (json-string, optional) - "format": format of new image (json-string, optional)
Example: Example: