aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-10-20 08:46:55 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2011-10-20 08:46:55 -0500
commita6e43daa732b90b9ca58e7c38f6faa5a82f4b176 (patch)
tree7c8c8e63ff65cef5e3f9b0e3cded21b160e4e93d
parent46cd37e7718f6c2c502228a61b3a0811c849c52f (diff)
parentee86c61f285042386c0a27edf69300627a1987b4 (diff)
Merge remote-tracking branch 'quintela/migration-pull' into staging
-rw-r--r--arch_init.c17
-rw-r--r--block-migration.c35
-rw-r--r--buffered_file.c44
-rw-r--r--hw/ds1225y.c28
-rw-r--r--hw/hw.h4
-rw-r--r--migration-exec.c39
-rw-r--r--migration-fd.c42
-rw-r--r--migration-tcp.c76
-rw-r--r--migration-unix.c113
-rw-r--r--migration.c439
-rw-r--r--migration.h85
-rw-r--r--savevm.c222
-rw-r--r--ui/spice-core.c4
13 files changed, 550 insertions, 598 deletions
diff --git a/arch_init.c b/arch_init.c
index a6c69c75a9..a411fdf263 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -256,6 +256,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
uint64_t bytes_transferred_last;
double bwidth = 0;
uint64_t expected_time = 0;
+ int ret;
if (stage < 0) {
cpu_physical_memory_set_dirty_tracking(0);
@@ -263,8 +264,8 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
}
if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
- qemu_file_set_error(f);
- return 0;
+ qemu_file_set_error(f, -EINVAL);
+ return -EINVAL;
}
if (stage == 1) {
@@ -300,7 +301,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
bytes_transferred_last = bytes_transferred;
bwidth = qemu_get_clock_ns(rt_clock);
- while (!qemu_file_rate_limit(f)) {
+ while ((ret = qemu_file_rate_limit(f)) == 0) {
int bytes_sent;
bytes_sent = ram_save_block(f);
@@ -310,6 +311,10 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
}
}
+ if (ret < 0) {
+ return ret;
+ }
+
bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
@@ -371,6 +376,7 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
{
ram_addr_t addr;
int flags;
+ int error;
if (version_id < 3 || version_id > 4) {
return -EINVAL;
@@ -451,8 +457,9 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
}
- if (qemu_file_has_error(f)) {
- return -EIO;
+ error = qemu_file_get_error(f);
+ if (error) {
+ return error;
}
} while (!(flags & RAM_SAVE_FLAG_EOS));
diff --git a/block-migration.c b/block-migration.c
index e2775ee50b..0bff07538b 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -263,7 +263,7 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
error:
monitor_printf(mon, "Error reading sector %" PRId64 "\n", cur_sector);
- qemu_file_set_error(f);
+ qemu_file_set_error(f, -EIO);
g_free(blk->buf);
g_free(blk);
return 0;
@@ -383,6 +383,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
int64_t total_sectors = bmds->total_sectors;
int64_t sector;
int nr_sectors;
+ int ret = -EIO;
for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
if (bmds_aio_inflight(bmds, sector)) {
@@ -418,8 +419,8 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
block_mig_state.submitted++;
bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
} else {
- if (bdrv_read(bmds->bs, sector, blk->buf,
- nr_sectors) < 0) {
+ ret = bdrv_read(bmds->bs, sector, blk->buf, nr_sectors);
+ if (ret < 0) {
goto error;
}
blk_send(f, blk);
@@ -439,7 +440,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
error:
monitor_printf(mon, "Error reading sector %" PRId64 "\n", sector);
- qemu_file_set_error(f);
+ qemu_file_set_error(f, ret);
g_free(blk->buf);
g_free(blk);
return 0;
@@ -473,7 +474,7 @@ static void flush_blks(QEMUFile* f)
break;
}
if (blk->ret < 0) {
- qemu_file_set_error(f);
+ qemu_file_set_error(f, blk->ret);
break;
}
blk_send(f, blk);
@@ -556,6 +557,8 @@ static void blk_mig_cleanup(Monitor *mon)
static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
{
+ int ret;
+
DPRINTF("Enter save live stage %d submitted %d transferred %d\n",
stage, block_mig_state.submitted, block_mig_state.transferred);
@@ -579,9 +582,10 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
flush_blks(f);
- if (qemu_file_has_error(f)) {
+ ret = qemu_file_get_error(f);
+ if (ret) {
blk_mig_cleanup(mon);
- return 0;
+ return ret;
}
blk_mig_reset_dirty_cursor();
@@ -607,9 +611,10 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
flush_blks(f);
- if (qemu_file_has_error(f)) {
+ ret = qemu_file_get_error(f);
+ if (ret) {
blk_mig_cleanup(mon);
- return 0;
+ return ret;
}
}
@@ -624,8 +629,9 @@ static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
/* report completion */
qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
- if (qemu_file_has_error(f)) {
- return 0;
+ ret = qemu_file_get_error(f);
+ if (ret) {
+ return ret;
}
monitor_printf(mon, "Block migration completed\n");
@@ -646,6 +652,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
uint8_t *buf;
int64_t total_sectors = 0;
int nr_sectors;
+ int ret;
do {
addr = qemu_get_be64(f);
@@ -654,7 +661,6 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
addr >>= BDRV_SECTOR_BITS;
if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) {
- int ret;
/* get device name */
len = qemu_get_byte(f);
qemu_get_buffer(f, (uint8_t *)device_name, len);
@@ -704,8 +710,9 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
fprintf(stderr, "Unknown flags\n");
return -EINVAL;
}
- if (qemu_file_has_error(f)) {
- return -EIO;
+ ret = qemu_file_get_error(f);
+ if (ret != 0) {
+ return ret;
}
} while (!(flags & BLK_MIG_FLAG_EOS));
diff --git a/buffered_file.c b/buffered_file.c
index 486af575d5..fed9a227bb 100644
--- a/buffered_file.c
+++ b/buffered_file.c
@@ -27,7 +27,6 @@ typedef struct QEMUFileBuffered
BufferedCloseFunc *close;
void *opaque;
QEMUFile *file;
- int has_error;
int freeze_output;
size_t bytes_xfer;
size_t xfer_limit;
@@ -72,9 +71,11 @@ static void buffered_append(QEMUFileBuffered *s,
static void buffered_flush(QEMUFileBuffered *s)
{
size_t offset = 0;
+ int error;
- if (s->has_error) {
- DPRINTF("flush when error, bailing\n");
+ error = qemu_file_get_error(s->file);
+ if (error != 0) {
+ DPRINTF("flush when error, bailing: %s\n", strerror(-error));
return;
}
@@ -93,7 +94,7 @@ static void buffered_flush(QEMUFileBuffered *s)
if (ret <= 0) {
DPRINTF("error flushing data, %zd\n", ret);
- s->has_error = 1;
+ qemu_file_set_error(s->file, ret);
break;
} else {
DPRINTF("flushed %zd byte(s)\n", ret);
@@ -109,14 +110,15 @@ static void buffered_flush(QEMUFileBuffered *s)
static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
{
QEMUFileBuffered *s = opaque;
- int offset = 0;
+ int offset = 0, error;
ssize_t ret;
DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
- if (s->has_error) {
- DPRINTF("flush when error, bailing\n");
- return -EINVAL;
+ error = qemu_file_get_error(s->file);
+ if (error) {
+ DPRINTF("flush when error, bailing: %s\n", strerror(-error));
+ return error;
}
DPRINTF("unfreezing output\n");
@@ -139,7 +141,7 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in
if (ret <= 0) {
DPRINTF("error putting\n");
- s->has_error = 1;
+ qemu_file_set_error(s->file, ret);
offset = -EINVAL;
break;
}
@@ -173,10 +175,10 @@ static int buffered_close(void *opaque)
DPRINTF("closing\n");
- while (!s->has_error && s->buffer_size) {
+ while (!qemu_file_get_error(s->file) && s->buffer_size) {
buffered_flush(s);
if (s->freeze_output)
- s->wait_for_unfreeze(s);
+ s->wait_for_unfreeze(s->opaque);
}
ret = s->close(s->opaque);
@@ -189,13 +191,21 @@ static int buffered_close(void *opaque)
return ret;
}
+/*
+ * The meaning of the return values is:
+ * 0: We can continue sending
+ * 1: Time to stop
+ * negative: There has been an error
+ */
static int buffered_rate_limit(void *opaque)
{
QEMUFileBuffered *s = opaque;
+ int ret;
- if (s->has_error)
- return 0;
-
+ ret = qemu_file_get_error(s->file);
+ if (ret) {
+ return ret;
+ }
if (s->freeze_output)
return 1;
@@ -208,9 +218,9 @@ static int buffered_rate_limit(void *opaque)
static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate)
{
QEMUFileBuffered *s = opaque;
- if (s->has_error)
+ if (qemu_file_get_error(s->file)) {
goto out;
-
+ }
if (new_rate > SIZE_MAX) {
new_rate = SIZE_MAX;
}
@@ -232,7 +242,7 @@ static void buffered_rate_tick(void *opaque)
{
QEMUFileBuffered *s = opaque;
- if (s->has_error) {
+ if (qemu_file_get_error(s->file)) {
buffered_close(s);
return;
}
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index 9875c445f8..6852a61d08 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -29,7 +29,7 @@ typedef struct {
DeviceState qdev;
uint32_t chip_size;
char *filename;
- QEMUFile *file;
+ FILE *file;
uint8_t *contents;
} NvRamState;
@@ -70,9 +70,9 @@ static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
s->contents[addr] = val;
if (s->file) {
- qemu_fseek(s->file, addr, SEEK_SET);
- qemu_put_byte(s->file, (int)val);
- qemu_fflush(s->file);
+ fseek(s->file, addr, SEEK_SET);
+ fputc(val, s->file);
+ fflush(s->file);
}
}
@@ -108,15 +108,17 @@ static int nvram_post_load(void *opaque, int version_id)
/* Close file, as filename may has changed in load/store process */
if (s->file) {
- qemu_fclose(s->file);
+ fclose(s->file);
}
/* Write back nvram contents */
- s->file = qemu_fopen(s->filename, "wb");
+ s->file = fopen(s->filename, "wb");
if (s->file) {
/* Write back contents, as 'wb' mode cleaned the file */
- qemu_put_buffer(s->file, s->contents, s->chip_size);
- qemu_fflush(s->file);
+ if (fwrite(s->contents, s->chip_size, 1, s->file) != 1) {
+ printf("nvram_post_load: short write\n");
+ }
+ fflush(s->file);
}
return 0;
@@ -143,7 +145,7 @@ typedef struct {
static int nvram_sysbus_initfn(SysBusDevice *dev)
{
NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram;
- QEMUFile *file;
+ FILE *file;
int s_io;
s->contents = g_malloc0(s->chip_size);
@@ -153,11 +155,13 @@ static int nvram_sysbus_initfn(SysBusDevice *dev)
sysbus_init_mmio(dev, s->chip_size, s_io);
/* Read current file */
- file = qemu_fopen(s->filename, "rb");
+ file = fopen(s->filename, "rb");
if (file) {
/* Read nvram contents */
- qemu_get_buffer(file, s->contents, s->chip_size);
- qemu_fclose(file);
+ if (fread(s->contents, s->chip_size, 1, file) != 1) {
+ printf("nvram_sysbus_initfn: short read\n");
+ }
+ fclose(file);
}
nvram_post_load(s, 0);
diff --git a/hw/hw.h b/hw/hw.h
index a124da9c26..ed20f5a27a 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -85,8 +85,8 @@ uint64_t qemu_get_be64(QEMUFile *f);
int qemu_file_rate_limit(QEMUFile *f);
int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
int64_t qemu_file_get_rate_limit(QEMUFile *f);
-int qemu_file_has_error(QEMUFile *f);
-void qemu_file_set_error(QEMUFile *f);
+int qemu_file_get_error(QEMUFile *f);
+void qemu_file_set_error(QEMUFile *f, int error);
/* Try to send any outstanding data. This function is useful when output is
* halted due to rate limiting or EAGAIN errors occur as it can be used to
diff --git a/migration-exec.c b/migration-exec.c
index 2cfb6f232c..b7b1055e88 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -32,17 +32,17 @@
do { } while (0)
#endif
-static int file_errno(FdMigrationState *s)
+static int file_errno(MigrationState *s)
{
return errno;
}
-static int file_write(FdMigrationState *s, const void * buf, size_t size)
+static int file_write(MigrationState *s, const void * buf, size_t size)
{
return write(s->fd, buf, size);
}
-static int exec_close(FdMigrationState *s)
+static int exec_close(MigrationState *s)
{
int ret = 0;
DPRINTF("exec_close\n");
@@ -61,22 +61,14 @@ static int exec_close(FdMigrationState *s)
return ret;
}
-MigrationState *exec_start_outgoing_migration(Monitor *mon,
- const char *command,
- int64_t bandwidth_limit,
- int detach,
- int blk,
- int inc)
+int exec_start_outgoing_migration(MigrationState *s, const char *command)
{
- FdMigrationState *s;
FILE *f;
- s = g_malloc0(sizeof(*s));
-
f = popen(command, "w");
if (f == NULL) {
DPRINTF("Unable to popen exec target\n");
- goto err_after_alloc;
+ goto err_after_popen;
}
s->fd = fileno(f);
@@ -92,29 +84,14 @@ MigrationState *exec_start_outgoing_migration(Monitor *mon,
s->close = exec_close;
s->get_error = file_errno;
s->write = file_write;
- s->mig_state.cancel = migrate_fd_cancel;
- s->mig_state.get_status = migrate_fd_get_status;
- s->mig_state.release = migrate_fd_release;
-
- s->mig_state.blk = blk;
- s->mig_state.shared = inc;
-
- s->state = MIG_STATE_ACTIVE;
- s->mon = NULL;
- s->bandwidth_limit = bandwidth_limit;
-
- if (!detach) {
- migrate_fd_monitor_suspend(s, mon);
- }
migrate_fd_connect(s);
- return &s->mig_state;
+ return 0;
err_after_open:
pclose(f);
-err_after_alloc:
- g_free(s);
- return NULL;
+err_after_popen:
+ return -1;
}
static void exec_accept_incoming_migration(void *opaque)
diff --git a/migration-fd.c b/migration-fd.c
index aee690aaed..d0aec89e8d 100644
--- a/migration-fd.c
+++ b/migration-fd.c
@@ -30,17 +30,17 @@
do { } while (0)
#endif
-static int fd_errno(FdMigrationState *s)
+static int fd_errno(MigrationState *s)
{
return errno;
}
-static int fd_write(FdMigrationState *s, const void * buf, size_t size)
+static int fd_write(MigrationState *s, const void * buf, size_t size)
{
return write(s->fd, buf, size);
}
-static int fd_close(FdMigrationState *s)
+static int fd_close(MigrationState *s)
{
DPRINTF("fd_close\n");
if (s->fd != -1) {
@@ -50,21 +50,12 @@ static int fd_close(FdMigrationState *s)
return 0;
}
-MigrationState *fd_start_outgoing_migration(Monitor *mon,
- const char *fdname,
- int64_t bandwidth_limit,
- int detach,
- int blk,
- int inc)
+int fd_start_outgoing_migration(MigrationState *s, const char *fdname)
{
- FdMigrationState *s;
-
- s = g_malloc0(sizeof(*s));
-
- s->fd = monitor_get_fd(mon, fdname);
+ s->fd = monitor_get_fd(s->mon, fdname);
if (s->fd == -1) {
DPRINTF("fd_migration: invalid file descriptor identifier\n");
- goto err_after_alloc;
+ goto err_after_get_fd;
}
if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) {
@@ -75,29 +66,14 @@ MigrationState *fd_start_outgoing_migration(Monitor *mon,
s->get_error = fd_errno;
s->write = fd_write;
s->close = fd_close;
- s->mig_state.cancel = migrate_fd_cancel;
- s->mig_state.get_status = migrate_fd_get_status;
- s->mig_state.release = migrate_fd_release;
-
- s->mig_state.blk = blk;
- s->mig_state.shared = inc;
-
- s->state = MIG_STATE_ACTIVE;
- s->mon = NULL;
- s->bandwidth_limit = bandwidth_limit;
-
- if (!detach) {
- migrate_fd_monitor_suspend(s, mon);
- }
migrate_fd_connect(s);
- return &s->mig_state;
+ return 0;
err_after_open:
close(s->fd);
-err_after_alloc:
- g_free(s);
- return NULL;
+err_after_get_fd:
+ return -1;
}
static void fd_accept_incoming_migration(void *opaque)
diff --git a/migration-tcp.c b/migration-tcp.c
index c431e03a48..5aa742c34b 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -28,17 +28,17 @@
do { } while (0)
#endif
-static int socket_errno(FdMigrationState *s)
+static int socket_errno(MigrationState *s)
{
return socket_error();
}
-static int socket_write(FdMigrationState *s, const void * buf, size_t size)
+static int socket_write(MigrationState *s, const void * buf, size_t size)
{
return send(s->fd, buf, size, 0);
}
-static int tcp_close(FdMigrationState *s)
+static int tcp_close(MigrationState *s)
{
DPRINTF("tcp_close\n");
if (s->fd != -1) {
@@ -48,17 +48,16 @@ static int tcp_close(FdMigrationState *s)
return 0;
}
-
static void tcp_wait_for_connect(void *opaque)
{
- FdMigrationState *s = opaque;
+ MigrationState *s = opaque;
int val, ret;
socklen_t valsize = sizeof(val);
DPRINTF("connect completed\n");
do {
ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
- } while (ret == -1 && (s->get_error(s)) == EINTR);
+ } while (ret == -1 && (socket_error()) == EINTR);
if (ret < 0) {
migrate_fd_error(s);
@@ -75,63 +74,46 @@ static void tcp_wait_for_connect(void *opaque)
}
}
-MigrationState *tcp_start_outgoing_migration(Monitor *mon,
- const char *host_port,
- int64_t bandwidth_limit,
- int detach,
- int blk,
- int inc)
+int tcp_start_outgoing_migration(MigrationState *s, const char *host_port)
{
struct sockaddr_in addr;
- FdMigrationState *s;
int ret;
- if (parse_host_port(&addr, host_port) < 0)
- return NULL;
-
- s = g_malloc0(sizeof(*s));
+ ret = parse_host_port(&addr, host_port);
+ if (ret < 0) {
+ return ret;
+ }
s->get_error = socket_errno;
s->write = socket_write;
s->close = tcp_close;
- s->mig_state.cancel = migrate_fd_cancel;
- s->mig_state.get_status = migrate_fd_get_status;
- s->mig_state.release = migrate_fd_release;
-
- s->mig_state.blk = blk;
- s->mig_state.shared = inc;
- s->state = MIG_STATE_ACTIVE;
- s->mon = NULL;
- s->bandwidth_limit = bandwidth_limit;
s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
if (s->fd == -1) {
- g_free(s);
- return NULL;
+ DPRINTF("Unable to open socket");
+ return -socket_error();
}
socket_set_nonblock(s->fd);
- if (!detach) {
- migrate_fd_monitor_suspend(s, mon);
- }
-
do {
ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
- if (ret == -1)
- ret = -(s->get_error(s));
-
- if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+ if (ret == -1) {
+ ret = -socket_error();
+ }
+ if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) {
qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
+ return 0;
+ }
} while (ret == -EINTR);
- if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+ if (ret < 0) {
DPRINTF("connect failed\n");
migrate_fd_error(s);
- } else if (ret >= 0)
- migrate_fd_connect(s);
-
- return &s->mig_state;
+ return ret;
+ }
+ migrate_fd_connect(s);
+ return 0;
}
static void tcp_accept_incoming_migration(void *opaque)
@@ -174,23 +156,27 @@ int tcp_start_incoming_migration(const char *host_port)
int val;
int s;
+ DPRINTF("Attempting to start an incoming migration\n");
+
if (parse_host_port(&addr, host_port) < 0) {
fprintf(stderr, "invalid host/port combination: %s\n", host_port);
return -EINVAL;
}
s = qemu_socket(PF_INET, SOCK_STREAM, 0);
- if (s == -1)
+ if (s == -1) {
return -socket_error();
+ }
val = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
- if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
goto err;
-
- if (listen(s, 1) == -1)
+ }
+ if (listen(s, 1) == -1) {
goto err;
+ }
qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
(void *)(intptr_t)s);
diff --git a/migration-unix.c b/migration-unix.c
index 6dc985d423..8596353d7d 100644
--- a/migration-unix.c
+++ b/migration-unix.c
@@ -28,17 +28,17 @@
do { } while (0)
#endif
-static int unix_errno(FdMigrationState *s)
+static int unix_errno(MigrationState *s)
{
return errno;
}
-static int unix_write(FdMigrationState *s, const void * buf, size_t size)
+static int unix_write(MigrationState *s, const void * buf, size_t size)
{
return write(s->fd, buf, size);
}
-static int unix_close(FdMigrationState *s)
+static int unix_close(MigrationState *s)
{
DPRINTF("unix_close\n");
if (s->fd != -1) {
@@ -50,14 +50,14 @@ static int unix_close(FdMigrationState *s)
static void unix_wait_for_connect(void *opaque)
{
- FdMigrationState *s = opaque;
+ MigrationState *s = opaque;
int val, ret;
socklen_t valsize = sizeof(val);
DPRINTF("connect completed\n");
do {
ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
- } while (ret == -1 && (s->get_error(s)) == EINTR);
+ } while (ret == -1 && errno == EINTR);
if (ret < 0) {
migrate_fd_error(s);
@@ -74,72 +74,43 @@ static void unix_wait_for_connect(void *opaque)
}
}
-MigrationState *unix_start_outgoing_migration(Monitor *mon,
- const char *path,
- int64_t bandwidth_limit,
- int detach,
- int blk,
- int inc)
+int unix_start_outgoing_migration(MigrationState *s, const char *path)
{
- FdMigrationState *s;
struct sockaddr_un addr;
int ret;
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
-
- s = g_malloc0(sizeof(*s));
-
s->get_error = unix_errno;
s->write = unix_write;
s->close = unix_close;
- s->mig_state.cancel = migrate_fd_cancel;
- s->mig_state.get_status = migrate_fd_get_status;
- s->mig_state.release = migrate_fd_release;
-
- s->mig_state.blk = blk;
- s->mig_state.shared = inc;
- s->state = MIG_STATE_ACTIVE;
- s->mon = NULL;
- s->bandwidth_limit = bandwidth_limit;
s->fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
- if (s->fd < 0) {
+ if (s->fd == -1) {
DPRINTF("Unable to open socket");
- goto err_after_alloc;
+ return -errno;
}
socket_set_nonblock(s->fd);
do {
ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
- if (ret == -1)
- ret = -(s->get_error(s));
-
- if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+ if (ret == -1) {
+ ret = -errno;
+ }
+ if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) {
qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
+ return 0;
+ }
} while (ret == -EINTR);
- if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+ if (ret < 0) {
DPRINTF("connect failed\n");
- goto err_after_open;
- }
-
- if (!detach) {
- migrate_fd_monitor_suspend(s, mon);
+ migrate_fd_error(s);
+ return ret;
}
-
- if (ret >= 0)
- migrate_fd_connect(s);
-
- return &s->mig_state;
-
-err_after_open:
- close(s->fd);
-
-err_after_alloc:
- g_free(s);
- return NULL;
+ migrate_fd_connect(s);
+ return 0;
}
static void unix_accept_incoming_migration(void *opaque)
@@ -152,13 +123,13 @@ static void unix_accept_incoming_migration(void *opaque)
do {
c = qemu_accept(s, (struct sockaddr *)&addr, &addrlen);
- } while (c == -1 && socket_error() == EINTR);
+ } while (c == -1 && errno == EINTR);
DPRINTF("accepted migration\n");
if (c == -1) {
fprintf(stderr, "could not accept migration connection\n");
- return;
+ goto out2;
}
f = qemu_fopen_socket(c);
@@ -170,45 +141,49 @@ static void unix_accept_incoming_migration(void *opaque)
process_incoming_migration(f);
qemu_fclose(f);
out:
+ close(c);
+out2:
qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
close(s);
- close(c);
}
int unix_start_incoming_migration(const char *path)
{
- struct sockaddr_un un;
- int sock;
+ struct sockaddr_un addr;
+ int s;
+ int ret;
DPRINTF("Attempting to start an incoming migration\n");
- sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
- if (sock < 0) {
+ s = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) {
fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno));
- return -EINVAL;
+ return -errno;
}
- memset(&un, 0, sizeof(un));
- un.sun_family = AF_UNIX;
- snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
- unlink(un.sun_path);
- if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
- fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
+ unlink(addr.sun_path);
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ret = -errno;
+ fprintf(stderr, "bind(unix:%s): %s\n", addr.sun_path, strerror(errno));
goto err;
}
- if (listen(sock, 1) < 0) {
- fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
+ if (listen(s, 1) == -1) {
+ fprintf(stderr, "listen(unix:%s): %s\n", addr.sun_path,
+ strerror(errno));
+ ret = -errno;
goto err;
}
- qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL,
- (void *)(intptr_t)sock);
+ qemu_set_fd_handler2(s, NULL, unix_accept_incoming_migration, NULL,
+ (void *)(intptr_t)s);
return 0;
err:
- close(sock);
-
- return -EINVAL;
+ close(s);
+ return ret;
}
diff --git a/migration.c b/migration.c
index 62b74a6e26..bdca72e008 100644
--- a/migration.c
+++ b/migration.c
@@ -31,14 +31,33 @@
do { } while (0)
#endif
-/* Migration speed throttling */
-static int64_t max_throttle = (32 << 20);
+enum {
+ MIG_STATE_ERROR,
+ MIG_STATE_SETUP,
+ MIG_STATE_CANCELLED,
+ MIG_STATE_ACTIVE,
+ MIG_STATE_COMPLETED,
+};
-static MigrationState *current_migration;
+#define MAX_THROTTLE (32 << 20) /* Migration speed throttling */
static NotifierList migration_state_notifiers =
NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
+/* When we add fault tolerance, we could have several
+ migrations at once. For now we don't need to add
+ dynamic creation of migration */
+
+static MigrationState *migrate_get_current(void)
+{
+ static MigrationState current_migration = {
+ .state = MIG_STATE_SETUP,
+ .bandwidth_limit = MAX_THROTTLE,
+ };
+
+ return &current_migration;
+}
+
int qemu_start_incoming_migration(const char *uri)
{
const char *p;
@@ -77,87 +96,6 @@ void process_incoming_migration(QEMUFile *f)
}
}
-int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- MigrationState *s = NULL;
- 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");
-
- if (current_migration &&
- current_migration->get_status(current_migration) == MIG_STATE_ACTIVE) {
- monitor_printf(mon, "migration already in progress\n");
- return -1;
- }
-
- if (qemu_savevm_state_blocked(mon)) {
- return -1;
- }
-
- if (strstart(uri, "tcp:", &p)) {
- s = tcp_start_outgoing_migration(mon, p, max_throttle, detach,
- blk, inc);
-#if !defined(WIN32)
- } else if (strstart(uri, "exec:", &p)) {
- s = exec_start_outgoing_migration(mon, p, max_throttle, detach,
- blk, inc);
- } else if (strstart(uri, "unix:", &p)) {
- s = unix_start_outgoing_migration(mon, p, max_throttle, detach,
- blk, inc);
- } else if (strstart(uri, "fd:", &p)) {
- s = fd_start_outgoing_migration(mon, p, max_throttle, detach,
- blk, inc);
-#endif
- } else {
- monitor_printf(mon, "unknown migration protocol: %s\n", uri);
- return -1;
- }
-
- if (s == NULL) {
- monitor_printf(mon, "migration failed\n");
- return -1;
- }
-
- if (current_migration) {
- current_migration->release(current_migration);
- }
-
- current_migration = s;
- notifier_list_notify(&migration_state_notifiers, NULL);
- return 0;
-}
-
-int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- MigrationState *s = current_migration;
-
- if (s)
- s->cancel(s);
-
- return 0;
-}
-
-int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- int64_t d;
- FdMigrationState *s;
-
- d = qdict_get_int(qdict, "value");
- if (d < 0) {
- d = 0;
- }
- max_throttle = d;
-
- s = migrate_to_fms(current_migration);
- if (s && s->file) {
- qemu_file_set_rate_limit(s->file, max_throttle);
- }
-
- return 0;
-}
-
/* amount of nanoseconds we are willing to wait for migration to be down.
* the choice of nanoseconds is because it is the maximum resolution that
* get_clock() can achieve. It is an internal measure. All user-visible
@@ -169,18 +107,6 @@ uint64_t migrate_max_downtime(void)
return max_downtime;
}
-int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
-{
- double d;
-
- d = qdict_get_double(qdict, "value") * 1e9;
- d = MAX(0, MIN(UINT64_MAX, d));
- max_downtime = (uint64_t)d;
-
- return 0;
-}
-
static void migrate_print_status(Monitor *mon, const char *name,
const QDict *status_dict)
{
@@ -228,41 +154,42 @@ static void migrate_put_status(QDict *qdict, const char *name,
void do_info_migrate(Monitor *mon, QObject **ret_data)
{
QDict *qdict;
- MigrationState *s = current_migration;
-
- if (s) {
- switch (s->get_status(s)) {
- case MIG_STATE_ACTIVE:
- qdict = qdict_new();
- qdict_put(qdict, "status", qstring_from_str("active"));
-
- migrate_put_status(qdict, "ram", ram_bytes_transferred(),
- ram_bytes_remaining(), ram_bytes_total());
-
- if (blk_mig_active()) {
- migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
- blk_mig_bytes_remaining(),
- blk_mig_bytes_total());
- }
-
- *ret_data = QOBJECT(qdict);
- break;
- case MIG_STATE_COMPLETED:
- *ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
- break;
- case MIG_STATE_ERROR:
- *ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
- break;
- case MIG_STATE_CANCELLED:
- *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
- break;
+ MigrationState *s = migrate_get_current();
+
+ switch (s->state) {
+ case MIG_STATE_SETUP:
+ /* no migration has happened ever */
+ break;
+ case MIG_STATE_ACTIVE:
+ qdict = qdict_new();
+ qdict_put(qdict, "status", qstring_from_str("active"));
+
+ migrate_put_status(qdict, "ram", ram_bytes_transferred(),
+ ram_bytes_remaining(), ram_bytes_total());
+
+ if (blk_mig_active()) {
+ migrate_put_status(qdict, "disk", blk_mig_bytes_transferred(),
+ blk_mig_bytes_remaining(),
+ blk_mig_bytes_total());
}
+
+ *ret_data = QOBJECT(qdict);
+ break;
+ case MIG_STATE_COMPLETED:
+ *ret_data = qobject_from_jsonf("{ 'status': 'completed' }");
+ break;
+ case MIG_STATE_ERROR:
+ *ret_data = qobject_from_jsonf("{ 'status': 'failed' }");
+ break;
+ case MIG_STATE_CANCELLED:
+ *ret_data = qobject_from_jsonf("{ 'status': 'cancelled' }");
+ break;
}
}
/* shared migration helpers */
-void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon)
+static void migrate_fd_monitor_suspend(MigrationState *s, Monitor *mon)
{
s->mon = mon;
if (monitor_suspend(mon) == 0) {
@@ -273,15 +200,7 @@ void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon)
}
}
-void migrate_fd_error(FdMigrationState *s)
-{
- DPRINTF("setting error state\n");
- s->state = MIG_STATE_ERROR;
- notifier_list_notify(&migration_state_notifiers, NULL);
- migrate_fd_cleanup(s);
-}
-
-int migrate_fd_cleanup(FdMigrationState *s)
+static int migrate_fd_cleanup(MigrationState *s)
{
int ret = 0;
@@ -307,19 +226,47 @@ int migrate_fd_cleanup(FdMigrationState *s)
return ret;
}
-void migrate_fd_put_notify(void *opaque)
+void migrate_fd_error(MigrationState *s)
{
- FdMigrationState *s = opaque;
+ DPRINTF("setting error state\n");
+ s->state = MIG_STATE_ERROR;
+ notifier_list_notify(&migration_state_notifiers, s);
+ migrate_fd_cleanup(s);
+}
+
+static void migrate_fd_completed(MigrationState *s)
+{
+ DPRINTF("setting completed state\n");
+ if (migrate_fd_cleanup(s) < 0) {
+ s->state = MIG_STATE_ERROR;
+ } else {
+ s->state = MIG_STATE_COMPLETED;
+ runstate_set(RUN_STATE_POSTMIGRATE);
+ }
+ notifier_list_notify(&migration_state_notifiers, s);
+}
+
+static void migrate_fd_put_notify(void *opaque)
+{
+ MigrationState *s = opaque;
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
qemu_file_put_notify(s->file);
+ if (qemu_file_get_error(s->file)) {
+ migrate_fd_error(s);
+ }
}
-ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
+static ssize_t migrate_fd_put_buffer(void *opaque, const void *data,
+ size_t size)
{
- FdMigrationState *s = opaque;
+ MigrationState *s = opaque;
ssize_t ret;
+ if (s->state != MIG_STATE_ACTIVE) {
+ return -EIO;
+ }
+
do {
ret = s->write(s, data, size);
} while (ret == -1 && ((s->get_error(s)) == EINTR));
@@ -329,115 +276,61 @@ ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
if (ret == -EAGAIN) {
qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s);
- } else if (ret < 0) {
- s->state = MIG_STATE_ERROR;
- notifier_list_notify(&migration_state_notifiers, NULL);
}
return ret;
}
-void migrate_fd_connect(FdMigrationState *s)
+static void migrate_fd_put_ready(void *opaque)
{
+ MigrationState *s = opaque;
int ret;
- s->file = qemu_fopen_ops_buffered(s,
- s->bandwidth_limit,
- migrate_fd_put_buffer,
- migrate_fd_put_ready,
- migrate_fd_wait_for_unfreeze,
- migrate_fd_close);
-
- DPRINTF("beginning savevm\n");
- 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);
- migrate_fd_error(s);
- return;
- }
-
- migrate_fd_put_ready(s);
-}
-
-void migrate_fd_put_ready(void *opaque)
-{
- FdMigrationState *s = opaque;
-
if (s->state != MIG_STATE_ACTIVE) {
DPRINTF("put_ready returning because of non-active state\n");
return;
}
DPRINTF("iterate\n");
- if (qemu_savevm_state_iterate(s->mon, s->file) == 1) {
- int state;
+ ret = qemu_savevm_state_iterate(s->mon, s->file);
+ if (ret < 0) {
+ migrate_fd_error(s);
+ } else if (ret == 1) {
int old_vm_running = runstate_is_running();
DPRINTF("done iterating\n");
vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
- if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) {
- if (old_vm_running) {
- vm_start();
- }
- state = MIG_STATE_ERROR;
+ if (qemu_savevm_state_complete(s->mon, s->file) < 0) {
+ migrate_fd_error(s);
} else {
- state = MIG_STATE_COMPLETED;
+ migrate_fd_completed(s);
}
- if (migrate_fd_cleanup(s) < 0) {
+ if (s->state != MIG_STATE_COMPLETED) {
if (old_vm_running) {
vm_start();
}
- state = MIG_STATE_ERROR;
- }
- if (state == MIG_STATE_COMPLETED) {
- runstate_set(RUN_STATE_POSTMIGRATE);
}
- s->state = state;
- notifier_list_notify(&migration_state_notifiers, NULL);
}
}
-int migrate_fd_get_status(MigrationState *mig_state)
+static void migrate_fd_cancel(MigrationState *s)
{
- FdMigrationState *s = migrate_to_fms(mig_state);
- return s->state;
-}
-
-void migrate_fd_cancel(MigrationState *mig_state)
-{
- FdMigrationState *s = migrate_to_fms(mig_state);
-
if (s->state != MIG_STATE_ACTIVE)
return;
DPRINTF("cancelling migration\n");
s->state = MIG_STATE_CANCELLED;
- notifier_list_notify(&migration_state_notifiers, NULL);
+ notifier_list_notify(&migration_state_notifiers, s);
qemu_savevm_state_cancel(s->mon, s->file);
migrate_fd_cleanup(s);
}
-void migrate_fd_release(MigrationState *mig_state)
-{
- FdMigrationState *s = migrate_to_fms(mig_state);
-
- DPRINTF("releasing state\n");
-
- if (s->state == MIG_STATE_ACTIVE) {
- s->state = MIG_STATE_CANCELLED;
- notifier_list_notify(&migration_state_notifiers, NULL);
- migrate_fd_cleanup(s);
- }
- g_free(s);
-}
-
-void migrate_fd_wait_for_unfreeze(void *opaque)
+static void migrate_fd_wait_for_unfreeze(void *opaque)
{
- FdMigrationState *s = opaque;
+ MigrationState *s = opaque;
int ret;
DPRINTF("wait for unfreeze\n");
@@ -452,11 +345,15 @@ void migrate_fd_wait_for_unfreeze(void *opaque)
ret = select(s->fd + 1, NULL, &wfds, NULL, NULL);
} while (ret == -1 && (s->get_error(s)) == EINTR);
+
+ if (ret == -1) {
+ qemu_file_set_error(s->file, -s->get_error(s));
+ }
}
-int migrate_fd_close(void *opaque)
+static int migrate_fd_close(void *opaque)
{
- FdMigrationState *s = opaque;
+ MigrationState *s = opaque;
if (s->mon) {
monitor_resume(s->mon);
@@ -475,11 +372,129 @@ void remove_migration_state_change_notifier(Notifier *notify)
notifier_list_remove(&migration_state_notifiers, notify);
}
-int get_migration_state(void)
+bool migration_has_finished(MigrationState *s)
+{
+ return s->state == MIG_STATE_COMPLETED;
+}
+
+void migrate_fd_connect(MigrationState *s)
{
- if (current_migration) {
- return migrate_fd_get_status(current_migration);
+ int ret;
+
+ s->state = MIG_STATE_ACTIVE;
+ s->file = qemu_fopen_ops_buffered(s,
+ s->bandwidth_limit,
+ migrate_fd_put_buffer,
+ migrate_fd_put_ready,
+ migrate_fd_wait_for_unfreeze,
+ migrate_fd_close);
+
+ DPRINTF("beginning savevm\n");
+ ret = qemu_savevm_state_begin(s->mon, s->file, s->blk, s->shared);
+ if (ret < 0) {
+ DPRINTF("failed, %d\n", ret);
+ migrate_fd_error(s);
+ return;
+ }
+ migrate_fd_put_ready(s);
+}
+
+static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc)
+{
+ MigrationState *s = migrate_get_current();
+ int64_t bandwidth_limit = s->bandwidth_limit;
+
+ memset(s, 0, sizeof(*s));
+ s->bandwidth_limit = bandwidth_limit;
+ s->blk = blk;
+ s->shared = inc;
+ s->mon = NULL;
+ s->bandwidth_limit = bandwidth_limit;
+ s->state = MIG_STATE_SETUP;
+
+ if (!detach) {
+ migrate_fd_monitor_suspend(s, mon);
+ }
+
+ return s;
+}
+
+int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ 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;
+ }
+
+ if (qemu_savevm_state_blocked(mon)) {
+ return -1;
+ }
+
+ s = migrate_init(mon, detach, blk, inc);
+
+ if (strstart(uri, "tcp:", &p)) {
+ ret = tcp_start_outgoing_migration(s, p);
+#if !defined(WIN32)
+ } else if (strstart(uri, "exec:", &p)) {
+ ret = exec_start_outgoing_migration(s, p);
+ } else if (strstart(uri, "unix:", &p)) {
+ ret = unix_start_outgoing_migration(s, p);
+ } else if (strstart(uri, "fd:", &p)) {
+ ret = fd_start_outgoing_migration(s, p);
+#endif
} else {
- return MIG_STATE_ERROR;
+ monitor_printf(mon, "unknown migration protocol: %s\n", uri);
+ ret = -EINVAL;
+ }
+
+ if (ret < 0) {
+ monitor_printf(mon, "migration failed: %s\n", strerror(-ret));
+ return ret;
+ }
+
+ notifier_list_notify(&migration_state_notifiers, s);
+ return 0;
+}
+
+int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ migrate_fd_cancel(migrate_get_current());
+ return 0;
+}
+
+int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ int64_t d;
+ MigrationState *s;
+
+ d = qdict_get_int(qdict, "value");
+ if (d < 0) {
+ d = 0;
}
+
+ s = migrate_get_current();
+ s->bandwidth_limit = d;
+ qemu_file_set_rate_limit(s->file, s->bandwidth_limit);
+
+ return 0;
+}
+
+int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
+ QObject **ret_data)
+{
+ double d;
+
+ d = qdict_get_double(qdict, "value") * 1e9;
+ d = MAX(0, MIN(UINT64_MAX, d));
+ max_downtime = (uint64_t)d;
+
+ return 0;
}
diff --git a/migration.h b/migration.h
index 050c56c5a4..a1f80d0728 100644
--- a/migration.h
+++ b/migration.h
@@ -18,37 +18,21 @@
#include "qemu-common.h"
#include "notify.h"
-#define MIG_STATE_ERROR -1
-#define MIG_STATE_COMPLETED 0
-#define MIG_STATE_CANCELLED 1
-#define MIG_STATE_ACTIVE 2
-
typedef struct MigrationState MigrationState;
struct MigrationState
{
- /* FIXME: add more accessors to print migration info */
- void (*cancel)(MigrationState *s);
- int (*get_status)(MigrationState *s);
- void (*release)(MigrationState *s);
- int blk;
- int shared;
-};
-
-typedef struct FdMigrationState FdMigrationState;
-
-struct FdMigrationState
-{
- MigrationState mig_state;
int64_t bandwidth_limit;
QEMUFile *file;
int fd;
Monitor *mon;
int state;
- int (*get_error)(struct FdMigrationState*);
- int (*close)(struct FdMigrationState*);
- int (*write)(struct FdMigrationState*, const void *, size_t);
+ int (*get_error)(MigrationState *s);
+ int (*close)(MigrationState *s);
+ int (*write)(MigrationState *s, const void *buff, size_t size);
void *opaque;
+ int blk;
+ int shared;
};
void process_incoming_migration(QEMUFile *f);
@@ -72,72 +56,27 @@ void do_info_migrate(Monitor *mon, QObject **ret_data);
int exec_start_incoming_migration(const char *host_port);
-MigrationState *exec_start_outgoing_migration(Monitor *mon,
- const char *host_port,
- int64_t bandwidth_limit,
- int detach,
- int blk,
- int inc);
+int exec_start_outgoing_migration(MigrationState *s, const char *host_port);
int tcp_start_incoming_migration(const char *host_port);
-MigrationState *tcp_start_outgoing_migration(Monitor *mon,
- const char *host_port,
- int64_t bandwidth_limit,
- int detach,
- int blk,
- int inc);
+int tcp_start_outgoing_migration(MigrationState *s, const char *host_port);
int unix_start_incoming_migration(const char *path);
-MigrationState *unix_start_outgoing_migration(Monitor *mon,
- const char *path,
- int64_t bandwidth_limit,
- int detach,
- int blk,
- int inc);
+int unix_start_outgoing_migration(MigrationState *s, const char *path);
int fd_start_incoming_migration(const char *path);
-MigrationState *fd_start_outgoing_migration(Monitor *mon,
- const char *fdname,
- int64_t bandwidth_limit,
- int detach,
- int blk,
- int inc);
-
-void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon);
-
-void migrate_fd_error(FdMigrationState *s);
+int fd_start_outgoing_migration(MigrationState *s, const char *fdname);
-int migrate_fd_cleanup(FdMigrationState *s);
+void migrate_fd_error(MigrationState *s);
-void migrate_fd_put_notify(void *opaque);
-
-ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size);
-
-void migrate_fd_connect(FdMigrationState *s);
-
-void migrate_fd_put_ready(void *opaque);
-
-int migrate_fd_get_status(MigrationState *mig_state);
-
-void migrate_fd_cancel(MigrationState *mig_state);
-
-void migrate_fd_release(MigrationState *mig_state);
-
-void migrate_fd_wait_for_unfreeze(void *opaque);
-
-int migrate_fd_close(void *opaque);
-
-static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state)
-{
- return container_of(mig_state, FdMigrationState, mig_state);
-}
+void migrate_fd_connect(MigrationState *s);
void add_migration_state_change_notifier(Notifier *notify);
void remove_migration_state_change_notifier(Notifier *notify);
-int get_migration_state(void);
+bool migration_has_finished(MigrationState *);
uint64_t ram_bytes_remaining(void);
uint64_t ram_bytes_transferred(void);
diff --git a/savevm.c b/savevm.c
index abb4a60643..cf79a56871 100644
--- a/savevm.c
+++ b/savevm.c
@@ -173,7 +173,7 @@ struct QEMUFile {
int buf_size; /* 0 when writing */
uint8_t buf[IO_BUF_SIZE];
- int has_error;
+ int last_error;
};
typedef struct QEMUFileStdio
@@ -425,14 +425,14 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
return f;
}
-int qemu_file_has_error(QEMUFile *f)
+int qemu_file_get_error(QEMUFile *f)
{
- return f->has_error;
+ return f->last_error;
}
-void qemu_file_set_error(QEMUFile *f)
+void qemu_file_set_error(QEMUFile *f, int ret)
{
- f->has_error = 1;
+ f->last_error = ret;
}
void qemu_fflush(QEMUFile *f)
@@ -447,7 +447,7 @@ void qemu_fflush(QEMUFile *f)
if (len > 0)
f->buf_offset += f->buf_index;
else
- f->has_error = 1;
+ f->last_error = -EINVAL;
f->buf_index = 0;
}
}
@@ -455,6 +455,7 @@ void qemu_fflush(QEMUFile *f)
static void qemu_fill_buffer(QEMUFile *f)
{
int len;
+ int pending;
if (!f->get_buffer)
return;
@@ -462,13 +463,20 @@ static void qemu_fill_buffer(QEMUFile *f)
if (f->is_write)
abort();
- len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE);
+ pending = f->buf_size - f->buf_index;
+ if (pending > 0) {
+ memmove(f->buf, f->buf + f->buf_index, pending);
+ }
+ f->buf_index = 0;
+ f->buf_size = pending;
+
+ len = f->get_buffer(f->opaque, f->buf + pending, f->buf_offset,
+ IO_BUF_SIZE - pending);
if (len > 0) {
- f->buf_index = 0;
- f->buf_size = len;
+ f->buf_size += len;
f->buf_offset += len;
} else if (len != -EAGAIN)
- f->has_error = 1;
+ f->last_error = len;
}
int qemu_fclose(QEMUFile *f)
@@ -490,13 +498,13 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
{
int l;
- if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+ if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
fprintf(stderr,
"Attempted to write to buffer while read buffer is not empty\n");
abort();
}
- while (!f->has_error && size > 0) {
+ while (!f->last_error && size > 0) {
l = IO_BUF_SIZE - f->buf_index;
if (l > size)
l = size;
@@ -512,7 +520,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
void qemu_put_byte(QEMUFile *f, int v)
{
- if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+ if (!f->last_error && f->is_write == 0 && f->buf_index > 0) {
fprintf(stderr,
"Attempted to write to buffer while read buffer is not empty\n");
abort();
@@ -524,56 +532,86 @@ void qemu_put_byte(QEMUFile *f, int v)
qemu_fflush(f);
}
-int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
+static void qemu_file_skip(QEMUFile *f, int size)
+{
+ if (f->buf_index + size <= f->buf_size) {
+ f->buf_index += size;
+ }
+}
+
+static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
{
- int size, l;
+ int pending;
+ int index;
- if (f->is_write)
+ if (f->is_write) {
abort();
+ }
- size = size1;
- while (size > 0) {
- l = f->buf_size - f->buf_index;
- if (l == 0) {
- qemu_fill_buffer(f);
- l = f->buf_size - f->buf_index;
- if (l == 0)
- break;
+ index = f->buf_index + offset;
+ pending = f->buf_size - index;
+ if (pending < size) {
+ qemu_fill_buffer(f);
+ index = f->buf_index + offset;
+ pending = f->buf_size - index;
+ }
+
+ if (pending <= 0) {
+ return 0;
+ }
+ if (size > pending) {
+ size = pending;
+ }
+
+ memcpy(buf, f->buf + index, size);
+ return size;
+}
+
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
+{
+ int pending = size;
+ int done = 0;
+
+ while (pending > 0) {
+ int res;
+
+ res = qemu_peek_buffer(f, buf, pending, 0);
+ if (res == 0) {
+ return done;
}
- if (l > size)
- l = size;
- memcpy(buf, f->buf + f->buf_index, l);
- f->buf_index += l;
- buf += l;
- size -= l;
+ qemu_file_skip(f, res);
+ buf += res;
+ pending -= res;
+ done += res;
}
- return size1 - size;
+ return done;
}
-static int qemu_peek_byte(QEMUFile *f)
+static int qemu_peek_byte(QEMUFile *f, int offset)
{
- if (f->is_write)
+ int index = f->buf_index + offset;
+
+ if (f->is_write) {
abort();
+ }
- if (f->buf_index >= f->buf_size) {
+ if (index >= f->buf_size) {
qemu_fill_buffer(f);
- if (f->buf_index >= f->buf_size)
+ index = f->buf_index + offset;
+ if (index >= f->buf_size) {
return 0;
+ }
}
- return f->buf[f->buf_index];
+ return f->buf[index];
}
int qemu_get_byte(QEMUFile *f)
{
- if (f->is_write)
- abort();
+ int result;
- if (f->buf_index >= f->buf_size) {
- qemu_fill_buffer(f);
- if (f->buf_index >= f->buf_size)
- return 0;
- }
- return f->buf[f->buf_index++];
+ result = qemu_peek_byte(f, 0);
+ qemu_file_skip(f, 1);
+ return result;
}
int64_t qemu_ftell(QEMUFile *f)
@@ -1466,6 +1504,7 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
int shared)
{
SaveStateEntry *se;
+ int ret;
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if(se->set_params == NULL) {
@@ -1495,17 +1534,27 @@ 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);
- se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+ ret = se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+ if (ret < 0) {
+ qemu_savevm_state_cancel(mon, f);
+ return ret;
+ }
}
-
- if (qemu_file_has_error(f)) {
+ ret = qemu_file_get_error(f);
+ if (ret != 0) {
qemu_savevm_state_cancel(mon, f);
- return -EIO;
}
- return 0;
+ return ret;
+
}
+/*
+ * this funtion has three return values:
+ * negative: there was one error, and we have -errno.
+ * 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)
{
SaveStateEntry *se;
@@ -1520,7 +1569,7 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
qemu_put_be32(f, se->section_id);
ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
- if (!ret) {
+ if (ret <= 0) {
/* Do not proceed to the next vmstate before this one reported
completion of the current stage. This serializes the migration
and reduces the probability that a faster changing state is
@@ -1528,21 +1577,20 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
break;
}
}
-
- if (ret)
- return 1;
-
- if (qemu_file_has_error(f)) {
+ if (ret != 0) {
+ return ret;
+ }
+ ret = qemu_file_get_error(f);
+ if (ret != 0) {
qemu_savevm_state_cancel(mon, f);
- return -EIO;
}
-
- return 0;
+ return ret;
}
int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
{
SaveStateEntry *se;
+ int ret;
cpu_synchronize_all_states();
@@ -1554,7 +1602,10 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
qemu_put_byte(f, QEMU_VM_SECTION_END);
qemu_put_be32(f, se->section_id);
- se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+ ret = se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+ if (ret < 0) {
+ return ret;
+ }
}
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
@@ -1580,10 +1631,7 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
qemu_put_byte(f, QEMU_VM_EOF);
- if (qemu_file_has_error(f))
- return -EIO;
-
- return 0;
+ return qemu_file_get_error(f);
}
void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
@@ -1619,8 +1667,9 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
ret = qemu_savevm_state_complete(mon, f);
out:
- if (qemu_file_has_error(f))
- ret = -EIO;
+ if (ret == 0) {
+ ret = qemu_file_get_error(f);
+ }
return ret;
}
@@ -1659,29 +1708,36 @@ static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection
static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque)
{
- const VMStateSubsection *sub = vmsd->subsections;
-
- if (!sub || !sub->needed) {
- return 0;
- }
-
- while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
+ while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
char idstr[256];
int ret;
- uint8_t version_id, len;
+ uint8_t version_id, len, size;
const VMStateDescription *sub_vmsd;
- qemu_get_byte(f); /* subsection */
- len = qemu_get_byte(f);
- qemu_get_buffer(f, (uint8_t *)idstr, len);
- idstr[len] = 0;
- version_id = qemu_get_be32(f);
+ len = qemu_peek_byte(f, 1);
+ if (len < strlen(vmsd->name) + 1) {
+ /* subsection name has be be "section_name/a" */
+ return 0;
+ }
+ size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
+ if (size != len) {
+ return 0;
+ }
+ idstr[size] = 0;
- sub_vmsd = vmstate_get_subsection(sub, idstr);
+ if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
+ /* it don't have a valid subsection name */
+ return 0;
+ }
+ sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
if (sub_vmsd == NULL) {
return -ENOENT;
}
- assert(!sub_vmsd->subsections);
+ qemu_file_skip(f, 1); /* subsection */
+ qemu_file_skip(f, 1); /* len */
+ qemu_file_skip(f, len); /* idstr */
+ version_id = qemu_get_be32(f);
+
ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
if (ret) {
return ret;
@@ -1705,7 +1761,6 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
qemu_put_byte(f, len);
qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
qemu_put_be32(f, vmsd->version_id);
- assert(!vmsd->subsections);
vmstate_save_state(f, vmsd, opaque);
}
sub++;
@@ -1831,8 +1886,9 @@ out:
g_free(le);
}
- if (qemu_file_has_error(f))
- ret = -EIO;
+ if (ret == 0) {
+ ret = qemu_file_get_error(f);
+ }
return ret;
}
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 3cbc721ee4..b33366e5d7 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -447,9 +447,9 @@ void do_info_spice(Monitor *mon, QObject **ret_data)
static void migration_state_notifier(Notifier *notifier, void *data)
{
- int state = get_migration_state();
+ MigrationState *s = data;
- if (state == MIG_STATE_COMPLETED) {
+ if (migration_has_finished(s)) {
#if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */
spice_server_migrate_switch(spice_server);
#endif