diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h index 2825e231a7..8344daaa03 100644 --- a/include/qemu/mmap-alloc.h +++ b/include/qemu/mmap-alloc.h @@ -1,8 +1,15 @@ #ifndef QEMU_MMAP_ALLOC_H #define QEMU_MMAP_ALLOC_H +typedef enum { + QEMU_FS_TYPE_UNKNOWN = 0, + QEMU_FS_TYPE_TMPFS, + QEMU_FS_TYPE_HUGETLBFS, + QEMU_FS_TYPE_NUM, +} QemuFsType; size_t qemu_fd_getpagesize(int fd); +QemuFsType qemu_fd_getfs(int fd); /** * qemu_ram_mmap: mmap anonymous memory, the specified file or device. diff --git a/migration/migration.c b/migration/migration.c index bda4789193..d91fe9fd86 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -364,8 +364,7 @@ static bool migrate_late_block_activate(void) s = migrate_get_current(); - return s->enabled_capabilities[ - MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]; + return s->capabilities[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]; } /* @@ -944,7 +943,7 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp) #endif caps = g_malloc0(sizeof(*caps)); caps->capability = i; - caps->state = s->enabled_capabilities[i]; + caps->state = s->capabilities[i]; QAPI_LIST_APPEND(tail, caps); } @@ -1140,24 +1139,26 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) size_t page_size = qemu_target_page_size(); info->ram = g_malloc0(sizeof(*info->ram)); - info->ram->transferred = stat64_get(&ram_atomic_counters.transferred); + info->ram->transferred = stat64_get(&ram_counters.transferred); info->ram->total = ram_bytes_total(); - info->ram->duplicate = stat64_get(&ram_atomic_counters.duplicate); + info->ram->duplicate = stat64_get(&ram_counters.zero_pages); /* legacy value. It is not used anymore */ info->ram->skipped = 0; - info->ram->normal = stat64_get(&ram_atomic_counters.normal); + info->ram->normal = stat64_get(&ram_counters.normal_pages); info->ram->normal_bytes = info->ram->normal * page_size; info->ram->mbps = s->mbps; - info->ram->dirty_sync_count = ram_counters.dirty_sync_count; + info->ram->dirty_sync_count = + stat64_get(&ram_counters.dirty_sync_count); info->ram->dirty_sync_missed_zero_copy = - ram_counters.dirty_sync_missed_zero_copy; - info->ram->postcopy_requests = ram_counters.postcopy_requests; + stat64_get(&ram_counters.dirty_sync_missed_zero_copy); + info->ram->postcopy_requests = + stat64_get(&ram_counters.postcopy_requests); info->ram->page_size = page_size; - info->ram->multifd_bytes = ram_counters.multifd_bytes; + info->ram->multifd_bytes = stat64_get(&ram_counters.multifd_bytes); info->ram->pages_per_second = s->pages_per_second; - info->ram->precopy_bytes = ram_counters.precopy_bytes; - info->ram->downtime_bytes = ram_counters.downtime_bytes; - info->ram->postcopy_bytes = stat64_get(&ram_atomic_counters.postcopy_bytes); + info->ram->precopy_bytes = stat64_get(&ram_counters.precopy_bytes); + info->ram->downtime_bytes = stat64_get(&ram_counters.downtime_bytes); + info->ram->postcopy_bytes = stat64_get(&ram_counters.postcopy_bytes); if (migrate_use_xbzrle()) { info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache)); @@ -1298,30 +1299,20 @@ WriteTrackingSupport migrate_query_write_tracking(void) } /** - * @migration_caps_check - check capability validity + * @migration_caps_check - check capability compatibility * - * @cap_list: old capability list, array of bool - * @params: new capabilities to be applied soon + * @old_caps: old capability list + * @new_caps: new capability list * @errp: set *errp if the check failed, with reason * * Returns true if check passed, otherwise false. */ -static bool migrate_caps_check(bool *cap_list, - MigrationCapabilityStatusList *params, - Error **errp) +static bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) { - MigrationCapabilityStatusList *cap; - bool old_postcopy_cap; MigrationIncomingState *mis = migration_incoming_get_current(); - old_postcopy_cap = cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]; - - for (cap = params; cap; cap = cap->next) { - cap_list[cap->value->capability] = cap->value->state; - } - #ifndef CONFIG_LIVE_BLOCK_MIGRATION - if (cap_list[MIGRATION_CAPABILITY_BLOCK]) { + if (new_caps[MIGRATION_CAPABILITY_BLOCK]) { error_setg(errp, "QEMU compiled without old-style (blk/-b, inc/-i) " "block migration"); error_append_hint(errp, "Use drive_mirror+NBD instead.\n"); @@ -1330,7 +1321,7 @@ static bool migrate_caps_check(bool *cap_list, #endif #ifndef CONFIG_REPLICATION - if (cap_list[MIGRATION_CAPABILITY_X_COLO]) { + if (new_caps[MIGRATION_CAPABILITY_X_COLO]) { error_setg(errp, "QEMU compiled without replication module" " can't enable COLO"); error_append_hint(errp, "Please enable replication before COLO.\n"); @@ -1338,12 +1329,13 @@ static bool migrate_caps_check(bool *cap_list, } #endif - if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) { + if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) { /* This check is reasonably expensive, so only when it's being * set the first time, also it's only the destination that needs * special support. */ - if (!old_postcopy_cap && runstate_check(RUN_STATE_INMIGRATE) && + if (!old_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] && + runstate_check(RUN_STATE_INMIGRATE) && !postcopy_ram_supported_by_host(mis)) { /* postcopy_ram_supported_by_host will have emitted a more * detailed message @@ -1352,13 +1344,13 @@ static bool migrate_caps_check(bool *cap_list, return false; } - if (cap_list[MIGRATION_CAPABILITY_X_IGNORE_SHARED]) { + if (new_caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED]) { error_setg(errp, "Postcopy is not compatible with ignore-shared"); return false; } } - if (cap_list[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) { + if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) { WriteTrackingSupport wt_support; int idx; /* @@ -1382,7 +1374,7 @@ static bool migrate_caps_check(bool *cap_list, */ for (idx = 0; idx < check_caps_background_snapshot.size; idx++) { int incomp_cap = check_caps_background_snapshot.caps[idx]; - if (cap_list[incomp_cap]) { + if (new_caps[incomp_cap]) { error_setg(errp, "Background-snapshot is not compatible with %s", MigrationCapability_str(incomp_cap)); @@ -1392,10 +1384,10 @@ static bool migrate_caps_check(bool *cap_list, } #ifdef CONFIG_LINUX - if (cap_list[MIGRATION_CAPABILITY_ZERO_COPY_SEND] && - (!cap_list[MIGRATION_CAPABILITY_MULTIFD] || - cap_list[MIGRATION_CAPABILITY_COMPRESS] || - cap_list[MIGRATION_CAPABILITY_XBZRLE] || + if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND] && + (!new_caps[MIGRATION_CAPABILITY_MULTIFD] || + new_caps[MIGRATION_CAPABILITY_COMPRESS] || + new_caps[MIGRATION_CAPABILITY_XBZRLE] || migrate_multifd_compression() || migrate_use_tls())) { error_setg(errp, @@ -1403,15 +1395,15 @@ static bool migrate_caps_check(bool *cap_list, return false; } #else - if (cap_list[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) { + if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) { error_setg(errp, "Zero copy currently only available on Linux"); return false; } #endif - if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) { - if (!cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) { + if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) { + if (!new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) { error_setg(errp, "Postcopy preempt requires postcopy-ram"); return false; } @@ -1422,14 +1414,14 @@ static bool migrate_caps_check(bool *cap_list, * different compression channels, which is not compatible with the * preempt assumptions on channel assignments. */ - if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) { + if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) { error_setg(errp, "Postcopy preempt not compatible with compress"); return false; } } - if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) { - if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) { + if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) { + if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) { error_setg(errp, "Multifd is not compatible with compress"); return false; } @@ -1485,20 +1477,24 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params, { MigrationState *s = migrate_get_current(); MigrationCapabilityStatusList *cap; - bool cap_list[MIGRATION_CAPABILITY__MAX]; + bool new_caps[MIGRATION_CAPABILITY__MAX]; if (migration_is_running(s->state)) { error_setg(errp, QERR_MIGRATION_ACTIVE); return; } - memcpy(cap_list, s->enabled_capabilities, sizeof(cap_list)); - if (!migrate_caps_check(cap_list, params, errp)) { + memcpy(new_caps, s->capabilities, sizeof(new_caps)); + for (cap = params; cap; cap = cap->next) { + new_caps[cap->value->capability] = cap->value->state; + } + + if (!migrate_caps_check(s->capabilities, new_caps, errp)) { return; } for (cap = params; cap; cap = cap->next) { - s->enabled_capabilities[cap->value->capability] = cap->value->state; + s->capabilities[cap->value->capability] = cap->value->state; } } @@ -2567,7 +2563,7 @@ bool migrate_release_ram(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_RELEASE_RAM]; + return s->capabilities[MIGRATION_CAPABILITY_RELEASE_RAM]; } bool migrate_postcopy_ram(void) @@ -2576,7 +2572,7 @@ bool migrate_postcopy_ram(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM]; + return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM]; } bool migrate_postcopy(void) @@ -2590,7 +2586,7 @@ bool migrate_auto_converge(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE]; + return s->capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE]; } bool migrate_zero_blocks(void) @@ -2599,7 +2595,7 @@ bool migrate_zero_blocks(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_ZERO_BLOCKS]; + return s->capabilities[MIGRATION_CAPABILITY_ZERO_BLOCKS]; } bool migrate_postcopy_blocktime(void) @@ -2608,7 +2604,7 @@ bool migrate_postcopy_blocktime(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME]; + return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME]; } bool migrate_use_compression(void) @@ -2617,7 +2613,7 @@ bool migrate_use_compression(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_COMPRESS]; + return s->capabilities[MIGRATION_CAPABILITY_COMPRESS]; } int migrate_compress_level(void) @@ -2662,7 +2658,7 @@ bool migrate_dirty_bitmaps(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS]; + return s->capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS]; } bool migrate_ignore_shared(void) @@ -2671,7 +2667,7 @@ bool migrate_ignore_shared(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_X_IGNORE_SHARED]; + return s->capabilities[MIGRATION_CAPABILITY_X_IGNORE_SHARED]; } bool migrate_validate_uuid(void) @@ -2680,7 +2676,7 @@ bool migrate_validate_uuid(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_VALIDATE_UUID]; + return s->capabilities[MIGRATION_CAPABILITY_VALIDATE_UUID]; } bool migrate_use_events(void) @@ -2689,7 +2685,7 @@ bool migrate_use_events(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_EVENTS]; + return s->capabilities[MIGRATION_CAPABILITY_EVENTS]; } bool migrate_use_multifd(void) @@ -2698,7 +2694,7 @@ bool migrate_use_multifd(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_MULTIFD]; + return s->capabilities[MIGRATION_CAPABILITY_MULTIFD]; } bool migrate_pause_before_switchover(void) @@ -2707,8 +2703,7 @@ bool migrate_pause_before_switchover(void) s = migrate_get_current(); - return s->enabled_capabilities[ - MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]; + return s->capabilities[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]; } int migrate_multifd_channels(void) @@ -2755,7 +2750,7 @@ bool migrate_use_zero_copy_send(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND]; + return s->capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND]; } #endif @@ -2774,7 +2769,7 @@ int migrate_use_xbzrle(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_XBZRLE]; + return s->capabilities[MIGRATION_CAPABILITY_XBZRLE]; } uint64_t migrate_xbzrle_cache_size(void) @@ -2801,7 +2796,7 @@ bool migrate_use_block(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_BLOCK]; + return s->capabilities[MIGRATION_CAPABILITY_BLOCK]; } bool migrate_use_return_path(void) @@ -2810,7 +2805,7 @@ bool migrate_use_return_path(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_RETURN_PATH]; + return s->capabilities[MIGRATION_CAPABILITY_RETURN_PATH]; } bool migrate_use_block_incremental(void) @@ -2828,7 +2823,7 @@ bool migrate_background_snapshot(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]; + return s->capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]; } bool migrate_postcopy_preempt(void) @@ -2837,7 +2832,7 @@ bool migrate_postcopy_preempt(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]; + return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]; } /* migration thread support */ @@ -3444,13 +3439,11 @@ static void migration_completion(MigrationState *s) MIGRATION_STATUS_DEVICE); } if (ret >= 0) { + s->block_inactive = inactivate; qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX); ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false, inactivate); } - if (inactivate && ret >= 0) { - s->block_inactive = true; - } } qemu_mutex_unlock_iothread(); @@ -3522,6 +3515,7 @@ fail_invalidate: bdrv_activate_all(&local_err); if (local_err) { error_report_err(local_err); + s->block_inactive = true; } else { s->block_inactive = false; } @@ -3580,7 +3574,7 @@ fail: bool migrate_colo_enabled(void) { MigrationState *s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_X_COLO]; + return s->capabilities[MIGRATION_CAPABILITY_X_COLO]; } typedef enum MigThrError { @@ -3778,7 +3772,7 @@ static MigThrError migration_detect_error(MigrationState *s) static uint64_t migration_total_bytes(MigrationState *s) { return qemu_file_total_transferred(s->to_dst_file) + - ram_counters.multifd_bytes; + stat64_get(&ram_counters.multifd_bytes); } static void migration_calculate_complete(MigrationState *s) @@ -4443,7 +4437,7 @@ void migration_global_dump(Monitor *mon) } #define DEFINE_PROP_MIG_CAP(name, x) \ - DEFINE_PROP_BOOL(name, MigrationState, enabled_capabilities[x], false) + DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false) static Property migration_properties[] = { DEFINE_PROP_BOOL("store-global-state", MigrationState, @@ -4632,27 +4626,14 @@ static void migration_instance_init(Object *obj) */ static bool migration_object_check(MigrationState *ms, Error **errp) { - MigrationCapabilityStatusList *head = NULL; /* Assuming all off */ - bool cap_list[MIGRATION_CAPABILITY__MAX] = { 0 }, ret; - int i; + bool old_caps[MIGRATION_CAPABILITY__MAX] = { 0 }; if (!migrate_params_check(&ms->parameters, errp)) { return false; } - for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { - if (ms->enabled_capabilities[i]) { - QAPI_LIST_PREPEND(head, migrate_cap_add(i, true)); - } - } - - ret = migrate_caps_check(cap_list, head, errp); - - /* It works with head == NULL */ - qapi_free_MigrationCapabilityStatusList(head); - - return ret; + return migrate_caps_check(old_caps, ms->capabilities, errp); } static const TypeInfo migration_type = { diff --git a/migration/migration.h b/migration/migration.h index 310ae8901b..04e0860b4e 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -310,7 +310,7 @@ struct MigrationState { int64_t downtime_start; int64_t downtime; int64_t expected_downtime; - bool enabled_capabilities[MIGRATION_CAPABILITY__MAX]; + bool capabilities[MIGRATION_CAPABILITY__MAX]; int64_t setup_time; /* * Whether guest was running when we enter the completion stage. diff --git a/migration/multifd.c b/migration/multifd.c index cbc0dfe39b..903df2117b 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -432,9 +432,9 @@ static int multifd_send_pages(QEMUFile *f) p->pages = pages; transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len; qemu_file_acct_rate_limit(f, transferred); - ram_counters.multifd_bytes += transferred; - stat64_add(&ram_atomic_counters.transferred, transferred); qemu_mutex_unlock(&p->mutex); + stat64_add(&ram_counters.transferred, transferred); + stat64_add(&ram_counters.multifd_bytes, transferred); qemu_sem_post(&p->sem); return 1; @@ -576,7 +576,7 @@ static int multifd_zero_copy_flush(QIOChannel *c) return -1; } if (ret == 1) { - dirty_sync_missed_zero_copy(); + stat64_add(&ram_counters.dirty_sync_missed_zero_copy, 1); } return ret; @@ -627,9 +627,9 @@ int multifd_send_sync_main(QEMUFile *f) p->flags |= MULTIFD_FLAG_SYNC; p->pending_job++; qemu_file_acct_rate_limit(f, p->packet_len); - ram_counters.multifd_bytes += p->packet_len; - stat64_add(&ram_atomic_counters.transferred, p->packet_len); qemu_mutex_unlock(&p->mutex); + stat64_add(&ram_counters.transferred, p->packet_len); + stat64_add(&ram_counters.multifd_bytes, p->packet_len); qemu_sem_post(&p->sem); } for (i = 0; i < migrate_multifd_channels(); i++) { diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 7d24dac397..d7b48dd920 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -36,6 +36,7 @@ #include "yank_functions.h" #include "tls.h" #include "qemu/userfaultfd.h" +#include "qemu/mmap-alloc.h" /* Arbitrary limit on size of each discard command, * keeps them around ~200 bytes @@ -336,11 +337,12 @@ static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis) /* Callback from postcopy_ram_supported_by_host block iterator. */ -static int test_ramblock_postcopiable(RAMBlock *rb, void *opaque) +static int test_ramblock_postcopiable(RAMBlock *rb) { const char *block_name = qemu_ram_get_idstr(rb); ram_addr_t length = qemu_ram_get_used_length(rb); size_t pagesize = qemu_ram_pagesize(rb); + QemuFsType fs; if (length % pagesize) { error_report("Postcopy requires RAM blocks to be a page size multiple," @@ -348,6 +350,15 @@ static int test_ramblock_postcopiable(RAMBlock *rb, void *opaque) "page size of 0x%zx", block_name, length, pagesize); return 1; } + + if (rb->fd >= 0) { + fs = qemu_fd_getfs(rb->fd); + if (fs != QEMU_FS_TYPE_TMPFS && fs != QEMU_FS_TYPE_HUGETLBFS) { + error_report("Host backend files need to be TMPFS or HUGETLBFS only"); + return 1; + } + } + return 0; } @@ -366,6 +377,7 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis) struct uffdio_range range_struct; uint64_t feature_mask; Error *local_err = NULL; + RAMBlock *block; if (qemu_target_page_size() > pagesize) { error_report("Target page size bigger than host page size"); @@ -390,9 +402,23 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis) goto out; } - /* We don't support postcopy with shared RAM yet */ - if (foreach_not_ignored_block(test_ramblock_postcopiable, NULL)) { - goto out; + /* + * We don't support postcopy with some type of ramblocks. + * + * NOTE: we explicitly ignored ramblock_is_ignored() instead we checked + * all possible ramblocks. This is because this function can be called + * when creating the migration object, during the phase RAM_MIGRATABLE + * is not even properly set for all the ramblocks. + * + * A side effect of this is we'll also check against RAM_SHARED + * ramblocks even if migrate_ignore_shared() is set (in which case + * we'll never migrate RAM_SHARED at all), but normally this shouldn't + * affect in reality, or we can revisit. + */ + RAMBLOCK_FOREACH(block) { + if (test_ramblock_postcopiable(block)) { + goto out; + } } /* diff --git a/migration/ram.c b/migration/ram.c index 79d881f735..229714045a 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -458,30 +458,18 @@ uint64_t ram_bytes_remaining(void) 0; } -/* - * NOTE: not all stats in ram_counters are used in reality. See comments - * for struct MigrationAtomicStats. The ultimate result of ram migration - * counters will be a merged version with both ram_counters and the atomic - * fields in ram_atomic_counters. - */ -MigrationStats ram_counters; -MigrationAtomicStats ram_atomic_counters; +RAMStats ram_counters; void ram_transferred_add(uint64_t bytes) { if (runstate_is_running()) { - ram_counters.precopy_bytes += bytes; + stat64_add(&ram_counters.precopy_bytes, bytes); } else if (migration_in_postcopy()) { - stat64_add(&ram_atomic_counters.postcopy_bytes, bytes); + stat64_add(&ram_counters.postcopy_bytes, bytes); } else { - ram_counters.downtime_bytes += bytes; + stat64_add(&ram_counters.downtime_bytes, bytes); } - stat64_add(&ram_atomic_counters.transferred, bytes); -} - -void dirty_sync_missed_zero_copy(void) -{ - ram_counters.dirty_sync_missed_zero_copy++; + stat64_add(&ram_counters.transferred, bytes); } struct MigrationOps { @@ -756,7 +744,7 @@ void mig_throttle_counter_reset(void) rs->time_last_bitmap_sync = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); rs->num_dirty_pages_period = 0; - rs->bytes_xfer_prev = stat64_get(&ram_atomic_counters.transferred); + rs->bytes_xfer_prev = stat64_get(&ram_counters.transferred); } /** @@ -776,7 +764,7 @@ static void xbzrle_cache_zero_page(RAMState *rs, ram_addr_t current_addr) /* We don't care if this fails to allocate a new cache page * as long as it updated an old one */ cache_insert(XBZRLE.cache, current_addr, XBZRLE.zero_target_page, - ram_counters.dirty_sync_count); + stat64_get(&ram_counters.dirty_sync_count)); } #define ENCODING_FLAG_XBZRLE 0x1 @@ -802,13 +790,13 @@ static int save_xbzrle_page(RAMState *rs, PageSearchStatus *pss, int encoded_len = 0, bytes_xbzrle; uint8_t *prev_cached_page; QEMUFile *file = pss->pss_channel; + uint64_t generation = stat64_get(&ram_counters.dirty_sync_count); - if (!cache_is_cached(XBZRLE.cache, current_addr, - ram_counters.dirty_sync_count)) { + if (!cache_is_cached(XBZRLE.cache, current_addr, generation)) { xbzrle_counters.cache_miss++; if (!rs->last_stage) { if (cache_insert(XBZRLE.cache, current_addr, *current_data, - ram_counters.dirty_sync_count) == -1) { + generation) == -1) { return -1; } else { /* update *current_data when the page has been @@ -1130,8 +1118,8 @@ uint64_t ram_pagesize_summary(void) uint64_t ram_get_total_transferred_pages(void) { - return stat64_get(&ram_atomic_counters.normal) + - stat64_get(&ram_atomic_counters.duplicate) + + return stat64_get(&ram_counters.normal_pages) + + stat64_get(&ram_counters.zero_pages) + compression_counters.pages + xbzrle_counters.pages; } @@ -1192,7 +1180,7 @@ static void migration_trigger_throttle(RAMState *rs) MigrationState *s = migrate_get_current(); uint64_t threshold = s->parameters.throttle_trigger_threshold; uint64_t bytes_xfer_period = - stat64_get(&ram_atomic_counters.transferred) - rs->bytes_xfer_prev; + stat64_get(&ram_counters.transferred) - rs->bytes_xfer_prev; uint64_t bytes_dirty_period = rs->num_dirty_pages_period * TARGET_PAGE_SIZE; uint64_t bytes_dirty_threshold = bytes_xfer_period * threshold / 100; @@ -1221,7 +1209,7 @@ static void migration_bitmap_sync(RAMState *rs) RAMBlock *block; int64_t end_time; - ram_counters.dirty_sync_count++; + stat64_add(&ram_counters.dirty_sync_count, 1); if (!rs->time_last_bitmap_sync) { rs->time_last_bitmap_sync = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); @@ -1255,10 +1243,11 @@ static void migration_bitmap_sync(RAMState *rs) /* reset period counters */ rs->time_last_bitmap_sync = end_time; rs->num_dirty_pages_period = 0; - rs->bytes_xfer_prev = stat64_get(&ram_atomic_counters.transferred); + rs->bytes_xfer_prev = stat64_get(&ram_counters.transferred); } if (migrate_use_events()) { - qapi_event_send_migration_pass(ram_counters.dirty_sync_count); + uint64_t generation = stat64_get(&ram_counters.dirty_sync_count); + qapi_event_send_migration_pass(generation); } } @@ -1331,7 +1320,7 @@ static int save_zero_page(PageSearchStatus *pss, QEMUFile *f, RAMBlock *block, int len = save_zero_page_to_file(pss, f, block, offset); if (len) { - stat64_add(&ram_atomic_counters.duplicate, 1); + stat64_add(&ram_counters.zero_pages, 1); ram_transferred_add(len); return 1; } @@ -1368,9 +1357,9 @@ static bool control_save_page(PageSearchStatus *pss, RAMBlock *block, } if (bytes_xmit > 0) { - stat64_add(&ram_atomic_counters.normal, 1); + stat64_add(&ram_counters.normal_pages, 1); } else if (bytes_xmit == 0) { - stat64_add(&ram_atomic_counters.duplicate, 1); + stat64_add(&ram_counters.zero_pages, 1); } return true; @@ -1402,7 +1391,7 @@ static int save_normal_page(PageSearchStatus *pss, RAMBlock *block, qemu_put_buffer(file, buf, TARGET_PAGE_SIZE); } ram_transferred_add(TARGET_PAGE_SIZE); - stat64_add(&ram_atomic_counters.normal, 1); + stat64_add(&ram_counters.normal_pages, 1); return 1; } @@ -1458,7 +1447,7 @@ static int ram_save_multifd_page(QEMUFile *file, RAMBlock *block, if (multifd_queue_page(file, block, offset) < 0) { return -1; } - stat64_add(&ram_atomic_counters.normal, 1); + stat64_add(&ram_counters.normal_pages, 1); return 1; } @@ -1497,7 +1486,7 @@ update_compress_thread_counts(const CompressParam *param, int bytes_xmit) ram_transferred_add(bytes_xmit); if (param->zero_page) { - stat64_add(&ram_atomic_counters.duplicate, 1); + stat64_add(&ram_counters.zero_pages, 1); return; } @@ -2180,7 +2169,7 @@ int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len) RAMBlock *ramblock; RAMState *rs = ram_state; - ram_counters.postcopy_requests++; + stat64_add(&ram_counters.postcopy_requests, 1); RCU_READ_LOCK_GUARD(); if (!rbname) { @@ -2632,9 +2621,9 @@ void acct_update_position(QEMUFile *f, size_t size, bool zero) uint64_t pages = size / TARGET_PAGE_SIZE; if (zero) { - stat64_add(&ram_atomic_counters.duplicate, pages); + stat64_add(&ram_counters.zero_pages, pages); } else { - stat64_add(&ram_atomic_counters.normal, pages); + stat64_add(&ram_counters.normal_pages, pages); ram_transferred_add(size); qemu_file_credit_transfer(f, size); } @@ -3293,7 +3282,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) migration_ops = g_malloc0(sizeof(MigrationOps)); migration_ops->ram_save_target_page = ram_save_target_page_legacy; - ret = multifd_send_sync_main(f); + ret = multifd_send_sync_main(f); if (ret < 0) { return ret; } diff --git a/migration/ram.h b/migration/ram.h index 81cbb0947c..a6e0d70226 100644 --- a/migration/ram.h +++ b/migration/ram.h @@ -35,25 +35,27 @@ #include "qemu/stats64.h" /* - * These are the migration statistic counters that need to be updated using - * atomic ops (can be accessed by more than one thread). Here since we - * cannot modify MigrationStats directly to use Stat64 as it was defined in - * the QAPI scheme, we define an internal structure to hold them, and we - * propagate the real values when QMP queries happen. - * - * IOW, the corresponding fields within ram_counters on these specific - * fields will be always zero and not being used at all; they're just - * placeholders to make it QAPI-compatible. + * These are the ram migration statistic counters. It is loosely + * based on MigrationStats. We change to Stat64 any counter that + * needs to be updated using atomic ops (can be accessed by more than + * one thread). */ typedef struct { - Stat64 transferred; - Stat64 duplicate; - Stat64 normal; + int64_t dirty_pages_rate; + Stat64 dirty_sync_count; + Stat64 dirty_sync_missed_zero_copy; + Stat64 downtime_bytes; + Stat64 zero_pages; + Stat64 multifd_bytes; + Stat64 normal_pages; Stat64 postcopy_bytes; -} MigrationAtomicStats; + Stat64 postcopy_requests; + Stat64 precopy_bytes; + int64_t remaining; + Stat64 transferred; +} RAMStats; -extern MigrationAtomicStats ram_atomic_counters; -extern MigrationStats ram_counters; +extern RAMStats ram_counters; extern XBZRLECacheStats xbzrle_counters; extern CompressionStats compression_counters; @@ -112,6 +114,4 @@ void ram_write_tracking_prepare(void); int ram_write_tracking_start(void); void ram_write_tracking_stop(void); -void dirty_sync_missed_zero_copy(void); - #endif diff --git a/migration/rdma.c b/migration/rdma.c index df646be35e..f35f021963 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -4179,7 +4179,7 @@ void rdma_start_outgoing_migration(void *opaque, } ret = qemu_rdma_source_init(rdma, - s->enabled_capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp); + s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp); if (ret) { goto err; @@ -4201,7 +4201,7 @@ void rdma_start_outgoing_migration(void *opaque, } ret = qemu_rdma_source_init(rdma_return_path, - s->enabled_capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp); + s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp); if (ret) { goto return_path_err; diff --git a/migration/savevm.c b/migration/savevm.c index aa54a67fda..589ef926ab 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -253,7 +253,7 @@ static uint32_t get_validatable_capabilities_count(void) uint32_t result = 0; int i; for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { - if (should_validate_capability(i) && s->enabled_capabilities[i]) { + if (should_validate_capability(i) && s->capabilities[i]) { result++; } } @@ -275,7 +275,7 @@ static int configuration_pre_save(void *opaque) state->capabilities = g_renew(MigrationCapability, state->capabilities, state->caps_count); for (i = j = 0; i < MIGRATION_CAPABILITY__MAX; i++) { - if (should_validate_capability(i) && s->enabled_capabilities[i]) { + if (should_validate_capability(i) && s->capabilities[i]) { state->capabilities[j++] = i; } } @@ -325,7 +325,7 @@ static bool configuration_validate_capabilities(SaveState *state) continue; } source_state = test_bit(i, source_caps_bm); - target_state = s->enabled_capabilities[i]; + target_state = s->capabilities[i]; if (source_state != target_state) { error_report("Capability %s is %s, but received capability is %s", MigrationCapability_str(i), diff --git a/softmmu/vl.c b/softmmu/vl.c index 5cb72a56fc..fb6c221e8e 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3583,14 +3583,19 @@ void qemu_init(int argc, char **argv) machine_class->name, machine_class->deprecation_reason); } + /* + * Create backends before creating migration objects, so that it can + * check against compatibilities on the backend memories (e.g. postcopy + * over memory-backend-file objects). + */ + qemu_create_late_backends(); + /* * Note: creates a QOM object, must run only after global and * compat properties have been set up. */ migration_object_init(); - qemu_create_late_backends(); - /* parse features once if machine provides default cpu_type */ current_machine->cpu_type = machine_class->default_cpu_type; if (cpu_option) { diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c index 5ed7d29183..ed14f9c64d 100644 --- a/util/mmap-alloc.c +++ b/util/mmap-alloc.c @@ -27,8 +27,36 @@ #ifdef CONFIG_LINUX #include +#include #endif +QemuFsType qemu_fd_getfs(int fd) +{ +#ifdef CONFIG_LINUX + struct statfs fs; + int ret; + + if (fd < 0) { + return QEMU_FS_TYPE_UNKNOWN; + } + + do { + ret = fstatfs(fd, &fs); + } while (ret != 0 && errno == EINTR); + + switch (fs.f_type) { + case TMPFS_MAGIC: + return QEMU_FS_TYPE_TMPFS; + case HUGETLBFS_MAGIC: + return QEMU_FS_TYPE_HUGETLBFS; + default: + return QEMU_FS_TYPE_UNKNOWN; + } +#else + return QEMU_FS_TYPE_UNKNOWN; +#endif +} + size_t qemu_fd_getpagesize(int fd) { #ifdef CONFIG_LINUX