diff options
Diffstat (limited to 'migration')
-rw-r--r-- | migration/fd.c | 24 | ||||
-rw-r--r-- | migration/migration.c | 12 | ||||
-rw-r--r-- | migration/qemu-file-buf.c | 10 | ||||
-rw-r--r-- | migration/qemu-file-unix.c | 23 | ||||
-rw-r--r-- | migration/qemu-file.c | 12 |
5 files changed, 71 insertions, 10 deletions
diff --git a/migration/fd.c b/migration/fd.c index d2e523a..129da99 100644 --- a/migration/fd.c +++ b/migration/fd.c @@ -31,13 +31,29 @@ do { } while (0) #endif +static bool fd_is_socket(int fd) +{ + struct stat stat; + int ret = fstat(fd, &stat); + if (ret == -1) { + /* When in doubt say no */ + return false; + } + return S_ISSOCK(stat.st_mode); +} + void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp) { int fd = monitor_get_fd(cur_mon, fdname, errp); if (fd == -1) { return; } - s->file = qemu_fdopen(fd, "wb"); + + if (fd_is_socket(fd)) { + s->file = qemu_fopen_socket(fd, "wb"); + } else { + s->file = qemu_fdopen(fd, "wb"); + } migrate_fd_connect(s); } @@ -58,7 +74,11 @@ void fd_start_incoming_migration(const char *infd, Error **errp) DPRINTF("Attempting to start an incoming migration via fd\n"); fd = strtol(infd, NULL, 0); - f = qemu_fdopen(fd, "rb"); + if (fd_is_socket(fd)) { + f = qemu_fopen_socket(fd, "rb"); + } else { + f = qemu_fdopen(fd, "rb"); + } if(f == NULL) { error_setg_errno(errp, errno, "failed to open the source descriptor"); return; diff --git a/migration/migration.c b/migration/migration.c index c49a05a..b3adbc6 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -330,6 +330,7 @@ void migrate_fd_error(MigrationState *s) static void migrate_fd_cancel(MigrationState *s) { int old_state ; + QEMUFile *f = migrate_get_current()->file; trace_migrate_fd_cancel(); do { @@ -339,6 +340,17 @@ static void migrate_fd_cancel(MigrationState *s) } migrate_set_state(s, old_state, MIG_STATE_CANCELLING); } while (s->state != MIG_STATE_CANCELLING); + + /* + * If we're unlucky the migration code might be stuck somewhere in a + * send/write while the network has failed and is waiting to timeout; + * if we've got shutdown(2) available then we can force it to quit. + * The outgoing qemu file gets closed in migrate_fd_cleanup that is + * called in a bh, so there is no race against this cancel. + */ + if (s->state == MIG_STATE_CANCELLING && f) { + qemu_file_shutdown(f); + } } void add_migration_state_change_notifier(Notifier *notify) diff --git a/migration/qemu-file-buf.c b/migration/qemu-file-buf.c index d33dd44..e97e0bd 100644 --- a/migration/qemu-file-buf.c +++ b/migration/qemu-file-buf.c @@ -395,6 +395,7 @@ QEMUSizedBuffer *qsb_clone(const QEMUSizedBuffer *qsb) typedef struct QEMUBuffer { QEMUSizedBuffer *qsb; QEMUFile *file; + bool qsb_allocated; } QEMUBuffer; static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) @@ -424,7 +425,9 @@ static int buf_close(void *opaque) { QEMUBuffer *s = opaque; - qsb_free(s->qsb); + if (s->qsb_allocated) { + qsb_free(s->qsb); + } g_free(s); @@ -463,12 +466,11 @@ QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input) } s = g_malloc0(sizeof(QEMUBuffer)); - if (mode[0] == 'r') { - s->qsb = input; - } + s->qsb = input; if (s->qsb == NULL) { s->qsb = qsb_create(NULL, 0); + s->qsb_allocated = true; } if (!s->qsb) { g_free(s); diff --git a/migration/qemu-file-unix.c b/migration/qemu-file-unix.c index 9682396..bfbc086 100644 --- a/migration/qemu-file-unix.c +++ b/migration/qemu-file-unix.c @@ -26,6 +26,7 @@ #include "qemu/sockets.h" #include "block/coroutine.h" #include "migration/qemu-file.h" +#include "migration/qemu-file-internal.h" typedef struct QEMUFileSocket { int fd; @@ -84,6 +85,17 @@ static int socket_close(void *opaque) return 0; } +static int socket_shutdown(void *opaque, bool rd, bool wr) +{ + QEMUFileSocket *s = opaque; + + if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) { + return -errno; + } else { + return 0; + } +} + static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, int64_t pos) { @@ -192,15 +204,18 @@ QEMUFile *qemu_fdopen(int fd, const char *mode) } static const QEMUFileOps socket_read_ops = { - .get_fd = socket_get_fd, + .get_fd = socket_get_fd, .get_buffer = socket_get_buffer, - .close = socket_close + .close = socket_close, + .shut_down = socket_shutdown + }; static const QEMUFileOps socket_write_ops = { - .get_fd = socket_get_fd, + .get_fd = socket_get_fd, .writev_buffer = socket_writev_buffer, - .close = socket_close + .close = socket_close, + .shut_down = socket_shutdown }; QEMUFile *qemu_fopen_socket(int fd, const char *mode) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index a7f2a34..edc2830 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -30,6 +30,18 @@ #include "migration/qemu-file-internal.h" #include "trace.h" +/* + * Stop a file from being read/written - not all backing files can do this + * typically only sockets can. + */ +int qemu_file_shutdown(QEMUFile *f) +{ + if (!f->ops->shut_down) { + return -ENOSYS; + } + return f->ops->shut_down(f->opaque, true, true); +} + bool qemu_file_mode_is_not_valid(const char *mode) { if (mode == NULL || |