* later. See the COPYING file in the top-level directory.
*
*/
+
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qemu-common.h"
#include "qemu/cutils.h"
#include "rdma.h"
#include "migration.h"
#include "qemu-file-channel.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
+#include "qemu/module.h"
+#include "qemu/rcu.h"
#include "qemu/sockets.h"
#include "qemu/bitmap.h"
#include "qemu/coroutine.h"
+#include "exec/memory.h"
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
" to abort!"); \
rdma->error_reported = 1; \
} \
- rcu_read_unlock(); \
return rdma->error_state; \
} \
} while (0)
*/
static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp)
{
- struct ibv_port_attr port_attr;
-
/* This bug only exists in linux, to our knowledge. */
#ifdef CONFIG_LINUX
+ struct ibv_port_attr port_attr;
/*
* Verbs are only NULL if management has bound to '[::]'.
size_t i;
size_t len = 0;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
rdma = atomic_rcu_read(&rioc->rdmaout);
if (!rdma) {
- rcu_read_unlock();
return -EIO;
}
ret = qemu_rdma_write_flush(f, rdma);
if (ret < 0) {
rdma->error_state = ret;
- rcu_read_unlock();
return ret;
}
if (ret < 0) {
rdma->error_state = ret;
- rcu_read_unlock();
return ret;
}
}
}
- rcu_read_unlock();
return done;
}
ssize_t i;
size_t done = 0;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
rdma = atomic_rcu_read(&rioc->rdmain);
if (!rdma) {
- rcu_read_unlock();
return -EIO;
}
if (ret < 0) {
rdma->error_state = ret;
- rcu_read_unlock();
return ret;
}
/* Still didn't get enough, so lets just return */
if (want) {
if (done == 0) {
- rcu_read_unlock();
return QIO_CHANNEL_ERR_BLOCK;
} else {
break;
}
}
}
- rcu_read_unlock();
return done;
}
GIOCondition cond = 0;
*timeout = -1;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
if (rsource->condition == G_IO_IN) {
rdma = atomic_rcu_read(&rsource->rioc->rdmain);
} else {
if (!rdma) {
error_report("RDMAContext is NULL when prepare Gsource");
- rcu_read_unlock();
return FALSE;
}
}
cond |= G_IO_OUT;
- rcu_read_unlock();
return cond & rsource->condition;
}
RDMAContext *rdma;
GIOCondition cond = 0;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
if (rsource->condition == G_IO_IN) {
rdma = atomic_rcu_read(&rsource->rioc->rdmain);
} else {
if (!rdma) {
error_report("RDMAContext is NULL when check Gsource");
- rcu_read_unlock();
return FALSE;
}
}
cond |= G_IO_OUT;
- rcu_read_unlock();
return cond & rsource->condition;
}
RDMAContext *rdma;
GIOCondition cond = 0;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
if (rsource->condition == G_IO_IN) {
rdma = atomic_rcu_read(&rsource->rioc->rdmain);
} else {
if (!rdma) {
error_report("RDMAContext is NULL when dispatch Gsource");
- rcu_read_unlock();
return FALSE;
}
}
cond |= G_IO_OUT;
- rcu_read_unlock();
return (*func)(QIO_CHANNEL(rsource->rioc),
(cond & rsource->condition),
user_data);
}
}
+struct rdma_close_rcu {
+ struct rcu_head rcu;
+ RDMAContext *rdmain;
+ RDMAContext *rdmaout;
+};
+
+/* callback from qio_channel_rdma_close via call_rcu */
+static void qio_channel_rdma_close_rcu(struct rdma_close_rcu *rcu)
+{
+ if (rcu->rdmain) {
+ qemu_rdma_cleanup(rcu->rdmain);
+ }
+
+ if (rcu->rdmaout) {
+ qemu_rdma_cleanup(rcu->rdmaout);
+ }
+
+ g_free(rcu->rdmain);
+ g_free(rcu->rdmaout);
+ g_free(rcu);
+}
+
static int qio_channel_rdma_close(QIOChannel *ioc,
Error **errp)
{
QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
RDMAContext *rdmain, *rdmaout;
+ struct rdma_close_rcu *rcu = g_new(struct rdma_close_rcu, 1);
+
trace_qemu_rdma_close();
rdmain = rioc->rdmain;
atomic_rcu_set(&rioc->rdmaout, NULL);
}
- synchronize_rcu();
-
- if (rdmain) {
- qemu_rdma_cleanup(rdmain);
- }
-
- if (rdmaout) {
- qemu_rdma_cleanup(rdmaout);
- }
-
- g_free(rdmain);
- g_free(rdmaout);
+ rcu->rdmain = rdmain;
+ rcu->rdmaout = rdmaout;
+ call_rcu(rcu, qio_channel_rdma_close_rcu, rcu);
return 0;
}
QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc);
RDMAContext *rdmain, *rdmaout;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
rdmain = atomic_rcu_read(&rioc->rdmain);
rdmaout = atomic_rcu_read(&rioc->rdmain);
break;
}
- rcu_read_unlock();
return 0;
}
RDMAContext *rdma;
int ret;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
rdma = atomic_rcu_read(&rioc->rdmaout);
if (!rdma) {
- rcu_read_unlock();
return -EIO;
}
CHECK_ERROR_STATE();
- if (migrate_get_current()->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
- rcu_read_unlock();
+ if (migration_in_postcopy()) {
return RAM_SAVE_CONTROL_NOT_SUPP;
}
}
}
- rcu_read_unlock();
return RAM_SAVE_CONTROL_DELAYED;
err:
rdma->error_state = ret;
- rcu_read_unlock();
return ret;
}
if (cm_event->event == RDMA_CM_EVENT_DISCONNECTED ||
cm_event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) {
- error_report("receive cm event, cm event is %d", cm_event->event);
- rdma->error_state = -EPIPE;
- if (rdma->return_path) {
- rdma->return_path->error_state = -EPIPE;
+ if (!rdma->error_state &&
+ migration_incoming_get_current()->state !=
+ MIGRATION_STATUS_COMPLETED) {
+ error_report("receive cm event, cm event is %d", cm_event->event);
+ rdma->error_state = -EPIPE;
+ if (rdma->return_path) {
+ rdma->return_path->error_state = -EPIPE;
+ }
}
if (mis->migration_incoming_co) {
int count = 0;
int i = 0;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
rdma = atomic_rcu_read(&rioc->rdmain);
if (!rdma) {
- rcu_read_unlock();
return -EIO;
}
if (ret < 0) {
rdma->error_state = ret;
}
- rcu_read_unlock();
return ret;
}
int curr;
int found = -1;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
rdma = atomic_rcu_read(&rioc->rdmain);
if (!rdma) {
- rcu_read_unlock();
return -EIO;
}
if (found == -1) {
error_report("RAMBlock '%s' not found on destination", name);
- rcu_read_unlock();
return -ENOENT;
}
trace_rdma_block_notification_handle(name, rdma->next_src_index);
rdma->next_src_index++;
- rcu_read_unlock();
return 0;
}
QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
RDMAContext *rdma;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
rdma = atomic_rcu_read(&rioc->rdmaout);
if (!rdma) {
- rcu_read_unlock();
return -EIO;
}
CHECK_ERROR_STATE();
- if (migrate_get_current()->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
- rcu_read_unlock();
+ if (migration_in_postcopy()) {
return 0;
}
qemu_put_be64(f, RAM_SAVE_FLAG_HOOK);
qemu_fflush(f);
- rcu_read_unlock();
return 0;
}
static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque,
uint64_t flags, void *data)
{
- Error *local_err = NULL, **errp = &local_err;
QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(opaque);
RDMAContext *rdma;
RDMAControlHeader head = { .len = 0, .repeat = 1 };
int ret = 0;
- rcu_read_lock();
+ RCU_READ_LOCK_GUARD();
rdma = atomic_rcu_read(&rioc->rdmaout);
if (!rdma) {
- rcu_read_unlock();
return -EIO;
}
CHECK_ERROR_STATE();
- if (migrate_get_current()->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
- rcu_read_unlock();
+ if (migration_in_postcopy()) {
return 0;
}
®_result_idx, rdma->pin_all ?
qemu_rdma_reg_whole_ram_blocks : NULL);
if (ret < 0) {
- ERROR(errp, "receiving remote info!");
- rcu_read_unlock();
+ fprintf(stderr, "receiving remote info!");
return ret;
}
*/
if (local->nb_blocks != nb_dest_blocks) {
- ERROR(errp, "ram blocks mismatch (Number of blocks %d vs %d) "
- "Your QEMU command line parameters are probably "
- "not identical on both the source and destination.",
- local->nb_blocks, nb_dest_blocks);
+ fprintf(stderr, "ram blocks mismatch (Number of blocks %d vs %d) "
+ "Your QEMU command line parameters are probably "
+ "not identical on both the source and destination.",
+ local->nb_blocks, nb_dest_blocks);
rdma->error_state = -EINVAL;
- rcu_read_unlock();
return -EINVAL;
}
/* We require that the blocks are in the same order */
if (rdma->dest_blocks[i].length != local->block[i].length) {
- ERROR(errp, "Block %s/%d has a different length %" PRIu64
- "vs %" PRIu64, local->block[i].block_name, i,
- local->block[i].length,
- rdma->dest_blocks[i].length);
+ fprintf(stderr, "Block %s/%d has a different length %" PRIu64
+ "vs %" PRIu64, local->block[i].block_name, i,
+ local->block[i].length,
+ rdma->dest_blocks[i].length);
rdma->error_state = -EINVAL;
- rcu_read_unlock();
return -EINVAL;
}
local->block[i].remote_host_addr =
goto err;
}
- rcu_read_unlock();
return 0;
err:
rdma->error_state = ret;
- rcu_read_unlock();
return ret;
}
RDMAContext *rdma = opaque;
int ret;
QEMUFile *f;
- Error *local_err = NULL, **errp = &local_err;
+ Error *local_err = NULL;
trace_qemu_rdma_accept_incoming_migration();
ret = qemu_rdma_accept(rdma);
if (ret) {
- ERROR(errp, "RDMA Migration initialization failed!");
+ fprintf(stderr, "RDMA ERROR: Migration initialization failed\n");
return;
}
f = qemu_fopen_rdma(rdma, "rb");
if (f == NULL) {
- ERROR(errp, "could not qemu_fopen_rdma!");
+ fprintf(stderr, "RDMA ERROR: could not qemu_fopen_rdma\n");
qemu_rdma_cleanup(rdma);
return;
}
rdma->migration_started_on_destination = 1;
- migration_fd_process_incoming(f);
+ migration_fd_process_incoming(f, &local_err);
+ if (local_err) {
+ error_reportf_err(local_err, "RDMA ERROR:");
+ }
}
void rdma_start_incoming_migration(const char *host_port, Error **errp)
Error *local_err = NULL;
trace_rdma_start_incoming_migration();
- rdma = qemu_rdma_data_init(host_port, &local_err);
+ /* Avoid ram_block_discard_disable(), cannot change during migration. */
+ if (ram_block_discard_is_required()) {
+ error_setg(errp, "RDMA: cannot disable RAM discard");
+ return;
+ }
+
+ rdma = qemu_rdma_data_init(host_port, &local_err);
if (rdma == NULL) {
goto err;
}
return;
err:
error_propagate(errp, local_err);
+ if (rdma) {
+ g_free(rdma->host);
+ }
g_free(rdma);
g_free(rdma_return_path);
}
const char *host_port, Error **errp)
{
MigrationState *s = opaque;
- RDMAContext *rdma = qemu_rdma_data_init(host_port, errp);
RDMAContext *rdma_return_path = NULL;
+ RDMAContext *rdma;
int ret = 0;
+ /* Avoid ram_block_discard_disable(), cannot change during migration. */
+ if (ram_block_discard_is_required()) {
+ error_setg(errp, "RDMA: cannot disable RAM discard");
+ return;
+ }
+
+ rdma = qemu_rdma_data_init(host_port, errp);
if (rdma == NULL) {
goto err;
}
rdma_return_path = qemu_rdma_data_init(host_port, errp);
if (rdma_return_path == NULL) {
- goto err;
+ goto return_path_err;
}
ret = qemu_rdma_source_init(rdma_return_path,
s->enabled_capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp);
if (ret) {
- goto err;
+ goto return_path_err;
}
ret = qemu_rdma_connect(rdma_return_path, errp);
if (ret) {
- goto err;
+ goto return_path_err;
}
rdma->return_path = rdma_return_path;
s->to_dst_file = qemu_fopen_rdma(rdma, "wb");
migrate_fd_connect(s, NULL);
return;
+return_path_err:
+ qemu_rdma_cleanup(rdma);
err:
g_free(rdma);
g_free(rdma_return_path);