Migration pull request for softfreeze

v2:
 - Patch "migration: Move cpu-throttle.c from system to migration",
   fix build on MacOS, and subject spelling
 
 NOTE: checkpatch.pl could report a false positive on this branch:
 
   WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
   #21:
    {include/sysemu => migration}/cpu-throttle.h | 0
 
 That's covered by "F: migration/" entry.
 
 Changelog:
 
 - Peter's cleanup patch on migrate_fd_cleanup()
 - Peter's cleanup patch to introduce thread name macros
 - Hanna's error path fix for vmstate subsection save()s
 - Hyman's auto converge enhancement on background dirty sync
 - Peter's additional tracepoints for save state entries
 - Thomas's build fix for OpenBSD in dirtyrate.c
 - Peter's deprecation of query-migrationthreads command
 - Peter's cleanup/fixes from the "export misc.h" series
 - Maciej's two small patches from multifd+vfio series
 -----BEGIN PGP SIGNATURE-----
 
 iIgEABYKADAWIQS5GE3CDMRX2s990ak7X8zN86vXBgUCZyTbVRIccGV0ZXJ4QHJl
 ZGhhdC5jb20ACgkQO1/MzfOr1wan3wD+L4TVNDc34Hy4mvWu7u1lCOePX0GBdUEc
 oEeBGblwbrcBAIR8d+5z9O5YcWH1coozG1aUC4qCtSHHk5TGbJk4/UUD
 =XB5Q
 -----END PGP SIGNATURE-----

Merge tag 'migration-20241030-pull-request' of https://gitlab.com/peterx/qemu into staging

Migration pull request for softfreeze

v2:
- Patch "migration: Move cpu-throttle.c from system to migration",
  fix build on MacOS, and subject spelling

NOTE: checkpatch.pl could report a false positive on this branch:

  WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
  #21:
   {include/sysemu => migration}/cpu-throttle.h | 0

That's covered by "F: migration/" entry.

Changelog:

- Peter's cleanup patch on migrate_fd_cleanup()
- Peter's cleanup patch to introduce thread name macros
- Hanna's error path fix for vmstate subsection save()s
- Hyman's auto converge enhancement on background dirty sync
- Peter's additional tracepoints for save state entries
- Thomas's build fix for OpenBSD in dirtyrate.c
- Peter's deprecation of query-migrationthreads command
- Peter's cleanup/fixes from the "export misc.h" series
- Maciej's two small patches from multifd+vfio series

# -----BEGIN PGP SIGNATURE-----
#
# iIgEABYKADAWIQS5GE3CDMRX2s990ak7X8zN86vXBgUCZyTbVRIccGV0ZXJ4QHJl
# ZGhhdC5jb20ACgkQO1/MzfOr1wan3wD+L4TVNDc34Hy4mvWu7u1lCOePX0GBdUEc
# oEeBGblwbrcBAIR8d+5z9O5YcWH1coozG1aUC4qCtSHHk5TGbJk4/UUD
# =XB5Q
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 01 Nov 2024 13:44:53 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-20241030-pull-request' of https://gitlab.com/peterx/qemu:
  migration/multifd: Zero p->flags before starting filling a packet
  migration/ram: Add load start trace event
  migration: Drop migration_is_idle()
  migration: Drop migration_is_setup_or_active()
  migration: Unexport ram_mig_init()
  migration: Unexport dirty_bitmap_mig_init()
  migration: Take migration object refcount earlier for threads
  migration: Deprecate query-migrationthreads command
  migration/dirtyrate: Silence warning about strcpy() on OpenBSD
  tests/migration: Add case for periodic ramblock dirty sync
  migration: Support periodic RAMBlock dirty bitmap sync
  migration: Remove "rs" parameter in migration_bitmap_sync_precopy
  migration: Move cpu-throttle.c from system to migration
  migration: Stop CPU throttling conditionally
  accel/tcg/icount-common: Remove the reference to the unused header file
  migration: Ensure vmstate_save() sets errp
  migration: Put thread names together with macros
  migration: Cleanup migrate_fd_cleanup() on accessing to_dst_file

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-11-04 12:31:45 +00:00
commit cbad455118
26 changed files with 254 additions and 122 deletions

View File

@ -36,7 +36,6 @@
#include "sysemu/runstate.h"
#include "hw/core/cpu.h"
#include "sysemu/cpu-timers.h"
#include "sysemu/cpu-throttle.h"
#include "sysemu/cpu-timers-internal.h"
/*

View File

@ -147,6 +147,14 @@ options are removed in favor of using explicit ``blockdev-create`` and
``blockdev-add`` calls. See :doc:`/interop/live-block-operations` for
details.
``query-migrationthreads`` (since 9.2)
''''''''''''''''''''''''''''''''''''''
To be removed with no replacement, as it reports only a limited set of
threads (for example, it only reports source side of multifd threads,
without reporting any destination threads, or non-multifd source threads).
For debugging purpose, please use ``-name $VM,debug-threads=on`` instead.
Incorrectly typed ``device_add`` arguments (since 6.2)
''''''''''''''''''''''''''''''''''''''''''''''''''''''

View File

@ -149,7 +149,7 @@ bool vfio_viommu_preset(VFIODevice *vbasedev)
static void vfio_set_migration_error(int ret)
{
if (migration_is_setup_or_active()) {
if (migration_is_running()) {
migration_file_set_error(ret, NULL);
}
}

View File

@ -188,7 +188,7 @@ static bool virtio_mem_is_busy(void)
* after plugging them) until we're running on the destination (as we didn't
* migrate these blocks when they were unplugged).
*/
return migration_in_incoming_postcopy() || !migration_is_idle();
return migration_in_incoming_postcopy() || migration_is_running();
}
typedef int (*virtio_mem_range_cb)(VirtIOMEM *vmem, void *arg,

View File

@ -39,7 +39,6 @@ void precopy_add_notifier(NotifierWithReturn *n);
void precopy_remove_notifier(NotifierWithReturn *n);
int precopy_notify(PrecopyNotifyReason reason, Error **errp);
void ram_mig_init(void);
void qemu_guest_free_page_hint(void *addr, size_t len);
bool migrate_ram_is_ignored(RAMBlock *block);
@ -53,11 +52,11 @@ void dump_vmstate_json_to_file(FILE *out_fp);
/* migration/migration.c */
void migration_object_init(void);
void migration_shutdown(void);
bool migration_is_idle(void);
bool migration_is_active(void);
bool migration_is_device(void);
bool migration_is_running(void);
bool migration_thread_is_self(void);
bool migration_is_setup_or_active(void);
typedef enum MigrationEventType {
MIG_EVENT_PRECOPY_SETUP,
@ -96,7 +95,6 @@ void migration_add_notifier_mode(NotifierWithReturn *notify,
MigrationNotifyFunc func, MigMode mode);
void migration_remove_notifier(NotifierWithReturn *notify);
bool migration_is_running(void);
void migration_file_set_error(int ret, Error *err);
/* True if incoming migration entered POSTCOPY_INCOMING_DISCARD */
@ -108,7 +106,4 @@ bool migration_incoming_postcopy_advised(void);
/* True if background snapshot is active */
bool migration_in_bg_snapshot(void);
/* migration/block-dirty-bitmap.c */
void dirty_bitmap_mig_init(void);
#endif

View File

@ -65,4 +65,18 @@ bool cpu_throttle_active(void);
*/
int cpu_throttle_get_percentage(void);
/**
* cpu_throttle_dirty_sync_timer_tick:
*
* Dirty sync timer hook.
*/
void cpu_throttle_dirty_sync_timer_tick(void *opaque);
/**
* cpu_throttle_dirty_sync_timer:
*
* Start or stop the dirty sync timer.
*/
void cpu_throttle_dirty_sync_timer(bool enable);
#endif /* SYSEMU_CPU_THROTTLE_H */

View File

@ -935,7 +935,8 @@ void coroutine_fn colo_incoming_co(void)
assert(bql_locked());
assert(migration_incoming_colo_enabled());
qemu_thread_create(&th, "mig/dst/colo", colo_process_incoming_thread,
qemu_thread_create(&th, MIGRATION_THREAD_DST_COLO,
colo_process_incoming_thread,
mis, QEMU_THREAD_JOINABLE);
mis->colo_incoming_co = qemu_coroutine_self();

View File

@ -28,16 +28,23 @@
#include "qemu/main-loop.h"
#include "sysemu/cpus.h"
#include "sysemu/cpu-throttle.h"
#include "migration.h"
#include "migration-stats.h"
#include "trace.h"
/* vcpu throttling controls */
static QEMUTimer *throttle_timer;
static QEMUTimer *throttle_timer, *throttle_dirty_sync_timer;
static unsigned int throttle_percentage;
static bool throttle_dirty_sync_timer_active;
static uint64_t throttle_dirty_sync_count_prev;
#define CPU_THROTTLE_PCT_MIN 1
#define CPU_THROTTLE_PCT_MAX 99
#define CPU_THROTTLE_TIMESLICE_NS 10000000
/* Making sure RAMBlock dirty bitmap is synchronized every five seconds */
#define CPU_THROTTLE_DIRTY_SYNC_TIMESLICE_MS 5000
static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque)
{
double pct;
@ -112,6 +119,7 @@ void cpu_throttle_set(int new_throttle_pct)
void cpu_throttle_stop(void)
{
qatomic_set(&throttle_percentage, 0);
cpu_throttle_dirty_sync_timer(false);
}
bool cpu_throttle_active(void)
@ -124,8 +132,68 @@ int cpu_throttle_get_percentage(void)
return qatomic_read(&throttle_percentage);
}
void cpu_throttle_dirty_sync_timer_tick(void *opaque)
{
uint64_t sync_cnt = stat64_get(&mig_stats.dirty_sync_count);
/*
* The first iteration copies all memory anyhow and has no
* effect on guest performance, therefore omit it to avoid
* paying extra for the sync penalty.
*/
if (sync_cnt <= 1) {
goto end;
}
if (sync_cnt == throttle_dirty_sync_count_prev) {
trace_cpu_throttle_dirty_sync();
WITH_RCU_READ_LOCK_GUARD() {
migration_bitmap_sync_precopy(false);
}
}
end:
throttle_dirty_sync_count_prev = stat64_get(&mig_stats.dirty_sync_count);
timer_mod(throttle_dirty_sync_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) +
CPU_THROTTLE_DIRTY_SYNC_TIMESLICE_MS);
}
static bool cpu_throttle_dirty_sync_active(void)
{
return qatomic_read(&throttle_dirty_sync_timer_active);
}
void cpu_throttle_dirty_sync_timer(bool enable)
{
assert(throttle_dirty_sync_timer);
if (enable) {
if (!cpu_throttle_dirty_sync_active()) {
/*
* Always reset the dirty sync count cache, in case migration
* was cancelled once.
*/
throttle_dirty_sync_count_prev = 0;
timer_mod(throttle_dirty_sync_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) +
CPU_THROTTLE_DIRTY_SYNC_TIMESLICE_MS);
qatomic_set(&throttle_dirty_sync_timer_active, 1);
}
} else {
if (cpu_throttle_dirty_sync_active()) {
timer_del(throttle_dirty_sync_timer);
qatomic_set(&throttle_dirty_sync_timer_active, 0);
}
}
}
void cpu_throttle_init(void)
{
throttle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
cpu_throttle_timer_tick, NULL);
throttle_dirty_sync_timer =
timer_new_ms(QEMU_CLOCK_VIRTUAL_RT,
cpu_throttle_dirty_sync_timer_tick, NULL);
}

View File

@ -29,6 +29,7 @@
#include "sysemu/runstate.h"
#include "exec/memory.h"
#include "qemu/xxhash.h"
#include "migration.h"
/*
* total_dirty_pages is procted by BQL and is used
@ -436,6 +437,7 @@ static void get_ramblock_dirty_info(RAMBlock *block,
struct DirtyRateConfig *config)
{
uint64_t sample_pages_per_gigabytes = config->sample_pages_per_gigabytes;
gsize len;
/* Right shift 30 bits to calc ramblock size in GB */
info->sample_pages_count = (qemu_ram_get_used_length(block) *
@ -444,7 +446,9 @@ static void get_ramblock_dirty_info(RAMBlock *block,
info->ramblock_pages = qemu_ram_get_used_length(block) >>
qemu_target_page_bits();
info->ramblock_addr = qemu_ram_get_host_addr(block);
strcpy(info->idstr, qemu_ram_get_idstr(block));
len = g_strlcpy(info->idstr, qemu_ram_get_idstr(block),
sizeof(info->idstr));
g_assert(len < sizeof(info->idstr));
}
static void free_ramblock_dirty_info(struct RamblockDirtyInfo *infos, int count)
@ -839,8 +843,9 @@ void qmp_calc_dirty_rate(int64_t calc_time,
init_dirtyrate_stat(config);
qemu_thread_create(&thread, "get_dirtyrate", get_dirtyrate_thread,
(void *)&config, QEMU_THREAD_DETACHED);
qemu_thread_create(&thread, MIGRATION_THREAD_DIRTY_RATE,
get_dirtyrate_thread, (void *)&config,
QEMU_THREAD_DETACHED);
}

View File

@ -13,6 +13,7 @@ system_ss.add(files(
'block-dirty-bitmap.c',
'channel.c',
'channel-block.c',
'cpu-throttle.c',
'dirtyrate.c',
'exec.c',
'fd.c',

View File

@ -263,6 +263,9 @@ void migration_object_init(void)
ram_mig_init();
dirty_bitmap_mig_init();
/* Initialize cpu throttle timers */
cpu_throttle_init();
}
typedef struct {
@ -1110,33 +1113,6 @@ void migrate_send_rp_resume_ack(MigrationIncomingState *mis, uint32_t value)
migrate_send_rp_message(mis, MIG_RP_MSG_RESUME_ACK, sizeof(buf), &buf);
}
/*
* Return true if we're already in the middle of a migration
* (i.e. any of the active or setup states)
*/
bool migration_is_setup_or_active(void)
{
MigrationState *s = current_migration;
switch (s->state) {
case MIGRATION_STATUS_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_ACTIVE:
case MIGRATION_STATUS_POSTCOPY_PAUSED:
case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP:
case MIGRATION_STATUS_POSTCOPY_RECOVER:
case MIGRATION_STATUS_SETUP:
case MIGRATION_STATUS_PRE_SWITCHOVER:
case MIGRATION_STATUS_DEVICE:
case MIGRATION_STATUS_WAIT_UNPLUG:
case MIGRATION_STATUS_COLO:
return true;
default:
return false;
}
}
bool migration_is_running(void)
{
MigrationState *s = current_migration;
@ -1152,11 +1128,10 @@ bool migration_is_running(void)
case MIGRATION_STATUS_DEVICE:
case MIGRATION_STATUS_WAIT_UNPLUG:
case MIGRATION_STATUS_CANCELLING:
case MIGRATION_STATUS_COLO:
return true;
default:
return false;
}
}
@ -1405,6 +1380,9 @@ void migrate_set_state(MigrationStatus *state, MigrationStatus old_state,
static void migrate_fd_cleanup(MigrationState *s)
{
MigrationEventType type;
QEMUFile *tmp = NULL;
trace_migrate_fd_cleanup();
g_free(s->hostname);
s->hostname = NULL;
@ -1415,26 +1393,29 @@ static void migrate_fd_cleanup(MigrationState *s)
close_return_path_on_source(s);
if (s->to_dst_file) {
QEMUFile *tmp;
trace_migrate_fd_cleanup();
if (s->migration_thread_running) {
bql_unlock();
if (s->migration_thread_running) {
qemu_thread_join(&s->thread);
s->migration_thread_running = false;
}
qemu_thread_join(&s->thread);
s->migration_thread_running = false;
bql_lock();
}
multifd_send_shutdown();
qemu_mutex_lock(&s->qemu_file_lock);
WITH_QEMU_LOCK_GUARD(&s->qemu_file_lock) {
/*
* Close the file handle without the lock to make sure the critical
* section won't block for long.
*/
tmp = s->to_dst_file;
s->to_dst_file = NULL;
qemu_mutex_unlock(&s->qemu_file_lock);
}
if (tmp) {
/*
* Close the file handle without the lock to make sure the
* critical section won't block for long.
* We only need to shutdown multifd if tmp!=NULL, because if
* tmp==NULL, it means the main channel isn't established, while
* multifd is only setup after that (in migration_thread()).
*/
multifd_send_shutdown();
migration_ioc_unregister_yank_from_file(tmp);
qemu_fclose(tmp);
}
@ -1649,27 +1630,7 @@ bool migration_incoming_postcopy_advised(void)
bool migration_in_bg_snapshot(void)
{
return migrate_background_snapshot() &&
migration_is_setup_or_active();
}
bool migration_is_idle(void)
{
MigrationState *s = current_migration;
if (!s) {
return true;
}
switch (s->state) {
case MIGRATION_STATUS_NONE:
case MIGRATION_STATUS_CANCELLED:
case MIGRATION_STATUS_COMPLETED:
case MIGRATION_STATUS_FAILED:
return true;
default:
return false;
}
return migrate_background_snapshot() && migration_is_running();
}
bool migration_is_active(void)
@ -1750,7 +1711,7 @@ static bool is_busy(Error **reasonp, Error **errp)
ERRP_GUARD();
/* Snapshots are similar to migrations, so check RUN_STATE_SAVE_VM too. */
if (runstate_check(RUN_STATE_SAVE_VM) || !migration_is_idle()) {
if (runstate_check(RUN_STATE_SAVE_VM) || migration_is_running()) {
error_propagate_prepend(errp, *reasonp,
"disallowing migration blocker "
"(migration/snapshot in progress) for: ");
@ -2323,7 +2284,7 @@ static void *source_return_path_thread(void *opaque)
trace_source_return_path_thread_entry();
rcu_register_thread();
while (migration_is_setup_or_active()) {
while (migration_is_running()) {
trace_source_return_path_thread_loop_top();
header_type = qemu_get_be16(rp);
@ -2478,7 +2439,7 @@ static int open_return_path_on_source(MigrationState *ms)
trace_open_return_path_on_source();
qemu_thread_create(&ms->rp_state.rp_thread, "mig/src/rp-thr",
qemu_thread_create(&ms->rp_state.rp_thread, MIGRATION_THREAD_SRC_RETURN,
source_return_path_thread, ms, QEMU_THREAD_JOINABLE);
ms->rp_state.rp_thread_created = true;
@ -3288,10 +3249,17 @@ static MigIterateState migration_iteration_run(MigrationState *s)
static void migration_iteration_finish(MigrationState *s)
{
/* If we enabled cpu throttling for auto-converge, turn it off. */
cpu_throttle_stop();
bql_lock();
/*
* If we enabled cpu throttling for auto-converge, turn it off.
* Stopping CPU throttle should be serialized by BQL to avoid
* racing for the throttle_dirty_sync_timer.
*/
if (migrate_auto_converge()) {
cpu_throttle_stop();
}
switch (s->state) {
case MIGRATION_STATUS_COMPLETED:
runstate_set(RUN_STATE_POSTMIGRATE);
@ -3467,11 +3435,11 @@ static void *migration_thread(void *opaque)
Error *local_err = NULL;
int ret;
thread = migration_threads_add("live_migration", qemu_get_thread_id());
thread = migration_threads_add(MIGRATION_THREAD_SRC_MAIN,
qemu_get_thread_id());
rcu_register_thread();
object_ref(OBJECT(s));
update_iteration_initial_status(s);
if (!multifd_send_setup()) {
@ -3508,6 +3476,11 @@ static void *migration_thread(void *opaque)
qemu_savevm_send_colo_enable(s->to_dst_file);
}
if (migrate_auto_converge()) {
/* Start RAMBlock dirty bitmap sync timer */
cpu_throttle_dirty_sync_timer(true);
}
bql_lock();
ret = qemu_savevm_state_setup(s->to_dst_file, &local_err);
bql_unlock();
@ -3604,7 +3577,6 @@ static void *bg_migration_thread(void *opaque)
int ret;
rcu_register_thread();
object_ref(OBJECT(s));
migration_rate_set(RATE_LIMIT_DISABLED);
@ -3816,11 +3788,19 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
}
}
/*
* Take a refcount to make sure the migration object won't get freed by
* the main thread already in migration_shutdown().
*
* The refcount will be released at the end of the thread function.
*/
object_ref(OBJECT(s));
if (migrate_background_snapshot()) {
qemu_thread_create(&s->thread, "mig/snapshot",
qemu_thread_create(&s->thread, MIGRATION_THREAD_SNAPSHOT,
bg_migration_thread, s, QEMU_THREAD_JOINABLE);
} else {
qemu_thread_create(&s->thread, "mig/src/main",
qemu_thread_create(&s->thread, MIGRATION_THREAD_SRC_MAIN,
migration_thread, s, QEMU_THREAD_JOINABLE);
}
s->migration_thread_running = true;

View File

@ -28,6 +28,20 @@
#include "sysemu/runstate.h"
#include "migration/misc.h"
#define MIGRATION_THREAD_SNAPSHOT "mig/snapshot"
#define MIGRATION_THREAD_DIRTY_RATE "mig/dirtyrate"
#define MIGRATION_THREAD_SRC_MAIN "mig/src/main"
#define MIGRATION_THREAD_SRC_MULTIFD "mig/src/send_%d"
#define MIGRATION_THREAD_SRC_RETURN "mig/src/return"
#define MIGRATION_THREAD_SRC_TLS "mig/src/tls"
#define MIGRATION_THREAD_DST_COLO "mig/dst/colo"
#define MIGRATION_THREAD_DST_MULTIFD "mig/src/recv_%d"
#define MIGRATION_THREAD_DST_FAULT "mig/dst/fault"
#define MIGRATION_THREAD_DST_LISTEN "mig/dst/listen"
#define MIGRATION_THREAD_DST_PREEMPT "mig/dst/preempt"
struct PostcopyBlocktimeContext;
#define MIGRATION_RESUME_ACK_VALUE (1)
@ -537,4 +551,9 @@ int migration_rp_wait(MigrationState *s);
*/
void migration_rp_kick(MigrationState *s);
void migration_bitmap_sync_precopy(bool last_stage);
/* migration/block-dirty-bitmap.c */
void dirty_bitmap_mig_init(void);
#endif

View File

@ -600,6 +600,7 @@ static void *multifd_send_thread(void *opaque)
* qatomic_store_release() in multifd_send().
*/
if (qatomic_load_acquire(&p->pending_job)) {
p->flags = 0;
p->iovs_num = 0;
assert(!multifd_payload_empty(p->data));
@ -651,7 +652,6 @@ static void *multifd_send_thread(void *opaque)
}
/* p->next_packet_size will always be zero for a SYNC packet */
stat64_add(&mig_stats.multifd_bytes, p->packet_len);
p->flags = 0;
}
qatomic_set(&p->pending_sync, false);
@ -723,7 +723,7 @@ static bool multifd_tls_channel_connect(MultiFDSendParams *p,
args->p = p;
p->tls_thread_created = true;
qemu_thread_create(&p->tls_thread, "mig/src/tls",
qemu_thread_create(&p->tls_thread, MIGRATION_THREAD_SRC_TLS,
multifd_tls_handshake_thread, args,
QEMU_THREAD_JOINABLE);
return true;
@ -841,7 +841,7 @@ bool multifd_send_setup(void)
+ sizeof(uint64_t) * page_count;
p->packet = g_malloc0(p->packet_len);
}
p->name = g_strdup_printf("mig/src/send_%d", i);
p->name = g_strdup_printf(MIGRATION_THREAD_SRC_MULTIFD, i);
p->write_flags = 0;
if (!multifd_new_send_channel_create(p, &local_err)) {
@ -1259,7 +1259,7 @@ int multifd_recv_setup(Error **errp)
+ sizeof(uint64_t) * page_count;
p->packet = g_malloc0(p->packet_len);
}
p->name = g_strdup_printf("mig/dst/recv_%d", i);
p->name = g_strdup_printf(MIGRATION_THREAD_DST_MULTIFD, i);
p->normal = g_new0(ram_addr_t, page_count);
p->zero = g_new0(ram_addr_t, page_count);
}

View File

@ -1230,7 +1230,8 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
return -1;
}
postcopy_thread_create(mis, &mis->fault_thread, "mig/dst/fault",
postcopy_thread_create(mis, &mis->fault_thread,
MIGRATION_THREAD_DST_FAULT,
postcopy_ram_fault_thread, QEMU_THREAD_JOINABLE);
mis->have_fault_thread = true;
@ -1250,7 +1251,8 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
* This thread needs to be created after the temp pages because
* it'll fetch RAM_CHANNEL_POSTCOPY PostcopyTmpPage immediately.
*/
postcopy_thread_create(mis, &mis->postcopy_prio_thread, "mig/dst/preempt",
postcopy_thread_create(mis, &mis->postcopy_prio_thread,
MIGRATION_THREAD_DST_PREEMPT,
postcopy_preempt_thread, QEMU_THREAD_JOINABLE);
mis->preempt_thread_status = PREEMPT_THREAD_CREATED;
}

View File

@ -1088,9 +1088,10 @@ static void migration_bitmap_sync(RAMState *rs, bool last_stage)
}
}
static void migration_bitmap_sync_precopy(RAMState *rs, bool last_stage)
void migration_bitmap_sync_precopy(bool last_stage)
{
Error *local_err = NULL;
assert(ram_state);
/*
* The current notifier usage is just an optimization to migration, so we
@ -1101,7 +1102,7 @@ static void migration_bitmap_sync_precopy(RAMState *rs, bool last_stage)
local_err = NULL;
}
migration_bitmap_sync(rs, last_stage);
migration_bitmap_sync(ram_state, last_stage);
if (precopy_notify(PRECOPY_NOTIFY_AFTER_BITMAP_SYNC, &local_err)) {
error_report_err(local_err);
@ -2782,7 +2783,7 @@ static bool ram_init_bitmaps(RAMState *rs, Error **errp)
if (!ret) {
goto out_unlock;
}
migration_bitmap_sync_precopy(rs, false);
migration_bitmap_sync_precopy(false);
}
}
out_unlock:
@ -2859,7 +2860,7 @@ void qemu_guest_free_page_hint(void *addr, size_t len)
size_t used_len, start, npages;
/* This function is currently expected to be used during live migration */
if (!migration_is_setup_or_active()) {
if (!migration_is_running()) {
return;
}
@ -3207,8 +3208,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
}
out:
if (ret >= 0
&& migration_is_setup_or_active()) {
if (ret >= 0 && migration_is_running()) {
if (migrate_multifd() && migrate_multifd_flush_after_each_section() &&
!migrate_mapped_ram()) {
ret = multifd_ram_flush_and_sync();
@ -3248,7 +3248,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
WITH_RCU_READ_LOCK_GUARD() {
if (!migration_in_postcopy()) {
migration_bitmap_sync_precopy(rs, true);
migration_bitmap_sync_precopy(true);
}
ret = rdma_registration_start(f, RAM_CONTROL_FINISH);
@ -3330,7 +3330,7 @@ static void ram_state_pending_exact(void *opaque, uint64_t *must_precopy,
if (!migration_in_postcopy()) {
bql_lock();
WITH_RCU_READ_LOCK_GUARD() {
migration_bitmap_sync_precopy(rs, false);
migration_bitmap_sync_precopy(false);
}
bql_unlock();
}
@ -4294,6 +4294,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
* it will be necessary to reduce the granularity of this
* critical section.
*/
trace_ram_load_start();
WITH_RCU_READ_LOCK_GUARD() {
if (postcopy_running) {
/*
@ -4498,7 +4499,7 @@ static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host,
return;
}
if (!migration_is_idle()) {
if (migration_is_running()) {
/*
* Precopy code on the source cannot deal with the size of RAM blocks
* changing at random points in time - especially after sending the

View File

@ -44,6 +44,7 @@ extern XBZRLECacheStats xbzrle_counters;
INTERNAL_RAMBLOCK_FOREACH(block) \
if (!qemu_ram_is_migratable(block)) {} else
void ram_mig_init(void);
int xbzrle_cache_resize(uint64_t new_size, Error **errp);
uint64_t ram_bytes_remaining(void);
uint64_t ram_bytes_total(void);

View File

@ -2131,7 +2131,8 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)
}
mis->have_listen_thread = true;
postcopy_thread_create(mis, &mis->listen_thread, "mig/dst/listen",
postcopy_thread_create(mis, &mis->listen_thread,
MIGRATION_THREAD_DST_LISTEN,
postcopy_ram_listen_thread, QEMU_THREAD_DETACHED);
trace_loadvm_postcopy_handle_listen("return");

View File

@ -115,6 +115,7 @@ colo_flush_ram_cache_end(void) ""
save_xbzrle_page_skipping(void) ""
save_xbzrle_page_overflow(void) ""
ram_save_iterate_big_wait(uint64_t milliconds, int iterations) "big wait: %" PRIu64 " milliseconds, %d iterations"
ram_load_start(void) ""
ram_load_complete(int ret, uint64_t seq_iter) "exit_code %d seq iteration %" PRIu64
ram_write_tracking_ramblock_start(const char *block_id, size_t page_size, void *addr, size_t length) "%s: page_size: %zu addr: %p length: %zu"
ram_write_tracking_ramblock_stop(const char *block_id, size_t page_size, void *addr, size_t length) "%s: page_size: %zu addr: %p length: %zu"
@ -378,3 +379,7 @@ migration_block_progression(unsigned percent) "Completed %u%%"
# page_cache.c
migration_pagecache_init(int64_t max_num_items) "Setting cache buckets to %" PRId64
migration_pagecache_insert(void) "Error allocating page"
# cpu-throttle.c
cpu_throttle_set(int new_throttle_pct) "set guest CPU throttled by %d%%"
cpu_throttle_dirty_sync(void) ""

View File

@ -22,7 +22,8 @@
#include "trace.h"
static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, JSONWriter *vmdesc);
void *opaque, JSONWriter *vmdesc,
Error **errp);
static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque);
@ -441,12 +442,13 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
json_writer_end_array(vmdesc);
}
ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc);
ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc, errp);
if (vmsd->post_save) {
int ps_ret = vmsd->post_save(opaque);
if (!ret) {
if (!ret && ps_ret) {
ret = ps_ret;
error_setg(errp, "post-save failed: %s", vmsd->name);
}
}
return ret;
@ -518,7 +520,8 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
}
static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, JSONWriter *vmdesc)
void *opaque, JSONWriter *vmdesc,
Error **errp)
{
const VMStateDescription * const *sub = vmsd->subsections;
bool vmdesc_has_subsections = false;
@ -546,7 +549,7 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
qemu_put_byte(f, len);
qemu_put_buffer(f, (uint8_t *)vmsdsub->name, len);
qemu_put_be32(f, vmsdsub->version_id);
ret = vmstate_save_state(f, vmsdsub, opaque, vmdesc);
ret = vmstate_save_state_with_err(f, vmsdsub, opaque, vmdesc, errp);
if (ret) {
return ret;
}

View File

@ -375,8 +375,7 @@ static int vhost_vdpa_net_data_start(NetClientState *nc)
assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
if (s->always_svq ||
migration_is_setup_or_active()) {
if (s->always_svq || migration_is_running()) {
v->shadow_vqs_enabled = true;
} else {
v->shadow_vqs_enabled = false;

View File

@ -2284,12 +2284,17 @@
#
# Returns information of migration threads
#
# Features:
#
# @deprecated: This command is deprecated with no replacement yet.
#
# Returns: @MigrationThreadInfo
#
# Since: 7.2
##
{ 'command': 'query-migrationthreads',
'returns': ['MigrationThreadInfo'] }
'returns': ['MigrationThreadInfo'],
'features': ['deprecated'] }
##
# @snapshot-save:

View File

@ -35,7 +35,6 @@
#include "sysemu/runstate.h"
#include "hw/core/cpu.h"
#include "sysemu/cpu-timers.h"
#include "sysemu/cpu-throttle.h"
#include "sysemu/cpu-timers-internal.h"
/* clock and ticks */
@ -272,6 +271,4 @@ void cpu_timers_init(void)
seqlock_init(&timers_state.vm_clock_seqlock);
qemu_spin_init(&timers_state.vm_clock_lock);
vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
cpu_throttle_init();
}

View File

@ -10,7 +10,6 @@ system_ss.add(files(
'balloon.c',
'bootdevice.c',
'cpus.c',
'cpu-throttle.c',
'cpu-timers.c',
'datadir.c',
'dirtylimit.c',

View File

@ -679,7 +679,7 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts,
return NULL;
}
if (!migration_is_idle()) {
if (migration_is_running()) {
error_setg(errp, "device_add not allowed while migrating");
return NULL;
}
@ -928,7 +928,7 @@ void qdev_unplug(DeviceState *dev, Error **errp)
return;
}
if (!migration_is_idle() && !dev->allow_unplug_during_migration) {
if (migration_is_running() && !dev->allow_unplug_during_migration) {
error_setg(errp, "device_del not allowed while migrating");
return;
}

View File

@ -44,6 +44,3 @@ dirtylimit_state_finalize(void)
dirtylimit_throttle_pct(int cpu_index, uint64_t pct, int64_t time_us) "CPU[%d] throttle percent: %" PRIu64 ", throttle adjust time %"PRIi64 " us"
dirtylimit_set_vcpu(int cpu_index, uint64_t quota) "CPU[%d] set dirty page rate limit %"PRIu64
dirtylimit_vcpu_execute(int cpu_index, int64_t sleep_time_us) "CPU[%d] sleep %"PRIi64 " us"
# cpu-throttle.c
cpu_throttle_set(int new_throttle_pct) "set guest CPU throttled by %d%%"

View File

@ -2791,6 +2791,8 @@ static void test_migrate_auto_converge(void)
* so we need to decrease a bandwidth.
*/
const int64_t init_pct = 5, inc_pct = 25, max_pct = 95;
uint64_t prev_dirty_sync_cnt, dirty_sync_cnt;
int max_try_count, hit = 0;
if (test_migrate_start(&from, &to, uri, &args)) {
return;
@ -2827,6 +2829,36 @@ static void test_migrate_auto_converge(void)
} while (true);
/* The first percentage of throttling should be at least init_pct */
g_assert_cmpint(percentage, >=, init_pct);
/*
* End the loop when the dirty sync count greater than 1.
*/
while ((dirty_sync_cnt = get_migration_pass(from)) < 2) {
usleep(1000 * 1000);
}
prev_dirty_sync_cnt = dirty_sync_cnt;
/*
* The RAMBlock dirty sync count must changes in 5 seconds, here we set
* the timeout to 10 seconds to ensure it changes.
*
* Note that migrate_ensure_non_converge set the max-bandwidth to 3MB/s,
* while the qtest mem is >= 100MB, one iteration takes at least 33s (100/3)
* to complete; this ensures that the RAMBlock dirty sync occurs.
*/
max_try_count = 10;
while (--max_try_count) {
dirty_sync_cnt = get_migration_pass(from);
if (dirty_sync_cnt != prev_dirty_sync_cnt) {
hit = 1;
break;
}
prev_dirty_sync_cnt = dirty_sync_cnt;
sleep(1);
}
g_assert_cmpint(hit, ==, 1);
/* Now, when we tested that throttling works, let it converge */
migrate_ensure_converge(from);