From patchwork Mon Mar 5 17:34:01 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 144728 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 9C9A8B6F9D for ; Tue, 6 Mar 2012 04:40:01 +1100 (EST) Received: from localhost ([::1]:47295 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S4bor-0007wo-S7 for incoming@patchwork.ozlabs.org; Mon, 05 Mar 2012 12:35:33 -0500 Received: from eggs.gnu.org ([208.118.235.92]:49848) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S4boC-0006dK-Tc for qemu-devel@nongnu.org; Mon, 05 Mar 2012 12:35:01 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S4bo9-0002BF-4d for qemu-devel@nongnu.org; Mon, 05 Mar 2012 12:34:52 -0500 Received: from mail-pw0-f45.google.com ([209.85.160.45]:39869) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S4bo8-00023Q-RG for qemu-devel@nongnu.org; Mon, 05 Mar 2012 12:34:49 -0500 Received: by mail-pw0-f45.google.com with SMTP id uo5so4612123pbc.4 for ; Mon, 05 Mar 2012 09:34:48 -0800 (PST) Received-SPF: pass (google.com: domain of paolo.bonzini@gmail.com designates 10.68.237.201 as permitted sender) client-ip=10.68.237.201; Authentication-Results: mr.google.com; spf=pass (google.com: domain of paolo.bonzini@gmail.com designates 10.68.237.201 as permitted sender) smtp.mail=paolo.bonzini@gmail.com; dkim=pass header.i=paolo.bonzini@gmail.com Received: from mr.google.com ([10.68.237.201]) by 10.68.237.201 with SMTP id ve9mr35292064pbc.45.1330968888008 (num_hops = 1); Mon, 05 Mar 2012 09:34:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=X64UpuwVeUSg159nNu20FJmOMmbHO9p7agZuh2SyH78=; b=n8cEfsPHwTcFp1CsGN0u5Eqc9OD9uVDwwz4ev2z+yDlVC8eUtfMxnsfAguVlWFRNMD hO7Yzk12i5tXdOrrJg0YHU0AcYROy+b0nNQ4RLr/5fndZkA2e8dNEKrNdGfw57XEQWOo EOn4MOcWYwbWCtlSOG43WNTSQCr4Zt/MmRQ/01BI1t/ko9ygbEUc7MP9axe8NVrighBD nik0ErFXhhc4QwpJ1SOaDwc5KE0FsE94mfYcVr6Dwaeh2Iq23cP7G/PxQZRfH132/1FA 07voMc3Qn87qgNwGT2mMmho7VUOJ6GldGerppcz9hmT9LabvwBOb3pNYoq/RAZoQOwTH mQ8A== Received: by 10.68.237.201 with SMTP id ve9mr30563321pbc.45.1330968887943; Mon, 05 Mar 2012 09:34:47 -0800 (PST) Received: from yakj.usersys.redhat.com (93-34-182-16.ip50.fastwebnet.it. [93.34.182.16]) by mx.google.com with ESMTPS id i9sm13836905pba.22.2012.03.05.09.34.43 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 05 Mar 2012 09:34:46 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Mon, 5 Mar 2012 18:34:01 +0100 Message-Id: <1330968842-24635-8-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.7.7.6 In-Reply-To: <1330968842-24635-1-git-send-email-pbonzini@redhat.com> References: <1330968842-24635-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.160.45 Cc: kwolf@redhat.com, fsimonce@redhat.com, eblake@redhat.com, stefanha@linux.vnet.ibm.com, lcapitulino@redhat.com Subject: [Qemu-devel] [PATCH v3 7/8] add mirroring to transaction X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- blockdev.c | 53 +++++++++++++++++++++++++++++++++++++++++++---------- qapi-schema.json | 21 +++++++++++++++++++-- qmp-commands.hx | 12 +++++++++++- 3 files changed, 73 insertions(+), 13 deletions(-) diff --git a/blockdev.c b/blockdev.c index 06c3017..df086d1 100644 --- a/blockdev.c +++ b/blockdev.c @@ -689,6 +689,7 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp) int ret = 0; BlockdevActionList *dev_entry = dev_list; BlkTransactionStates *states; + char *new_source = NULL; QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionStates) snap_bdrv_states; QSIMPLEQ_INIT(&snap_bdrv_states); @@ -700,7 +701,8 @@ 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; @@ -724,16 +726,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_DRIVE_MIRROR: + device = dev_info->drive_mirror->device; + drv = bdrv_find_format("blkmirror"); + if (!dev_info->drive_mirror->has_mode) { + dev_info->drive_mirror->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; + } + new_image_file = dev_info->drive_mirror->target; + if (dev_info->drive_mirror->has_format) { + format = dev_info->drive_mirror->format; + } + mode = dev_info->drive_mirror->mode; + new_source = g_strdup_printf("blkmirror:%s:%s", format, + dev_info->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) { @@ -757,7 +779,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; @@ -765,10 +787,18 @@ 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 (mode == 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); + } else { + uint64_t size; + bdrv_get_geometry(states->old_bs, &size); + size *= 512; + ret = bdrv_img_create(new_image_file, format, + NULL, NULL, NULL, size, flags); + } if (ret) { error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file); goto delete_and_fail; @@ -777,12 +807,14 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp) /* 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; } @@ -810,6 +842,7 @@ exit: QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) { g_free(states); } + g_free(new_source); return; } diff --git a/qapi-schema.json b/qapi-schema.json index 0d24240..a61e90c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1133,7 +1133,7 @@ # Since: 1.1 ## { 'enum': 'NewImageMode' - 'data': [ 'existing', 'absolute-paths' ] } + 'data': [ 'existing', 'absolute-paths', 'no-backing-file' ] } ## # @BlockdevSnapshot @@ -1152,6 +1152,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 @@ -1159,7 +1175,8 @@ ## { 'union': 'BlockdevAction', 'data': { - 'blockdev-snapshot-sync': 'BlockdevSnapshot' + 'blockdev-snapshot-sync': 'BlockdevSnapshot', + 'drive-mirror': 'BlockdevMirror', } } ## diff --git a/qmp-commands.hx b/qmp-commands.hx index dfe8a5b..9dcafd4 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -701,12 +701,16 @@ operation for now is snapshotting. If there is any failure performing 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. @@ -716,7 +720,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) @@ -724,6 +728,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 "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: