Merge tag 'pull-migration-20220421a' of https://gitlab.com/dagrh/qemu into staging

V2: Migration pull 2022-04-21

  Dan: Test fixes and improvements (TLS mostly)
  Peter: Postcopy improvements
  Me: Race fix for info migrate, and compilation fix

V2:
  Fixed checkpatch nit of unneeded NULL check

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEERfXHG0oMt/uXep+pBRYzHrxb/ecFAmJhpLIACgkQBRYzHrxb
# /edCPQ//dITFWStcsvon8gBBRWY/ekz/EdmWd2KFUp1r/yzopXExW5Gy+MzzTEwk
# axf7s991eyjta1gU0IYCzWcuR36LE8YsZRgDlOhttZ/674ZnX5ZIJBggwDKE/bYE
# IEHd8qsHy6oV8UIFvBQ6wvIDJmH+8gOwnPUzOO9Ek2UkSgBGsptZ8d6Hi0hTzYFB
# omhgc2eO3XQUlxM+8MwlrZU84QkxnBn2g7nVgDQyRokAou46Yf8FD/bWv3CKAdO+
# Ph+4XjBiddBFYUtf4XWSTvVfi23kij1k/4bjH3zaocE86gQ6CUteImFtowwr6N95
# sJl1EXBOtz0BP5xONqkywpWi1Qqg+mecF4KrS4XAHszaUkaj3sTFOyItwlTzZErF
# /2dZRsPRs9fTcjjzpOe/CKoGr+CcyZdxY1qbCNfHaJagdxytN2qxOaneTUbKYUE5
# n4Om9zxDS2esZCnkx26e2wylJ1wzKZBbjsoKYQA4IGaQ6Qz8Zciea0tApwhgyVjs
# KHcYtvScPLxmEEKgzDap6B7fJxyaOg3KNX+0XzLLpLS1oaeqwvSIQM/QMMrnwGxs
# uA1LI2uqlQBitaJOhgLMnNH4ze27HC3DM4OWAE+iOhpD+LNAWstjWraNNXbG4sSj
# 55ndJHJxOCjPlFY4dB/ytUbUo7XBkztCR4c1+I+lSUbMTq3KuUg=
# =M5sx
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 21 Apr 2022 11:38:42 AM PDT
# gpg:                using RSA key 45F5C71B4A0CB7FB977A9FA90516331EBC5BFDE7
# gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>" [full]

* tag 'pull-migration-20220421a' of https://gitlab.com/dagrh/qemu:
  migration: Read state once
  migration: Fix operator type
  migration: Allow migrate-recover to run multiple times
  migration: Move channel setup out of postcopy_try_recover()
  migration: Export ram_load_postcopy()
  migration: Move migrate_allow_multifd and helpers into migration.c
  migration: Add pss.postcopy_requested status
  migration: Drop multifd tls_hostname cache
  migration: Postpone releasing MigrationState.hostname
  tests: expand the migration precopy helper to support failures
  tests: switch migration FD passing test to use common precopy helper
  tests: introduce ability to provide hooks for migration precopy test
  tests: merge code for UNIX and TCP migration pre-copy tests
  tests: switch MigrateStart struct to be stack allocated
  migration: fix use of TLS PSK credentials with a UNIX socket
  tests: print newline after QMP response in qtest logs
  tests: support QTEST_TRACE env variable
  tests: improve error message when saving TLS PSK file fails

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson
2022-04-21 18:48:18 -07:00
12 changed files with 268 additions and 239 deletions
-1
View File
@@ -96,6 +96,5 @@ void migration_channel_connect(MigrationState *s,
}
}
migrate_fd_connect(s, error);
g_free(s->hostname);
error_free(error);
}
+36 -30
View File
@@ -180,6 +180,18 @@ static int migration_maybe_pause(MigrationState *s,
int new_state);
static void migrate_fd_cancel(MigrationState *s);
static bool migrate_allow_multi_channels = true;
void migrate_protocol_allow_multi_channels(bool allow)
{
migrate_allow_multi_channels = allow;
}
bool migrate_multi_channels_is_allowed(void)
{
return migrate_allow_multi_channels;
}
static gint page_request_addr_cmp(gconstpointer ap, gconstpointer bp)
{
uintptr_t a = (uintptr_t) ap, b = (uintptr_t) bp;
@@ -469,12 +481,12 @@ static void qemu_start_incoming_migration(const char *uri, Error **errp)
{
const char *p = NULL;
migrate_protocol_allow_multifd(false); /* reset it anyway */
migrate_protocol_allow_multi_channels(false); /* reset it anyway */
qapi_event_send_migration(MIGRATION_STATUS_SETUP);
if (strstart(uri, "tcp:", &p) ||
strstart(uri, "unix:", NULL) ||
strstart(uri, "vsock:", NULL)) {
migrate_protocol_allow_multifd(true);
migrate_protocol_allow_multi_channels(true);
socket_start_incoming_migration(p ? p : uri, errp);
#ifdef CONFIG_RDMA
} else if (strstart(uri, "rdma:", &p)) {
@@ -659,19 +671,20 @@ void migration_incoming_process(void)
}
/* Returns true if recovered from a paused migration, otherwise false */
static bool postcopy_try_recover(QEMUFile *f)
static bool postcopy_try_recover(void)
{
MigrationIncomingState *mis = migration_incoming_get_current();
if (mis->state == MIGRATION_STATUS_POSTCOPY_PAUSED) {
/* Resumed from a paused postcopy migration */
mis->from_src_file = f;
/* This should be set already in migration_incoming_setup() */
assert(mis->from_src_file);
/* Postcopy has standalone thread to do vm load */
qemu_file_set_blocking(f, true);
qemu_file_set_blocking(mis->from_src_file, true);
/* Re-configure the return path */
mis->to_src_file = qemu_file_get_return_path(f);
mis->to_src_file = qemu_file_get_return_path(mis->from_src_file);
migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_PAUSED,
MIGRATION_STATUS_POSTCOPY_RECOVER);
@@ -692,11 +705,10 @@ static bool postcopy_try_recover(QEMUFile *f)
void migration_fd_process_incoming(QEMUFile *f, Error **errp)
{
if (postcopy_try_recover(f)) {
if (!migration_incoming_setup(f, errp)) {
return;
}
if (!migration_incoming_setup(f, errp)) {
if (postcopy_try_recover()) {
return;
}
migration_incoming_process();
@@ -712,11 +724,6 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
/* The first connection (multifd may have multiple) */
QEMUFile *f = qemu_fopen_channel_input(ioc);
/* If it's a recovery, we're done */
if (postcopy_try_recover(f)) {
return;
}
if (!migration_incoming_setup(f, errp)) {
return;
}
@@ -737,6 +744,10 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
}
if (start_migration) {
/* If it's a recovery, we're done */
if (postcopy_try_recover()) {
return;
}
migration_incoming_process();
}
}
@@ -1073,6 +1084,7 @@ static void populate_disk_info(MigrationInfo *info)
static void fill_source_migration_info(MigrationInfo *info)
{
MigrationState *s = migrate_get_current();
int state = qatomic_read(&s->state);
GSList *cur_blocker = migration_blockers;
info->blocked_reasons = NULL;
@@ -1092,7 +1104,7 @@ static void fill_source_migration_info(MigrationInfo *info)
}
info->has_blocked_reasons = info->blocked_reasons != NULL;
switch (s->state) {
switch (state) {
case MIGRATION_STATUS_NONE:
/* no migration has happened ever */
/* do not overwrite destination migration status */
@@ -1137,7 +1149,7 @@ static void fill_source_migration_info(MigrationInfo *info)
info->has_status = true;
break;
}
info->status = s->state;
info->status = state;
}
typedef enum WriteTrackingSupport {
@@ -1261,7 +1273,7 @@ static bool migrate_caps_check(bool *cap_list,
/* incoming side only */
if (runstate_check(RUN_STATE_INMIGRATE) &&
!migrate_multifd_is_allowed() &&
!migrate_multi_channels_is_allowed() &&
cap_list[MIGRATION_CAPABILITY_MULTIFD]) {
error_setg(errp, "multifd is not supported by current protocol");
return false;
@@ -1809,6 +1821,9 @@ static void migrate_fd_cleanup(MigrationState *s)
qemu_bh_delete(s->cleanup_bh);
s->cleanup_bh = NULL;
g_free(s->hostname);
s->hostname = NULL;
qemu_savevm_state_cleanup();
if (s->to_dst_file) {
@@ -2148,11 +2163,8 @@ void qmp_migrate_recover(const char *uri, Error **errp)
return;
}
if (qatomic_cmpxchg(&mis->postcopy_recover_triggered,
false, true) == true) {
error_setg(errp, "Migrate recovery is triggered already");
return;
}
/* If there's an existing transport, release it */
migration_incoming_transport_cleanup(mis);
/*
* Note that this call will never start a real migration; it will
@@ -2160,12 +2172,6 @@ void qmp_migrate_recover(const char *uri, Error **errp)
* to continue using that newly established channel.
*/
qemu_start_incoming_migration(uri, errp);
/* Safe to dereference with the assert above */
if (*errp) {
/* Reset the flag so user could still retry */
qatomic_set(&mis->postcopy_recover_triggered, false);
}
}
void qmp_migrate_pause(Error **errp)
@@ -2319,11 +2325,11 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
}
}
migrate_protocol_allow_multifd(false);
migrate_protocol_allow_multi_channels(false);
if (strstart(uri, "tcp:", &p) ||
strstart(uri, "unix:", NULL) ||
strstart(uri, "vsock:", NULL)) {
migrate_protocol_allow_multifd(true);
migrate_protocol_allow_multi_channels(true);
socket_start_outgoing_migration(s, p ? p : uri, &local_err);
#ifdef CONFIG_RDMA
} else if (strstart(uri, "rdma:", &p)) {
+3 -1
View File
@@ -139,7 +139,6 @@ struct MigrationIncomingState {
struct PostcopyBlocktimeContext *blocktime_ctx;
/* notify PAUSED postcopy incoming migrations to try to continue */
bool postcopy_recover_triggered;
QemuSemaphore postcopy_pause_sem_dst;
QemuSemaphore postcopy_pause_sem_fault;
@@ -430,4 +429,7 @@ void migration_cancel(const Error *error);
void populate_vfio_info(MigrationInfo *info);
void postcopy_temp_page_reset(PostcopyTmpPage *tmp_page);
bool migrate_multi_channels_is_allowed(void);
void migrate_protocol_allow_multi_channels(bool allow);
#endif
+7 -22
View File
@@ -517,7 +517,7 @@ void multifd_save_cleanup(void)
{
int i;
if (!migrate_use_multifd() || !migrate_multifd_is_allowed()) {
if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) {
return;
}
multifd_send_terminate_threads(NULL);
@@ -542,8 +542,6 @@ void multifd_save_cleanup(void)
qemu_sem_destroy(&p->sem_sync);
g_free(p->name);
p->name = NULL;
g_free(p->tls_hostname);
p->tls_hostname = NULL;
multifd_pages_clear(p->pages);
p->pages = NULL;
p->packet_len = 0;
@@ -763,7 +761,7 @@ static void multifd_tls_channel_connect(MultiFDSendParams *p,
Error **errp)
{
MigrationState *s = migrate_get_current();
const char *hostname = p->tls_hostname;
const char *hostname = s->hostname;
QIOChannelTLS *tioc;
tioc = migration_tls_client_create(s, ioc, hostname, errp);
@@ -787,7 +785,8 @@ static bool multifd_channel_connect(MultiFDSendParams *p,
MigrationState *s = migrate_get_current();
trace_multifd_set_outgoing_channel(
ioc, object_get_typename(OBJECT(ioc)), p->tls_hostname, error);
ioc, object_get_typename(OBJECT(ioc)),
migrate_get_current()->hostname, error);
if (!error) {
if (s->parameters.tls_creds &&
@@ -858,33 +857,20 @@ cleanup:
multifd_new_send_channel_cleanup(p, sioc, local_err);
}
static bool migrate_allow_multifd = true;
void migrate_protocol_allow_multifd(bool allow)
{
migrate_allow_multifd = allow;
}
bool migrate_multifd_is_allowed(void)
{
return migrate_allow_multifd;
}
int multifd_save_setup(Error **errp)
{
int thread_count;
uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size();
uint8_t i;
MigrationState *s;
if (!migrate_use_multifd()) {
return 0;
}
if (!migrate_multifd_is_allowed()) {
if (!migrate_multi_channels_is_allowed()) {
error_setg(errp, "multifd is not supported by current protocol");
return -1;
}
s = migrate_get_current();
thread_count = migrate_multifd_channels();
multifd_send_state = g_malloc0(sizeof(*multifd_send_state));
multifd_send_state->params = g_new0(MultiFDSendParams, thread_count);
@@ -909,7 +895,6 @@ int multifd_save_setup(Error **errp)
p->packet->magic = cpu_to_be32(MULTIFD_MAGIC);
p->packet->version = cpu_to_be32(MULTIFD_VERSION);
p->name = g_strdup_printf("multifdsend_%d", i);
p->tls_hostname = g_strdup(s->hostname);
/* We need one extra place for the packet header */
p->iov = g_new0(struct iovec, page_count + 1);
p->normal = g_new0(ram_addr_t, page_count);
@@ -980,7 +965,7 @@ int multifd_load_cleanup(Error **errp)
{
int i;
if (!migrate_use_multifd() || !migrate_multifd_is_allowed()) {
if (!migrate_use_multifd() || !migrate_multi_channels_is_allowed()) {
return 0;
}
multifd_recv_terminate_threads(NULL);
@@ -1129,7 +1114,7 @@ int multifd_load_setup(Error **errp)
if (!migrate_use_multifd()) {
return 0;
}
if (!migrate_multifd_is_allowed()) {
if (!migrate_multi_channels_is_allowed()) {
error_setg(errp, "multifd is not supported by current protocol");
return -1;
}
-4
View File
@@ -13,8 +13,6 @@
#ifndef QEMU_MIGRATION_MULTIFD_H
#define QEMU_MIGRATION_MULTIFD_H
bool migrate_multifd_is_allowed(void);
void migrate_protocol_allow_multifd(bool allow);
int multifd_save_setup(Error **errp);
void multifd_save_cleanup(void);
int multifd_load_setup(Error **errp);
@@ -72,8 +70,6 @@ typedef struct {
uint8_t id;
/* channel thread name */
char *name;
/* tls hostname */
char *tls_hostname;
/* channel thread id */
QemuThread thread;
/* communication channel */
+8 -2
View File
@@ -414,6 +414,8 @@ struct PageSearchStatus {
unsigned long page;
/* Set once we wrap around */
bool complete_round;
/* Whether current page is explicitly requested by postcopy */
bool postcopy_requested;
};
typedef struct PageSearchStatus PageSearchStatus;
@@ -1289,7 +1291,7 @@ static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
offset | RAM_SAVE_FLAG_PAGE));
if (async) {
qemu_put_buffer_async(rs->f, buf, TARGET_PAGE_SIZE,
migrate_release_ram() &
migrate_release_ram() &&
migration_in_postcopy());
} else {
qemu_put_buffer(rs->f, buf, TARGET_PAGE_SIZE);
@@ -1487,6 +1489,9 @@ retry:
*/
static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again)
{
/* This is not a postcopy requested page */
pss->postcopy_requested = false;
pss->page = migration_bitmap_find_dirty(rs, pss->block, pss->page);
if (pss->complete_round && pss->block == rs->last_seen_block &&
pss->page >= rs->last_page) {
@@ -1981,6 +1986,7 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss)
* really rare.
*/
pss->complete_round = false;
pss->postcopy_requested = true;
}
return !!block;
@@ -3639,7 +3645,7 @@ int ram_postcopy_incoming_init(MigrationIncomingState *mis)
*
* @f: QEMUFile where to send the data
*/
static int ram_load_postcopy(QEMUFile *f)
int ram_load_postcopy(QEMUFile *f)
{
int flags = 0, ret = 0;
bool place_needed = false;
+1
View File
@@ -61,6 +61,7 @@ void ram_postcopy_send_discard_bitmap(MigrationState *ms);
/* For incoming postcopy discard */
int ram_discard_range(const char *block_name, uint64_t start, size_t length);
int ram_postcopy_incoming_init(MigrationIncomingState *mis);
int ram_load_postcopy(QEMUFile *f);
void ram_handle_compressed(void *host, uint8_t ch, uint64_t size);
-3
View File
@@ -2589,9 +2589,6 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis)
assert(migrate_postcopy_ram());
/* Clear the triggered bit to allow one recovery */
mis->postcopy_recover_triggered = false;
/*
* Unregister yank with either from/to src would work, since ioc behind it
* is the same
-4
View File
@@ -137,10 +137,6 @@ QIOChannelTLS *migration_tls_client_create(MigrationState *s,
if (s->parameters.tls_hostname && *s->parameters.tls_hostname) {
hostname = s->parameters.tls_hostname;
}
if (!hostname) {
error_setg(errp, "No hostname available for TLS");
return NULL;
}
tioc = qio_channel_tls_new_client(
ioc, creds, hostname, errp);
+10 -3
View File
@@ -259,6 +259,9 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
gchar *qmp_socket_path;
gchar *command;
const char *qemu_binary = qtest_qemu_binary();
const char *trace = g_getenv("QTEST_TRACE");
g_autofree char *tracearg = trace ?
g_strdup_printf("-trace %s ", trace) : g_strdup("");
s = g_new(QTestState, 1);
@@ -281,14 +284,15 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
qtest_add_abrt_handler(kill_qemu_hook_func, s);
command = g_strdup_printf("exec %s "
command = g_strdup_printf("exec %s %s"
"-qtest unix:%s "
"-qtest-log %s "
"-chardev socket,path=%s,id=char0 "
"-mon chardev=char0,mode=control "
"-display none "
"%s"
" -accel qtest", qemu_binary, socket_path,
" -accel qtest",
qemu_binary, tracearg, socket_path,
getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null",
qmp_socket_path,
extra_args ?: "");
@@ -608,10 +612,13 @@ QDict *qmp_fd_receive(int fd)
}
if (log) {
len = write(2, &c, 1);
g_assert(write(2, &c, 1) == 1);
}
json_message_parser_feed(&qmp.parser, &c, 1);
}
if (log) {
g_assert(write(2, "\n", 1) == 1);
}
json_message_parser_destroy(&qmp.parser);
return qmp.response;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -30,7 +30,7 @@ void test_tls_psk_init(const char *pskfile)
fp = fopen(pskfile, "w");
if (fp == NULL) {
g_critical("Failed to create pskfile %s", pskfile);
g_critical("Failed to create pskfile %s: %s", pskfile, strerror(errno));
abort();
}
/* Don't do this in real applications! Use psktool. */