iostatus: reorganize io error code

Move the common part of IDE/SCSI/virtio error handling to the block
layer.  The new function bdrv_error_action subsumes all three of
bdrv_emit_qmp_error_event, vm_stop, bdrv_iostatus_set_err.

The same scheme will be used for errors in block jobs.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Paolo Bonzini 2012-09-28 17:22:57 +02:00 committed by Kevin Wolf
parent 1ceee0d5cc
commit 3e1caa5f76
6 changed files with 64 additions and 55 deletions

46
block.c
View file

@ -29,6 +29,7 @@
#include "blockjob.h"
#include "module.h"
#include "qjson.h"
#include "sysemu.h"
#include "qemu-coroutine.h"
#include "qmp-commands.h"
#include "qemu-timer.h"
@ -1386,8 +1387,8 @@ void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
}
}
void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
BlockErrorAction action, bool is_read)
static void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
BlockErrorAction action, bool is_read)
{
QObject *data;
const char *action_str;
@ -2486,6 +2487,39 @@ BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read)
return is_read ? bs->on_read_error : bs->on_write_error;
}
BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error)
{
BlockdevOnError on_err = is_read ? bs->on_read_error : bs->on_write_error;
switch (on_err) {
case BLOCKDEV_ON_ERROR_ENOSPC:
return (error == ENOSPC) ? BDRV_ACTION_STOP : BDRV_ACTION_REPORT;
case BLOCKDEV_ON_ERROR_STOP:
return BDRV_ACTION_STOP;
case BLOCKDEV_ON_ERROR_REPORT:
return BDRV_ACTION_REPORT;
case BLOCKDEV_ON_ERROR_IGNORE:
return BDRV_ACTION_IGNORE;
default:
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 bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
bool is_read, int error)
{
assert(error >= 0);
bdrv_emit_qmp_error_event(bs, action, is_read);
if (action == BDRV_ACTION_STOP) {
vm_stop(RUN_STATE_IO_ERROR);
bdrv_iostatus_set_err(bs, error);
}
}
int bdrv_is_read_only(BlockDriverState *bs)
{
return bs->read_only;
@ -4226,14 +4260,10 @@ void bdrv_iostatus_reset(BlockDriverState *bs)
}
}
/* XXX: Today this is set by device models because it makes the implementation
quite simple. However, the block layer knows about the error, so it's
possible to implement this without device models being involved */
void bdrv_iostatus_set_err(BlockDriverState *bs, int error)
{
if (bdrv_iostatus_is_enabled(bs) &&
bs->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
assert(error >= 0);
assert(bdrv_iostatus_is_enabled(bs));
if (bs->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
bs->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
BLOCK_DEVICE_IO_STATUS_FAILED;
}

View file

@ -108,8 +108,6 @@ void bdrv_iostatus_reset(BlockDriverState *bs);
void bdrv_iostatus_disable(BlockDriverState *bs);
bool bdrv_iostatus_is_enabled(const BlockDriverState *bs);
void bdrv_iostatus_set_err(BlockDriverState *bs, int error);
void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv,
BlockErrorAction action, bool is_read);
void bdrv_info_print(Monitor *mon, const QObject *data);
void bdrv_info(Monitor *mon, QObject **ret_data);
void bdrv_stats_print(Monitor *mon, const QObject *data);
@ -282,6 +280,9 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error,
BlockdevOnError on_write_error);
BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read);
BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error);
void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
bool is_read, int error);
int bdrv_is_read_only(BlockDriverState *bs);
int bdrv_is_sg(BlockDriverState *bs);
int bdrv_enable_write_cache(BlockDriverState *bs);

View file

@ -557,31 +557,21 @@ void ide_dma_error(IDEState *s)
static int ide_handle_rw_error(IDEState *s, int error, int op)
{
bool is_read = (op & BM_STATUS_RETRY_READ) != 0;
BlockdevOnError action = bdrv_get_on_error(s->bs, is_read);
BlockErrorAction action = bdrv_get_error_action(s->bs, is_read, error);
if (action == BLOCKDEV_ON_ERROR_IGNORE) {
bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_IGNORE, is_read);
return 0;
}
if ((error == ENOSPC && action == BLOCKDEV_ON_ERROR_ENOSPC)
|| action == BLOCKDEV_ON_ERROR_STOP) {
if (action == BDRV_ACTION_STOP) {
s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
s->bus->error_status = op;
bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
bdrv_iostatus_set_err(s->bs, error);
} else {
} else if (action == BDRV_ACTION_REPORT) {
if (op & BM_STATUS_DMA_RETRY) {
dma_buf_commit(s);
ide_dma_error(s);
} else {
ide_rw_error(s);
}
bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_REPORT, is_read);
}
return 1;
bdrv_error_action(s->bs, action, is_read, error);
return action != BDRV_ACTION_IGNORE;
}
void ide_dma_cb(void *opaque, int ret)

View file

@ -388,21 +388,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
{
bool is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
BlockdevOnError action = bdrv_get_on_error(s->qdev.conf.bs, is_read);
BlockErrorAction action = bdrv_get_error_action(s->qdev.conf.bs, is_read, error);
if (action == BLOCKDEV_ON_ERROR_IGNORE) {
bdrv_emit_qmp_error_event(s->qdev.conf.bs, BDRV_ACTION_IGNORE, is_read);
return 0;
}
if ((error == ENOSPC && action == BLOCKDEV_ON_ERROR_ENOSPC)
|| action == BLOCKDEV_ON_ERROR_STOP) {
bdrv_emit_qmp_error_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
bdrv_iostatus_set_err(s->qdev.conf.bs, error);
scsi_req_retry(&r->req);
} else {
if (action == BDRV_ACTION_REPORT) {
switch (error) {
case ENOMEDIUM:
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
@ -417,9 +405,12 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
}
bdrv_emit_qmp_error_event(s->qdev.conf.bs, BDRV_ACTION_REPORT, is_read);
}
return 1;
bdrv_error_action(s->qdev.conf.bs, action, is_read, error);
if (action == BDRV_ACTION_STOP) {
scsi_req_retry(&r->req);
}
return action != BDRV_ACTION_IGNORE;
}
static void scsi_write_complete(void * opaque, int ret)

View file

@ -66,29 +66,20 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
bool is_read)
{
BlockdevOnError action = bdrv_get_on_error(req->dev->bs, is_read);
BlockErrorAction action = bdrv_get_error_action(req->dev->bs, is_read, error);
VirtIOBlock *s = req->dev;
if (action == BLOCKDEV_ON_ERROR_IGNORE) {
bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_IGNORE, is_read);
return 0;
}
if ((error == ENOSPC && action == BLOCKDEV_ON_ERROR_ENOSPC)
|| action == BLOCKDEV_ON_ERROR_STOP) {
if (action == BDRV_ACTION_STOP) {
req->next = s->rq;
s->rq = req;
bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
bdrv_iostatus_set_err(s->bs, error);
} else {
} else if (action == BDRV_ACTION_REPORT) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
bdrv_acct_done(s->bs, &req->acct);
g_free(req);
bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_REPORT, is_read);
}
return 1;
bdrv_error_action(s->bs, action, is_read, error);
return action != BDRV_ACTION_IGNORE;
}
static void virtio_blk_rw_complete(void *opaque, int ret)

View file

@ -19,6 +19,7 @@
#include "qemu-log.h"
#include "migration.h"
#include "main-loop.h"
#include "sysemu.h"
#include "qemu_socket.h"
#include "slirp/libslirp.h"
@ -37,6 +38,11 @@ const char *qemu_get_vm_name(void)
Monitor *cur_mon;
void vm_stop(RunState state)
{
abort();
}
int monitor_cur_is_qmp(void)
{
return 0;