From f86002aeec6fc0b2d9b3c18361b9c275a7e370ed Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Fri, 23 Mar 2012 12:12:56 -0300 Subject: [RHEL6 qemu-kvm PATCH 3/5] add mirroring to transaction RH-Author: Federico Simoncelli Message-id: <1332504778-17403-12-git-send-email-fsimonce@redhat.com> Patchwork-id: 38954 O-Subject: [RHEL6.3 qemu-kvm PATCH v6 11/13] add mirroring to transaction Bugzilla: 802284 RH-Acked-by: Paolo Bonzini RH-Acked-by: Jeffrey Cody RH-Acked-by: Laszlo Ersek From: Paolo Bonzini With it comes a new image creation mode, "no-backing-file", that can be used to stream an image so that the destination does not need the original image's backing file(s). Both bdrv_append and blkmirror will set the backing_hd on the target, even if the image is created without one, so that both streaming and copy-on-write work properly (at least with qcow2 or qed, not raw). Streaming mode works with the following gotchas: - streaming will rewrite every bit of the source image; - zero writes are not supported by the blkmirror driver, hence both the source and the destination image will grow to full size. Signed-off-by: Paolo Bonzini BZ: 802284 Based on an patch posted upstream: http://lists.gnu.org/archive/html/qemu-devel/2012-03/msg00901.html Deviations from upstream: - drive-mirror transaction renamed with a downstream prefix --- blockdev.c | 71 ++++++++++++++++++++++++++++++++++++++++++----------- qapi-schema.json | 22 ++++++++++++++++- qemu-monitor.hx | 16 ++++++++++-- 3 files changed, 90 insertions(+), 19 deletions(-) Signed-off-by: Eduardo Habkost --- blockdev.c | 71 ++++++++++++++++++++++++++++++++++++++++++----------- qapi-schema.json | 22 ++++++++++++++++- qemu-monitor.hx | 16 ++++++++++-- 3 files changed, 90 insertions(+), 19 deletions(-) diff --git a/blockdev.c b/blockdev.c index ffc9d36..bdbb5a1 100644 --- a/blockdev.c +++ b/blockdev.c @@ -679,6 +679,7 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp) int ret = 0; BlockdevActionList *dev_entry = dev_list; BlkTransactionStates *states, *next; + char *new_source = NULL; QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionStates) snap_bdrv_states; QSIMPLEQ_INIT(&snap_bdrv_states); @@ -690,12 +691,14 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp) while (NULL != dev_entry) { BlockdevAction *dev_info = NULL; BlockDriver *proto_drv; - BlockDriver *drv; + BlockDriver *target_drv; + BlockDriver *drv = NULL; int flags; enum NewImageMode mode; const char *new_image_file; const char *device; const char *format = "qcow2"; + uint64_t size; dev_info = dev_entry->value; dev_entry = dev_entry->next; @@ -714,16 +717,36 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp) format = dev_info->blockdev_snapshot_sync->format; } mode = dev_info->blockdev_snapshot_sync->mode; + new_source = g_strdup(new_image_file); break; + + case BLOCKDEV_ACTION_KIND___COM_REDHAT_DRIVE_MIRROR: + device = dev_info->__com_redhat_drive_mirror->device; + drv = bdrv_find_format("blkmirror"); + if (!dev_info->__com_redhat_drive_mirror->has_mode) { + dev_info->__com_redhat_drive_mirror->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; + } + new_image_file = dev_info->__com_redhat_drive_mirror->target; + if (dev_info->__com_redhat_drive_mirror->has_format) { + format = dev_info->__com_redhat_drive_mirror->format; + } + mode = dev_info->__com_redhat_drive_mirror->mode; + new_source = g_strdup_printf("blkmirror:%s:%s", format, + dev_info->__com_redhat_drive_mirror->target); + break; + default: abort(); } - drv = bdrv_find_format(format); - if (!drv) { + target_drv = bdrv_find_format(format); + if (!target_drv) { error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); goto delete_and_fail; } + if (!drv) { + drv = target_drv; + } states->old_bs = bdrv_find(device); if (!states->old_bs) { @@ -747,7 +770,7 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp) flags = states->old_bs->open_flags; - proto_drv = bdrv_find_protocol(new_image_file); + proto_drv = bdrv_find_protocol(new_source); if (!proto_drv) { error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); goto delete_and_fail; @@ -759,25 +782,42 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp) } /* create new image w/backing file */ - if (mode != NEW_IMAGE_MODE_EXISTING) { - 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, new_image_file); - goto delete_and_fail; - } + switch (mode) { + case NEW_IMAGE_MODE_EXISTING: + ret = 0; + break; + case NEW_IMAGE_MODE_ABSOLUTE_PATHS: + ret = bdrv_img_create(new_image_file, format, + states->old_bs->filename, + states->old_bs->drv->format_name, + NULL, -1, flags); + break; + case NEW_IMAGE_MODE_NO_BACKING_FILE: + bdrv_get_geometry(states->old_bs, &size); + size *= 512; + ret = bdrv_img_create(new_image_file, format, + NULL, NULL, NULL, size, flags); + break; + default: + ret = -1; + break; + } + + if (ret) { + 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, new_image_file, + ret = bdrv_open(states->new_bs, new_source, flags | BDRV_O_NO_BACKING, drv); if (ret != 0) { - error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file); + error_set(errp, QERR_OPEN_FILE_FAILED, new_source); goto delete_and_fail; } + g_free(new_source); + new_source = NULL; } @@ -805,6 +845,7 @@ exit: QSIMPLEQ_FOREACH_SAFE(states, &snap_bdrv_states, entry, next) { g_free(states); } + g_free(new_source); return; } #endif diff --git a/qapi-schema.json b/qapi-schema.json index f436cea..24f6b99 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -14,10 +14,12 @@ # @absolute-paths: QEMU should create a new image with absolute paths # for the backing file. # +# @no-backing-file: QEMU should create a new image with no backing file. +# # Since: 1.1 ## { 'enum': 'NewImageMode' - 'data': [ 'existing', 'absolute-paths' ] } + 'data': [ 'existing', 'absolute-paths', 'no-backing-file' ] } ## # @BlockdevSnapshot @@ -36,6 +38,23 @@ '*mode': 'NewImageMode' } } ## +# @BlockdevMirror +# +# @device: the name of the device to start mirroring. +# +# @target: the image that will start receiving writes for @device. A new +# file will be created unless @mode is "existing". +# +# @format: #optional the format of the target image, default is 'qcow2'. +# +# @mode: #optional whether and how QEMU should create a new image, default is +# 'absolute-paths'. +## +{ 'type': 'BlockdevMirror', + 'data': { 'device': 'str', 'target': 'str', '*format': 'str', + '*mode': 'NewImageMode' } } + +## # @BlockdevAction # # A discriminated record of operations that can be performed with @@ -44,6 +63,7 @@ { 'union': 'BlockdevAction', 'data': { 'blockdev-snapshot-sync': 'BlockdevSnapshot', + '__com.redhat_drive-mirror': 'BlockdevMirror', } } ## diff --git a/qemu-monitor.hx b/qemu-monitor.hx index a96b733..b492bce 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -1497,12 +1497,16 @@ SQMP transaction ----------- -Atomically operate on one or more block devices. The only supported -operation for now is snapshotting. If there is any failure performing +Atomically operate on one or more block devices, snapshotting them +or enabling mirrored writes. 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. +Mirrored writes keep the previous image file open, and start writing +data also to the new file specified in the command. + 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. @@ -1517,7 +1521,7 @@ Arguments: actions array: - "type": the operation to perform. The only supported - value is "blockdev-snapshot-sync". (json-string) + values are "blockdev-snapshot-sync" and "mirror". (json-string) - "data": a dictionary. The contents depend on the value of "type". When "type" is "blockdev-snapshot-sync": - "device": device name to snapshot (json-string) @@ -1525,6 +1529,12 @@ actions array: - "format": format of new image (json-string, optional) - "mode": whether and how QEMU should create the snapshot file (NewImageMode, optional, default "absolute-paths") + When "type" is "__com.redhat_drive-mirror": + - "device": device name to snapshot (json-string) + - "target": name of destination image file (json-string) + - "format": format of new image (json-string, optional) + - "mode": how QEMU should look for an existing image file + (NewImageMode, optional, default "absolute-paths") Example: -- 1.7.3.2