From e98f7226541dc1bf0f8c684f28419f90e3ab18a6 Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Fri, 23 Mar 2012 12:12:53 -0300 Subject: [RHEL6 qemu-kvm PATCH 8/9] qmp: convert blockdev-snapshot-sync to a wrapper around transactions RH-Author: Federico Simoncelli Message-id: <1332504778-17403-9-git-send-email-fsimonce@redhat.com> Patchwork-id: 38947 O-Subject: [RHEL6.3 qemu-kvm PATCH v6 08/13] qmp: convert blockdev-snapshot-sync to a wrapper around transactions Bugzilla: 802284 RH-Acked-by: Kevin Wolf RH-Acked-by: Jeffrey Cody RH-Acked-by: Paolo Bonzini From: Paolo Bonzini 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 Signed-off-by: Kevin Wolf BZ: 802284 (cherry picked from commit 6cc2a4157b31c47303da96c5ed7836db3c10def6) --- blockdev.c | 85 ++++++++++++++--------------------------------------- hmp.c | 6 +++- qapi-schema.json | 15 +++++---- qemu-monitor.hx | 15 ++++++--- 4 files changed, 46 insertions(+), 75 deletions(-) Signed-off-by: Eduardo Habkost --- blockdev.c | 85 ++++++++++++++--------------------------------------- hmp.c | 6 +++- qapi-schema.json | 15 +++++---- qemu-monitor.hx | 15 ++++++--- 4 files changed, 46 insertions(+), 75 deletions(-) diff --git a/blockdev.c b/blockdev.c index 4cb2d6d..ffc9d36 100644 --- a/blockdev.c +++ b/blockdev.c @@ -631,72 +631,33 @@ void do_commit(Monitor *mon, const QDict *qdict) } #ifdef CONFIG_LIVE_SNAPSHOTS +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, bool has_format, const char *format, + bool has_mode, enum NewImageMode mode, Error **errp) { - BlockDriverState *bs; - BlockDriver *drv, *old_drv, *proto_drv; - int ret = 0; - int flags; - char old_filename[1024]; - - bs = bdrv_find(device); - if (!bs) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); - return; - } - 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); - } - } + BlockdevSnapshot snapshot = { + .device = (char *) device, + .snapshot_file = (char *) snapshot_file, + .has_format = has_format, + .format = (char *) format, + .has_mode = has_mode, + .mode = mode, + }; + blockdev_do_action(BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC, &snapshot, + errp); } #endif diff --git a/hmp.c b/hmp.c index dccd5ff..7391a9a 100644 --- a/hmp.c +++ b/hmp.c @@ -28,6 +28,8 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) const char *device = qdict_get_str(qdict, "device"); const char *filename = qdict_get_try_str(qdict, "snapshot-file"); const char *format = qdict_get_try_str(qdict, "format"); + int reuse = qdict_get_try_bool(qdict, "reuse", 0); + enum NewImageMode mode; Error *errp = NULL; if (!filename) { @@ -38,7 +40,9 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict) 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); } #endif diff --git a/qapi-schema.json b/qapi-schema.json index 278aab1..f436cea 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -27,6 +27,9 @@ # @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'. +# +# @mode: #optional whether and how QEMU should create a new image, default is +# 'absolute-paths'. ## { 'type': 'BlockdevSnapshot', 'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str', @@ -83,19 +86,17 @@ # # @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 # If @device is not a valid block device, DeviceNotFound # If @snapshot-file can't be opened, OpenFileFailed # 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 ## { 'command': 'blockdev-snapshot-sync', - 'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str' } } + 'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str', + '*mode': 'NewImageMode'} } #endif diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 1817a71..a96b733 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -1245,14 +1245,17 @@ EQMP #ifdef CONFIG_LIVE_SNAPSHOTS { .name = "snapshot_blkdev", - .args_type = "device:B,snapshot-file:s?,format:s?", - .params = "device [new-image-file] [format]", + .args_type = "reuse:-n,device:B,snapshot-file:s?,format:s?", + .params = "[-n] device [new-image-file] [format]", .help = "initiates a live snapshot\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" "If format is specified, the snapshot file will\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, }, #endif @@ -1541,8 +1544,8 @@ EQMP #ifdef CONFIG_LIVE_SNAPSHOTS { .name = "blockdev-snapshot-sync", - .args_type = "device:B,snapshot-file:s,format:s?", - .params = "device [new-image-file] [format]", + .args_type = "device:B,snapshot-file:s,mode:s?,format:s?", + .params = "device [new-image-file] [mode] [format]", .user_print = monitor_user_noop, .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync, }, @@ -1562,6 +1565,8 @@ Arguments: - "device": device name to snapshot (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) Example: -- 1.7.3.2