From patchwork Tue Jul 24 11:04:11 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 172874 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 1C4A62C0090 for ; Tue, 24 Jul 2012 22:40:36 +1000 (EST) Received: from localhost ([::1]:42748 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1StcxD-0000Qu-5B for incoming@patchwork.ozlabs.org; Tue, 24 Jul 2012 07:07:03 -0400 Received: from eggs.gnu.org ([208.118.235.92]:56931) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1StcwX-000851-Nf for qemu-devel@nongnu.org; Tue, 24 Jul 2012 07:06:26 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1StcwS-0005rg-85 for qemu-devel@nongnu.org; Tue, 24 Jul 2012 07:06:21 -0400 Received: from mail-gg0-f173.google.com ([209.85.161.173]:58807) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1StcwS-0005ql-2k for qemu-devel@nongnu.org; Tue, 24 Jul 2012 07:06:16 -0400 Received: by mail-gg0-f173.google.com with SMTP id p1so6580043ggn.4 for ; Tue, 24 Jul 2012 04:06:16 -0700 (PDT) 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=c6nv0fQg0GofkIuIzmEnRGNh4SGmh/IX9ym3euaON+o=; b=GrIGwQyw5n+OYCeadVkEV9oGZDl2XJ+SBGK/qJyuPtySadDXZ9BgQaUWM71w3dyOim dtHRup0TaSWqZTEY1FBS88ih+2CWeWAF//TfNv8HsdZQO4yCbr/4N3n1BXMucpDdubu1 dGt4HQlFyfhNMAUHeBVmEFwyGA3zcZB6/pHGhioOr0UYyJRyO+so5yMhVzpQuLsutu3d HWUvKPhdKnFQGsCfdnUqrE6ST+BOVwE5vjw4f7DNdZbO1CJieXEqUTz/m67NZ3eg5b3P PS3sf2tQIz1bDXGyOHpkVcc6Pq89zXhm3itPsNtkts69PgSXHu/BlczAE8mpq9fMTbRx cKzA== Received: by 10.42.10.73 with SMTP id p9mr14392605icp.43.1343127975682; Tue, 24 Jul 2012 04:06:15 -0700 (PDT) Received: from yakj.usersys.redhat.com (93-34-189-113.ip51.fastwebnet.it. [93.34.189.113]) by mx.google.com with ESMTPS id if4sm1752561igc.10.2012.07.24.04.06.12 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 24 Jul 2012 04:06:14 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Tue, 24 Jul 2012 13:04:11 +0200 Message-Id: <1343127865-16608-34-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1343127865-16608-1-git-send-email-pbonzini@redhat.com> References: <1343127865-16608-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.161.173 Cc: kwolf@redhat.com, jcody@redhat.com, eblake@redhat.com, stefanha@linux.vnet.ibm.com Subject: [Qemu-devel] [PATCH 33/47] mirror: add support for on-source-error/on-target-error 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 Error management is important for mirroring; otherwise, an error on the target (even something as "innocent" as ENOSPC) requires to start again with a full copy. Similar to on_read_error/on_write_error, two separate knobs are provided for on_source_error (reads) and on_target_error (writes). The default is 'report' for both. The 'ignore' policy will leave the sector dirty, so that it will be retried later. Thus, it will not cause corruption. Signed-off-by: Paolo Bonzini --- block/mirror.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- block_int.h | 4 ++++ blockdev.c | 14 ++++++++++++-- hmp.c | 3 ++- qapi-schema.json | 12 +++++++++++- qmp-commands.hx | 8 +++++++- 6 files changed, 81 insertions(+), 10 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 4454ef3..fb54d27 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -32,13 +32,15 @@ typedef struct MirrorBlockJob { RateLimit limit; BlockDriverState *target; MirrorSyncMode mode; + BlockdevOnError on_source_error, on_target_error; bool synced; bool complete; int64_t sector_num; uint8_t *buf; } MirrorBlockJob; -static int coroutine_fn mirror_iteration(MirrorBlockJob *s) +static int coroutine_fn mirror_iteration(MirrorBlockJob *s, + BlockErrorAction *p_action) { BlockDriverState *source = s->common.bs; BlockDriverState *target = s->target; @@ -60,9 +62,24 @@ static int coroutine_fn mirror_iteration(MirrorBlockJob *s) trace_mirror_one_iteration(s, s->sector_num, nb_sectors); ret = bdrv_co_readv(source, s->sector_num, nb_sectors, &qiov); if (ret < 0) { - return ret; + *p_action = block_job_error_action(&s->common, source, + s->on_source_error, true, -ret); + s->synced = false; + goto fail; } - return bdrv_co_writev(target, s->sector_num, nb_sectors, &qiov); + ret = bdrv_co_writev(target, s->sector_num, nb_sectors, &qiov); + if (ret < 0) { + *p_action = block_job_error_action(&s->common, target, + s->on_target_error, false, -ret); + s->synced = false; + goto fail; + } + return 0; + +fail: + /* Try again later. */ + bdrv_set_dirty(source, s->sector_num, nb_sectors); + return ret; } static void coroutine_fn mirror_run(void *opaque) @@ -118,8 +135,9 @@ static void coroutine_fn mirror_run(void *opaque) cnt = bdrv_get_dirty_count(bs); if (cnt != 0) { - ret = mirror_iteration(s); - if (ret < 0) { + BlockErrorAction action = BDRV_ACTION_REPORT; + ret = mirror_iteration(s, &action); + if (ret < 0 && action == BDRV_ACTION_REPORT) { break; } cnt = bdrv_get_dirty_count(bs); @@ -193,6 +211,7 @@ static void coroutine_fn mirror_run(void *opaque) immediate_exit: g_free(s->buf); bdrv_set_dirty_tracking(bs, false); + bdrv_iostatus_disable(s->target); if (s->complete && ret == 0) { bdrv_swap(s->target, s->common.bs); } else { @@ -213,6 +232,13 @@ static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp) ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME); } +static void mirror_iostatus_reset(BlockJob *job) +{ + MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); + + bdrv_iostatus_reset(s->target); +} + static void mirror_query(BlockJob *job, BlockJobInfo *info) { MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); @@ -249,25 +275,39 @@ static BlockJobType mirror_job_type = { .instance_size = sizeof(MirrorBlockJob), .job_type = "mirror", .set_speed = mirror_set_speed, + .iostatus_reset= mirror_iostatus_reset, .query = mirror_query, .complete = mirror_complete, }; void mirror_start(BlockDriverState *bs, BlockDriverState *target, int64_t speed, MirrorSyncMode mode, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) { MirrorBlockJob *s; + if ((on_source_error == BLOCKDEV_ON_ERROR_STOP || + on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) && + !bdrv_iostatus_is_enabled(bs)) { + error_set(errp, QERR_INVALID_PARAMETER, "on-source-error"); + return; + } + s = block_job_create(&mirror_job_type, bs, speed, cb, opaque, errp); if (!s) { return; } + s->on_source_error = on_source_error; + s->on_target_error = on_target_error; s->target = target; s->mode = mode; bdrv_set_dirty_tracking(bs, true); + bdrv_set_on_error(s->target, on_target_error, on_target_error); + bdrv_iostatus_enable(s->target); s->common.co = qemu_coroutine_create(mirror_run); trace_mirror_start(bs, s, s->common.co, opaque); qemu_coroutine_enter(s->common.co, s); diff --git a/block_int.h b/block_int.h index 714f939..0de2fdc 100644 --- a/block_int.h +++ b/block_int.h @@ -311,6 +311,8 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, * @target: Block device to write to. * @speed: The maximum speed, in bytes per second, or 0 for unlimited. * @mode: Whether to collapse all images in the chain to the target. + * @on_source_error: The action to take upon error reading from the source. + * @on_target_error: The action to take upon error writing to the target. * @cb: Completion function for the job. * @opaque: Opaque pointer value passed to @cb. * @errp: Error object. @@ -322,6 +324,8 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, */ void mirror_start(BlockDriverState *bs, BlockDriverState *target, int64_t speed, MirrorSyncMode mode, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp); diff --git a/blockdev.c b/blockdev.c index 4b4574a..eb528cd 100644 --- a/blockdev.c +++ b/blockdev.c @@ -831,7 +831,10 @@ void qmp_drive_mirror(const char *device, const char *target, bool has_format, const char *format, enum MirrorSyncMode sync, bool has_mode, enum NewImageMode mode, - bool has_speed, int64_t speed, Error **errp) + bool has_speed, int64_t speed, + bool has_on_source_error, BlockdevOnError on_source_error, + bool has_on_target_error, BlockdevOnError on_target_error, + Error **errp) { BlockDriverInfo bdi; BlockDriverState *bs; @@ -846,6 +849,12 @@ void qmp_drive_mirror(const char *device, const char *target, if (!has_speed) { speed = 0; } + if (!has_on_source_error) { + on_source_error = BLOCKDEV_ON_ERROR_REPORT; + } + if (!has_on_target_error) { + on_target_error = BLOCKDEV_ON_ERROR_REPORT; + } if (!has_mode) { mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; } @@ -938,7 +947,8 @@ void qmp_drive_mirror(const char *device, const char *target, } } - mirror_start(bs, target_bs, speed, sync, block_job_cb, bs, &local_err); + mirror_start(bs, target_bs, speed, sync, on_source_error, on_target_error, + block_job_cb, bs, &local_err); if (local_err != NULL) { bdrv_delete(target_bs); error_propagate(errp, local_err); diff --git a/hmp.c b/hmp.c index 1d6a606..b6bc263 100644 --- a/hmp.c +++ b/hmp.c @@ -719,7 +719,8 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) qmp_drive_mirror(device, filename, !!format, format, full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, - true, mode, false, 0, &errp); + true, mode, false, 0, + false, 0, false, 0, &errp); hmp_handle_error(mon, &errp); } diff --git a/qapi-schema.json b/qapi-schema.json index f5c20ca..7a97fad 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1389,17 +1389,27 @@ # (all the disk, only the sectors allocated in the topmost image, or # only new I/O). # +# @on-source-error: #optional the action to take on an error on the source, +# default 'report'. 'stop' and 'enospc' can only be used +# if the block device supports io-status (see BlockInfo). +# +# @on-target-error: #optional the action to take on an error on the target, +# default 'report' (no limitations, since this applies to +# a different block device than @device). +# # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound # If @target can't be opened, OpenFileFailed # If @format is invalid, InvalidBlockFormat +# If @on_source_error is not supported, InvalidParameter # # Since 1.2 ## { 'command': 'drive-mirror', 'data': { 'device': 'str', 'target': 'str', '*format': 'str', 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', - '*speed': 'int' } } + '*speed': 'int', '*on-source-error': 'BlockdevOnError', + '*on-target-error': 'BlockdevOnError' } } ## # @migrate_cancel diff --git a/qmp-commands.hx b/qmp-commands.hx index 7a32bb6..5081b01 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -838,7 +838,8 @@ EQMP { .name = "drive-mirror", - .args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?", + .args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?," + "on-source-error:s?,on-target-error:s?", .mhandler.cmd_new = qmp_marshal_input_drive_mirror, }, @@ -866,6 +867,11 @@ Arguments: possibilities include "full" for all the disk, "top" for only the sectors allocated in the topmost image, or "none" to only replicate new I/O (MirrorSyncMode). +- "on-source-error": the action to take on an error on the source + (BlockdevOnError, default 'report') +- "on-target-error": the action to take on an error on the target + (BlockdevOnError, default 'report') + Example: