From 4ec7fcc7da214d48d39b63fd2c6a4d19ac42ae04 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: live migration: Allow cleanup after cancellation or error Introduce qemu_savevm_state_cancel and inject a stage -1 to cancel a live migration. This gives the involved subsystems a chance to clean up dynamically allocated resources. Namely, the block migration layer can now free its device descriptors and pending blocks. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- sysemu.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sysemu.h') diff --git a/sysemu.h b/sysemu.h index 70a2b044d..0149bd16c 100644 --- a/sysemu.h +++ b/sysemu.h @@ -65,6 +65,7 @@ void main_loop_wait(int timeout); int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared); int qemu_savevm_state_iterate(QEMUFile *f); int qemu_savevm_state_complete(QEMUFile *f); +void qemu_savevm_state_cancel(QEMUFile *f); int qemu_savevm_state(QEMUFile *f); int qemu_loadvm_state(QEMUFile *f); -- cgit v1.2.3-65-gdbad From f327aa0c608b4bae3c93f0fbd0afcfdd9c9635bc Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Nov 2009 18:21:21 +0100 Subject: live migration: Propagate output monitor to callback handler In order to allow proper progress reporting to the monitor that initiated the migration, forward the monitor reference through the migration layer down to SaveLiveStateHandler. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- block-migration.c | 2 +- hw/hw.h | 3 ++- migration-exec.c | 12 +++++++----- migration-fd.c | 9 +++++---- migration-tcp.c | 10 ++++++---- migration-unix.c | 10 ++++++---- migration.c | 30 ++++++++++++++++-------------- migration.h | 13 ++++++++----- savevm.c | 31 ++++++++++++++++--------------- sysemu.h | 10 +++++----- vl.c | 2 +- 11 files changed, 73 insertions(+), 59 deletions(-) (limited to 'sysemu.h') diff --git a/block-migration.c b/block-migration.c index 15b76de9b..b56be7908 100644 --- a/block-migration.c +++ b/block-migration.c @@ -352,7 +352,7 @@ static void blk_mig_cleanup(void) printf("\n"); } -static int block_save_live(QEMUFile *f, int stage, void *opaque) +static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) { dprintf("Enter save live stage %d submitted %d transferred %d\n", stage, block_mig_state.submitted, block_mig_state.transferred); diff --git a/hw/hw.h b/hw/hw.h index 5f3499196..7b500f4e4 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -244,7 +244,8 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque); typedef void SaveStateHandler(QEMUFile *f, void *opaque); -typedef int SaveLiveStateHandler(QEMUFile *f, int stage, void *opaque); +typedef int SaveLiveStateHandler(Monitor *mon, QEMUFile *f, int stage, + void *opaque); typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); int register_savevm(const char *idstr, diff --git a/migration-exec.c b/migration-exec.c index c83066959..87f645b68 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -52,7 +52,8 @@ static int exec_close(FdMigrationState *s) return 0; } -MigrationState *exec_start_outgoing_migration(const char *command, +MigrationState *exec_start_outgoing_migration(Monitor *mon, + const char *command, int64_t bandwidth_limit, int detach, int blk, @@ -88,13 +89,14 @@ MigrationState *exec_start_outgoing_migration(const char *command, s->mig_state.blk = blk; s->mig_state.shared = inc; - + s->state = MIG_STATE_ACTIVE; - s->mon_resume = NULL; + s->mon = NULL; s->bandwidth_limit = bandwidth_limit; - if (!detach) - migrate_fd_monitor_suspend(s); + if (!detach) { + migrate_fd_monitor_suspend(s, mon); + } migrate_fd_connect(s); return &s->mig_state; diff --git a/migration-fd.c b/migration-fd.c index 587f9d8e8..ef7edbc5e 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -82,13 +82,14 @@ MigrationState *fd_start_outgoing_migration(Monitor *mon, s->mig_state.blk = blk; s->mig_state.shared = inc; - + s->state = MIG_STATE_ACTIVE; - s->mon_resume = NULL; + s->mon = NULL; s->bandwidth_limit = bandwidth_limit; - if (!detach) - migrate_fd_monitor_suspend(s); + if (!detach) { + migrate_fd_monitor_suspend(s, mon); + } migrate_fd_connect(s); return &s->mig_state; diff --git a/migration-tcp.c b/migration-tcp.c index efa7c74c6..b77ed8762 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -76,7 +76,8 @@ static void tcp_wait_for_connect(void *opaque) } } -MigrationState *tcp_start_outgoing_migration(const char *host_port, +MigrationState *tcp_start_outgoing_migration(Monitor *mon, + const char *host_port, int64_t bandwidth_limit, int detach, int blk, @@ -102,7 +103,7 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, s->mig_state.shared = inc; s->state = MIG_STATE_ACTIVE; - s->mon_resume = NULL; + s->mon = NULL; s->bandwidth_limit = bandwidth_limit; s->fd = socket(PF_INET, SOCK_STREAM, 0); if (s->fd == -1) { @@ -112,8 +113,9 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, socket_set_nonblock(s->fd); - if (!detach) - migrate_fd_monitor_suspend(s); + if (!detach) { + migrate_fd_monitor_suspend(s, mon); + } do { ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); diff --git a/migration-unix.c b/migration-unix.c index 25cd6d3d2..7dd787cd9 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -75,7 +75,8 @@ static void unix_wait_for_connect(void *opaque) } } -MigrationState *unix_start_outgoing_migration(const char *path, +MigrationState *unix_start_outgoing_migration(Monitor *mon, + const char *path, int64_t bandwidth_limit, int detach, int blk, @@ -101,7 +102,7 @@ MigrationState *unix_start_outgoing_migration(const char *path, s->mig_state.shared = inc; s->state = MIG_STATE_ACTIVE; - s->mon_resume = NULL; + s->mon = NULL; s->bandwidth_limit = bandwidth_limit; s->fd = socket(PF_UNIX, SOCK_STREAM, 0); if (s->fd < 0) { @@ -111,8 +112,9 @@ MigrationState *unix_start_outgoing_migration(const char *path, socket_set_nonblock(s->fd); - if (!detach) - migrate_fd_monitor_suspend(s); + if (!detach) { + migrate_fd_monitor_suspend(s, mon); + } do { ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); diff --git a/migration.c b/migration.c index f8a15fb48..f4d30222d 100644 --- a/migration.c +++ b/migration.c @@ -66,16 +66,16 @@ void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data) } if (strstart(uri, "tcp:", &p)) - s = tcp_start_outgoing_migration(p, max_throttle, detach, + s = tcp_start_outgoing_migration(mon, p, max_throttle, detach, (int)qdict_get_int(qdict, "blk"), (int)qdict_get_int(qdict, "inc")); #if !defined(WIN32) else if (strstart(uri, "exec:", &p)) - s = exec_start_outgoing_migration(p, max_throttle, detach, + s = exec_start_outgoing_migration(mon, p, max_throttle, detach, (int)qdict_get_int(qdict, "blk"), (int)qdict_get_int(qdict, "inc")); else if (strstart(uri, "unix:", &p)) - s = unix_start_outgoing_migration(p, max_throttle, detach, + s = unix_start_outgoing_migration(mon, p, max_throttle, detach, (int)qdict_get_int(qdict, "blk"), (int)qdict_get_int(qdict, "inc")); else if (strstart(uri, "fd:", &p)) @@ -190,14 +190,15 @@ void do_info_migrate(Monitor *mon) /* shared migration helpers */ -void migrate_fd_monitor_suspend(FdMigrationState *s) +void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon) { - s->mon_resume = cur_mon; - if (monitor_suspend(cur_mon) == 0) + s->mon = mon; + if (monitor_suspend(mon) == 0) { dprintf("suspending monitor\n"); - else - monitor_printf(cur_mon, "terminal does not allow synchronous " + } else { + monitor_printf(mon, "terminal does not allow synchronous " "migration, continuing detached\n"); + } } void migrate_fd_error(FdMigrationState *s) @@ -221,8 +222,9 @@ void migrate_fd_cleanup(FdMigrationState *s) close(s->fd); /* Don't resume monitor until we've flushed all of the buffers */ - if (s->mon_resume) - monitor_resume(s->mon_resume); + if (s->mon) { + monitor_resume(s->mon); + } s->fd = -1; } @@ -265,7 +267,7 @@ void migrate_fd_connect(FdMigrationState *s) migrate_fd_close); dprintf("beginning savevm\n"); - ret = qemu_savevm_state_begin(s->file, s->mig_state.blk, + ret = qemu_savevm_state_begin(s->mon, s->file, s->mig_state.blk, s->mig_state.shared); if (ret < 0) { dprintf("failed, %d\n", ret); @@ -286,7 +288,7 @@ void migrate_fd_put_ready(void *opaque) } dprintf("iterate\n"); - if (qemu_savevm_state_iterate(s->file) == 1) { + if (qemu_savevm_state_iterate(s->mon, s->file) == 1) { int state; int old_vm_running = vm_running; @@ -295,7 +297,7 @@ void migrate_fd_put_ready(void *opaque) qemu_aio_flush(); bdrv_flush_all(); - if ((qemu_savevm_state_complete(s->file)) < 0) { + if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) { if (old_vm_running) { vm_start(); } @@ -324,7 +326,7 @@ void migrate_fd_cancel(MigrationState *mig_state) dprintf("cancelling migration\n"); s->state = MIG_STATE_CANCELLED; - qemu_savevm_state_cancel(s->file); + qemu_savevm_state_cancel(s->mon, s->file); migrate_fd_cleanup(s); } diff --git a/migration.h b/migration.h index 56adf05e6..3f2b3df2b 100644 --- a/migration.h +++ b/migration.h @@ -42,7 +42,7 @@ struct FdMigrationState int64_t bandwidth_limit; QEMUFile *file; int fd; - Monitor *mon_resume; + Monitor *mon; int state; int (*get_error)(struct FdMigrationState*); int (*close)(struct FdMigrationState*); @@ -66,7 +66,8 @@ void do_info_migrate(Monitor *mon); int exec_start_incoming_migration(const char *host_port); -MigrationState *exec_start_outgoing_migration(const char *host_port, +MigrationState *exec_start_outgoing_migration(Monitor *mon, + const char *host_port, int64_t bandwidth_limit, int detach, int blk, @@ -74,7 +75,8 @@ MigrationState *exec_start_outgoing_migration(const char *host_port, int tcp_start_incoming_migration(const char *host_port); -MigrationState *tcp_start_outgoing_migration(const char *host_port, +MigrationState *tcp_start_outgoing_migration(Monitor *mon, + const char *host_port, int64_t bandwidth_limit, int detach, int blk, @@ -82,7 +84,8 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port, int unix_start_incoming_migration(const char *path); -MigrationState *unix_start_outgoing_migration(const char *path, +MigrationState *unix_start_outgoing_migration(Monitor *mon, + const char *path, int64_t bandwidth_limit, int detach, int blk, @@ -97,7 +100,7 @@ MigrationState *fd_start_outgoing_migration(Monitor *mon, int blk, int inc); -void migrate_fd_monitor_suspend(FdMigrationState *s); +void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon); void migrate_fd_error(FdMigrationState *s); diff --git a/savevm.c b/savevm.c index 9a7a78ecc..db44ed607 100644 --- a/savevm.c +++ b/savevm.c @@ -1264,7 +1264,8 @@ static void vmstate_save(QEMUFile *f, SaveStateEntry *se) #define QEMU_VM_SECTION_END 0x03 #define QEMU_VM_SECTION_FULL 0x04 -int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared) +int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable, + int shared) { SaveStateEntry *se; @@ -1296,18 +1297,18 @@ int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared) qemu_put_be32(f, se->instance_id); qemu_put_be32(f, se->version_id); - se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque); + se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque); } if (qemu_file_has_error(f)) { - qemu_savevm_state_cancel(f); + qemu_savevm_state_cancel(mon, f); return -EIO; } return 0; } -int qemu_savevm_state_iterate(QEMUFile *f) +int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f) { SaveStateEntry *se; int ret = 1; @@ -1320,21 +1321,21 @@ int qemu_savevm_state_iterate(QEMUFile *f) qemu_put_byte(f, QEMU_VM_SECTION_PART); qemu_put_be32(f, se->section_id); - ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque); + ret &= !!se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque); } if (ret) return 1; if (qemu_file_has_error(f)) { - qemu_savevm_state_cancel(f); + qemu_savevm_state_cancel(mon, f); return -EIO; } return 0; } -int qemu_savevm_state_complete(QEMUFile *f) +int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f) { SaveStateEntry *se; @@ -1346,7 +1347,7 @@ int qemu_savevm_state_complete(QEMUFile *f) qemu_put_byte(f, QEMU_VM_SECTION_END); qemu_put_be32(f, se->section_id); - se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque); + se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque); } QTAILQ_FOREACH(se, &savevm_handlers, entry) { @@ -1378,18 +1379,18 @@ int qemu_savevm_state_complete(QEMUFile *f) return 0; } -void qemu_savevm_state_cancel(QEMUFile *f) +void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f) { SaveStateEntry *se; QTAILQ_FOREACH(se, &savevm_handlers, entry) { if (se->save_live_state) { - se->save_live_state(f, -1, se->opaque); + se->save_live_state(mon, f, -1, se->opaque); } } } -int qemu_savevm_state(QEMUFile *f) +static int qemu_savevm_state(Monitor *mon, QEMUFile *f) { int saved_vm_running; int ret; @@ -1399,17 +1400,17 @@ int qemu_savevm_state(QEMUFile *f) bdrv_flush_all(); - ret = qemu_savevm_state_begin(f, 0, 0); + ret = qemu_savevm_state_begin(mon, f, 0, 0); if (ret < 0) goto out; do { - ret = qemu_savevm_state_iterate(f); + ret = qemu_savevm_state_iterate(mon, f); if (ret < 0) goto out; } while (ret == 0); - ret = qemu_savevm_state_complete(f); + ret = qemu_savevm_state_complete(mon, f); out: if (qemu_file_has_error(f)) @@ -1698,7 +1699,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) monitor_printf(mon, "Could not open VM state file\n"); goto the_end; } - ret = qemu_savevm_state(f); + ret = qemu_savevm_state(mon, f); vm_state_size = qemu_ftell(f); qemu_fclose(f); if (ret < 0) { diff --git a/sysemu.h b/sysemu.h index 0149bd16c..e7819de9a 100644 --- a/sysemu.h +++ b/sysemu.h @@ -62,11 +62,11 @@ void qemu_announce_self(void); void main_loop_wait(int timeout); -int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared); -int qemu_savevm_state_iterate(QEMUFile *f); -int qemu_savevm_state_complete(QEMUFile *f); -void qemu_savevm_state_cancel(QEMUFile *f); -int qemu_savevm_state(QEMUFile *f); +int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable, + int shared); +int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f); +int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f); +void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f); int qemu_loadvm_state(QEMUFile *f); void qemu_errors_to_file(FILE *fp); diff --git a/vl.c b/vl.c index f6c655b8d..e9b75c9b8 100644 --- a/vl.c +++ b/vl.c @@ -2927,7 +2927,7 @@ uint64_t ram_bytes_total(void) return last_ram_offset; } -static int ram_save_live(QEMUFile *f, int stage, void *opaque) +static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) { ram_addr_t addr; uint64_t bytes_transferred_last; -- cgit v1.2.3-65-gdbad From f785009961c335a4c9c735b2bf96d5a0d2e5bde1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 27 Nov 2009 13:25:36 +0100 Subject: Rename DriveInfo.onerror to on_write_error Either rename variables and functions to refer to write errors (which is what they actually do) or introduce a parameter to distinguish reads and writes. Signed-off-by: Kevin Wolf Signed-off-by: Anthony Liguori --- hw/ide/core.c | 2 +- hw/scsi-disk.c | 3 ++- hw/virtio-blk.c | 2 +- sysemu.h | 6 ++++-- vl.c | 11 ++++++++--- 5 files changed, 16 insertions(+), 8 deletions(-) (limited to 'sysemu.h') diff --git a/hw/ide/core.c b/hw/ide/core.c index 7b1ff8f95..49bbdcde1 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -473,7 +473,7 @@ void ide_dma_error(IDEState *s) static int ide_handle_write_error(IDEState *s, int error, int op) { - BlockInterfaceErrorAction action = drive_get_onerror(s->bs); + BlockInterfaceErrorAction action = drive_get_on_error(s->bs, 0); if (action == BLOCK_ERR_IGNORE) return 0; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index c802ccdbd..67e300898 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -172,7 +172,8 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) static int scsi_handle_write_error(SCSIDiskReq *r, int error) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - BlockInterfaceErrorAction action = drive_get_onerror(s->qdev.dinfo->bdrv); + BlockInterfaceErrorAction action = + drive_get_on_error(s->qdev.dinfo->bdrv, 0); if (action == BLOCK_ERR_IGNORE) return 0; diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 42b766fa2..a93d20dfa 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -100,7 +100,7 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status) static int virtio_blk_handle_write_error(VirtIOBlockReq *req, int error) { - BlockInterfaceErrorAction action = drive_get_onerror(req->dev->bs); + BlockInterfaceErrorAction action = drive_get_on_error(req->dev->bs, 0); VirtIOBlock *s = req->dev; if (action == BLOCK_ERR_IGNORE) diff --git a/sysemu.h b/sysemu.h index e7819de9a..c79a019e7 100644 --- a/sysemu.h +++ b/sysemu.h @@ -180,7 +180,7 @@ typedef struct DriveInfo { int bus; int unit; QemuOpts *opts; - BlockInterfaceErrorAction onerror; + BlockInterfaceErrorAction on_write_error; char serial[BLOCK_SERIAL_STRLEN + 1]; QTAILQ_ENTRY(DriveInfo) next; } DriveInfo; @@ -197,7 +197,9 @@ extern DriveInfo *drive_get_by_id(const char *id); extern int drive_get_max_bus(BlockInterfaceType type); extern void drive_uninit(DriveInfo *dinfo); extern const char *drive_get_serial(BlockDriverState *bdrv); -extern BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv); + +extern BlockInterfaceErrorAction drive_get_on_error( + BlockDriverState *bdrv, int is_read); BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type); diff --git a/vl.c b/vl.c index 78a4ec4d9..b0a2e883d 100644 --- a/vl.c +++ b/vl.c @@ -1959,13 +1959,18 @@ const char *drive_get_serial(BlockDriverState *bdrv) return "\0"; } -BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv) +BlockInterfaceErrorAction drive_get_on_error( + BlockDriverState *bdrv, int is_read) { DriveInfo *dinfo; + if (is_read) { + return BLOCK_ERR_REPORT; + } + QTAILQ_FOREACH(dinfo, &drives, next) { if (dinfo->bdrv == bdrv) - return dinfo->onerror; + return dinfo->on_write_error; } return BLOCK_ERR_STOP_ENOSPC; @@ -2263,7 +2268,7 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque, dinfo->type = type; dinfo->bus = bus_id; dinfo->unit = unit_id; - dinfo->onerror = onerror; + dinfo->on_write_error = onerror; dinfo->opts = opts; if (serial) strncpy(dinfo->serial, serial, sizeof(serial)); -- cgit v1.2.3-65-gdbad From e9b2e81889d9877415710484b876ee57a42b0bcb Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 27 Nov 2009 13:25:37 +0100 Subject: Introduce rerror option for drives rerror controls the action to be taken when an error occurs while accessing the guest image file. It corresponds to werror which already controls the action take for write errors. This purely introduces parsing rerror command line option into the right structures, real support for it in the device emulation is added in the following patches. Signed-off-by: Kevin Wolf Signed-off-by: Anthony Liguori --- qemu-config.c | 3 +++ sysemu.h | 1 + vl.c | 59 ++++++++++++++++++++++++++++++++++++++++------------------- 3 files changed, 44 insertions(+), 19 deletions(-) (limited to 'sysemu.h') diff --git a/qemu-config.c b/qemu-config.c index 590fc052f..92b5363ec 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -64,6 +64,9 @@ QemuOptsList qemu_drive_opts = { },{ .name = "serial", .type = QEMU_OPT_STRING, + },{ + .name = "rerror", + .type = QEMU_OPT_STRING, },{ .name = "werror", .type = QEMU_OPT_STRING, diff --git a/sysemu.h b/sysemu.h index c79a019e7..efed771d0 100644 --- a/sysemu.h +++ b/sysemu.h @@ -180,6 +180,7 @@ typedef struct DriveInfo { int bus; int unit; QemuOpts *opts; + BlockInterfaceErrorAction on_read_error; BlockInterfaceErrorAction on_write_error; char serial[BLOCK_SERIAL_STRLEN + 1]; QTAILQ_ENTRY(DriveInfo) next; diff --git a/vl.c b/vl.c index b0a2e883d..3d64fc653 100644 --- a/vl.c +++ b/vl.c @@ -1964,16 +1964,12 @@ BlockInterfaceErrorAction drive_get_on_error( { DriveInfo *dinfo; - if (is_read) { - return BLOCK_ERR_REPORT; - } - QTAILQ_FOREACH(dinfo, &drives, next) { if (dinfo->bdrv == bdrv) - return dinfo->on_write_error; + return is_read ? dinfo->on_read_error : dinfo->on_write_error; } - return BLOCK_ERR_STOP_ENOSPC; + return is_read ? BLOCK_ERR_REPORT : BLOCK_ERR_STOP_ENOSPC; } static void bdrv_format_print(void *opaque, const char *name) @@ -1989,6 +1985,23 @@ void drive_uninit(DriveInfo *dinfo) qemu_free(dinfo); } +static int parse_block_error_action(const char *buf, int is_read) +{ + if (!strcmp(buf, "ignore")) { + return BLOCK_ERR_IGNORE; + } else if (!is_read && !strcmp(buf, "enospc")) { + return BLOCK_ERR_STOP_ENOSPC; + } else if (!strcmp(buf, "stop")) { + return BLOCK_ERR_STOP_ANY; + } else if (!strcmp(buf, "report")) { + return BLOCK_ERR_REPORT; + } else { + fprintf(stderr, "qemu: '%s' invalid %s error action\n", + buf, is_read ? "read" : "write"); + return -1; + } +} + DriveInfo *drive_init(QemuOpts *opts, void *opaque, int *fatal_error) { @@ -2008,7 +2021,8 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque, int cache; int aio = 0; int ro = 0; - int bdrv_flags, onerror; + int bdrv_flags; + int on_read_error, on_write_error; const char *devaddr; DriveInfo *dinfo; int snapshot = 0; @@ -2169,22 +2183,28 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque, } } - onerror = BLOCK_ERR_STOP_ENOSPC; + on_write_error = BLOCK_ERR_STOP_ENOSPC; if ((buf = qemu_opt_get(opts, "werror")) != NULL) { if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO) { fprintf(stderr, "werror is no supported by this format\n"); return NULL; } - if (!strcmp(buf, "ignore")) - onerror = BLOCK_ERR_IGNORE; - else if (!strcmp(buf, "enospc")) - onerror = BLOCK_ERR_STOP_ENOSPC; - else if (!strcmp(buf, "stop")) - onerror = BLOCK_ERR_STOP_ANY; - else if (!strcmp(buf, "report")) - onerror = BLOCK_ERR_REPORT; - else { - fprintf(stderr, "qemu: '%s' invalid write error action\n", buf); + + on_write_error = parse_block_error_action(buf, 0); + if (on_write_error < 0) { + return NULL; + } + } + + on_read_error = BLOCK_ERR_REPORT; + if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { + if (1) { + fprintf(stderr, "rerror is no supported by this format\n"); + return NULL; + } + + on_read_error = parse_block_error_action(buf, 1); + if (on_read_error < 0) { return NULL; } } @@ -2268,7 +2288,8 @@ DriveInfo *drive_init(QemuOpts *opts, void *opaque, dinfo->type = type; dinfo->bus = bus_id; dinfo->unit = unit_id; - dinfo->on_write_error = onerror; + dinfo->on_read_error = on_read_error; + dinfo->on_write_error = on_write_error; dinfo->opts = opts; if (serial) strncpy(dinfo->serial, serial, sizeof(serial)); -- cgit v1.2.3-65-gdbad