Skip to content

Commit

Permalink
Merge tag 'migration-staging-pull-request' of https://gitlab.com/pete…
Browse files Browse the repository at this point in the history
…rx/qemu into staging

Migration pull

- William's fix on hwpoison migration which used to crash QEMU
- Peter's multifd cleanup + bugfix + optimizations
- Avihai's fix on multifd crash over non-socket channels
- Fabiano's multifd thread-race fix
- Peter's CI fix series

# -----BEGIN PGP SIGNATURE-----
#
# iIgEABYKADAWIQS5GE3CDMRX2s990ak7X8zN86vXBgUCZcREtRIccGV0ZXJ4QHJl
# ZGhhdC5jb20ACgkQO1/MzfOr1wacrwEAl2aeQkh51h/e+OKX7MG4/4Y6Edf6Oz7o
# IJLk/cyrUFQA/2exo2lOdv5zHNOJKwAYj8HYDraezrC/MK1eED4Wji0M
# =k53l
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 08 Feb 2024 03:04:21 GMT
# gpg:                using EDDSA key B9184DC20CC457DACF7DD1A93B5FCCCDF3ABD706
# gpg:                issuer "peterx@redhat.com"
# gpg: Good signature from "Peter Xu <xzpeter@gmail.com>" [marginal]
# gpg:                 aka "Peter Xu <peterx@redhat.com>" [marginal]
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: B918 4DC2 0CC4 57DA CF7D  D1A9 3B5F CCCD F3AB D706

* tag 'migration-staging-pull-request' of https://gitlab.com/peterx/qemu: (34 commits)
  ci: Update comment for migration-compat-aarch64
  ci: Remove tag dependency for build-previous-qemu
  tests/migration-test: Stick with gicv3 in aarch64 test
  migration/multifd: Add a synchronization point for channel creation
  migration/multifd: Unify multifd and TLS connection paths
  migration/multifd: Move multifd_send_setup into migration thread
  migration/multifd: Move multifd_send_setup error handling in to the function
  migration/multifd: Remove p->running
  migration/multifd: Join the TLS thread
  migration: Fix logic of channels and transport compatibility check
  migration/multifd: Optimize sender side to be lockless
  migration/multifd: Fix MultiFDSendParams.packet_num race
  migration/multifd: Stick with send/recv on function names
  migration/multifd: Cleanup multifd_load_cleanup()
  migration/multifd: Cleanup multifd_save_cleanup()
  migration/multifd: Rewrite multifd_queue_page()
  migration/multifd: Change retval of multifd_send_pages()
  migration/multifd: Change retval of multifd_queue_page()
  migration/multifd: Split multifd_send_terminate_threads()
  migration/multifd: Forbid spurious wakeups
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Feb 9, 2024
2 parents e2beaf7 + 940bf8f commit 5d1fc61
Show file tree
Hide file tree
Showing 12 changed files with 547 additions and 396 deletions.
9 changes: 6 additions & 3 deletions .gitlab-ci.d/buildtest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ build-previous-qemu:
TARGETS: x86_64-softmmu aarch64-softmmu
before_script:
- export QEMU_PREV_VERSION="$(sed 's/\([0-9.]*\)\.[0-9]*/v\1.0/' VERSION)"
- git remote add upstream https://gitlab.com/qemu-project/qemu
- git fetch upstream $QEMU_PREV_VERSION
- git checkout $QEMU_PREV_VERSION
after_script:
- mv build build-previous
Expand Down Expand Up @@ -217,9 +219,10 @@ build-previous-qemu:
- QTEST_QEMU_BINARY_DST=./qemu-system-${TARGET}
QTEST_QEMU_BINARY=../build/qemu-system-${TARGET} ./tests/qtest/migration-test

# This job is disabled until we release 9.0. The existing
# migration-test in 8.2 is broken on aarch64. The fix was already
# commited, but it will only take effect once 9.0 is out.
# This job needs to be disabled until we can have an aarch64 CPU model that
# will both (1) support both KVM and TCG, and (2) provide a stable ABI.
# Currently only "-cpu max" can provide (1), however it doesn't guarantee
# (2). Mark this test skipped until later.
migration-compat-aarch64:
extends: .migration-compat-common
variables:
Expand Down
10 changes: 10 additions & 0 deletions accel/kvm/kvm-all.c
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,11 @@ int kvm_vm_check_extension(KVMState *s, unsigned int extension)
return ret;
}

/*
* We track the poisoned pages to be able to:
* - replace them on VM reset
* - block a migration for a VM with a poisoned page
*/
typedef struct HWPoisonPage {
ram_addr_t ram_addr;
QLIST_ENTRY(HWPoisonPage) list;
Expand Down Expand Up @@ -1152,6 +1157,11 @@ void kvm_hwpoison_page_add(ram_addr_t ram_addr)
QLIST_INSERT_HEAD(&hwpoison_page_list, page, list);
}

bool kvm_hwpoisoned_mem(void)
{
return !QLIST_EMPTY(&hwpoison_page_list);
}

static uint32_t adjust_ioeventfd_endianness(uint32_t val, uint32_t size)
{
#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
Expand Down
5 changes: 5 additions & 0 deletions accel/stubs/kvm-stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,8 @@ uint32_t kvm_dirty_ring_size(void)
{
return 0;
}

bool kvm_hwpoisoned_mem(void)
{
return false;
}
6 changes: 6 additions & 0 deletions include/sysemu/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,4 +538,10 @@ bool kvm_arch_cpu_check_are_resettable(void);
bool kvm_dirty_ring_enabled(void);

uint32_t kvm_dirty_ring_size(void);

/**
* kvm_hwpoisoned_mem - indicate if there is any hwpoisoned page
* reported for the VM.
*/
bool kvm_hwpoisoned_mem(void);
#endif
48 changes: 28 additions & 20 deletions migration/migration.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
#include "options.h"
#include "sysemu/dirtylimit.h"
#include "qemu/sockets.h"
#include "sysemu/kvm.h"

static NotifierList migration_state_notifiers =
NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
Expand Down Expand Up @@ -128,20 +129,25 @@ static bool migration_needs_multiple_sockets(void)
return migrate_multifd() || migrate_postcopy_preempt();
}

static bool transport_supports_multi_channels(SocketAddress *saddr)
static bool transport_supports_multi_channels(MigrationAddress *addr)
{
return saddr->type == SOCKET_ADDRESS_TYPE_INET ||
saddr->type == SOCKET_ADDRESS_TYPE_UNIX ||
saddr->type == SOCKET_ADDRESS_TYPE_VSOCK;
if (addr->transport == MIGRATION_ADDRESS_TYPE_SOCKET) {
SocketAddress *saddr = &addr->u.socket;

return saddr->type == SOCKET_ADDRESS_TYPE_INET ||
saddr->type == SOCKET_ADDRESS_TYPE_UNIX ||
saddr->type == SOCKET_ADDRESS_TYPE_VSOCK;
}

return false;
}

static bool
migration_channels_and_transport_compatible(MigrationAddress *addr,
Error **errp)
{
if (migration_needs_multiple_sockets() &&
(addr->transport == MIGRATION_ADDRESS_TYPE_SOCKET) &&
!transport_supports_multi_channels(&addr->u.socket)) {
!transport_supports_multi_channels(addr)) {
error_setg(errp, "Migration requires multi-channel URIs (e.g. tcp)");
return false;
}
Expand Down Expand Up @@ -311,7 +317,7 @@ void migration_incoming_state_destroy(void)
{
struct MigrationIncomingState *mis = migration_incoming_get_current();

multifd_load_cleanup();
multifd_recv_cleanup();
compress_threads_load_cleanup();

if (mis->to_src_file) {
Expand Down Expand Up @@ -662,7 +668,7 @@ static void process_incoming_migration_bh(void *opaque)

trace_vmstate_downtime_checkpoint("dst-precopy-bh-announced");

multifd_load_shutdown();
multifd_recv_shutdown();

dirty_bitmap_mig_before_vm_start();

Expand Down Expand Up @@ -759,7 +765,7 @@ process_incoming_migration_co(void *opaque)
MIGRATION_STATUS_FAILED);
qemu_fclose(mis->from_src_file);

multifd_load_cleanup();
multifd_recv_cleanup();
compress_threads_load_cleanup();

exit(EXIT_FAILURE);
Expand Down Expand Up @@ -885,7 +891,7 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
default_channel = !mis->from_src_file;
}

if (multifd_load_setup(errp) != 0) {
if (multifd_recv_setup(errp) != 0) {
return;
}

Expand Down Expand Up @@ -1331,7 +1337,7 @@ static void migrate_fd_cleanup(MigrationState *s)
}
bql_lock();

multifd_save_cleanup();
multifd_send_shutdown();
qemu_mutex_lock(&s->qemu_file_lock);
tmp = s->to_dst_file;
s->to_dst_file = NULL;
Expand Down Expand Up @@ -1906,6 +1912,12 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
return false;
}

if (kvm_hwpoisoned_mem()) {
error_setg(errp, "Can't migrate this vm with hardware poisoned memory, "
"please reboot the vm and try again");
return false;
}

if (migration_is_blocked(errp)) {
return false;
}
Expand Down Expand Up @@ -3315,6 +3327,10 @@ static void *migration_thread(void *opaque)
object_ref(OBJECT(s));
update_iteration_initial_status(s);

if (!multifd_send_setup()) {
goto out;
}

bql_lock();
qemu_savevm_state_header(s->to_dst_file);
bql_unlock();
Expand Down Expand Up @@ -3386,6 +3402,7 @@ static void *migration_thread(void *opaque)
urgent = migration_rate_limit();
}

out:
trace_migration_thread_after_loop();
migration_iteration_finish(s);
object_unref(OBJECT(s));
Expand Down Expand Up @@ -3623,15 +3640,6 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
return;
}

if (multifd_save_setup(&local_err) != 0) {
migrate_set_error(s, local_err);
error_report_err(local_err);
migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_FAILED);
migrate_fd_cleanup(s);
return;
}

if (migrate_background_snapshot()) {
qemu_thread_create(&s->thread, "bg_snapshot",
bg_migration_thread, s, QEMU_THREAD_JOINABLE);
Expand Down
11 changes: 8 additions & 3 deletions migration/multifd-zlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,20 @@ static void zlib_send_cleanup(MultiFDSendParams *p, Error **errp)
*/
static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
{
MultiFDPages_t *pages = p->pages;
struct zlib_data *z = p->data;
z_stream *zs = &z->zs;
uint32_t out_size = 0;
int ret;
uint32_t i;

for (i = 0; i < p->normal_num; i++) {
multifd_send_prepare_header(p);

for (i = 0; i < pages->num; i++) {
uint32_t available = z->zbuff_len - out_size;
int flush = Z_NO_FLUSH;

if (i == p->normal_num - 1) {
if (i == pages->num - 1) {
flush = Z_SYNC_FLUSH;
}

Expand All @@ -135,7 +138,7 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
* with compression. zlib does not guarantee that this is safe,
* therefore copy the page before calling deflate().
*/
memcpy(z->buf, p->pages->block->host + p->normal[i], p->page_size);
memcpy(z->buf, p->pages->block->host + pages->offset[i], p->page_size);
zs->avail_in = p->page_size;
zs->next_in = z->buf;

Expand Down Expand Up @@ -171,6 +174,8 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
p->next_packet_size = out_size;
p->flags |= MULTIFD_FLAG_ZLIB;

multifd_send_fill_packet(p);

return 0;
}

Expand Down
11 changes: 8 additions & 3 deletions migration/multifd-zstd.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,21 +113,24 @@ static void zstd_send_cleanup(MultiFDSendParams *p, Error **errp)
*/
static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
{
MultiFDPages_t *pages = p->pages;
struct zstd_data *z = p->data;
int ret;
uint32_t i;

multifd_send_prepare_header(p);

z->out.dst = z->zbuff;
z->out.size = z->zbuff_len;
z->out.pos = 0;

for (i = 0; i < p->normal_num; i++) {
for (i = 0; i < pages->num; i++) {
ZSTD_EndDirective flush = ZSTD_e_continue;

if (i == p->normal_num - 1) {
if (i == pages->num - 1) {
flush = ZSTD_e_flush;
}
z->in.src = p->pages->block->host + p->normal[i];
z->in.src = p->pages->block->host + pages->offset[i];
z->in.size = p->page_size;
z->in.pos = 0;

Expand Down Expand Up @@ -160,6 +163,8 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
p->next_packet_size = z->out.pos;
p->flags |= MULTIFD_FLAG_ZSTD;

multifd_send_fill_packet(p);

return 0;
}

Expand Down

0 comments on commit 5d1fc61

Please sign in to comment.