diff options
-rw-r--r-- | block.c | 21 | ||||
-rw-r--r-- | block/sheepdog.c | 1 | ||||
-rw-r--r-- | cpus.c | 1 | ||||
-rw-r--r-- | docs/qmp/qmp-events.txt | 2 | ||||
-rw-r--r-- | hw/block/m25p80.c | 30 | ||||
-rw-r--r-- | include/sysemu/sysemu.h | 1 | ||||
-rw-r--r-- | stubs/vm-stop.c | 7 | ||||
-rw-r--r-- | target-lm32/op_helper.c | 2 | ||||
-rw-r--r-- | util/qemu-option.c | 28 | ||||
-rw-r--r-- | vl.c | 85 |
10 files changed, 122 insertions, 56 deletions
@@ -3626,10 +3626,27 @@ void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action, bool is_read, int error) { assert(error >= 0); - bdrv_emit_qmp_error_event(bs, QEVENT_BLOCK_IO_ERROR, action, is_read); + if (action == BDRV_ACTION_STOP) { - vm_stop(RUN_STATE_IO_ERROR); + /* 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). + */ bdrv_iostatus_set_err(bs, 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(); + bdrv_emit_qmp_error_event(bs, QEVENT_BLOCK_IO_ERROR, action, is_read); + qemu_system_vmstop_request(RUN_STATE_IO_ERROR); + } else { + bdrv_emit_qmp_error_event(bs, QEVENT_BLOCK_IO_ERROR, action, is_read); } } diff --git a/block/sheepdog.c b/block/sheepdog.c index 2dcc5959f4..8d9350c26d 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1756,6 +1756,7 @@ static int sd_create(const char *filename, QemuOpts *opts, bdrv_unref(bs); } + s->aio_context = qemu_get_aio_context(); ret = do_sd_create(s, &vid, 0, errp); if (ret) { goto out; @@ -1206,6 +1206,7 @@ void cpu_stop_current(void) int vm_stop(RunState state) { if (qemu_in_vcpu_thread()) { + qemu_system_vmstop_request_prepare(); qemu_system_vmstop_request(state); /* * FIXME: should not return to device code in case diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt index 019db53ec8..22fea580a9 100644 --- a/docs/qmp/qmp-events.txt +++ b/docs/qmp/qmp-events.txt @@ -62,7 +62,7 @@ Data: - "action": action that has been taken, it's one of the following (json-string): "ignore": error has been ignored "report": error has been reported to the device - "stop": error caused VM to be stopped + "stop": the VM is going to stop because of the error Example: diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 4076114b32..5893773f0c 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -288,18 +288,20 @@ static void bdrv_sync_complete(void *opaque, int ret) static void flash_sync_page(Flash *s, int page) { - if (s->bdrv) { - int bdrv_sector, nb_sectors; - QEMUIOVector iov; - - bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE; - nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE); - qemu_iovec_init(&iov, 1); - qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE, - nb_sectors * BDRV_SECTOR_SIZE); - bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors, - bdrv_sync_complete, NULL); + int bdrv_sector, nb_sectors; + QEMUIOVector iov; + + if (!s->bdrv || bdrv_is_read_only(s->bdrv)) { + return; } + + bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE; + nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE); + qemu_iovec_init(&iov, 1); + qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE); + bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors, bdrv_sync_complete, + NULL); } static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) @@ -307,7 +309,7 @@ static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) int64_t start, end, nb_sectors; QEMUIOVector iov; - if (!s->bdrv) { + if (!s->bdrv || bdrv_is_read_only(s->bdrv)) { return; } @@ -625,10 +627,6 @@ static int m25p80_init(SSISlave *ss) if (dinfo && dinfo->bdrv) { DB_PRINT_L(0, "Binding to IF_MTD drive\n"); s->bdrv = dinfo->bdrv; - if (bdrv_is_read_only(s->bdrv)) { - fprintf(stderr, "Can't use a read-only drive"); - return 1; - } /* FIXME: Move to late init */ if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size, diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 277230db49..6b4cc133c5 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -62,6 +62,7 @@ void qemu_system_powerdown_request(void); void qemu_register_powerdown_notifier(Notifier *notifier); void qemu_system_debug_request(void); void qemu_system_vmstop_request(RunState reason); +void qemu_system_vmstop_request_prepare(void); int qemu_shutdown_requested_get(void); int qemu_reset_requested_get(void); void qemu_system_killed(int signal, pid_t pid); diff --git a/stubs/vm-stop.c b/stubs/vm-stop.c index f82c897dfe..69fd86b2e8 100644 --- a/stubs/vm-stop.c +++ b/stubs/vm-stop.c @@ -1,7 +1,12 @@ #include "qemu-common.h" #include "sysemu/sysemu.h" -int vm_stop(RunState state) +void qemu_system_vmstop_request_prepare(void) +{ + abort(); +} + +void qemu_system_vmstop_request(RunState state) { abort(); } diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c index 308742a74e..61209c19b2 100644 --- a/target-lm32/op_helper.c +++ b/target-lm32/op_helper.c @@ -42,7 +42,7 @@ void HELPER(ill)(CPULM32State *env) fprintf(stderr, "VM paused due to illegal instruction. " "Connect a debugger or switch to the monitor console " "to find out more.\n"); - qemu_system_vmstop_request(RUN_STATE_PAUSED); + vm_stop(RUN_STATE_PAUSED); cs->halted = 1; raise_exception(env, EXCP_HALTED); #endif diff --git a/util/qemu-option.c b/util/qemu-option.c index 836055a4d2..43de3add29 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -310,8 +310,13 @@ static void qemu_opt_del_all(QemuOpts *opts, const char *name) const char *qemu_opt_get(QemuOpts *opts, const char *name) { - QemuOpt *opt = qemu_opt_find(opts, name); + QemuOpt *opt; + if (opts == NULL) { + return NULL; + } + + opt = qemu_opt_find(opts, name); if (!opt) { const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); if (desc && desc->def_value_str) { @@ -364,9 +369,14 @@ bool qemu_opt_has_help_opt(QemuOpts *opts) static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name, bool defval, bool del) { - QemuOpt *opt = qemu_opt_find(opts, name); + QemuOpt *opt; bool ret = defval; + if (opts == NULL) { + return ret; + } + + opt = qemu_opt_find(opts, name); if (opt == NULL) { const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); if (desc && desc->def_value_str) { @@ -395,9 +405,14 @@ bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval) static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name, uint64_t defval, bool del) { - QemuOpt *opt = qemu_opt_find(opts, name); + QemuOpt *opt; uint64_t ret = defval; + if (opts == NULL) { + return ret; + } + + opt = qemu_opt_find(opts, name); if (opt == NULL) { const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); if (desc && desc->def_value_str) { @@ -427,9 +442,14 @@ uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name, static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name, uint64_t defval, bool del) { - QemuOpt *opt = qemu_opt_find(opts, name); + QemuOpt *opt; uint64_t ret = defval; + if (opts == NULL) { + return ret; + } + + opt = qemu_opt_find(opts, name); if (opt == NULL) { const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); if (desc && desc->def_value_str) { @@ -574,6 +574,10 @@ static int default_driver_check(QemuOpts *opts, void *opaque) static RunState current_run_state = RUN_STATE_PRELAUNCH; +/* We use RUN_STATE_MAX but any invalid value will do */ +static RunState vmstop_requested = RUN_STATE_MAX; +static QemuMutex vmstop_lock; + typedef struct { RunState from; RunState to; @@ -650,10 +654,11 @@ static void runstate_init(void) const RunStateTransition *p; memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions)); - for (p = &runstate_transitions_def[0]; p->from != RUN_STATE_MAX; p++) { runstate_valid_transitions[p->from][p->to] = true; } + + qemu_mutex_init(&vmstop_lock); } /* This function will abort() on invalid state transitions */ @@ -693,6 +698,54 @@ StatusInfo *qmp_query_status(Error **errp) return info; } +static bool qemu_vmstop_requested(RunState *r) +{ + qemu_mutex_lock(&vmstop_lock); + *r = vmstop_requested; + vmstop_requested = RUN_STATE_MAX; + qemu_mutex_unlock(&vmstop_lock); + return *r < RUN_STATE_MAX; +} + +void qemu_system_vmstop_request_prepare(void) +{ + qemu_mutex_lock(&vmstop_lock); +} + +void qemu_system_vmstop_request(RunState state) +{ + vmstop_requested = state; + qemu_mutex_unlock(&vmstop_lock); + qemu_notify_event(); +} + +void vm_start(void) +{ + RunState requested; + + qemu_vmstop_requested(&requested); + if (runstate_is_running() && requested == RUN_STATE_MAX) { + return; + } + + /* Ensure that a STOP/RESUME pair of events is emitted if a + * vmstop request was pending. The BLOCK_IO_ERROR event, for + * example, according to documentation is always followed by + * the STOP event. + */ + if (runstate_is_running()) { + monitor_protocol_event(QEVENT_STOP, NULL); + } else { + cpu_enable_ticks(); + runstate_set(RUN_STATE_RUNNING); + vm_state_notify(1, RUN_STATE_RUNNING); + resume_all_vcpus(); + } + + monitor_protocol_event(QEVENT_RESUME, NULL); +} + + /***********************************************************/ /* real time host monotonic timer */ @@ -1658,17 +1711,6 @@ void vm_state_notify(int running, RunState state) } } -void vm_start(void) -{ - if (!runstate_is_running()) { - cpu_enable_ticks(); - runstate_set(RUN_STATE_RUNNING); - vm_state_notify(1, RUN_STATE_RUNNING); - resume_all_vcpus(); - monitor_protocol_event(QEVENT_RESUME, NULL); - } -} - /* reset/shutdown handler */ typedef struct QEMUResetEntry { @@ -1693,7 +1735,6 @@ static NotifierList suspend_notifiers = static NotifierList wakeup_notifiers = NOTIFIER_LIST_INITIALIZER(wakeup_notifiers); static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE); -static RunState vmstop_requested = RUN_STATE_MAX; int qemu_shutdown_requested_get(void) { @@ -1761,18 +1802,6 @@ static int qemu_debug_requested(void) return r; } -/* We use RUN_STATE_MAX but any invalid value will do */ -static bool qemu_vmstop_requested(RunState *r) -{ - if (vmstop_requested < RUN_STATE_MAX) { - *r = vmstop_requested; - vmstop_requested = RUN_STATE_MAX; - return true; - } - - return false; -} - void qemu_register_reset(QEMUResetHandler *func, void *opaque) { QEMUResetEntry *re = g_malloc0(sizeof(QEMUResetEntry)); @@ -1922,12 +1951,6 @@ void qemu_system_debug_request(void) qemu_notify_event(); } -void qemu_system_vmstop_request(RunState state) -{ - vmstop_requested = state; - qemu_notify_event(); -} - static bool main_loop_should_exit(void) { RunState r; |