From patchwork Tue Jul 31 05:16:13 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Cody X-Patchwork-Id: 174142 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 97B6B2C009B for ; Tue, 31 Jul 2012 15:16:53 +1000 (EST) Received: from localhost ([::1]:59713 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Sw4p9-00088r-Jn for incoming@patchwork.ozlabs.org; Tue, 31 Jul 2012 01:16:51 -0400 Received: from eggs.gnu.org ([208.118.235.92]:34068) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Sw4oq-0007yH-4m for qemu-devel@nongnu.org; Tue, 31 Jul 2012 01:16:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Sw4oo-0005wR-KP for qemu-devel@nongnu.org; Tue, 31 Jul 2012 01:16:32 -0400 Received: from mx1.redhat.com ([209.132.183.28]:55911) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Sw4oo-0005wN-CJ for qemu-devel@nongnu.org; Tue, 31 Jul 2012 01:16:30 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q6V5GR3a020557 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 31 Jul 2012 01:16:27 -0400 Received: from localhost (ovpn-112-31.phx2.redhat.com [10.3.112.31]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q6V5GP90028411 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Tue, 31 Jul 2012 01:16:26 -0400 From: Jeff Cody To: qemu-devel@nongnu.org Date: Tue, 31 Jul 2012 01:16:13 -0400 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com, pbonzini@redhat.com, stefanha@gmail.com, supriyak@linux.vnet.ibm.com Subject: [Qemu-devel] [RFC PATCH 4/4] QAPI: add command for live block commit, 'block-commit' 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 The command for live block commit is added, which has the following arguments: device: the block device to perform the commit on (mandatory) base: the base image to commit into; optional (if not specified, it is the underlying original image) top: the top image of the commit - all data from inside top down to base will be committed into base. optional (if not specified, it is the active image) - see note below speed: maximum speed, in bytes/sec on_error: action to take on error (optional - default is report) note: eventually this will support merging down the active layer, but that code is not yet complete. If the active layer is passed in currently as top, or top is left to the default, then the error QERR_TOP_NOT_FOUND will be returned. The is down as a block job, so upon completion a BLOCK_JOB_COMPLETED will be emitted. Signed-off-by: Jeff Cody --- blockdev.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ qapi-schema.json | 33 +++++++++++++++++++++++ qmp-commands.hx | 6 +++++ 3 files changed, 117 insertions(+) diff --git a/blockdev.c b/blockdev.c index f39d301..a61ee38 100644 --- a/blockdev.c +++ b/blockdev.c @@ -831,6 +831,84 @@ exit: return; } +void qmp_block_commit(const char *device, + bool has_base, const char *base, + bool has_top, const char *top, + bool has_speed, int64_t speed, + bool has_on_error, BlockdevOnError on_error, + Error **errp) +{ + BlockDriverState *bs; + BlockDriverState *base_bs, *top_bs; + Error *local_err = NULL; + int orig_base_flags, orig_top_flags; + + if (!has_on_error) { + on_error = BLOCKDEV_ON_ERROR_REPORT; + } + + /* drain all i/o before commits */ + bdrv_drain_all(); + + + bs = bdrv_find(device); + if (!bs) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return; + } + if (base && has_base) { + base_bs = bdrv_find_backing_image(bs, base); + if (base_bs == NULL) { + error_set(errp, QERR_BASE_NOT_FOUND, base); + return; + } + } else { + base_bs = bdrv_find_base(bs); + if (base_bs == NULL) { + error_set(errp, QERR_BASE_NOT_FOUND, "NULL"); + return; + } + } + + if (top && has_top) { + /* if we want to allow the active layer, + * use 'bdrv_find_image()' here */ + top_bs = bdrv_find_backing_image(bs, top); + if (top_bs == NULL) { + error_set(errp, QERR_TOP_NOT_FOUND, top); + return; + } + } else { + top_bs = bs; + } + + orig_base_flags = bdrv_get_flags(base_bs); + /* convert base_bs to r/w, if necessary */ + if (!(orig_base_flags & BDRV_O_RDWR)) { + bdrv_reopen(base_bs, orig_base_flags | BDRV_O_RDWR); + } + + /* need to also make top r/w, so that when the commit is + * finished we can change the backing file */ + orig_top_flags = bdrv_get_flags(top_bs); + /* convert top_bs to r/w, if necessary */ + if (!(orig_top_flags & BDRV_O_RDWR)) { + bdrv_reopen(top_bs, orig_top_flags | BDRV_O_RDWR); + } + + commit_start(bs, base_bs, top_bs, speed, on_error, + block_job_cb, bs, orig_base_flags, orig_top_flags, + &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + /* Grab a reference so hotplug does not delete the BlockDriverState from + * underneath us. + */ + drive_get_ref(drive_get_by_blockdev(bs)); +} + void qmp_drive_mirror(const char *device, const char *target, bool has_format, const char *format, enum MirrorSyncMode sync, diff --git a/qapi-schema.json b/qapi-schema.json index db6903f..9ab6f90 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1365,6 +1365,39 @@ 'returns': 'str' } ## +# @block-commit +# +# Live commit of data from child image nodes into parent nodes - i.e., +# writes data between 'top' and 'base' into 'base'. +# +# @device: the name of the device +# +# @base: #optional The parent image of the device to write data into. +# If not specified, this is the original parent image. +# +# @top: #optional The child image, above which data will not be commited +# down. If not specified, this is the active layer. +# +# @speed: #optional the maximum speed, in bytes per second +# +# @on_error: #optional the action to take on an error (default report) +# +# Returns: Nothing on success +# If commit or stream is already active on this device, DeviceInUse +# If @device does not exist, DeviceNotFound +# If image commit is not supported by this device, NotSupported +# If @base does not exist, BaseNotFound +# If @top does not exist, TopNotFound +# If @speed is invalid, InvalidParameter +# +# Since: 1.2 +# +## +{ 'command': 'block-commit', + 'data': { 'device': 'str', '*base': 'str', '*top': 'str', + '*speed': 'int', '*on_error': 'BlockdevOnError' } } + +## # @drive-mirror # # Start mirroring a block device's writes to a new destination. diff --git a/qmp-commands.hx b/qmp-commands.hx index bde96cf..2f21142 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -723,6 +723,12 @@ EQMP }, { + .name = "block-commit", + .args_type = "device:B,base:s?,top:s?,speed:o?,on_error:s?", + .mhandler.cmd_new = qmp_marshal_input_block_commit, + }, + + { .name = "block-job-set-speed", .args_type = "device:B,speed:o", .mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,