e1c37d0e94
The migrate command is one of those commands where HMP and QMP completely mix up together. This made the conversion to the QAPI (which separates the command into QMP and HMP parts) a bit difficult. The first important change to be noticed is that this commit completes the removal of the Monitor object from migration code, started by the previous commit. Another important and tricky change is about supporting the non-detached mode. That is, if the user doesn't pass '-d' the migrate command will lock the monitor and will only release it when migration is finished. To support this in the new HMP command (hmp_migrate()), it is necessary to create a timer which runs every second and checks if the migration is still active. If it is, the timer callback will re-schedule itself to run one second in the future. If the migration has already finished, the monitor lock is released and the user can use it normally. All these changes should be transparent to the user. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
129 lines
2.9 KiB
C
129 lines
2.9 KiB
C
/*
|
|
* QEMU live migration via generic fd
|
|
*
|
|
* Copyright Red Hat, Inc. 2009
|
|
*
|
|
* Authors:
|
|
* Chris Lalancette <clalance@redhat.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
|
* the COPYING file in the top-level directory.
|
|
*
|
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
* GNU GPL, version 2 or (at your option) any later version.
|
|
*/
|
|
|
|
#include "qemu-common.h"
|
|
#include "qemu_socket.h"
|
|
#include "migration.h"
|
|
#include "monitor.h"
|
|
#include "qemu-char.h"
|
|
#include "buffered_file.h"
|
|
#include "block.h"
|
|
#include "qemu_socket.h"
|
|
|
|
//#define DEBUG_MIGRATION_FD
|
|
|
|
#ifdef DEBUG_MIGRATION_FD
|
|
#define DPRINTF(fmt, ...) \
|
|
do { printf("migration-fd: " fmt, ## __VA_ARGS__); } while (0)
|
|
#else
|
|
#define DPRINTF(fmt, ...) \
|
|
do { } while (0)
|
|
#endif
|
|
|
|
static int fd_errno(MigrationState *s)
|
|
{
|
|
return errno;
|
|
}
|
|
|
|
static int fd_write(MigrationState *s, const void * buf, size_t size)
|
|
{
|
|
return write(s->fd, buf, size);
|
|
}
|
|
|
|
static int fd_close(MigrationState *s)
|
|
{
|
|
struct stat st;
|
|
int ret;
|
|
|
|
DPRINTF("fd_close\n");
|
|
if (s->fd != -1) {
|
|
ret = fstat(s->fd, &st);
|
|
if (ret == 0 && S_ISREG(st.st_mode)) {
|
|
/*
|
|
* If the file handle is a regular file make sure the
|
|
* data is flushed to disk before signaling success.
|
|
*/
|
|
ret = fsync(s->fd);
|
|
if (ret != 0) {
|
|
ret = -errno;
|
|
perror("migration-fd: fsync");
|
|
return ret;
|
|
}
|
|
}
|
|
ret = close(s->fd);
|
|
s->fd = -1;
|
|
if (ret != 0) {
|
|
ret = -errno;
|
|
perror("migration-fd: close");
|
|
return ret;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int fd_start_outgoing_migration(MigrationState *s, const char *fdname)
|
|
{
|
|
s->fd = monitor_get_fd(cur_mon, fdname);
|
|
if (s->fd == -1) {
|
|
DPRINTF("fd_migration: invalid file descriptor identifier\n");
|
|
goto err_after_get_fd;
|
|
}
|
|
|
|
if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) {
|
|
DPRINTF("Unable to set nonblocking mode on file descriptor\n");
|
|
goto err_after_open;
|
|
}
|
|
|
|
s->get_error = fd_errno;
|
|
s->write = fd_write;
|
|
s->close = fd_close;
|
|
|
|
migrate_fd_connect(s);
|
|
return 0;
|
|
|
|
err_after_open:
|
|
close(s->fd);
|
|
err_after_get_fd:
|
|
return -1;
|
|
}
|
|
|
|
static void fd_accept_incoming_migration(void *opaque)
|
|
{
|
|
QEMUFile *f = opaque;
|
|
|
|
process_incoming_migration(f);
|
|
qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
|
|
qemu_fclose(f);
|
|
}
|
|
|
|
int fd_start_incoming_migration(const char *infd)
|
|
{
|
|
int fd;
|
|
QEMUFile *f;
|
|
|
|
DPRINTF("Attempting to start an incoming migration via fd\n");
|
|
|
|
fd = strtol(infd, NULL, 0);
|
|
f = qemu_fdopen(fd, "rb");
|
|
if(f == NULL) {
|
|
DPRINTF("Unable to apply qemu wrapper to file descriptor\n");
|
|
return -errno;
|
|
}
|
|
|
|
qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL, f);
|
|
|
|
return 0;
|
|
}
|