Merge remote-tracking branch 'quintela/migration-pull' into staging

This commit is contained in:
Anthony Liguori 2011-10-20 08:46:55 -05:00
commit a6e43daa73
13 changed files with 557 additions and 605 deletions

View File

@ -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));

View File

@ -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));

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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;
migrate_fd_error(s);
return ret;
}
if (!detach) {
migrate_fd_monitor_suspend(s, mon);
}
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;
}

View File

@ -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;
MigrationState *s = migrate_get_current();
if (s) {
switch (s->get_status(s)) {
case MIG_STATE_ACTIVE:
qdict = qdict_new();
qdict_put(qdict, "status", qstring_from_str("active"));
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());
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;
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)
static void migrate_fd_wait_for_unfreeze(void *opaque)
{
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)
{
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)
{
if (current_migration) {
return migrate_fd_get_status(current_migration);
} else {
return MIG_STATE_ERROR;
}
return s->state == MIG_STATE_COMPLETED;
}
void migrate_fd_connect(MigrationState *s)
{
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 {
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;
}

View File

@ -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);
int fd_start_outgoing_migration(MigrationState *s, const char *fdname);
void migrate_fd_monitor_suspend(FdMigrationState *s, Monitor *mon);
void migrate_fd_error(MigrationState *s);
void migrate_fd_error(FdMigrationState *s);
int migrate_fd_cleanup(FdMigrationState *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);

238
savevm.c
View File

@ -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)
{
int size, l;
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;
}
if (l > size)
l = size;
memcpy(buf, f->buf + f->buf_index, l);
f->buf_index += l;
buf += l;
size -= l;
if (f->buf_index + size <= f->buf_size) {
f->buf_index += size;
}
return size1 - size;
}
static int qemu_peek_byte(QEMUFile *f)
static int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
{
if (f->is_write)
abort();
int pending;
int index;
if (f->buf_index >= f->buf_size) {
qemu_fill_buffer(f);
if (f->buf_index >= f->buf_size)
return 0;
if (f->is_write) {
abort();
}
return f->buf[f->buf_index];
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;
}
qemu_file_skip(f, res);
buf += res;
pending -= res;
done += res;
}
return done;
}
static int qemu_peek_byte(QEMUFile *f, int offset)
{
int index = f->buf_index + offset;
if (f->is_write) {
abort();
}
if (index >= f->buf_size) {
qemu_fill_buffer(f);
index = f->buf_index + offset;
if (index >= f->buf_size) {
return 0;
}
}
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)) {
qemu_savevm_state_cancel(mon, f);
return -EIO;
if (ret != 0) {
return ret;
}
return 0;
ret = qemu_file_get_error(f);
if (ret != 0) {
qemu_savevm_state_cancel(mon, f);
}
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;
}

View File

@ -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