From patchwork Wed Jun 25 19:40:11 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Cody X-Patchwork-Id: 364130 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id E838514009E for ; Thu, 26 Jun 2014 05:42:33 +1000 (EST) Received: from localhost ([::1]:40687 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Wzt5T-0008EM-VT for incoming@patchwork.ozlabs.org; Wed, 25 Jun 2014 15:42:31 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40702) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Wzt3Z-0005Nj-4e for qemu-devel@nongnu.org; Wed, 25 Jun 2014 15:40:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Wzt3S-0000RY-Tz for qemu-devel@nongnu.org; Wed, 25 Jun 2014 15:40:33 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49309) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Wzt3S-0000RF-Li for qemu-devel@nongnu.org; Wed, 25 Jun 2014 15:40:26 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s5PJeOtY006023 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 25 Jun 2014 15:40:24 -0400 Received: from localhost ([10.3.112.8]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s5PJeM0w022216 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=NO); Wed, 25 Jun 2014 15:40:23 -0400 From: Jeff Cody To: qemu-devel@nongnu.org Date: Wed, 25 Jun 2014 15:40:11 -0400 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com, benoit.canet@irqsave.net, pkrempa@redhat.com, famz@redhat.com, stefanha@redhat.com Subject: [Qemu-devel] [PATCH v7 for 2.1 3/4] block: add backing-file option to block-stream 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 On some image chains, QEMU may not always be able to resolve the filenames properly, when updating the backing file of an image after a block job. For instance, certain relative pathnames may fail, or drives may have been specified originally by file descriptor (e.g. /dev/fd/???), or a relative protocol pathname may have been used. In these instances, QEMU may lack the information to be able to make the correct choice, but the user or management layer most likely does have that knowledge. With this extension to the block-stream api, the user is able to change the backing file of the active layer as part of the block-stream operation. This allows the change to be 'safe', in the sense that if the attempt to write the active image metadata fails, then the block-stream operation returns failure, without disrupting the guest. If a backing file string is not specified in the command, the backing file string to use is determined in the same manner as it was previously. Reviewed-by: Eric Blake Signed-off-by: Jeff Cody --- block/stream.c | 11 +++++------ blockdev.c | 23 +++++++++++++++++++---- hmp.c | 2 +- qapi/block-core.json | 19 +++++++++++++++++-- qmp-commands.hx | 2 +- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/block/stream.c b/block/stream.c index 0433409..34de8ba 100644 --- a/block/stream.c +++ b/block/stream.c @@ -32,7 +32,7 @@ typedef struct StreamBlockJob { RateLimit limit; BlockDriverState *base; BlockdevOnError on_error; - char backing_file_id[1024]; + char *backing_file_str; } StreamBlockJob; static int coroutine_fn stream_populate(BlockDriverState *bs, @@ -186,7 +186,7 @@ wait: if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) { const char *base_id = NULL, *base_fmt = NULL; if (base) { - base_id = s->backing_file_id; + base_id = s->backing_file_str; if (base->drv) { base_fmt = base->drv->format_name; } @@ -196,6 +196,7 @@ wait: } qemu_vfree(buf); + g_free(s->backing_file_str); block_job_completed(&s->common, ret); } @@ -217,7 +218,7 @@ static const BlockJobDriver stream_job_driver = { }; void stream_start(BlockDriverState *bs, BlockDriverState *base, - const char *base_id, int64_t speed, + const char *backing_file_str, int64_t speed, BlockdevOnError on_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) @@ -237,9 +238,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, } s->base = base; - if (base_id) { - pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id); - } + s->backing_file_str = g_strdup(backing_file_str); s->on_error = on_error; s->common.co = qemu_coroutine_create(stream_run); diff --git a/blockdev.c b/blockdev.c index 4a7885e..61b84d0 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1866,14 +1866,17 @@ static void block_job_cb(void *opaque, int ret) bdrv_put_ref_bh_schedule(bs); } -void qmp_block_stream(const char *device, bool has_base, - const char *base, bool has_speed, int64_t speed, +void qmp_block_stream(const char *device, + bool has_base, const char *base, + bool has_backing_file, const char *backing_file, + bool has_speed, int64_t speed, bool has_on_error, BlockdevOnError on_error, Error **errp) { BlockDriverState *bs; BlockDriverState *base_bs = NULL; Error *local_err = NULL; + const char *base_name = NULL; if (!has_on_error) { on_error = BLOCKDEV_ON_ERROR_REPORT; @@ -1889,15 +1892,27 @@ void qmp_block_stream(const char *device, bool has_base, return; } - if (base) { + if (has_base) { base_bs = bdrv_find_backing_image(bs, base); if (base_bs == NULL) { error_set(errp, QERR_BASE_NOT_FOUND, base); return; } + base_name = base; } - stream_start(bs, base_bs, base, has_speed ? speed : 0, + /* if we are streaming the entire chain, the result will have no backing + * file, and specifying one is therefore an error */ + if (base_bs == NULL && has_backing_file) { + error_setg(errp, "backing file specified, but streaming the " + "entire chain"); + return; + } + + /* backing_file string overrides base bs filename */ + base_name = has_backing_file ? backing_file : base_name; + + stream_start(bs, base_bs, base_name, has_speed ? speed : 0, on_error, block_job_cb, bs, &local_err); if (local_err) { error_propagate(errp, local_err); diff --git a/hmp.c b/hmp.c index dc3d279..0dc2499 100644 --- a/hmp.c +++ b/hmp.c @@ -1175,7 +1175,7 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict) const char *base = qdict_get_try_str(qdict, "base"); int64_t speed = qdict_get_try_int(qdict, "speed", 0); - qmp_block_stream(device, base != NULL, base, + qmp_block_stream(device, base != NULL, base, false, NULL, qdict_haskey(qdict, "speed"), speed, true, BLOCKDEV_ON_ERROR_REPORT, &error); diff --git a/qapi/block-core.json b/qapi/block-core.json index 9ebe38c..f1b505b 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -888,6 +888,21 @@ # # @base: #optional the common backing file name # +# @backing-file: #optional The backing file string to write into the active +# layer. This filename is not validated. +# +# If a pathname string is such that it cannot be +# resolved by QEMU, that means that subsequent QMP or +# HMP commands must use node-names for the image in +# question, as filename lookup methods will fail. +# +# If not specified, QEMU will automatically determine +# the backing file string to use, or error out if there +# is no obvious choice. Care should be taken when +# specifying the string, to specify a valid filename or +# protocol. +# (Since 2.1) +# # @speed: #optional the maximum speed, in bytes per second # # @on-error: #optional the action to take on an error (default report). @@ -900,8 +915,8 @@ # Since: 1.1 ## { 'command': 'block-stream', - 'data': { 'device': 'str', '*base': 'str', '*speed': 'int', - '*on-error': 'BlockdevOnError' } } + 'data': { 'device': 'str', '*base': 'str', '*backing-file': 'str', + '*speed': 'int', '*on-error': 'BlockdevOnError' } } ## # @block-job-set-speed: diff --git a/qmp-commands.hx b/qmp-commands.hx index e0dea3f..7b029c4 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -979,7 +979,7 @@ EQMP { .name = "block-stream", - .args_type = "device:B,base:s?,speed:o?,on-error:s?", + .args_type = "device:B,base:s?,speed:o?,backing-file:s?,on-error:s?", .mhandler.cmd_new = qmp_marshal_input_block_stream, },