diff options
author | Max Reitz <mreitz@redhat.com> | 2015-10-19 17:53:22 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2015-10-23 18:18:23 +0200 |
commit | 373340b26caa1572cf0f155131569dfc527aa133 (patch) | |
tree | fe453b08000c1d5c59402c0e74c675825c0335be /block | |
parent | 7f0e9da6f134c5303be51333696e1ff54697f3e0 (diff) |
block: Move I/O status and error actions into BB
These options are only relevant for the user of a whole BDS tree (like a
guest device or a block job) and should thus be moved into the
BlockBackend.
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/backup.c | 17 | ||||
-rw-r--r-- | block/block-backend.c | 116 | ||||
-rw-r--r-- | block/commit.c | 3 | ||||
-rw-r--r-- | block/mirror.c | 17 | ||||
-rw-r--r-- | block/qapi.c | 4 | ||||
-rw-r--r-- | block/stream.c | 3 |
6 files changed, 141 insertions, 19 deletions
diff --git a/block/backup.c b/block/backup.c index 5696431711..ec01db8eff 100644 --- a/block/backup.c +++ b/block/backup.c @@ -21,6 +21,7 @@ #include "block/blockjob.h" #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" +#include "sysemu/block-backend.h" #define BACKUP_CLUSTER_BITS 16 #define BACKUP_CLUSTER_SIZE (1 << BACKUP_CLUSTER_BITS) @@ -215,7 +216,9 @@ static void backup_iostatus_reset(BlockJob *job) { BackupBlockJob *s = container_of(job, BackupBlockJob, common); - bdrv_iostatus_reset(s->target); + if (s->target->blk) { + blk_iostatus_reset(s->target->blk); + } } static const BlockJobDriver backup_job_driver = { @@ -360,8 +363,10 @@ static void coroutine_fn backup_run(void *opaque) job->bitmap = hbitmap_alloc(end, 0); bdrv_set_enable_write_cache(target, true); - bdrv_set_on_error(target, on_target_error, on_target_error); - bdrv_iostatus_enable(target); + if (target->blk) { + blk_set_on_error(target->blk, on_target_error, on_target_error); + blk_iostatus_enable(target->blk); + } bdrv_add_before_write_notifier(bs, &before_write); @@ -451,7 +456,9 @@ static void coroutine_fn backup_run(void *opaque) } hbitmap_free(job->bitmap); - bdrv_iostatus_disable(target); + if (target->blk) { + blk_iostatus_disable(target->blk); + } bdrv_op_unblock_all(target, job->common.blocker); data = g_malloc(sizeof(*data)); @@ -480,7 +487,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target, if ((on_source_error == BLOCKDEV_ON_ERROR_STOP || on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) && - !bdrv_iostatus_is_enabled(bs)) { + (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) { error_setg(errp, QERR_INVALID_PARAMETER, "on-source-error"); return; } diff --git a/block/block-backend.c b/block/block-backend.c index a52037b418..2708ad146c 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -12,7 +12,9 @@ #include "sysemu/block-backend.h" #include "block/block_int.h" +#include "block/blockjob.h" #include "sysemu/blockdev.h" +#include "sysemu/sysemu.h" #include "qapi-event.h" /* Number of coroutines to reserve per attached device model */ @@ -37,6 +39,10 @@ struct BlockBackend { /* I/O stats (display with "info blockstats"). */ BlockAcctStats stats; + + BlockdevOnError on_read_error, on_write_error; + bool iostatus_enabled; + BlockDeviceIoStatus iostatus; }; typedef struct BlockBackendAIOCB { @@ -330,7 +336,7 @@ int blk_attach_dev(BlockBackend *blk, void *dev) } blk_ref(blk); blk->dev = dev; - bdrv_iostatus_reset(blk->bs); + blk_iostatus_reset(blk); return 0; } @@ -462,7 +468,47 @@ void blk_dev_resize_cb(BlockBackend *blk) void blk_iostatus_enable(BlockBackend *blk) { - bdrv_iostatus_enable(blk->bs); + blk->iostatus_enabled = true; + blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK; +} + +/* The I/O status is only enabled if the drive explicitly + * enables it _and_ the VM is configured to stop on errors */ +bool blk_iostatus_is_enabled(const BlockBackend *blk) +{ + return (blk->iostatus_enabled && + (blk->on_write_error == BLOCKDEV_ON_ERROR_ENOSPC || + blk->on_write_error == BLOCKDEV_ON_ERROR_STOP || + blk->on_read_error == BLOCKDEV_ON_ERROR_STOP)); +} + +BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk) +{ + return blk->iostatus; +} + +void blk_iostatus_disable(BlockBackend *blk) +{ + blk->iostatus_enabled = false; +} + +void blk_iostatus_reset(BlockBackend *blk) +{ + if (blk_iostatus_is_enabled(blk)) { + blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK; + if (blk->bs && blk->bs->job) { + block_job_iostatus_reset(blk->bs->job); + } + } +} + +void blk_iostatus_set_err(BlockBackend *blk, int error) +{ + assert(blk_iostatus_is_enabled(blk)); + if (blk->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { + blk->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE : + BLOCK_DEVICE_IO_STATUS_FAILED; + } } static int blk_check_byte_request(BlockBackend *blk, int64_t offset, @@ -738,21 +784,81 @@ void blk_drain_all(void) bdrv_drain_all(); } +void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, + BlockdevOnError on_write_error) +{ + blk->on_read_error = on_read_error; + blk->on_write_error = on_write_error; +} + BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read) { - return bdrv_get_on_error(blk->bs, is_read); + return is_read ? blk->on_read_error : blk->on_write_error; } BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, int error) { - return bdrv_get_error_action(blk->bs, is_read, error); + BlockdevOnError on_err = blk_get_on_error(blk, is_read); + + switch (on_err) { + case BLOCKDEV_ON_ERROR_ENOSPC: + return (error == ENOSPC) ? + BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT; + case BLOCKDEV_ON_ERROR_STOP: + return BLOCK_ERROR_ACTION_STOP; + case BLOCKDEV_ON_ERROR_REPORT: + return BLOCK_ERROR_ACTION_REPORT; + case BLOCKDEV_ON_ERROR_IGNORE: + return BLOCK_ERROR_ACTION_IGNORE; + default: + abort(); + } } +static void send_qmp_error_event(BlockBackend *blk, + BlockErrorAction action, + bool is_read, int error) +{ + IoOperationType optype; + + optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE; + qapi_event_send_block_io_error(blk_name(blk), optype, action, + blk_iostatus_is_enabled(blk), + error == ENOSPC, strerror(error), + &error_abort); +} + +/* This is done by device models because, while the block layer knows + * about the error, it does not know whether an operation comes from + * the device or the block layer (from a job, for example). + */ void blk_error_action(BlockBackend *blk, BlockErrorAction action, bool is_read, int error) { - bdrv_error_action(blk->bs, action, is_read, error); + assert(error >= 0); + + if (action == BLOCK_ERROR_ACTION_STOP) { + /* First set the iostatus, so that "info block" returns an iostatus + * that matches the events raised so far (an additional error iostatus + * is fine, but not a lost one). + */ + blk_iostatus_set_err(blk, error); + + /* Then raise the request to stop the VM and the event. + * qemu_system_vmstop_request_prepare has two effects. First, + * it ensures that the STOP event always comes after the + * BLOCK_IO_ERROR event. Second, it ensures that even if management + * can observe the STOP event and do a "cont" before the STOP + * event is issued, the VM will not stop. In this case, vm_start() + * also ensures that the STOP/RESUME pair of events is emitted. + */ + qemu_system_vmstop_request_prepare(); + send_qmp_error_event(blk, action, is_read, error); + qemu_system_vmstop_request(RUN_STATE_IO_ERROR); + } else { + send_qmp_error_event(blk, action, is_read, error); + } } int blk_is_read_only(BlockBackend *blk) diff --git a/block/commit.c b/block/commit.c index d12e26fab6..fdebe87c16 100644 --- a/block/commit.c +++ b/block/commit.c @@ -17,6 +17,7 @@ #include "block/blockjob.h" #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" +#include "sysemu/block-backend.h" enum { /* @@ -213,7 +214,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, if ((on_error == BLOCKDEV_ON_ERROR_STOP || on_error == BLOCKDEV_ON_ERROR_ENOSPC) && - !bdrv_iostatus_is_enabled(bs)) { + (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) { error_setg(errp, "Invalid parameter combination"); return; } diff --git a/block/mirror.c b/block/mirror.c index 7e43511832..b1252a1b29 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -14,6 +14,7 @@ #include "trace.h" #include "block/blockjob.h" #include "block/block_int.h" +#include "sysemu/block-backend.h" #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" #include "qemu/bitmap.h" @@ -599,7 +600,9 @@ immediate_exit: g_free(s->cow_bitmap); g_free(s->in_flight_bitmap); bdrv_release_dirty_bitmap(bs, s->dirty_bitmap); - bdrv_iostatus_disable(s->target); + if (s->target->blk) { + blk_iostatus_disable(s->target->blk); + } data = g_malloc(sizeof(*data)); data->ret = ret; @@ -621,7 +624,9 @@ static void mirror_iostatus_reset(BlockJob *job) { MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); - bdrv_iostatus_reset(s->target); + if (s->target->blk) { + blk_iostatus_reset(s->target->blk); + } } static void mirror_complete(BlockJob *job, Error **errp) @@ -704,7 +709,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, if ((on_source_error == BLOCKDEV_ON_ERROR_STOP || on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) && - !bdrv_iostatus_is_enabled(bs)) { + (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) { error_setg(errp, QERR_INVALID_PARAMETER, "on-source-error"); return; } @@ -740,8 +745,10 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, return; } bdrv_set_enable_write_cache(s->target, true); - bdrv_set_on_error(s->target, on_target_error, on_target_error); - bdrv_iostatus_enable(s->target); + if (s->target->blk) { + blk_set_on_error(s->target->blk, on_target_error, on_target_error); + blk_iostatus_enable(s->target->blk); + } 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/qapi.c b/block/qapi.c index 7c8209b0cb..3b46f97b8d 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -301,9 +301,9 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, info->tray_open = blk_dev_is_tray_open(blk); } - if (bdrv_iostatus_is_enabled(bs)) { + if (blk_iostatus_is_enabled(blk)) { info->has_io_status = true; - info->io_status = bs->iostatus; + info->io_status = blk_iostatus(blk); } if (!QLIST_EMPTY(&bs->dirty_bitmaps)) { diff --git a/block/stream.c b/block/stream.c index 3f64fa2245..25af7eff62 100644 --- a/block/stream.c +++ b/block/stream.c @@ -16,6 +16,7 @@ #include "block/blockjob.h" #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" +#include "sysemu/block-backend.h" enum { /* @@ -222,7 +223,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, if ((on_error == BLOCKDEV_ON_ERROR_STOP || on_error == BLOCKDEV_ON_ERROR_ENOSPC) && - !bdrv_iostatus_is_enabled(bs)) { + (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) { error_setg(errp, QERR_INVALID_PARAMETER, "on-error"); return; } |