mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
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:
parent
1ceee0d5cc
commit
3e1caa5f76
6 changed files with 64 additions and 55 deletions
46
block.c
46
block.c
|
@ -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;
|
||||
}
|
||||
|
|
5
block.h
5
block.h
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue