Migration pull for 2021-06-09
Yank crash fix from Leo RDMA fix from Li mptcp support from me dirty-rate changes from Hyman and Peter (Note I've switched to the gitlab I've been using for virtiofs pulls) Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEERfXHG0oMt/uXep+pBRYzHrxb/ecFAmDA0sEACgkQBRYzHrxb /efn9g/+ICIELbh99KRg6GiZ1BxraixpXgNaN6yjWqdHHTa67/pE0p3xHpLuWFnX pt4SDCXYWZ1XC3Eq4AMXyQr4yq8tUjsKV7H99WI7e8NvYzNPW7C4MlNkiiRUCxyc /SQMrGw6KOByc2PtRBBCW+47aJv1ZaaE09g3s4la6BfT6xeLegncKrxKjWgsxArR BhZVhvmDLn3Njp2iMPLGlDU1+gUcCls2DtQ4WebpyJo511BoIDDzZu8qlLNhKQv0 wCYRB51FsFyZXptELS5NRgPzjbgojp11F6Ugy4qbp/CqMVLBFi78Jq3FSzlLy4IJ SRcPGMTxk1grarb/y+ojrQlPn5VU7U2bgRGOTWKW0pav0+5ehRc4To9wMzTQgv83 tEYwSYCkMBk0Kzr76rxHj39fGnghtsVzd4abXn9Pe5bShebWE1OBriHafDs4fWKV MUgxyp0fpBCC1dHYgUDrQyVHWaQt4nDgFw2xlTuZcWEexBRZZEMBl9ugROtKsbqx 3QXvjn9fw1Vmnf1WPYp80FLwxTGXHi4RHFpIOKzzB5eqf/ggp9YwuuaBMoPhFM2s mh4+A9eo4LEaZcDFxEbxAp1WDLrA1ZyKzerySaJXJaCgd9l2i74PJ4pzQq0ZqVsZ yRZlbnbn7KrgWqMpqRwiPrxePkwZcTmkPz6i1+BrJlZ8KTCZt4I= =eLBm -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgilbert-gitlab/tags/pull-migration-20210609a' into staging Migration pull for 2021-06-09 Yank crash fix from Leo RDMA fix from Li mptcp support from me dirty-rate changes from Hyman and Peter (Note I've switched to the gitlab I've been using for virtiofs pulls) Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> # gpg: Signature made Wed 09 Jun 2021 15:40:01 BST # gpg: using RSA key 45F5C71B4A0CB7FB977A9FA90516331EBC5BFDE7 # gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>" [full] # Primary key fingerprint: 45F5 C71B 4A0C B7FB 977A 9FA9 0516 331E BC5B FDE7 * remotes/dgilbert-gitlab/tags/pull-migration-20210609a: hmp: Add "calc_dirty_rate" and "info dirty_rate" cmds migration/dirtyrate: make sample page count configurable sockets: Support multipath TCP migration/socket: Close the listener at the end migration: Add cleanup hook for inwards migration io/net-listener: Call the notifier during finalize channel-socket: Only set CLOEXEC if we have space for fds migration/rdma: Fix cm event use after free yank: Unregister function when using TLS migration Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7fe7fae8b4
@ -867,3 +867,16 @@ SRST
|
||||
``info replay``
|
||||
Display the record/replay information: mode and the current icount.
|
||||
ERST
|
||||
|
||||
{
|
||||
.name = "dirty_rate",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show dirty rate information",
|
||||
.cmd = hmp_info_dirty_rate,
|
||||
},
|
||||
|
||||
SRST
|
||||
``info dirty_rate``
|
||||
Display the vcpu dirty rate information.
|
||||
ERST
|
||||
|
@ -1727,3 +1727,17 @@ ERST
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
``calc_dirty_rate`` *second*
|
||||
Start a round of dirty rate measurement with the period specified in *second*.
|
||||
The result of the dirty rate measurement may be observed with ``info
|
||||
dirty_rate`` command.
|
||||
ERST
|
||||
|
||||
{
|
||||
.name = "calc_dirty_rate",
|
||||
.args_type = "second:l,sample_pages_per_GB:l?",
|
||||
.params = "second [sample_pages_per_GB]",
|
||||
.help = "start a round of guest dirty rate measurement",
|
||||
.cmd = hmp_calc_dirty_rate,
|
||||
},
|
||||
|
@ -129,5 +129,7 @@ void hmp_info_replay(Monitor *mon, const QDict *qdict);
|
||||
void hmp_replay_break(Monitor *mon, const QDict *qdict);
|
||||
void hmp_replay_delete_break(Monitor *mon, const QDict *qdict);
|
||||
void hmp_replay_seek(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict);
|
||||
void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif
|
||||
|
@ -487,15 +487,15 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
|
||||
|
||||
memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS));
|
||||
|
||||
#ifdef MSG_CMSG_CLOEXEC
|
||||
sflags |= MSG_CMSG_CLOEXEC;
|
||||
#endif
|
||||
|
||||
msg.msg_iov = (struct iovec *)iov;
|
||||
msg.msg_iovlen = niov;
|
||||
if (fds && nfds) {
|
||||
msg.msg_control = control;
|
||||
msg.msg_controllen = sizeof(control);
|
||||
#ifdef MSG_CMSG_CLOEXEC
|
||||
sflags |= MSG_CMSG_CLOEXEC;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
retry:
|
||||
|
@ -122,6 +122,10 @@ static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
|
||||
.ipv4 = iaddr->ipv4,
|
||||
.has_ipv6 = iaddr->has_ipv6,
|
||||
.ipv6 = iaddr->ipv6,
|
||||
#ifdef IPPROTO_MPTCP
|
||||
.has_mptcp = iaddr->has_mptcp,
|
||||
.mptcp = iaddr->mptcp,
|
||||
#endif
|
||||
};
|
||||
|
||||
(*addrs)[i] = newaddr;
|
||||
|
@ -292,6 +292,9 @@ static void qio_net_listener_finalize(Object *obj)
|
||||
QIONetListener *listener = QIO_NET_LISTENER(obj);
|
||||
size_t i;
|
||||
|
||||
if (listener->io_notify) {
|
||||
listener->io_notify(listener->io_data);
|
||||
}
|
||||
qio_net_listener_disconnect(listener);
|
||||
|
||||
for (i = 0; i < listener->nsioc; i++) {
|
||||
|
@ -38,18 +38,19 @@ void migration_channel_process_incoming(QIOChannel *ioc)
|
||||
trace_migration_set_incoming_channel(
|
||||
ioc, object_get_typename(OBJECT(ioc)));
|
||||
|
||||
if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET)) {
|
||||
yank_register_function(MIGRATION_YANK_INSTANCE,
|
||||
migration_yank_iochannel,
|
||||
QIO_CHANNEL(ioc));
|
||||
}
|
||||
|
||||
if (s->parameters.tls_creds &&
|
||||
*s->parameters.tls_creds &&
|
||||
!object_dynamic_cast(OBJECT(ioc),
|
||||
TYPE_QIO_CHANNEL_TLS)) {
|
||||
migration_tls_channel_process_incoming(s, ioc, &local_err);
|
||||
} else {
|
||||
if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) ||
|
||||
object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) {
|
||||
yank_register_function(MIGRATION_YANK_INSTANCE,
|
||||
migration_yank_iochannel,
|
||||
QIO_CHANNEL(ioc));
|
||||
}
|
||||
|
||||
migration_ioc_process_incoming(ioc, &local_err);
|
||||
}
|
||||
|
||||
@ -76,12 +77,6 @@ void migration_channel_connect(MigrationState *s,
|
||||
ioc, object_get_typename(OBJECT(ioc)), hostname, error);
|
||||
|
||||
if (!error) {
|
||||
if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET)) {
|
||||
yank_register_function(MIGRATION_YANK_INSTANCE,
|
||||
migration_yank_iochannel,
|
||||
QIO_CHANNEL(ioc));
|
||||
}
|
||||
|
||||
if (s->parameters.tls_creds &&
|
||||
*s->parameters.tls_creds &&
|
||||
!object_dynamic_cast(OBJECT(ioc),
|
||||
@ -99,6 +94,13 @@ void migration_channel_connect(MigrationState *s,
|
||||
} else {
|
||||
QEMUFile *f = qemu_fopen_channel_output(ioc);
|
||||
|
||||
if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) ||
|
||||
object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) {
|
||||
yank_register_function(MIGRATION_YANK_INSTANCE,
|
||||
migration_yank_iochannel,
|
||||
QIO_CHANNEL(ioc));
|
||||
}
|
||||
|
||||
qemu_mutex_lock(&s->qemu_file_lock);
|
||||
s->to_dst_file = f;
|
||||
qemu_mutex_unlock(&s->qemu_file_lock);
|
||||
|
@ -20,6 +20,9 @@
|
||||
#include "ram.h"
|
||||
#include "trace.h"
|
||||
#include "dirtyrate.h"
|
||||
#include "monitor/hmp.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
|
||||
static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED;
|
||||
static struct DirtyRateStat DirtyStat;
|
||||
@ -48,6 +51,12 @@ static bool is_sample_period_valid(int64_t sec)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_sample_pages_valid(int64_t pages)
|
||||
{
|
||||
return pages >= MIN_SAMPLE_PAGE_COUNT &&
|
||||
pages <= MAX_SAMPLE_PAGE_COUNT;
|
||||
}
|
||||
|
||||
static int dirtyrate_set_state(int *state, int old_state, int new_state)
|
||||
{
|
||||
assert(new_state < DIRTY_RATE_STATUS__MAX);
|
||||
@ -72,13 +81,15 @@ static struct DirtyRateInfo *query_dirty_rate_info(void)
|
||||
info->status = CalculatingState;
|
||||
info->start_time = DirtyStat.start_time;
|
||||
info->calc_time = DirtyStat.calc_time;
|
||||
info->sample_pages = DirtyStat.sample_pages;
|
||||
|
||||
trace_query_dirty_rate_info(DirtyRateStatus_str(CalculatingState));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void init_dirtyrate_stat(int64_t start_time, int64_t calc_time)
|
||||
static void init_dirtyrate_stat(int64_t start_time, int64_t calc_time,
|
||||
uint64_t sample_pages)
|
||||
{
|
||||
DirtyStat.total_dirty_samples = 0;
|
||||
DirtyStat.total_sample_count = 0;
|
||||
@ -86,6 +97,7 @@ static void init_dirtyrate_stat(int64_t start_time, int64_t calc_time)
|
||||
DirtyStat.dirty_rate = -1;
|
||||
DirtyStat.start_time = start_time;
|
||||
DirtyStat.calc_time = calc_time;
|
||||
DirtyStat.sample_pages = sample_pages;
|
||||
}
|
||||
|
||||
static void update_dirtyrate_stat(struct RamblockDirtyInfo *info)
|
||||
@ -361,6 +373,7 @@ void *get_dirtyrate_thread(void *arg)
|
||||
int ret;
|
||||
int64_t start_time;
|
||||
int64_t calc_time;
|
||||
uint64_t sample_pages;
|
||||
|
||||
ret = dirtyrate_set_state(&CalculatingState, DIRTY_RATE_STATUS_UNSTARTED,
|
||||
DIRTY_RATE_STATUS_MEASURING);
|
||||
@ -371,7 +384,8 @@ void *get_dirtyrate_thread(void *arg)
|
||||
|
||||
start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000;
|
||||
calc_time = config.sample_period_seconds;
|
||||
init_dirtyrate_stat(start_time, calc_time);
|
||||
sample_pages = config.sample_pages_per_gigabytes;
|
||||
init_dirtyrate_stat(start_time, calc_time, sample_pages);
|
||||
|
||||
calculate_dirtyrate(config);
|
||||
|
||||
@ -383,7 +397,8 @@ void *get_dirtyrate_thread(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qmp_calc_dirty_rate(int64_t calc_time, Error **errp)
|
||||
void qmp_calc_dirty_rate(int64_t calc_time, bool has_sample_pages,
|
||||
int64_t sample_pages, Error **errp)
|
||||
{
|
||||
static struct DirtyRateConfig config;
|
||||
QemuThread thread;
|
||||
@ -404,6 +419,17 @@ void qmp_calc_dirty_rate(int64_t calc_time, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_sample_pages) {
|
||||
if (!is_sample_pages_valid(sample_pages)) {
|
||||
error_setg(errp, "sample-pages is out of range[%d, %d].",
|
||||
MIN_SAMPLE_PAGE_COUNT,
|
||||
MAX_SAMPLE_PAGE_COUNT);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
sample_pages = DIRTYRATE_DEFAULT_SAMPLE_PAGES;
|
||||
}
|
||||
|
||||
/*
|
||||
* Init calculation state as unstarted.
|
||||
*/
|
||||
@ -415,7 +441,7 @@ void qmp_calc_dirty_rate(int64_t calc_time, Error **errp)
|
||||
}
|
||||
|
||||
config.sample_period_seconds = calc_time;
|
||||
config.sample_pages_per_gigabytes = DIRTYRATE_DEFAULT_SAMPLE_PAGES;
|
||||
config.sample_pages_per_gigabytes = sample_pages;
|
||||
qemu_thread_create(&thread, "get_dirtyrate", get_dirtyrate_thread,
|
||||
(void *)&config, QEMU_THREAD_DETACHED);
|
||||
}
|
||||
@ -424,3 +450,47 @@ struct DirtyRateInfo *qmp_query_dirty_rate(Error **errp)
|
||||
{
|
||||
return query_dirty_rate_info();
|
||||
}
|
||||
|
||||
void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
DirtyRateInfo *info = query_dirty_rate_info();
|
||||
|
||||
monitor_printf(mon, "Status: %s\n",
|
||||
DirtyRateStatus_str(info->status));
|
||||
monitor_printf(mon, "Start Time: %"PRIi64" (ms)\n",
|
||||
info->start_time);
|
||||
monitor_printf(mon, "Sample Pages: %"PRIu64" (per GB)\n",
|
||||
info->sample_pages);
|
||||
monitor_printf(mon, "Period: %"PRIi64" (sec)\n",
|
||||
info->calc_time);
|
||||
monitor_printf(mon, "Dirty rate: ");
|
||||
if (info->has_dirty_rate) {
|
||||
monitor_printf(mon, "%"PRIi64" (MB/s)\n", info->dirty_rate);
|
||||
} else {
|
||||
monitor_printf(mon, "(not ready)\n");
|
||||
}
|
||||
g_free(info);
|
||||
}
|
||||
|
||||
void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
int64_t sec = qdict_get_try_int(qdict, "second", 0);
|
||||
int64_t sample_pages = qdict_get_try_int(qdict, "sample_pages_per_GB", -1);
|
||||
bool has_sample_pages = (sample_pages != -1);
|
||||
Error *err = NULL;
|
||||
|
||||
if (!sec) {
|
||||
monitor_printf(mon, "Incorrect period length specified!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages, &err);
|
||||
if (err) {
|
||||
hmp_handle_error(mon, err);
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "Starting dirty rate measurement with period %"PRIi64
|
||||
" seconds\n", sec);
|
||||
monitor_printf(mon, "[Please use 'info dirty_rate' to check results]\n");
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
/*
|
||||
* Sample 512 pages per GB as default.
|
||||
* TODO: Make it configurable.
|
||||
*/
|
||||
#define DIRTYRATE_DEFAULT_SAMPLE_PAGES 512
|
||||
|
||||
@ -35,6 +34,12 @@
|
||||
#define MIN_FETCH_DIRTYRATE_TIME_SEC 1
|
||||
#define MAX_FETCH_DIRTYRATE_TIME_SEC 60
|
||||
|
||||
/*
|
||||
* Take 1/16 pages in 1G as the maxmum sample page count
|
||||
*/
|
||||
#define MIN_SAMPLE_PAGE_COUNT 128
|
||||
#define MAX_SAMPLE_PAGE_COUNT 16384
|
||||
|
||||
struct DirtyRateConfig {
|
||||
uint64_t sample_pages_per_gigabytes; /* sample pages per GB */
|
||||
int64_t sample_period_seconds; /* time duration between two sampling */
|
||||
@ -63,6 +68,7 @@ struct DirtyRateStat {
|
||||
int64_t dirty_rate; /* dirty rate in MB/s */
|
||||
int64_t start_time; /* calculation start time in units of second */
|
||||
int64_t calc_time; /* time duration of two sampling in units of second */
|
||||
uint64_t sample_pages; /* sample pages per GB */
|
||||
};
|
||||
|
||||
void *get_dirtyrate_thread(void *arg);
|
||||
|
@ -280,6 +280,9 @@ void migration_incoming_state_destroy(void)
|
||||
g_array_free(mis->postcopy_remote_fds, TRUE);
|
||||
mis->postcopy_remote_fds = NULL;
|
||||
}
|
||||
if (mis->transport_cleanup) {
|
||||
mis->transport_cleanup(mis->transport_data);
|
||||
}
|
||||
|
||||
qemu_event_reset(&mis->main_thread_load_event);
|
||||
|
||||
|
@ -49,6 +49,10 @@ struct PostcopyBlocktimeContext;
|
||||
struct MigrationIncomingState {
|
||||
QEMUFile *from_src_file;
|
||||
|
||||
/* A hook to allow cleanup at the end of incoming migration */
|
||||
void *transport_data;
|
||||
void (*transport_cleanup)(void *data);
|
||||
|
||||
/*
|
||||
* Free at the start of the main state load, set as the main thread finishes
|
||||
* loading state.
|
||||
|
@ -987,7 +987,8 @@ int multifd_load_cleanup(Error **errp)
|
||||
for (i = 0; i < migrate_multifd_channels(); i++) {
|
||||
MultiFDRecvParams *p = &multifd_recv_state->params[i];
|
||||
|
||||
if (object_dynamic_cast(OBJECT(p->c), TYPE_QIO_CHANNEL_SOCKET)
|
||||
if ((object_dynamic_cast(OBJECT(p->c), TYPE_QIO_CHANNEL_SOCKET) ||
|
||||
object_dynamic_cast(OBJECT(p->c), TYPE_QIO_CHANNEL_TLS))
|
||||
&& OBJECT(p->c)->ref == 1) {
|
||||
yank_unregister_function(MIGRATION_YANK_INSTANCE,
|
||||
migration_yank_iochannel,
|
||||
@ -1165,6 +1166,11 @@ bool multifd_recv_all_channels_created(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!multifd_recv_state) {
|
||||
/* Called before any connections created */
|
||||
return false;
|
||||
}
|
||||
|
||||
return thread_count == qatomic_read(&multifd_recv_state->count);
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "qemu-file-channel.h"
|
||||
#include "qemu-file.h"
|
||||
#include "io/channel-socket.h"
|
||||
#include "io/channel-tls.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/yank.h"
|
||||
#include "yank_functions.h"
|
||||
@ -106,7 +107,8 @@ static int channel_close(void *opaque, Error **errp)
|
||||
int ret;
|
||||
QIOChannel *ioc = QIO_CHANNEL(opaque);
|
||||
ret = qio_channel_close(ioc, errp);
|
||||
if (object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET)
|
||||
if ((object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_SOCKET) ||
|
||||
object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS))
|
||||
&& OBJECT(ioc)->ref == 1) {
|
||||
yank_unregister_function(MIGRATION_YANK_INSTANCE,
|
||||
migration_yank_iochannel,
|
||||
|
@ -1539,16 +1539,20 @@ static int qemu_rdma_wait_comp_channel(RDMAContext *rdma)
|
||||
|
||||
if (pfds[1].revents) {
|
||||
ret = rdma_get_cm_event(rdma->channel, &cm_event);
|
||||
if (!ret) {
|
||||
rdma_ack_cm_event(cm_event);
|
||||
if (ret) {
|
||||
error_report("failed to get cm event while wait "
|
||||
"completion channel");
|
||||
return -EPIPE;
|
||||
}
|
||||
|
||||
error_report("receive cm event while wait comp channel,"
|
||||
"cm event is %d", cm_event->event);
|
||||
if (cm_event->event == RDMA_CM_EVENT_DISCONNECTED ||
|
||||
cm_event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) {
|
||||
rdma_ack_cm_event(cm_event);
|
||||
return -EPIPE;
|
||||
}
|
||||
rdma_ack_cm_event(cm_event);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -3285,7 +3289,6 @@ static void rdma_cm_poll_handler(void *opaque)
|
||||
error_report("get_cm_event failed %d", errno);
|
||||
return;
|
||||
}
|
||||
rdma_ack_cm_event(cm_event);
|
||||
|
||||
if (cm_event->event == RDMA_CM_EVENT_DISCONNECTED ||
|
||||
cm_event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) {
|
||||
@ -3298,12 +3301,14 @@ static void rdma_cm_poll_handler(void *opaque)
|
||||
rdma->return_path->error_state = -EPIPE;
|
||||
}
|
||||
}
|
||||
rdma_ack_cm_event(cm_event);
|
||||
|
||||
if (mis->migration_incoming_co) {
|
||||
qemu_coroutine_enter(mis->migration_incoming_co);
|
||||
}
|
||||
return;
|
||||
}
|
||||
rdma_ack_cm_event(cm_event);
|
||||
}
|
||||
|
||||
static int qemu_rdma_accept(RDMAContext *rdma)
|
||||
|
@ -126,22 +126,31 @@ static void socket_accept_incoming_migration(QIONetListener *listener,
|
||||
{
|
||||
trace_migration_socket_incoming_accepted();
|
||||
|
||||
if (migration_has_all_channels()) {
|
||||
error_report("%s: Extra incoming migration connection; ignoring",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
qio_channel_set_name(QIO_CHANNEL(cioc), "migration-socket-incoming");
|
||||
migration_channel_process_incoming(QIO_CHANNEL(cioc));
|
||||
|
||||
if (migration_has_all_channels()) {
|
||||
/* Close listening socket as its no longer needed */
|
||||
qio_net_listener_disconnect(listener);
|
||||
object_unref(OBJECT(listener));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
socket_incoming_migration_end(void *opaque)
|
||||
{
|
||||
QIONetListener *listener = opaque;
|
||||
|
||||
qio_net_listener_disconnect(listener);
|
||||
object_unref(OBJECT(listener));
|
||||
}
|
||||
|
||||
static void
|
||||
socket_start_incoming_migration_internal(SocketAddress *saddr,
|
||||
Error **errp)
|
||||
{
|
||||
QIONetListener *listener = qio_net_listener_new();
|
||||
MigrationIncomingState *mis = migration_incoming_get_current();
|
||||
size_t i;
|
||||
int num = 1;
|
||||
|
||||
@ -156,6 +165,9 @@ socket_start_incoming_migration_internal(SocketAddress *saddr,
|
||||
return;
|
||||
}
|
||||
|
||||
mis->transport_data = listener;
|
||||
mis->transport_cleanup = socket_incoming_migration_end;
|
||||
|
||||
qio_net_listener_set_client_func_full(listener,
|
||||
socket_accept_incoming_migration,
|
||||
NULL, NULL,
|
||||
|
@ -1740,6 +1740,9 @@
|
||||
#
|
||||
# @calc-time: time in units of second for sample dirty pages
|
||||
#
|
||||
# @sample-pages: page count per GB for sample dirty pages
|
||||
# the default value is 512 (since 6.1)
|
||||
#
|
||||
# Since: 5.2
|
||||
#
|
||||
##
|
||||
@ -1747,7 +1750,8 @@
|
||||
'data': {'*dirty-rate': 'int64',
|
||||
'status': 'DirtyRateStatus',
|
||||
'start-time': 'int64',
|
||||
'calc-time': 'int64'} }
|
||||
'calc-time': 'int64',
|
||||
'sample-pages': 'uint64'} }
|
||||
|
||||
##
|
||||
# @calc-dirty-rate:
|
||||
@ -1756,13 +1760,18 @@
|
||||
#
|
||||
# @calc-time: time in units of second for sample dirty pages
|
||||
#
|
||||
# @sample-pages: page count per GB for sample dirty pages
|
||||
# the default value is 512 (since 6.1)
|
||||
#
|
||||
# Since: 5.2
|
||||
#
|
||||
# Example:
|
||||
# {"command": "calc-dirty-rate", "data": {"calc-time": 1} }
|
||||
# {"command": "calc-dirty-rate", "data": {"calc-time": 1,
|
||||
# 'sample-pages': 512} }
|
||||
#
|
||||
##
|
||||
{ 'command': 'calc-dirty-rate', 'data': {'calc-time': 'int64'} }
|
||||
{ 'command': 'calc-dirty-rate', 'data': {'calc-time': 'int64',
|
||||
'*sample-pages': 'int'} }
|
||||
|
||||
##
|
||||
# @query-dirty-rate:
|
||||
|
@ -57,6 +57,8 @@
|
||||
# @keep-alive: enable keep-alive when connecting to this socket. Not supported
|
||||
# for passive sockets. (Since 4.2)
|
||||
#
|
||||
# @mptcp: enable multi-path TCP. (Since 6.1)
|
||||
#
|
||||
# Since: 1.3
|
||||
##
|
||||
{ 'struct': 'InetSocketAddress',
|
||||
@ -66,7 +68,8 @@
|
||||
'*to': 'uint16',
|
||||
'*ipv4': 'bool',
|
||||
'*ipv6': 'bool',
|
||||
'*keep-alive': 'bool' } }
|
||||
'*keep-alive': 'bool',
|
||||
'*mptcp': { 'type': 'bool', 'if': 'defined(IPPROTO_MPTCP)' } } }
|
||||
|
||||
##
|
||||
# @UnixSocketAddress:
|
||||
|
@ -278,6 +278,11 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
|
||||
|
||||
/* create socket + bind/listen */
|
||||
for (e = res; e != NULL; e = e->ai_next) {
|
||||
#ifdef IPPROTO_MPTCP
|
||||
if (saddr->has_mptcp && saddr->mptcp) {
|
||||
e->ai_protocol = IPPROTO_MPTCP;
|
||||
}
|
||||
#endif
|
||||
getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
|
||||
uaddr,INET6_ADDRSTRLEN,uport,32,
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
@ -456,6 +461,13 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp)
|
||||
for (e = res; e != NULL; e = e->ai_next) {
|
||||
error_free(local_err);
|
||||
local_err = NULL;
|
||||
|
||||
#ifdef IPPROTO_MPTCP
|
||||
if (saddr->has_mptcp && saddr->mptcp) {
|
||||
e->ai_protocol = IPPROTO_MPTCP;
|
||||
}
|
||||
#endif
|
||||
|
||||
sock = inet_connect_addr(saddr, e, &local_err);
|
||||
if (sock >= 0) {
|
||||
break;
|
||||
@ -687,6 +699,17 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
|
||||
}
|
||||
addr->has_keep_alive = true;
|
||||
}
|
||||
#ifdef IPPROTO_MPTCP
|
||||
begin = strstr(optstr, ",mptcp");
|
||||
if (begin) {
|
||||
if (inet_parse_flag("mptcp", begin + strlen(",mptcp"),
|
||||
&addr->mptcp, errp) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
addr->has_mptcp = true;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user