Skip to content

Commit

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

Migration Pull request for 8.0

Last patches found:
- peter xu preempt channel fixes.
  needed for backward compatibility with old machine types.
- lukas fix to get compress working again.

- fix ram on s390x.  Get back to the old code, even when it shouldn't
  be needed, but as it fails on s390x, just revert.

Later, Juan.

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEGJn/jt6/WMzuA0uC9IfvGFhy1yMFAmQ3HgQACgkQ9IfvGFhy
# 1yPXGQ/+Pf6HepNUlIr7naYOcpRriXPQF+q1zqo74F9fy2vrGcwJOI6qmRTjsX4E
# 9KgXipOz7+b5wSemF7PDKcnBiwyt6UHCH+XXe0h4TpyuORbtABKRgtOhA1/sa84D
# HnKp0TwImpAO26tzPa7u49aau/EEVBKAzFVcyn4w56S9qiDWicOpd5kG0CJBIsMJ
# Mnvy5fXaqQRewnKiwFoJGWfyhzEToDO6Z/SkT5xYON94P+eiM2xMwXOC5WcGfmY7
# wFGDB+SuyEP8TTn7mV0mmnlFjYe4G07hVARHSDFX3ho4b6q5F+WzfW095G6QKiu9
# n3Pzr7IBGX3sgetPtYwOwGsE9JrfHMFzBRxQZZwq5GSmjk7+agkbXmV7RyV82EYs
# KYOhuNF91ca0qvCrGA/eGbbJqVrd7SR5FhS4SQ7oKd5n2au/ZHoKwAgm5lBdcvES
# 2TB0MBN1s0JPh6KMV8tPB2miZyqPRa++oA8qIX7Asoe1X4xVT1FwiDaFL8TO8i2A
# 7uBis3KLZqOHC6dAiXlCDtaADAWgQxjcdoS1l8jTF6MgBSe+zQhXG+pcIDuSiV9N
# WfDiUPY97iqPTvpzdz3Is+LbBax2uY5ZR05KSdmCBpIgfvSWMqXtwRydclt6G5h7
# ZiOcTwrgMpXdbhdsFZTqVWAJG2sTkj4TA+IezVpXzPeQNLZ+T8k=
# =kW3P
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 12 Apr 2023 22:09:24 BST
# gpg:                using RSA key 1899FF8EDEBF58CCEE034B82F487EF185872D723
# gpg: Good signature from "Juan Quintela <quintela@redhat.com>" [full]
# gpg:                 aka "Juan Quintela <quintela@trasno.org>" [full]
# Primary key fingerprint: 1899 FF8E DEBF 58CC EE03  4B82 F487 EF18 5872 D723

* tag 'migration-20230412-pull-request' of https://gitlab.com/juan.quintela/qemu:
  migration: fix ram_state_pending_exact()
  migration/ram.c: Fix migration with compress enabled
  migration: Recover behavior of preempt channel creation for pre-7.2
  migration: Fix potential race on postcopy_qemufile_src
  io: tls: Inherit QIO_CHANNEL_FEATURE_SHUTDOWN on server side

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Apr 13, 2023
2 parents 69d4e74 + 28ef533 commit c38b2ca
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 24 deletions.
1 change: 1 addition & 0 deletions hw/core/machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
GlobalProperty hw_compat_7_2[] = {
{ "e1000e", "migrate-timadj", "off" },
{ "virtio-mem", "x-early-migration", "false" },
{ "migration", "x-preempt-pre-7-2", "true" },
};
const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2);

Expand Down
3 changes: 3 additions & 0 deletions io/channel-tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ qio_channel_tls_new_server(QIOChannel *master,
ioc = QIO_CHANNEL_TLS(object_new(TYPE_QIO_CHANNEL_TLS));

ioc->master = master;
if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SHUTDOWN);
}
object_ref(OBJECT(master));

ioc->session = qcrypto_tls_session_new(
Expand Down
19 changes: 17 additions & 2 deletions migration/migration.c
Original file line number Diff line number Diff line change
Expand Up @@ -3464,8 +3464,12 @@ static void migration_completion(MigrationState *s)
qemu_savevm_state_complete_postcopy(s->to_dst_file);
qemu_mutex_unlock_iothread();

/* Shutdown the postcopy fast path thread */
if (migrate_postcopy_preempt()) {
/*
* Shutdown the postcopy fast path thread. This is only needed
* when dest QEMU binary is old (7.1/7.2). QEMU 8.0+ doesn't need
* this.
*/
if (migrate_postcopy_preempt() && s->preempt_pre_7_2) {
postcopy_preempt_shutdown_file(s);
}

Expand Down Expand Up @@ -4384,6 +4388,15 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
}
}

/*
* This needs to be done before resuming a postcopy. Note: for newer
* QEMUs we will delay the channel creation until postcopy_start(), to
* avoid disorder of channel creations.
*/
if (migrate_postcopy_preempt() && s->preempt_pre_7_2) {
postcopy_preempt_setup(s);
}

if (resume) {
/* Wakeup the main migration thread to do the recovery */
migrate_set_state(&s->state, MIGRATION_STATUS_POSTCOPY_PAUSED,
Expand Down Expand Up @@ -4443,6 +4456,8 @@ static Property migration_properties[] = {
decompress_error_check, true),
DEFINE_PROP_UINT8("x-clear-bitmap-shift", MigrationState,
clear_bitmap_shift, CLEAR_BITMAP_SHIFT_DEFAULT),
DEFINE_PROP_BOOL("x-preempt-pre-7-2", MigrationState,
preempt_pre_7_2, false),

/* Migration parameters */
DEFINE_PROP_UINT8("x-compress-level", MigrationState,
Expand Down
41 changes: 40 additions & 1 deletion migration/migration.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ typedef struct {
bool all_zero;
} PostcopyTmpPage;

typedef enum {
PREEMPT_THREAD_NONE = 0,
PREEMPT_THREAD_CREATED,
PREEMPT_THREAD_QUIT,
} PreemptThreadStatus;

/* State for the incoming migration */
struct MigrationIncomingState {
QEMUFile *from_src_file;
Expand Down Expand Up @@ -124,7 +130,12 @@ struct MigrationIncomingState {
QemuSemaphore postcopy_qemufile_dst_done;
/* Postcopy priority thread is used to receive postcopy requested pages */
QemuThread postcopy_prio_thread;
bool postcopy_prio_thread_created;
/*
* Always set by the main vm load thread only, but can be read by the
* postcopy preempt thread. "volatile" makes sure all reads will be
* uptodate across cores.
*/
volatile PreemptThreadStatus preempt_thread_status;
/*
* Used to sync between the ram load main thread and the fast ram load
* thread. It protects postcopy_qemufile_dst, which is the postcopy
Expand Down Expand Up @@ -364,6 +375,34 @@ struct MigrationState {
* do not trigger spurious decompression errors.
*/
bool decompress_error_check;
/*
* This variable only affects behavior when postcopy preempt mode is
* enabled.
*
* When set:
*
* - postcopy preempt src QEMU instance will generate an EOS message at
* the end of migration to shut the preempt channel on dest side.
*
* - postcopy preempt channel will be created at the setup phase on src
QEMU.
*
* When clear:
*
* - postcopy preempt src QEMU instance will _not_ generate an EOS
* message at the end of migration, the dest qemu will shutdown the
* channel itself.
*
* - postcopy preempt channel will be created at the switching phase
* from precopy -> postcopy (to avoid race condtion of misordered
* creation of channels).
*
* NOTE: See message-id <ZBoShWArKDPpX/D7@work-vm> on qemu-devel
* mailing list for more information on the possible race. Everyone
* should probably just keep this value untouched after set by the
* machine type (or the default).
*/
bool preempt_pre_7_2;

/*
* This decides the size of guest memory chunk that will be used
Expand Down
30 changes: 23 additions & 7 deletions migration/postcopy-ram.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,9 +568,14 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)
{
trace_postcopy_ram_incoming_cleanup_entry();

if (mis->postcopy_prio_thread_created) {
if (mis->preempt_thread_status == PREEMPT_THREAD_CREATED) {
/* Notify the fast load thread to quit */
mis->preempt_thread_status = PREEMPT_THREAD_QUIT;
if (mis->postcopy_qemufile_dst) {
qemu_file_shutdown(mis->postcopy_qemufile_dst);
}
qemu_thread_join(&mis->postcopy_prio_thread);
mis->postcopy_prio_thread_created = false;
mis->preempt_thread_status = PREEMPT_THREAD_NONE;
}

if (mis->have_fault_thread) {
Expand Down Expand Up @@ -1203,7 +1208,7 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
*/
postcopy_thread_create(mis, &mis->postcopy_prio_thread, "fault-fast",
postcopy_preempt_thread, QEMU_THREAD_JOINABLE);
mis->postcopy_prio_thread_created = true;
mis->preempt_thread_status = PREEMPT_THREAD_CREATED;
}

trace_postcopy_ram_enable_notify();
Expand Down Expand Up @@ -1625,8 +1630,14 @@ int postcopy_preempt_establish_channel(MigrationState *s)
return 0;
}

/* Kick off async task to establish preempt channel */
postcopy_preempt_setup(s);
/*
* Kick off async task to establish preempt channel. Only do so with
* 8.0+ machines, because 7.1/7.2 require the channel to be created in
* setup phase of migration (even if racy in an unreliable network).
*/
if (!s->preempt_pre_7_2) {
postcopy_preempt_setup(s);
}

/*
* We need the postcopy preempt channel to be established before
Expand All @@ -1652,6 +1663,11 @@ static void postcopy_pause_ram_fast_load(MigrationIncomingState *mis)
trace_postcopy_pause_fast_load_continued();
}

static bool preempt_thread_should_run(MigrationIncomingState *mis)
{
return mis->preempt_thread_status != PREEMPT_THREAD_QUIT;
}

void *postcopy_preempt_thread(void *opaque)
{
MigrationIncomingState *mis = opaque;
Expand All @@ -1671,11 +1687,11 @@ void *postcopy_preempt_thread(void *opaque)

/* Sending RAM_SAVE_FLAG_EOS to terminate this thread */
qemu_mutex_lock(&mis->postcopy_prio_thread_mutex);
while (1) {
while (preempt_thread_should_run(mis)) {
ret = ram_load_postcopy(mis->postcopy_qemufile_dst,
RAM_CHANNEL_POSTCOPY);
/* If error happened, go into recovery routine */
if (ret) {
if (ret && preempt_thread_should_run(mis)) {
postcopy_pause_ram_fast_load(mis);
} else {
/* We're done */
Expand Down
27 changes: 13 additions & 14 deletions migration/ram.c
Original file line number Diff line number Diff line change
Expand Up @@ -688,12 +688,11 @@ static int compress_threads_save_setup(void)
* @offset: offset inside the block for the page
* in the lower bits, it contains flags
*/
static size_t save_page_header(PageSearchStatus *pss, RAMBlock *block,
ram_addr_t offset)
static size_t save_page_header(PageSearchStatus *pss, QEMUFile *f,
RAMBlock *block, ram_addr_t offset)
{
size_t size, len;
bool same_block = (block == pss->last_sent_block);
QEMUFile *f = pss->pss_channel;

if (same_block) {
offset |= RAM_SAVE_FLAG_CONTINUE;
Expand Down Expand Up @@ -867,7 +866,7 @@ static int save_xbzrle_page(RAMState *rs, PageSearchStatus *pss,
}

/* Send XBZRLE based compressed page */
bytes_xbzrle = save_page_header(pss, block,
bytes_xbzrle = save_page_header(pss, pss->pss_channel, block,
offset | RAM_SAVE_FLAG_XBZRLE);
qemu_put_byte(file, ENCODING_FLAG_XBZRLE);
qemu_put_be16(file, encoded_len);
Expand Down Expand Up @@ -1302,15 +1301,14 @@ void ram_release_page(const char *rbname, uint64_t offset)
* @block: block that contains the page we want to send
* @offset: offset inside the block for the page
*/
static int save_zero_page_to_file(PageSearchStatus *pss,
static int save_zero_page_to_file(PageSearchStatus *pss, QEMUFile *file,
RAMBlock *block, ram_addr_t offset)
{
uint8_t *p = block->host + offset;
QEMUFile *file = pss->pss_channel;
int len = 0;

if (buffer_is_zero(p, TARGET_PAGE_SIZE)) {
len += save_page_header(pss, block, offset | RAM_SAVE_FLAG_ZERO);
len += save_page_header(pss, file, block, offset | RAM_SAVE_FLAG_ZERO);
qemu_put_byte(file, 0);
len += 1;
ram_release_page(block->idstr, offset);
Expand All @@ -1327,10 +1325,10 @@ static int save_zero_page_to_file(PageSearchStatus *pss,
* @block: block that contains the page we want to send
* @offset: offset inside the block for the page
*/
static int save_zero_page(PageSearchStatus *pss, RAMBlock *block,
static int save_zero_page(PageSearchStatus *pss, QEMUFile *f, RAMBlock *block,
ram_addr_t offset)
{
int len = save_zero_page_to_file(pss, block, offset);
int len = save_zero_page_to_file(pss, f, block, offset);

if (len) {
stat64_add(&ram_atomic_counters.duplicate, 1);
Expand Down Expand Up @@ -1394,7 +1392,7 @@ static int save_normal_page(PageSearchStatus *pss, RAMBlock *block,
{
QEMUFile *file = pss->pss_channel;

ram_transferred_add(save_page_header(pss, block,
ram_transferred_add(save_page_header(pss, pss->pss_channel, block,
offset | RAM_SAVE_FLAG_PAGE));
if (async) {
qemu_put_buffer_async(file, buf, TARGET_PAGE_SIZE,
Expand Down Expand Up @@ -1473,11 +1471,11 @@ static bool do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block,
uint8_t *p = block->host + offset;
int ret;

if (save_zero_page_to_file(pss, block, offset)) {
if (save_zero_page_to_file(pss, f, block, offset)) {
return true;
}

save_page_header(pss, block, offset | RAM_SAVE_FLAG_COMPRESS_PAGE);
save_page_header(pss, f, block, offset | RAM_SAVE_FLAG_COMPRESS_PAGE);

/*
* copy it to a internal buffer to avoid it being modified by VM
Expand Down Expand Up @@ -2355,7 +2353,7 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss)
return 1;
}

res = save_zero_page(pss, block, offset);
res = save_zero_page(pss, pss->pss_channel, block, offset);
if (res > 0) {
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
* page would be stale
Expand Down Expand Up @@ -3508,12 +3506,13 @@ static void ram_state_pending_estimate(void *opaque, uint64_t *must_precopy,
static void ram_state_pending_exact(void *opaque, uint64_t *must_precopy,
uint64_t *can_postcopy)
{
MigrationState *s = migrate_get_current();
RAMState **temp = opaque;
RAMState *rs = *temp;

uint64_t remaining_size = rs->migration_dirty_pages * TARGET_PAGE_SIZE;

if (!migration_in_postcopy()) {
if (!migration_in_postcopy() && remaining_size < s->threshold_size) {
qemu_mutex_lock_iothread();
WITH_RCU_READ_LOCK_GUARD() {
migration_bitmap_sync_precopy(rs);
Expand Down

0 comments on commit c38b2ca

Please sign in to comment.