Commit 3e1caa5f authored by Paolo Bonzini's avatar Paolo Bonzini Committed by Kevin Wolf
Browse files

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: default avatarPaolo Bonzini <pbonzini@redhat.com>
Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent 1ceee0d5
......@@ -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;
}
......
......@@ -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);
......
......@@ -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)
......
......@@ -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)
......
......@@ -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)
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment