From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:58199) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SfY7h-0004hV-Vm for qemu-devel@nongnu.org; Fri, 15 Jun 2012 11:07:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SfY7b-0005CL-GL for qemu-devel@nongnu.org; Fri, 15 Jun 2012 11:07:41 -0400 Received: from mail-pb0-f45.google.com ([209.85.160.45]:47190) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SfY7b-0004gs-8G for qemu-devel@nongnu.org; Fri, 15 Jun 2012 11:07:35 -0400 Received: by mail-pb0-f45.google.com with SMTP id ro12so5648793pbb.4 for ; Fri, 15 Jun 2012 08:07:34 -0700 (PDT) Sender: Paolo Bonzini From: Paolo Bonzini Date: Fri, 15 Jun 2012 17:05:48 +0200 Message-Id: <1339772759-31004-26-git-send-email-pbonzini@redhat.com> In-Reply-To: <1339772759-31004-1-git-send-email-pbonzini@redhat.com> References: <1339772759-31004-1-git-send-email-pbonzini@redhat.com> Subject: [Qemu-devel] [RFC PATCH 25/36] mirror: add support for on_source_error/on_target_error List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: kwolf@redhat.com, stefanha@linux.vnet.ibm.com, lcapitulino@redhat.com (Mostly untested). Signed-off-by: Paolo Bonzini --- block/mirror.c | 50 +++++++++++++++++++++++++++++++++++++++++--------- block_int.h | 4 ++++ blockdev.c | 14 ++++++++++++-- hmp.c | 3 ++- qapi-schema.json | 7 ++++++- qmp-commands.hx | 8 +++++++- 6 files changed, 72 insertions(+), 14 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 4c1582d..bdcbe3e 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -32,11 +32,14 @@ typedef struct MirrorBlockJob { RateLimit limit; BlockDriverState *target; MirrorSyncMode mode; + BlockdevOnError on_source_error, on_target_error; + bool synced; int64_t sector_num; void *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; @@ -58,9 +61,23 @@ static int coroutine_fn mirror_iteration(MirrorBlockJob *s) 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); + 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) @@ -70,7 +87,6 @@ static void coroutine_fn mirror_run(void *opaque) int64_t sector_num, end; int ret = 0; int n; - bool synced = false; if (block_job_is_cancelled(&s->common)) { goto immediate_exit; @@ -116,8 +132,9 @@ static void coroutine_fn mirror_run(void *opaque) bool should_complete; if (bdrv_get_dirty_count(bs) != 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; } } @@ -128,11 +145,11 @@ static void coroutine_fn mirror_run(void *opaque) * I/O and report completion, so that drive-reopen can be * used to pivot to the mirroring target. */ - synced = true; + s->synced = true; s->common.offset = end * BDRV_SECTOR_SIZE; } - should_complete = synced && block_job_is_cancelled(&s->common); + should_complete = s->synced && block_job_is_cancelled(&s->common); if (should_complete) { /* The dirty bitmap is not updated while operations are pending. * If we're about to exit, wait for pending operations before @@ -147,7 +164,7 @@ static void coroutine_fn mirror_run(void *opaque) ret = 0; cnt = bdrv_get_dirty_count(bs); - if (synced) { + if (s->synced) { if (!should_complete) { delay_ns = (cnt == 0 ? SLICE_TIME : 0); block_job_sleep_ns(&s->common, rt_clock, delay_ns); @@ -185,6 +202,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); bdrv_close(s->target); bdrv_delete(s->target); block_job_completed(&s->common, ret); @@ -201,6 +219,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); @@ -215,11 +240,14 @@ 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, }; 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) { @@ -230,9 +258,13 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, 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 d7e1928..599eb37 100644 --- a/block_int.h +++ b/block_int.h @@ -312,6 +312,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. @@ -323,6 +325,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 29ecadc..4000d16 100644 --- a/blockdev.c +++ b/blockdev.c @@ -835,7 +835,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) { BlockDriverState *bs; BlockDriverState *source, *target_bs; @@ -846,6 +849,12 @@ void qmp_drive_mirror(const char *device, const char *target, uint64_t size; int ret; + 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; } @@ -929,7 +938,8 @@ void qmp_drive_mirror(const char *device, const char *target, return; } - 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 2dfc477..ce0d040 100644 --- a/hmp.c +++ b/hmp.c @@ -717,7 +717,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 7b619e9..2ee988b 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1379,6 +1379,10 @@ # (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 +# +# @on_target_error: #optional the action to take on an error on the target +# # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound # If @target can't be opened, OpenFileFailed @@ -1389,7 +1393,8 @@ { '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 cccea2f..aff1660 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -833,7 +833,8 @@ EQMP { .name = "drive-mirror", - .args_type = "sync:s,device:B,target:s,sync:s?,format:s?", + .args_type = "sync:s,device:B,target:s,sync:s?,format:s?," + "on_source_error:s?,on_target_error:s?", .mhandler.cmd_new = qmp_marshal_input_drive_mirror, }, @@ -860,6 +861,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) +- "on_target_error": the action to take on an error on the target + (BlockdevOnError) + Example: -- 1.7.10.2