aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch_init.c2
-rw-r--r--block-migration.c58
-rw-r--r--error.c13
-rw-r--r--error.h5
-rw-r--r--exec.c14
-rw-r--r--hmp-commands.hx3
-rw-r--r--hmp.c74
-rw-r--r--hmp.h1
-rw-r--r--hw/pci.c1
-rw-r--r--migration-fd.c2
-rw-r--r--migration.c74
-rw-r--r--migration.h5
-rw-r--r--pc-bios/bios.binbin131072 -> 131072 bytes
-rw-r--r--qapi-schema.json21
-rw-r--r--qerror.c8
-rw-r--r--qerror.h6
-rw-r--r--qmp-commands.hx9
-rw-r--r--roms/Makefile10
-rw-r--r--roms/config.seabios1
-rwxr-xr-xroms/configure-seabios.sh5
m---------roms/seabios0
-rw-r--r--savevm.c42
-rw-r--r--sysemu.h11
-rw-r--r--vmstate.h3
24 files changed, 231 insertions, 137 deletions
diff --git a/arch_init.c b/arch_init.c
index a95ef495fe..595badf50f 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -260,7 +260,7 @@ static void sort_ram_list(void)
g_free(blocks);
}
-int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
+int ram_save_live(QEMUFile *f, int stage, void *opaque)
{
ram_addr_t addr;
uint64_t bytes_transferred_last;
diff --git a/block-migration.c b/block-migration.c
index 4467468506..fd2ffff0d5 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -18,7 +18,6 @@
#include "hw/hw.h"
#include "qemu-queue.h"
#include "qemu-timer.h"
-#include "monitor.h"
#include "block-migration.h"
#include "migration.h"
#include "blockdev.h"
@@ -204,8 +203,7 @@ static void blk_mig_read_cb(void *opaque, int ret)
assert(block_mig_state.submitted >= 0);
}
-static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
- BlkMigDevState *bmds)
+static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
{
int64_t total_sectors = bmds->total_sectors;
int64_t cur_sector = bmds->cur_sector;
@@ -272,7 +270,6 @@ static void set_dirty_tracking(int enable)
static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
{
- Monitor *mon = opaque;
BlkMigDevState *bmds;
int64_t sectors;
@@ -295,19 +292,17 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
block_mig_state.total_sector_sum += sectors;
if (bmds->shared_base) {
- monitor_printf(mon, "Start migration for %s with shared base "
- "image\n",
- bs->device_name);
+ DPRINTF("Start migration for %s with shared base image\n",
+ bs->device_name);
} else {
- monitor_printf(mon, "Start full migration for %s\n",
- bs->device_name);
+ DPRINTF("Start full migration for %s\n", bs->device_name);
}
QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry);
}
}
-static void init_blk_migration(Monitor *mon, QEMUFile *f)
+static void init_blk_migration(QEMUFile *f)
{
block_mig_state.submitted = 0;
block_mig_state.read_done = 0;
@@ -318,10 +313,10 @@ static void init_blk_migration(Monitor *mon, QEMUFile *f)
block_mig_state.total_time = 0;
block_mig_state.reads = 0;
- bdrv_iterate(init_blk_migration_it, mon);
+ bdrv_iterate(init_blk_migration_it, NULL);
}
-static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f)
+static int blk_mig_save_bulked_block(QEMUFile *f)
{
int64_t completed_sector_sum = 0;
BlkMigDevState *bmds;
@@ -330,7 +325,7 @@ static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f)
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
if (bmds->bulk_completed == 0) {
- if (mig_save_device_bulk(mon, f, bmds) == 1) {
+ if (mig_save_device_bulk(f, bmds) == 1) {
/* completed bulk section for this device */
bmds->bulk_completed = 1;
}
@@ -352,8 +347,7 @@ static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f)
block_mig_state.prev_progress = progress;
qemu_put_be64(f, (progress << BDRV_SECTOR_BITS)
| BLK_MIG_FLAG_PROGRESS);
- monitor_printf(mon, "Completed %d %%\r", progress);
- monitor_flush(mon);
+ DPRINTF("Completed %d %%\r", progress);
}
return ret;
@@ -368,8 +362,8 @@ static void blk_mig_reset_dirty_cursor(void)
}
}
-static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
- BlkMigDevState *bmds, int is_async)
+static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
+ int is_async)
{
BlkMigBlock *blk;
int64_t total_sectors = bmds->total_sectors;
@@ -428,20 +422,20 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
return (bmds->cur_dirty >= bmds->total_sectors);
error:
- monitor_printf(mon, "Error reading sector %" PRId64 "\n", sector);
+ DPRINTF("Error reading sector %" PRId64 "\n", sector);
qemu_file_set_error(f, ret);
g_free(blk->buf);
g_free(blk);
return 0;
}
-static int blk_mig_save_dirty_block(Monitor *mon, QEMUFile *f, int is_async)
+static int blk_mig_save_dirty_block(QEMUFile *f, int is_async)
{
BlkMigDevState *bmds;
int ret = 0;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
- if (mig_save_device_dirty(mon, f, bmds, is_async) == 0) {
+ if (mig_save_device_dirty(f, bmds, is_async) == 0) {
ret = 1;
break;
}
@@ -520,7 +514,7 @@ static int is_stage2_completed(void)
return 0;
}
-static void blk_mig_cleanup(Monitor *mon)
+static void blk_mig_cleanup(void)
{
BlkMigDevState *bmds;
BlkMigBlock *blk;
@@ -540,11 +534,9 @@ static void blk_mig_cleanup(Monitor *mon)
g_free(blk->buf);
g_free(blk);
}
-
- monitor_printf(mon, "\n");
}
-static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
+static int block_save_live(QEMUFile *f, int stage, void *opaque)
{
int ret;
@@ -552,7 +544,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
stage, block_mig_state.submitted, block_mig_state.transferred);
if (stage < 0) {
- blk_mig_cleanup(mon);
+ blk_mig_cleanup();
return 0;
}
@@ -563,7 +555,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
}
if (stage == 1) {
- init_blk_migration(mon, f);
+ init_blk_migration(f);
/* start track dirty blocks */
set_dirty_tracking(1);
@@ -573,7 +565,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
ret = qemu_file_get_error(f);
if (ret) {
- blk_mig_cleanup(mon);
+ blk_mig_cleanup();
return ret;
}
@@ -586,12 +578,12 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
qemu_file_get_rate_limit(f)) {
if (block_mig_state.bulk_completed == 0) {
/* first finish the bulk phase */
- if (blk_mig_save_bulked_block(mon, f) == 0) {
+ if (blk_mig_save_bulked_block(f) == 0) {
/* finished saving bulk on all devices */
block_mig_state.bulk_completed = 1;
}
} else {
- if (blk_mig_save_dirty_block(mon, f, 1) == 0) {
+ if (blk_mig_save_dirty_block(f, 1) == 0) {
/* no more dirty blocks */
break;
}
@@ -602,7 +594,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
ret = qemu_file_get_error(f);
if (ret) {
- blk_mig_cleanup(mon);
+ blk_mig_cleanup();
return ret;
}
}
@@ -612,8 +604,8 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
all async read completed */
assert(block_mig_state.submitted == 0);
- while (blk_mig_save_dirty_block(mon, f, 0) != 0);
- blk_mig_cleanup(mon);
+ while (blk_mig_save_dirty_block(f, 0) != 0);
+ blk_mig_cleanup();
/* report completion */
qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
@@ -623,7 +615,7 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
return ret;
}
- monitor_printf(mon, "Block migration completed\n");
+ DPRINTF("Block migration completed\n");
}
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
diff --git a/error.c b/error.c
index 990050f792..d3455ab9e6 100644
--- a/error.c
+++ b/error.c
@@ -43,6 +43,19 @@ void error_set(Error **errp, const char *fmt, ...)
*errp = err;
}
+Error *error_copy(const Error *err)
+{
+ Error *err_new;
+
+ err_new = g_malloc0(sizeof(*err));
+ err_new->msg = g_strdup(err->msg);
+ err_new->fmt = err->fmt;
+ err_new->obj = err->obj;
+ QINCREF(err_new->obj);
+
+ return err_new;
+}
+
bool error_is_set(Error **errp)
{
return (errp && *errp);
diff --git a/error.h b/error.h
index 6361f407fd..45ff6c1ffe 100644
--- a/error.h
+++ b/error.h
@@ -35,6 +35,11 @@ void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
bool error_is_set(Error **err);
/**
+ * Returns an exact copy of the error passed as an argument.
+ */
+Error *error_copy(const Error *err);
+
+/**
* Get a human readable representation of an error object.
*/
const char *error_get_pretty(Error *err);
diff --git a/exec.c b/exec.c
index be392e2764..a3818ffeb7 100644
--- a/exec.c
+++ b/exec.c
@@ -2031,14 +2031,19 @@ static void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr,
cpu_physical_memory_set_dirty_flags(ram_addr, CODE_DIRTY_FLAG);
}
+static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe)
+{
+ return (tlbe->addr_write & (TLB_INVALID_MASK|TLB_MMIO|TLB_NOTDIRTY)) == 0;
+}
+
static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
unsigned long start, unsigned long length)
{
unsigned long addr;
- if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) {
+ if (tlb_is_dirty_ram(tlb_entry)) {
addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
if ((addr - start) < length) {
- tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
+ tlb_entry->addr_write |= TLB_NOTDIRTY;
}
}
}
@@ -2091,7 +2096,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
ram_addr_t ram_addr;
void *p;
- if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) {
+ if (tlb_is_dirty_ram(tlb_entry)) {
p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
+ tlb_entry->addend);
ram_addr = qemu_ram_addr_from_host_nofail(p);
@@ -4604,7 +4609,8 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
mr = iotlb_to_region(pd);
if (mr != &io_mem_ram && mr != &io_mem_rom
- && mr != &io_mem_notdirty && !mr->rom_device) {
+ && mr != &io_mem_notdirty && !mr->rom_device
+ && mr != &io_mem_watch) {
#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
cpu_unassigned_access(env1, addr, 0, 1, 0, 4);
#else
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 6980214a1a..bd35a3eb08 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -806,8 +806,7 @@ ETEXI
" full copy of disk\n\t\t\t -i for migration without "
"shared storage with incremental copy of disk "
"(base image shared between src and destination)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_migrate,
+ .mhandler.cmd = hmp_migrate,
},
diff --git a/hmp.c b/hmp.c
index 290c43d03a..9cf2d1345b 100644
--- a/hmp.c
+++ b/hmp.c
@@ -14,6 +14,7 @@
*/
#include "hmp.h"
+#include "qemu-timer.h"
#include "qmp-commands.h"
static void hmp_handle_error(Monitor *mon, Error **errp)
@@ -860,3 +861,76 @@ void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &error);
}
+
+typedef struct MigrationStatus
+{
+ QEMUTimer *timer;
+ Monitor *mon;
+ bool is_block_migration;
+} MigrationStatus;
+
+static void hmp_migrate_status_cb(void *opaque)
+{
+ MigrationStatus *status = opaque;
+ MigrationInfo *info;
+
+ info = qmp_query_migrate(NULL);
+ if (!info->has_status || strcmp(info->status, "active") == 0) {
+ if (info->has_disk) {
+ int progress;
+
+ if (info->disk->remaining) {
+ progress = info->disk->transferred * 100 / info->disk->total;
+ } else {
+ progress = 100;
+ }
+
+ monitor_printf(status->mon, "Completed %d %%\r", progress);
+ monitor_flush(status->mon);
+ }
+
+ qemu_mod_timer(status->timer, qemu_get_clock_ms(rt_clock) + 1000);
+ } else {
+ if (status->is_block_migration) {
+ monitor_printf(status->mon, "\n");
+ }
+ monitor_resume(status->mon);
+ qemu_del_timer(status->timer);
+ g_free(status);
+ }
+
+ qapi_free_MigrationInfo(info);
+}
+
+void hmp_migrate(Monitor *mon, const QDict *qdict)
+{
+ int detach = qdict_get_try_bool(qdict, "detach", 0);
+ int blk = qdict_get_try_bool(qdict, "blk", 0);
+ int inc = qdict_get_try_bool(qdict, "inc", 0);
+ const char *uri = qdict_get_str(qdict, "uri");
+ Error *err = NULL;
+
+ qmp_migrate(uri, !!blk, blk, !!inc, inc, false, false, &err);
+ if (err) {
+ monitor_printf(mon, "migrate: %s\n", error_get_pretty(err));
+ error_free(err);
+ return;
+ }
+
+ if (!detach) {
+ MigrationStatus *status;
+
+ if (monitor_suspend(mon) < 0) {
+ monitor_printf(mon, "terminal does not allow synchronous "
+ "migration, continuing detached\n");
+ return;
+ }
+
+ status = g_malloc0(sizeof(*status));
+ status->mon = mon;
+ status->is_block_migration = blk || inc;
+ status->timer = qemu_new_timer_ms(rt_clock, hmp_migrate_status_cb,
+ status);
+ qemu_mod_timer(status->timer, qemu_get_clock_ms(rt_clock));
+ }
+}
diff --git a/hmp.h b/hmp.h
index 5409464954..8807853e17 100644
--- a/hmp.h
+++ b/hmp.h
@@ -59,5 +59,6 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
void hmp_block_stream(Monitor *mon, const QDict *qdict);
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
+void hmp_migrate(Monitor *mon, const QDict *qdict);
#endif
diff --git a/hw/pci.c b/hw/pci.c
index bf046bfcad..ed8ec99073 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -841,7 +841,6 @@ static int pci_unregister_device(DeviceState *dev)
pci_unregister_io_regions(pci_dev);
pci_del_option_rom(pci_dev);
- g_free(pci_dev->romfile);
do_pci_unregister_device(pci_dev);
return 0;
}
diff --git a/migration-fd.c b/migration-fd.c
index 5a068c632a..50138edb34 100644
--- a/migration-fd.c
+++ b/migration-fd.c
@@ -75,7 +75,7 @@ static int fd_close(MigrationState *s)
int fd_start_outgoing_migration(MigrationState *s, const char *fdname)
{
- s->fd = monitor_get_fd(s->mon, fdname);
+ s->fd = monitor_get_fd(cur_mon, fdname);
if (s->fd == -1) {
DPRINTF("fd_migration: invalid file descriptor identifier\n");
goto err_after_get_fd;
diff --git a/migration.c b/migration.c
index 00fa1e3f72..8c119ba8ff 100644
--- a/migration.c
+++ b/migration.c
@@ -158,16 +158,6 @@ MigrationInfo *qmp_query_migrate(Error **errp)
/* shared migration helpers */
-static void migrate_fd_monitor_suspend(MigrationState *s, Monitor *mon)
-{
- if (monitor_suspend(mon) == 0) {
- DPRINTF("suspending monitor\n");
- } else {
- monitor_printf(mon, "terminal does not allow synchronous "
- "migration, continuing detached\n");
- }
-}
-
static int migrate_fd_cleanup(MigrationState *s)
{
int ret = 0;
@@ -178,10 +168,6 @@ static int migrate_fd_cleanup(MigrationState *s)
DPRINTF("closing file\n");
ret = qemu_fclose(s->file);
s->file = NULL;
- } else {
- if (s->mon) {
- monitor_resume(s->mon);
- }
}
if (s->fd != -1) {
@@ -258,7 +244,7 @@ static void migrate_fd_put_ready(void *opaque)
}
DPRINTF("iterate\n");
- ret = qemu_savevm_state_iterate(s->mon, s->file);
+ ret = qemu_savevm_state_iterate(s->file);
if (ret < 0) {
migrate_fd_error(s);
} else if (ret == 1) {
@@ -267,7 +253,7 @@ static void migrate_fd_put_ready(void *opaque)
DPRINTF("done iterating\n");
vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
- if (qemu_savevm_state_complete(s->mon, s->file) < 0) {
+ if (qemu_savevm_state_complete(s->file) < 0) {
migrate_fd_error(s);
} else {
migrate_fd_completed(s);
@@ -289,7 +275,7 @@ static void migrate_fd_cancel(MigrationState *s)
s->state = MIG_STATE_CANCELLED;
notifier_list_notify(&migration_state_notifiers, s);
- qemu_savevm_state_cancel(s->mon, s->file);
+ qemu_savevm_state_cancel(s->file);
migrate_fd_cleanup(s);
}
@@ -321,9 +307,6 @@ static int migrate_fd_close(void *opaque)
{
MigrationState *s = opaque;
- if (s->mon) {
- monitor_resume(s->mon);
- }
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
return s->close(s);
}
@@ -367,7 +350,7 @@ void migrate_fd_connect(MigrationState *s)
migrate_fd_close);
DPRINTF("beginning savevm\n");
- ret = qemu_savevm_state_begin(s->mon, s->file, s->blk, s->shared);
+ ret = qemu_savevm_state_begin(s->file, s->blk, s->shared);
if (ret < 0) {
DPRINTF("failed, %d\n", ret);
migrate_fd_error(s);
@@ -376,7 +359,7 @@ void migrate_fd_connect(MigrationState *s)
migrate_fd_put_ready(s);
}
-static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc)
+static MigrationState *migrate_init(int blk, int inc)
{
MigrationState *s = migrate_get_current();
int64_t bandwidth_limit = s->bandwidth_limit;
@@ -386,18 +369,9 @@ static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc)
s->blk = blk;
s->shared = inc;
- /* s->mon is used for two things:
- - pass fd in fd migration
- - suspend/resume monitor for not detached migration
- */
- s->mon = mon;
s->bandwidth_limit = bandwidth_limit;
s->state = MIG_STATE_SETUP;
- if (!detach) {
- migrate_fd_monitor_suspend(s, mon);
- }
-
return s;
}
@@ -413,32 +387,29 @@ void migrate_del_blocker(Error *reason)
migration_blockers = g_slist_remove(migration_blockers, reason);
}
-int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_migrate(const char *uri, bool has_blk, bool blk,
+ bool has_inc, bool inc, bool has_detach, bool detach,
+ Error **errp)
{
MigrationState *s = migrate_get_current();
const char *p;
- int detach = qdict_get_try_bool(qdict, "detach", 0);
- int blk = qdict_get_try_bool(qdict, "blk", 0);
- int inc = qdict_get_try_bool(qdict, "inc", 0);
- const char *uri = qdict_get_str(qdict, "uri");
int ret;
if (s->state == MIG_STATE_ACTIVE) {
- monitor_printf(mon, "migration already in progress\n");
- return -1;
+ error_set(errp, QERR_MIGRATION_ACTIVE);
+ return;
}
- if (qemu_savevm_state_blocked(mon)) {
- return -1;
+ if (qemu_savevm_state_blocked(errp)) {
+ return;
}
if (migration_blockers) {
- Error *err = migration_blockers->data;
- qerror_report_err(err);
- return -1;
+ *errp = error_copy(migration_blockers->data);
+ return;
}
- s = migrate_init(mon, detach, blk, inc);
+ s = migrate_init(blk, inc);
if (strstart(uri, "tcp:", &p)) {
ret = tcp_start_outgoing_migration(s, p);
@@ -451,21 +422,18 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
ret = fd_start_outgoing_migration(s, p);
#endif
} else {
- monitor_printf(mon, "unknown migration protocol: %s\n", uri);
- ret = -EINVAL;
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol");
+ return;
}
if (ret < 0) {
- monitor_printf(mon, "migration failed: %s\n", strerror(-ret));
- return ret;
- }
-
- if (detach) {
- s->mon = NULL;
+ DPRINTF("migration failed: %s\n", strerror(-ret));
+ /* FIXME: we should return meaningful errors */
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
}
notifier_list_notify(&migration_state_notifiers, s);
- return 0;
}
void qmp_migrate_cancel(Error **errp)
diff --git a/migration.h b/migration.h
index 372b066b48..691b367389 100644
--- a/migration.h
+++ b/migration.h
@@ -26,7 +26,6 @@ struct MigrationState
int64_t bandwidth_limit;
QEMUFile *file;
int fd;
- Monitor *mon;
int state;
int (*get_error)(MigrationState *s);
int (*close)(MigrationState *s);
@@ -40,8 +39,6 @@ void process_incoming_migration(QEMUFile *f);
int qemu_start_incoming_migration(const char *uri);
-int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
-
uint64_t migrate_max_downtime(void);
void do_info_migrate_print(Monitor *mon, const QObject *data);
@@ -78,7 +75,7 @@ uint64_t ram_bytes_remaining(void);
uint64_t ram_bytes_transferred(void);
uint64_t ram_bytes_total(void);
-int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque);
+int ram_save_live(QEMUFile *f, int stage, void *opaque);
int ram_load(QEMUFile *f, void *opaque, int version_id);
/**
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index 41e2b38ea2..e1f3923681 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differ
diff --git a/qapi-schema.json b/qapi-schema.json
index 04fa84fbde..3a962c1b40 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1663,3 +1663,24 @@
{ 'command': 'qom-list-types',
'data': { '*implements': 'str', '*abstract': 'bool' },
'returns': [ 'ObjectTypeInfo' ] }
+
+##
+# @migrate
+#
+# Migrates the current running guest to another Virtual Machine.
+#
+# @uri: the Uniform Resource Identifier of the destination VM
+#
+# @blk: #optional do block migration (full disk copy)
+#
+# @inc: #optional incremental disk copy migration
+#
+# @detach: this argument exists only for compatibility reasons and
+# is ignored by QEMU
+#
+# Returns: nothing on success
+#
+# Since: 0.14.0
+##
+{ 'command': 'migrate',
+ 'data': {'uri': 'str', '*blk': 'bool', '*inc': 'bool', '*detach': 'bool' } }
diff --git a/qerror.c b/qerror.c
index f55d435d11..41c729a01f 100644
--- a/qerror.c
+++ b/qerror.c
@@ -193,6 +193,14 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Using KVM without %(capability), %(feature) unavailable",
},
{
+ .error_fmt = QERR_MIGRATION_ACTIVE,
+ .desc = "There's a migration process in progress",
+ },
+ {
+ .error_fmt = QERR_MIGRATION_NOT_SUPPORTED,
+ .desc = "State blocked by non-migratable device '%(device)'",
+ },
+ {
.error_fmt = QERR_MIGRATION_EXPECTED,
.desc = "An incoming migration is expected before this command can be executed",
},
diff --git a/qerror.h b/qerror.h
index e26c63598d..e16f9c27e1 100644
--- a/qerror.h
+++ b/qerror.h
@@ -166,6 +166,12 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_KVM_MISSING_CAP \
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
+#define QERR_MIGRATION_ACTIVE \
+ "{ 'class': 'MigrationActive', 'data': {} }"
+
+#define QERR_MIGRATION_NOT_SUPPORTED \
+ "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }"
+
#define QERR_MIGRATION_EXPECTED \
"{ 'class': 'MigrationExpected', 'data': {} }"
diff --git a/qmp-commands.hx b/qmp-commands.hx
index dfe8a5b40b..8b820382bc 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -446,14 +446,7 @@ EQMP
{
.name = "migrate",
.args_type = "detach:-d,blk:-b,inc:-i,uri:s",
- .params = "[-d] [-b] [-i] uri",
- .help = "migrate to URI (using -d to not wait for completion)"
- "\n\t\t\t -b for migration without shared storage with"
- " full copy of disk\n\t\t\t -i for migration without "
- "shared storage with incremental copy of disk "
- "(base image shared between src and destination)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_migrate,
+ .mhandler.cmd_new = qmp_marshal_input_migrate,
},
SQMP
diff --git a/roms/Makefile b/roms/Makefile
new file mode 100644
index 0000000000..0114e6f33f
--- /dev/null
+++ b/roms/Makefile
@@ -0,0 +1,10 @@
+
+default:
+ @echo "nothing is build by default"
+ @echo "available build targets:"
+ @echo " bios -- update bios.bin (seabios)"
+
+bios: config.seabios
+ sh configure-seabios.sh $<
+ make -C seabios out/bios.bin
+ cp seabios/out/bios.bin ../pc-bios/bios.bin
diff --git a/roms/config.seabios b/roms/config.seabios
new file mode 100644
index 0000000000..c373b87a98
--- /dev/null
+++ b/roms/config.seabios
@@ -0,0 +1 @@
+# empty, default config works for us
diff --git a/roms/configure-seabios.sh b/roms/configure-seabios.sh
new file mode 100755
index 0000000000..98f59a24ba
--- /dev/null
+++ b/roms/configure-seabios.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+config="$1"
+make -C seabios clean distclean
+cp "$config" seabios/.config
+make -C seabios oldnoconfig
diff --git a/roms/seabios b/roms/seabios
-Subproject 80d11e8577bf03e98f2eb1b0cb3a281ab2879c9
+Subproject 2e8bd611ce4e1e36b5a80c9ca6e256e23802f09
diff --git a/savevm.c b/savevm.c
index 694eaa4f85..962175ac34 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1542,22 +1542,20 @@ static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
#define QEMU_VM_SECTION_FULL 0x04
#define QEMU_VM_SUBSECTION 0x05
-bool qemu_savevm_state_blocked(Monitor *mon)
+bool qemu_savevm_state_blocked(Error **errp)
{
SaveStateEntry *se;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (se->no_migrate) {
- monitor_printf(mon, "state blocked by non-migratable device '%s'\n",
- se->idstr);
+ error_set(errp, QERR_MIGRATION_NOT_SUPPORTED, se->idstr);
return true;
}
}
return false;
}
-int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
- int shared)
+int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared)
{
SaveStateEntry *se;
int ret;
@@ -1590,15 +1588,15 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
qemu_put_be32(f, se->instance_id);
qemu_put_be32(f, se->version_id);
- ret = se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+ ret = se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
if (ret < 0) {
- qemu_savevm_state_cancel(mon, f);
+ qemu_savevm_state_cancel(f);
return ret;
}
}
ret = qemu_file_get_error(f);
if (ret != 0) {
- qemu_savevm_state_cancel(mon, f);
+ qemu_savevm_state_cancel(f);
}
return ret;
@@ -1611,7 +1609,7 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
* 0 : We haven't finished, caller have to go again
* 1 : We have finished, we can go to complete phase
*/
-int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
+int qemu_savevm_state_iterate(QEMUFile *f)
{
SaveStateEntry *se;
int ret = 1;
@@ -1624,7 +1622,7 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
qemu_put_byte(f, QEMU_VM_SECTION_PART);
qemu_put_be32(f, se->section_id);
- ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
+ ret = se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
if (ret <= 0) {
/* Do not proceed to the next vmstate before this one reported
completion of the current stage. This serializes the migration
@@ -1638,12 +1636,12 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
}
ret = qemu_file_get_error(f);
if (ret != 0) {
- qemu_savevm_state_cancel(mon, f);
+ qemu_savevm_state_cancel(f);
}
return ret;
}
-int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
+int qemu_savevm_state_complete(QEMUFile *f)
{
SaveStateEntry *se;
int ret;
@@ -1658,7 +1656,7 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
qemu_put_byte(f, QEMU_VM_SECTION_END);
qemu_put_be32(f, se->section_id);
- ret = se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+ ret = se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
if (ret < 0) {
return ret;
}
@@ -1690,37 +1688,37 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
return qemu_file_get_error(f);
}
-void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
+void qemu_savevm_state_cancel(QEMUFile *f)
{
SaveStateEntry *se;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (se->save_live_state) {
- se->save_live_state(mon, f, -1, se->opaque);
+ se->save_live_state(f, -1, se->opaque);
}
}
}
-static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
+static int qemu_savevm_state(QEMUFile *f)
{
int ret;
- if (qemu_savevm_state_blocked(mon)) {
+ if (qemu_savevm_state_blocked(NULL)) {
ret = -EINVAL;
goto out;
}
- ret = qemu_savevm_state_begin(mon, f, 0, 0);
+ ret = qemu_savevm_state_begin(f, 0, 0);
if (ret < 0)
goto out;
do {
- ret = qemu_savevm_state_iterate(mon, f);
+ ret = qemu_savevm_state_iterate(f);
if (ret < 0)
goto out;
} while (ret == 0);
- ret = qemu_savevm_state_complete(mon, f);
+ ret = qemu_savevm_state_complete(f);
out:
if (ret == 0) {
@@ -1839,7 +1837,7 @@ int qemu_loadvm_state(QEMUFile *f)
unsigned int v;
int ret;
- if (qemu_savevm_state_blocked(default_mon)) {
+ if (qemu_savevm_state_blocked(NULL)) {
return -EINVAL;
}
@@ -2083,7 +2081,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(mon, f);
+ ret = qemu_savevm_state(f);
vm_state_size = qemu_ftell(f);
qemu_fclose(f);
if (ret < 0) {
diff --git a/sysemu.h b/sysemu.h
index 98118cc478..bc2c788921 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -76,12 +76,11 @@ void do_info_snapshots(Monitor *mon);
void qemu_announce_self(void);
-bool qemu_savevm_state_blocked(Monitor *mon);
-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);
+bool qemu_savevm_state_blocked(Error **errp);
+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_loadvm_state(QEMUFile *f);
/* SLIRP */
diff --git a/vmstate.h b/vmstate.h
index 9d3c49caca..82d97aead4 100644
--- a/vmstate.h
+++ b/vmstate.h
@@ -28,8 +28,7 @@
typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque);
typedef void SaveStateHandler(QEMUFile *f, void *opaque);
-typedef int SaveLiveStateHandler(Monitor *mon, QEMUFile *f, int stage,
- void *opaque);
+typedef int SaveLiveStateHandler(QEMUFile *f, int stage, void *opaque);
typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
int register_savevm(DeviceState *dev,