Migration Pull request (Take 2)

Hi
 
 This time I have disabled vmstate canary patches form Dave Gilbert.
 
 Let's see if it works.
 
 Later, Juan.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEGJn/jt6/WMzuA0uC9IfvGFhy1yMFAmH0NkEACgkQ9IfvGFhy
 1yM4VQ/+MML5ugA9XA5hOFV+Stwv2ENtMR4r4raQsC7UKdKMaCNuoj1BdlXMRaki
 E2TpoHYq99rfJX+AA0XihxHh84I1l9fpoiXrcr8pgNmhcj0qkBykY9Elzf95woMM
 UMyinL2jhHfHjby29AaE7BDelUZIA0BgyzQ3TMq8rO+l/ZqFYA8U1SEgPlDYj7cn
 gkDWFkPJx6IKgcI8M1obHw11azHgS7dmjjl9lXzxJ2/WfXnoZCuU0BtHd6a1rnAS
 qcO3gwLfCo+3aTGKRseJie1Cljz6sIP+ke0Xgn5O+e7alWjCOtlVZrWwd2MqQ07K
 2bf7uuTC2KQicLLH8DCnoH/BSvHmpyl/FglFrETRk/55KKg0bi+ZltXaTs9bC2uO
 jzNbBSRf8UMcX6Bp3ukhPaFQ1vxqP7KxN9bM+7LYP9aX7Lt/NCJciYjw1jCTwcwi
 nz0RS4d7cscMhoMEarPCKcaNJR6PJetdZY2VXavWjXv6er3407yTocvuei0Epdyb
 WZtbFnpI2tfx1GEr/Bz6Mnk/qn7kwo7BFEUtJoweFE05g5wHa1PojsblrrsqeOuc
 llpK8o8c8NFACxeiLa0z0VBkTjdOtao206eLhF+Se3ukubImayRQwZiOCEBBXwB3
 +LmVcmwNDfNonSWI04AA2WAy9gAdM3Ko/gBfWsuOPR5oIs65wns=
 =F/ek
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/quintela-gitlab/tags/migration-20220128-pull-request' into staging

Migration Pull request (Take 2)

Hi

This time I have disabled vmstate canary patches form Dave Gilbert.

Let's see if it works.

Later, Juan.

# gpg: Signature made Fri 28 Jan 2022 18:30:25 GMT
# 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

* remotes/quintela-gitlab/tags/migration-20220128-pull-request: (36 commits)
  migration: Move temp page setup and cleanup into separate functions
  migration: Simplify unqueue_page()
  migration: Add postcopy_has_request()
  migration: Enable UFFD_FEATURE_THREAD_ID even without blocktime feat
  migration: No off-by-one for pss->page update in host page size
  migration: Tally pre-copy, downtime and post-copy bytes independently
  migration: Introduce ram_transferred_add()
  migration: Don't return for postcopy_send_discard_bm_ram()
  migration: Drop return code for disgard ram process
  migration: Do chunk page in postcopy_each_ram_send_discard()
  migration: Drop postcopy_chunk_hostpages()
  migration: Don't return for postcopy_chunk_hostpages()
  migration: Drop dead code of ram_debug_dump_bitmap()
  migration/ram: clean up unused comment.
  migration: Report the error returned when save_live_iterate fails
  migration/migration.c: Remove the MIGRATION_STATUS_ACTIVE when migration finished
  migration/migration.c: Avoid COLO boot in postcopy migration
  migration/migration.c: Add missed default error handler for migration state
  Remove unnecessary minimum_version_id_old fields
  multifd: Rename pages_used to normal_pages
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2022-01-29 15:55:54 +00:00
commit d90e6f665d
38 changed files with 350 additions and 468 deletions

View file

@ -297,7 +297,6 @@ static const VMStateDescription vmstate_cpuhp_sts = {
.name = "CPU hotplug device state", .name = "CPU hotplug device state",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_BOOL(is_inserting, AcpiCpuStatus), VMSTATE_BOOL(is_inserting, AcpiCpuStatus),
VMSTATE_BOOL(is_removing, AcpiCpuStatus), VMSTATE_BOOL(is_removing, AcpiCpuStatus),
@ -311,7 +310,6 @@ const VMStateDescription vmstate_cpu_hotplug = {
.name = "CPU hotplug state", .name = "CPU hotplug state",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(selector, CPUHotplugState), VMSTATE_UINT32(selector, CPUHotplugState),
VMSTATE_UINT8(command, CPUHotplugState), VMSTATE_UINT8(command, CPUHotplugState),

View file

@ -163,7 +163,6 @@ static const VMStateDescription vmstate_memhp_state = {
.name = "ich9_pm/memhp", .name = "ich9_pm/memhp",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.needed = vmstate_test_use_memhp, .needed = vmstate_test_use_memhp,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs), VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs),
@ -181,7 +180,6 @@ static const VMStateDescription vmstate_tco_io_state = {
.name = "ich9_pm/tco", .name = "ich9_pm/tco",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.needed = vmstate_test_use_tco, .needed = vmstate_test_use_tco,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts, VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
@ -208,7 +206,6 @@ static const VMStateDescription vmstate_cpuhp_state = {
.name = "ich9_pm/cpuhp", .name = "ich9_pm/cpuhp",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.needed = vmstate_test_use_cpuhp, .needed = vmstate_test_use_cpuhp,
.pre_load = vmstate_cpuhp_pre_load, .pre_load = vmstate_cpuhp_pre_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {

View file

@ -318,7 +318,6 @@ static const VMStateDescription vmstate_memhp_sts = {
.name = "memory hotplug device state", .name = "memory hotplug device state",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_BOOL(is_enabled, MemStatus), VMSTATE_BOOL(is_enabled, MemStatus),
VMSTATE_BOOL(is_inserting, MemStatus), VMSTATE_BOOL(is_inserting, MemStatus),
@ -332,7 +331,6 @@ const VMStateDescription vmstate_memory_hotplug = {
.name = "memory hotplug state", .name = "memory hotplug state",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(selector, MemHotplugState), VMSTATE_UINT32(selector, MemHotplugState),
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, MemHotplugState, dev_count, VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, MemHotplugState, dev_count,

View file

@ -230,7 +230,6 @@ static const VMStateDescription vmstate_memhp_state = {
.name = "piix4_pm/memhp", .name = "piix4_pm/memhp",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.needed = vmstate_test_use_memhp, .needed = vmstate_test_use_memhp,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState), VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState),
@ -255,7 +254,6 @@ static const VMStateDescription vmstate_cpuhp_state = {
.name = "piix4_pm/cpuhp", .name = "piix4_pm/cpuhp",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.needed = vmstate_test_use_cpuhp, .needed = vmstate_test_use_cpuhp,
.pre_load = vmstate_cpuhp_pre_load, .pre_load = vmstate_cpuhp_pre_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {

View file

@ -239,7 +239,6 @@ const VMStateDescription vmstate_tco_io_sts = {
.name = "tco io device status", .name = "tco io device status",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT16(tco.rld, TCOIORegs), VMSTATE_UINT16(tco.rld, TCOIORegs),
VMSTATE_UINT8(tco.din, TCOIORegs), VMSTATE_UINT8(tco.din, TCOIORegs),

View file

@ -209,7 +209,6 @@ static const VMStateDescription vmstate_spk = {
.name = "pcspk", .name = "pcspk",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.needed = migrate_needed, .needed = migrate_needed,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT8(data_on, PCSpkState), VMSTATE_UINT8(data_on, PCSpkState),

View file

@ -616,7 +616,6 @@ static const VMStateDescription vmstate_macfb = {
.name = "macfb", .name = "macfb",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.post_load = macfb_post_load, .post_load = macfb_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3), VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),

View file

@ -806,7 +806,6 @@ static const VMStateDescription vmstate_zdma = {
.name = TYPE_XLNX_ZDMA, .name = TYPE_XLNX_ZDMA,
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, XlnxZDMA, ZDMA_R_MAX), VMSTATE_UINT32_ARRAY(regs, XlnxZDMA, ZDMA_R_MAX),
VMSTATE_UINT32(state, XlnxZDMA), VMSTATE_UINT32(state, XlnxZDMA),

View file

@ -677,7 +677,6 @@ static const VMStateDescription vmstate_xlnx_csu_dma = {
.name = TYPE_XLNX_CSU_DMA, .name = TYPE_XLNX_CSU_DMA,
.version_id = 0, .version_id = 0,
.minimum_version_id = 0, .minimum_version_id = 0,
.minimum_version_id_old = 0,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_PTIMER(src_timer, XlnxCSUDMA), VMSTATE_PTIMER(src_timer, XlnxCSUDMA),
VMSTATE_UINT16(width, XlnxCSUDMA), VMSTATE_UINT16(width, XlnxCSUDMA),

View file

@ -277,7 +277,6 @@ static const VMStateDescription vmstate_imx_gpio = {
.name = TYPE_IMX_GPIO, .name = TYPE_IMX_GPIO,
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(dr, IMXGPIOState), VMSTATE_UINT32(dr, IMXGPIOState),
VMSTATE_UINT32(gdir, IMXGPIOState), VMSTATE_UINT32(gdir, IMXGPIOState),

View file

@ -271,7 +271,6 @@ static const VMStateDescription vmstate_bcm2835_mbox = {
.name = TYPE_BCM2835_MBOX, .name = TYPE_BCM2835_MBOX,
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_BOOL_ARRAY(available, BCM2835MboxState, MBOX_CHAN_COUNT), VMSTATE_BOOL_ARRAY(available, BCM2835MboxState, MBOX_CHAN_COUNT),
VMSTATE_STRUCT_ARRAY(mbox, BCM2835MboxState, 2, 1, VMSTATE_STRUCT_ARRAY(mbox, BCM2835MboxState, 2, 1,

View file

@ -266,7 +266,6 @@ static const VMStateDescription vmstate_kvaser_pci = {
.name = "kvaser_pci", .name = "kvaser_pci",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, KvaserPCIState), VMSTATE_PCI_DEVICE(dev, KvaserPCIState),
/* Load this before sja_state. */ /* Load this before sja_state. */

View file

@ -203,7 +203,6 @@ static const VMStateDescription vmstate_mioe3680_pci = {
.name = "mioe3680_pci", .name = "mioe3680_pci",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, Mioe3680PCIState), VMSTATE_PCI_DEVICE(dev, Mioe3680PCIState),
VMSTATE_STRUCT(sja_state[0], Mioe3680PCIState, 0, vmstate_can_sja, VMSTATE_STRUCT(sja_state[0], Mioe3680PCIState, 0, vmstate_can_sja,

View file

@ -204,7 +204,6 @@ static const VMStateDescription vmstate_pcm3680i_pci = {
.name = "pcm3680i_pci", .name = "pcm3680i_pci",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState), VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState),
VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0, VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0,

View file

@ -928,7 +928,6 @@ const VMStateDescription vmstate_qemu_can_filter = {
.name = "qemu_can_filter", .name = "qemu_can_filter",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(can_id, qemu_can_filter), VMSTATE_UINT32(can_id, qemu_can_filter),
VMSTATE_UINT32(can_mask, qemu_can_filter), VMSTATE_UINT32(can_mask, qemu_can_filter),
@ -952,7 +951,6 @@ const VMStateDescription vmstate_can_sja = {
.name = "can_sja", .name = "can_sja",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.post_load = can_sja_post_load, .post_load = can_sja_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT8(mode, CanSJA1000State), VMSTATE_UINT8(mode, CanSJA1000State),

View file

@ -617,7 +617,6 @@ const VMStateDescription vmstate_qemu_ctucan_tx_buffer = {
.name = "qemu_ctucan_tx_buffer", .name = "qemu_ctucan_tx_buffer",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN), VMSTATE_UINT8_ARRAY(data, CtuCanCoreMsgBuffer, CTUCAN_CORE_MSG_MAX_LEN),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
@ -636,7 +635,6 @@ const VMStateDescription vmstate_ctucan = {
.name = "ctucan", .name = "ctucan",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.post_load = ctucan_post_load, .post_load = ctucan_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState), VMSTATE_UINT32(mode_settings.u32, CtuCanCoreState),

View file

@ -215,7 +215,6 @@ static const VMStateDescription vmstate_ctucan_pci = {
.name = "ctucan_pci", .name = "ctucan_pci",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, CtuCanPCIState), VMSTATE_PCI_DEVICE(dev, CtuCanPCIState),
VMSTATE_STRUCT(ctucan_state[0], CtuCanPCIState, 0, vmstate_ctucan, VMSTATE_STRUCT(ctucan_state[0], CtuCanPCIState, 0, vmstate_ctucan,

View file

@ -1049,7 +1049,6 @@ const VMStateDescription vmstate_ppc_timebase = {
.name = "timebase", .name = "timebase",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.pre_save = timebase_pre_save, .pre_save = timebase_pre_save,
.fields = (VMStateField []) { .fields = (VMStateField []) {
VMSTATE_UINT64(guest_timebase, PPCTimebase), VMSTATE_UINT64(guest_timebase, PPCTimebase),

View file

@ -2315,7 +2315,6 @@ static const VMStateDescription vmstate_megasas_gen2 = {
.name = "megasas-gen2", .name = "megasas-gen2",
.version_id = 0, .version_id = 0,
.minimum_version_id = 0, .minimum_version_id = 0,
.minimum_version_id_old = 0,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, MegasasState), VMSTATE_PCI_DEVICE(parent_obj, MegasasState),
VMSTATE_MSIX(parent_obj, MegasasState), VMSTATE_MSIX(parent_obj, MegasasState),

View file

@ -1363,7 +1363,6 @@ static const VMStateDescription vmstate_mptsas = {
.name = "mptsas", .name = "mptsas",
.version_id = 0, .version_id = 0,
.minimum_version_id = 0, .minimum_version_id = 0,
.minimum_version_id_old = 0,
.post_load = mptsas_post_load, .post_load = mptsas_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, MPTSASState), VMSTATE_PCI_DEVICE(dev, MPTSASState),

View file

@ -592,7 +592,6 @@ static const VMStateDescription vmstate_virtio_mmio = {
.name = "virtio_mmio", .name = "virtio_mmio",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },

View file

@ -131,7 +131,6 @@ static const VMStateDescription vmstate_virtio_pci = {
.name = "virtio_pci", .name = "virtio_pci",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },

View file

@ -2808,7 +2808,6 @@ static const VMStateDescription vmstate_virtio = {
.name = "virtio", .name = "virtio",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },

View file

@ -1014,6 +1014,9 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)
info->ram->page_size = page_size; info->ram->page_size = page_size;
info->ram->multifd_bytes = ram_counters.multifd_bytes; info->ram->multifd_bytes = ram_counters.multifd_bytes;
info->ram->pages_per_second = s->pages_per_second; 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 = ram_counters.postcopy_bytes;
if (migrate_use_xbzrle()) { if (migrate_use_xbzrle()) {
info->has_xbzrle_cache = true; info->has_xbzrle_cache = true;
@ -2991,10 +2994,7 @@ static int postcopy_start(MigrationState *ms)
* that are dirty * that are dirty
*/ */
if (migrate_postcopy_ram()) { if (migrate_postcopy_ram()) {
if (ram_postcopy_send_discard_bitmap(ms)) { ram_postcopy_send_discard_bitmap(ms);
error_report("postcopy send discard bitmap failed");
goto fail;
}
} }
/* /*
@ -3205,7 +3205,7 @@ static void migration_completion(MigrationState *s)
qemu_mutex_unlock_iothread(); qemu_mutex_unlock_iothread();
trace_migration_completion_postcopy_end_after_complete(); trace_migration_completion_postcopy_end_after_complete();
} else if (s->state == MIGRATION_STATUS_CANCELLING) { } else {
goto fail; goto fail;
} }
@ -3230,7 +3230,11 @@ static void migration_completion(MigrationState *s)
goto fail_invalidate; goto fail_invalidate;
} }
if (!migrate_colo_enabled()) { if (migrate_colo_enabled() && s->state == MIGRATION_STATUS_ACTIVE) {
/* COLO does not support postcopy */
migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_COLO);
} else {
migrate_set_state(&s->state, current_active_state, migrate_set_state(&s->state, current_active_state,
MIGRATION_STATUS_COMPLETED); MIGRATION_STATUS_COMPLETED);
} }
@ -3621,16 +3625,6 @@ static void migration_iteration_finish(MigrationState *s)
"COLO enabled", __func__); "COLO enabled", __func__);
} }
migrate_start_colo_process(s); migrate_start_colo_process(s);
/*
* Fixme: we will run VM in COLO no matter its old running state.
* After exited COLO, we will keep running.
*/
/* Fallthrough */
case MIGRATION_STATUS_ACTIVE:
/*
* We should really assert here, but since it's during
* migration, let's try to reduce the usage of assertions.
*/
s->vm_was_running = true; s->vm_was_running = true;
/* Fallthrough */ /* Fallthrough */
case MIGRATION_STATUS_FAILED: case MIGRATION_STATUS_FAILED:

View file

@ -51,16 +51,16 @@ static int zlib_send_setup(MultiFDSendParams *p, Error **errp)
zs->opaque = Z_NULL; zs->opaque = Z_NULL;
if (deflateInit(zs, migrate_multifd_zlib_level()) != Z_OK) { if (deflateInit(zs, migrate_multifd_zlib_level()) != Z_OK) {
g_free(z); g_free(z);
error_setg(errp, "multifd %d: deflate init failed", p->id); error_setg(errp, "multifd %u: deflate init failed", p->id);
return -1; return -1;
} }
/* To be safe, we reserve twice the size of the packet */ /* This is the maxium size of the compressed buffer */
z->zbuff_len = MULTIFD_PACKET_SIZE * 2; z->zbuff_len = compressBound(MULTIFD_PACKET_SIZE);
z->zbuff = g_try_malloc(z->zbuff_len); z->zbuff = g_try_malloc(z->zbuff_len);
if (!z->zbuff) { if (!z->zbuff) {
deflateEnd(&z->zs); deflateEnd(&z->zs);
g_free(z); g_free(z);
error_setg(errp, "multifd %d: out of memory for zbuff", p->id); error_setg(errp, "multifd %u: out of memory for zbuff", p->id);
return -1; return -1;
} }
p->data = z; p->data = z;
@ -106,16 +106,16 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
int ret; int ret;
uint32_t i; uint32_t i;
for (i = 0; i < p->pages->num; i++) { for (i = 0; i < p->normal_num; i++) {
uint32_t available = z->zbuff_len - out_size; uint32_t available = z->zbuff_len - out_size;
int flush = Z_NO_FLUSH; int flush = Z_NO_FLUSH;
if (i == p->pages->num - 1) { if (i == p->normal_num - 1) {
flush = Z_SYNC_FLUSH; flush = Z_SYNC_FLUSH;
} }
zs->avail_in = page_size; zs->avail_in = page_size;
zs->next_in = p->pages->block->host + p->pages->offset[i]; zs->next_in = p->pages->block->host + p->normal[i];
zs->avail_out = available; zs->avail_out = available;
zs->next_out = z->zbuff + out_size; zs->next_out = z->zbuff + out_size;
@ -132,42 +132,26 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
ret = deflate(zs, flush); ret = deflate(zs, flush);
} while (ret == Z_OK && zs->avail_in && zs->avail_out); } while (ret == Z_OK && zs->avail_in && zs->avail_out);
if (ret == Z_OK && zs->avail_in) { if (ret == Z_OK && zs->avail_in) {
error_setg(errp, "multifd %d: deflate failed to compress all input", error_setg(errp, "multifd %u: deflate failed to compress all input",
p->id); p->id);
return -1; return -1;
} }
if (ret != Z_OK) { if (ret != Z_OK) {
error_setg(errp, "multifd %d: deflate returned %d instead of Z_OK", error_setg(errp, "multifd %u: deflate returned %d instead of Z_OK",
p->id, ret); p->id, ret);
return -1; return -1;
} }
out_size += available - zs->avail_out; out_size += available - zs->avail_out;
} }
p->iov[p->iovs_num].iov_base = z->zbuff;
p->iov[p->iovs_num].iov_len = out_size;
p->iovs_num++;
p->next_packet_size = out_size; p->next_packet_size = out_size;
p->flags |= MULTIFD_FLAG_ZLIB; p->flags |= MULTIFD_FLAG_ZLIB;
return 0; return 0;
} }
/**
* zlib_send_write: do the actual write of the data
*
* Do the actual write of the comprresed buffer.
*
* Returns 0 for success or -1 for error
*
* @p: Params for the channel that we are using
* @used: number of pages used
* @errp: pointer to an error
*/
static int zlib_send_write(MultiFDSendParams *p, uint32_t used, Error **errp)
{
struct zlib_data *z = p->data;
return qio_channel_write_all(p->c, (void *)z->zbuff, p->next_packet_size,
errp);
}
/** /**
* zlib_recv_setup: setup receive side * zlib_recv_setup: setup receive side
* *
@ -190,7 +174,7 @@ static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp)
zs->avail_in = 0; zs->avail_in = 0;
zs->next_in = Z_NULL; zs->next_in = Z_NULL;
if (inflateInit(zs) != Z_OK) { if (inflateInit(zs) != Z_OK) {
error_setg(errp, "multifd %d: inflate init failed", p->id); error_setg(errp, "multifd %u: inflate init failed", p->id);
return -1; return -1;
} }
/* To be safe, we reserve twice the size of the packet */ /* To be safe, we reserve twice the size of the packet */
@ -198,7 +182,7 @@ static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp)
z->zbuff = g_try_malloc(z->zbuff_len); z->zbuff = g_try_malloc(z->zbuff_len);
if (!z->zbuff) { if (!z->zbuff) {
inflateEnd(zs); inflateEnd(zs);
error_setg(errp, "multifd %d: out of memory for zbuff", p->id); error_setg(errp, "multifd %u: out of memory for zbuff", p->id);
return -1; return -1;
} }
return 0; return 0;
@ -241,13 +225,13 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp)
uint32_t in_size = p->next_packet_size; uint32_t in_size = p->next_packet_size;
/* we measure the change of total_out */ /* we measure the change of total_out */
uint32_t out_size = zs->total_out; uint32_t out_size = zs->total_out;
uint32_t expected_size = p->pages->num * qemu_target_page_size(); uint32_t expected_size = p->normal_num * page_size;
uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
int ret; int ret;
int i; int i;
if (flags != MULTIFD_FLAG_ZLIB) { if (flags != MULTIFD_FLAG_ZLIB) {
error_setg(errp, "multifd %d: flags received %x flags expected %x", error_setg(errp, "multifd %u: flags received %x flags expected %x",
p->id, flags, MULTIFD_FLAG_ZLIB); p->id, flags, MULTIFD_FLAG_ZLIB);
return -1; return -1;
} }
@ -260,16 +244,16 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp)
zs->avail_in = in_size; zs->avail_in = in_size;
zs->next_in = z->zbuff; zs->next_in = z->zbuff;
for (i = 0; i < p->pages->num; i++) { for (i = 0; i < p->normal_num; i++) {
int flush = Z_NO_FLUSH; int flush = Z_NO_FLUSH;
unsigned long start = zs->total_out; unsigned long start = zs->total_out;
if (i == p->pages->num - 1) { if (i == p->normal_num - 1) {
flush = Z_SYNC_FLUSH; flush = Z_SYNC_FLUSH;
} }
zs->avail_out = page_size; zs->avail_out = page_size;
zs->next_out = p->pages->block->host + p->pages->offset[i]; zs->next_out = p->host + p->normal[i];
/* /*
* Welcome to inflate semantics * Welcome to inflate semantics
@ -284,19 +268,19 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp)
} while (ret == Z_OK && zs->avail_in } while (ret == Z_OK && zs->avail_in
&& (zs->total_out - start) < page_size); && (zs->total_out - start) < page_size);
if (ret == Z_OK && (zs->total_out - start) < page_size) { if (ret == Z_OK && (zs->total_out - start) < page_size) {
error_setg(errp, "multifd %d: inflate generated too few output", error_setg(errp, "multifd %u: inflate generated too few output",
p->id); p->id);
return -1; return -1;
} }
if (ret != Z_OK) { if (ret != Z_OK) {
error_setg(errp, "multifd %d: inflate returned %d instead of Z_OK", error_setg(errp, "multifd %u: inflate returned %d instead of Z_OK",
p->id, ret); p->id, ret);
return -1; return -1;
} }
} }
out_size = zs->total_out - out_size; out_size = zs->total_out - out_size;
if (out_size != expected_size) { if (out_size != expected_size) {
error_setg(errp, "multifd %d: packet size received %d size expected %d", error_setg(errp, "multifd %u: packet size received %u size expected %u",
p->id, out_size, expected_size); p->id, out_size, expected_size);
return -1; return -1;
} }
@ -307,7 +291,6 @@ static MultiFDMethods multifd_zlib_ops = {
.send_setup = zlib_send_setup, .send_setup = zlib_send_setup,
.send_cleanup = zlib_send_cleanup, .send_cleanup = zlib_send_cleanup,
.send_prepare = zlib_send_prepare, .send_prepare = zlib_send_prepare,
.send_write = zlib_send_write,
.recv_setup = zlib_recv_setup, .recv_setup = zlib_recv_setup,
.recv_cleanup = zlib_recv_cleanup, .recv_cleanup = zlib_recv_cleanup,
.recv_pages = zlib_recv_pages .recv_pages = zlib_recv_pages

View file

@ -55,7 +55,7 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp)
z->zcs = ZSTD_createCStream(); z->zcs = ZSTD_createCStream();
if (!z->zcs) { if (!z->zcs) {
g_free(z); g_free(z);
error_setg(errp, "multifd %d: zstd createCStream failed", p->id); error_setg(errp, "multifd %u: zstd createCStream failed", p->id);
return -1; return -1;
} }
@ -63,17 +63,17 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp)
if (ZSTD_isError(res)) { if (ZSTD_isError(res)) {
ZSTD_freeCStream(z->zcs); ZSTD_freeCStream(z->zcs);
g_free(z); g_free(z);
error_setg(errp, "multifd %d: initCStream failed with error %s", error_setg(errp, "multifd %u: initCStream failed with error %s",
p->id, ZSTD_getErrorName(res)); p->id, ZSTD_getErrorName(res));
return -1; return -1;
} }
/* To be safe, we reserve twice the size of the packet */ /* This is the maxium size of the compressed buffer */
z->zbuff_len = MULTIFD_PACKET_SIZE * 2; z->zbuff_len = ZSTD_compressBound(MULTIFD_PACKET_SIZE);
z->zbuff = g_try_malloc(z->zbuff_len); z->zbuff = g_try_malloc(z->zbuff_len);
if (!z->zbuff) { if (!z->zbuff) {
ZSTD_freeCStream(z->zcs); ZSTD_freeCStream(z->zcs);
g_free(z); g_free(z);
error_setg(errp, "multifd %d: out of memory for zbuff", p->id); error_setg(errp, "multifd %u: out of memory for zbuff", p->id);
return -1; return -1;
} }
return 0; return 0;
@ -121,13 +121,13 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
z->out.size = z->zbuff_len; z->out.size = z->zbuff_len;
z->out.pos = 0; z->out.pos = 0;
for (i = 0; i < p->pages->num; i++) { for (i = 0; i < p->normal_num; i++) {
ZSTD_EndDirective flush = ZSTD_e_continue; ZSTD_EndDirective flush = ZSTD_e_continue;
if (i == p->pages->num - 1) { if (i == p->normal_num - 1) {
flush = ZSTD_e_flush; flush = ZSTD_e_flush;
} }
z->in.src = p->pages->block->host + p->pages->offset[i]; z->in.src = p->pages->block->host + p->normal[i];
z->in.size = page_size; z->in.size = page_size;
z->in.pos = 0; z->in.pos = 0;
@ -144,41 +144,25 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
} while (ret > 0 && (z->in.size - z->in.pos > 0) } while (ret > 0 && (z->in.size - z->in.pos > 0)
&& (z->out.size - z->out.pos > 0)); && (z->out.size - z->out.pos > 0));
if (ret > 0 && (z->in.size - z->in.pos > 0)) { if (ret > 0 && (z->in.size - z->in.pos > 0)) {
error_setg(errp, "multifd %d: compressStream buffer too small", error_setg(errp, "multifd %u: compressStream buffer too small",
p->id); p->id);
return -1; return -1;
} }
if (ZSTD_isError(ret)) { if (ZSTD_isError(ret)) {
error_setg(errp, "multifd %d: compressStream error %s", error_setg(errp, "multifd %u: compressStream error %s",
p->id, ZSTD_getErrorName(ret)); p->id, ZSTD_getErrorName(ret));
return -1; return -1;
} }
} }
p->iov[p->iovs_num].iov_base = z->zbuff;
p->iov[p->iovs_num].iov_len = z->out.pos;
p->iovs_num++;
p->next_packet_size = z->out.pos; p->next_packet_size = z->out.pos;
p->flags |= MULTIFD_FLAG_ZSTD; p->flags |= MULTIFD_FLAG_ZSTD;
return 0; return 0;
} }
/**
* zstd_send_write: do the actual write of the data
*
* Do the actual write of the comprresed buffer.
*
* Returns 0 for success or -1 for error
*
* @p: Params for the channel that we are using
* @used: number of pages used
* @errp: pointer to an error
*/
static int zstd_send_write(MultiFDSendParams *p, uint32_t used, Error **errp)
{
struct zstd_data *z = p->data;
return qio_channel_write_all(p->c, (void *)z->zbuff, p->next_packet_size,
errp);
}
/** /**
* zstd_recv_setup: setup receive side * zstd_recv_setup: setup receive side
* *
@ -198,7 +182,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp)
z->zds = ZSTD_createDStream(); z->zds = ZSTD_createDStream();
if (!z->zds) { if (!z->zds) {
g_free(z); g_free(z);
error_setg(errp, "multifd %d: zstd createDStream failed", p->id); error_setg(errp, "multifd %u: zstd createDStream failed", p->id);
return -1; return -1;
} }
@ -206,7 +190,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp)
if (ZSTD_isError(ret)) { if (ZSTD_isError(ret)) {
ZSTD_freeDStream(z->zds); ZSTD_freeDStream(z->zds);
g_free(z); g_free(z);
error_setg(errp, "multifd %d: initDStream failed with error %s", error_setg(errp, "multifd %u: initDStream failed with error %s",
p->id, ZSTD_getErrorName(ret)); p->id, ZSTD_getErrorName(ret));
return -1; return -1;
} }
@ -217,7 +201,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp)
if (!z->zbuff) { if (!z->zbuff) {
ZSTD_freeDStream(z->zds); ZSTD_freeDStream(z->zds);
g_free(z); g_free(z);
error_setg(errp, "multifd %d: out of memory for zbuff", p->id); error_setg(errp, "multifd %u: out of memory for zbuff", p->id);
return -1; return -1;
} }
return 0; return 0;
@ -258,14 +242,14 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp)
uint32_t in_size = p->next_packet_size; uint32_t in_size = p->next_packet_size;
uint32_t out_size = 0; uint32_t out_size = 0;
size_t page_size = qemu_target_page_size(); size_t page_size = qemu_target_page_size();
uint32_t expected_size = p->pages->num * page_size; uint32_t expected_size = p->normal_num * page_size;
uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
struct zstd_data *z = p->data; struct zstd_data *z = p->data;
int ret; int ret;
int i; int i;
if (flags != MULTIFD_FLAG_ZSTD) { if (flags != MULTIFD_FLAG_ZSTD) {
error_setg(errp, "multifd %d: flags received %x flags expected %x", error_setg(errp, "multifd %u: flags received %x flags expected %x",
p->id, flags, MULTIFD_FLAG_ZSTD); p->id, flags, MULTIFD_FLAG_ZSTD);
return -1; return -1;
} }
@ -279,8 +263,8 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp)
z->in.size = in_size; z->in.size = in_size;
z->in.pos = 0; z->in.pos = 0;
for (i = 0; i < p->pages->num; i++) { for (i = 0; i < p->normal_num; i++) {
z->out.dst = p->pages->block->host + p->pages->offset[i]; z->out.dst = p->host + p->normal[i];
z->out.size = page_size; z->out.size = page_size;
z->out.pos = 0; z->out.pos = 0;
@ -297,19 +281,19 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp)
} while (ret > 0 && (z->in.size - z->in.pos > 0) } while (ret > 0 && (z->in.size - z->in.pos > 0)
&& (z->out.pos < page_size)); && (z->out.pos < page_size));
if (ret > 0 && (z->out.pos < page_size)) { if (ret > 0 && (z->out.pos < page_size)) {
error_setg(errp, "multifd %d: decompressStream buffer too small", error_setg(errp, "multifd %u: decompressStream buffer too small",
p->id); p->id);
return -1; return -1;
} }
if (ZSTD_isError(ret)) { if (ZSTD_isError(ret)) {
error_setg(errp, "multifd %d: decompressStream returned %s", error_setg(errp, "multifd %u: decompressStream returned %s",
p->id, ZSTD_getErrorName(ret)); p->id, ZSTD_getErrorName(ret));
return ret; return ret;
} }
out_size += z->out.pos; out_size += z->out.pos;
} }
if (out_size != expected_size) { if (out_size != expected_size) {
error_setg(errp, "multifd %d: packet size received %d size expected %d", error_setg(errp, "multifd %u: packet size received %u size expected %u",
p->id, out_size, expected_size); p->id, out_size, expected_size);
return -1; return -1;
} }
@ -320,7 +304,6 @@ static MultiFDMethods multifd_zstd_ops = {
.send_setup = zstd_send_setup, .send_setup = zstd_send_setup,
.send_cleanup = zstd_send_cleanup, .send_cleanup = zstd_send_cleanup,
.send_prepare = zstd_send_prepare, .send_prepare = zstd_send_prepare,
.send_write = zstd_send_write,
.recv_setup = zstd_recv_setup, .recv_setup = zstd_recv_setup,
.recv_cleanup = zstd_recv_cleanup, .recv_cleanup = zstd_recv_cleanup,
.recv_pages = zstd_recv_pages .recv_pages = zstd_recv_pages

View file

@ -86,27 +86,20 @@ static void nocomp_send_cleanup(MultiFDSendParams *p, Error **errp)
*/ */
static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp) static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp)
{ {
p->next_packet_size = p->pages->num * qemu_target_page_size(); MultiFDPages_t *pages = p->pages;
size_t page_size = qemu_target_page_size();
for (int i = 0; i < p->normal_num; i++) {
p->iov[p->iovs_num].iov_base = pages->block->host + p->normal[i];
p->iov[p->iovs_num].iov_len = page_size;
p->iovs_num++;
}
p->next_packet_size = p->normal_num * page_size;
p->flags |= MULTIFD_FLAG_NOCOMP; p->flags |= MULTIFD_FLAG_NOCOMP;
return 0; return 0;
} }
/**
* nocomp_send_write: do the actual write of the data
*
* For no compression we just have to write the data.
*
* Returns 0 for success or -1 for error
*
* @p: Params for the channel that we are using
* @used: number of pages used
* @errp: pointer to an error
*/
static int nocomp_send_write(MultiFDSendParams *p, uint32_t used, Error **errp)
{
return qio_channel_writev_all(p->c, p->pages->iov, used, errp);
}
/** /**
* nocomp_recv_setup: setup receive side * nocomp_recv_setup: setup receive side
* *
@ -146,20 +139,24 @@ static void nocomp_recv_cleanup(MultiFDRecvParams *p)
static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp) static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp)
{ {
uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK; uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
size_t page_size = qemu_target_page_size();
if (flags != MULTIFD_FLAG_NOCOMP) { if (flags != MULTIFD_FLAG_NOCOMP) {
error_setg(errp, "multifd %d: flags received %x flags expected %x", error_setg(errp, "multifd %u: flags received %x flags expected %x",
p->id, flags, MULTIFD_FLAG_NOCOMP); p->id, flags, MULTIFD_FLAG_NOCOMP);
return -1; return -1;
} }
return qio_channel_readv_all(p->c, p->pages->iov, p->pages->num, errp); for (int i = 0; i < p->normal_num; i++) {
p->iov[i].iov_base = p->host + p->normal[i];
p->iov[i].iov_len = page_size;
}
return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp);
} }
static MultiFDMethods multifd_nocomp_ops = { static MultiFDMethods multifd_nocomp_ops = {
.send_setup = nocomp_send_setup, .send_setup = nocomp_send_setup,
.send_cleanup = nocomp_send_cleanup, .send_cleanup = nocomp_send_cleanup,
.send_prepare = nocomp_send_prepare, .send_prepare = nocomp_send_prepare,
.send_write = nocomp_send_write,
.recv_setup = nocomp_recv_setup, .recv_setup = nocomp_recv_setup,
.recv_cleanup = nocomp_recv_cleanup, .recv_cleanup = nocomp_recv_cleanup,
.recv_pages = nocomp_recv_pages .recv_pages = nocomp_recv_pages
@ -212,8 +209,8 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp)
} }
if (msg.version != MULTIFD_VERSION) { if (msg.version != MULTIFD_VERSION) {
error_setg(errp, "multifd: received packet version %d " error_setg(errp, "multifd: received packet version %u "
"expected %d", msg.version, MULTIFD_VERSION); "expected %u", msg.version, MULTIFD_VERSION);
return -1; return -1;
} }
@ -229,8 +226,8 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp)
} }
if (msg.id > migrate_multifd_channels()) { if (msg.id > migrate_multifd_channels()) {
error_setg(errp, "multifd: received channel version %d " error_setg(errp, "multifd: received channel version %u "
"expected %d", msg.version, MULTIFD_VERSION); "expected %u", msg.version, MULTIFD_VERSION);
return -1; return -1;
} }
@ -242,7 +239,6 @@ static MultiFDPages_t *multifd_pages_init(size_t size)
MultiFDPages_t *pages = g_new0(MultiFDPages_t, 1); MultiFDPages_t *pages = g_new0(MultiFDPages_t, 1);
pages->allocated = size; pages->allocated = size;
pages->iov = g_new0(struct iovec, size);
pages->offset = g_new0(ram_addr_t, size); pages->offset = g_new0(ram_addr_t, size);
return pages; return pages;
@ -254,8 +250,6 @@ static void multifd_pages_clear(MultiFDPages_t *pages)
pages->allocated = 0; pages->allocated = 0;
pages->packet_num = 0; pages->packet_num = 0;
pages->block = NULL; pages->block = NULL;
g_free(pages->iov);
pages->iov = NULL;
g_free(pages->offset); g_free(pages->offset);
pages->offset = NULL; pages->offset = NULL;
g_free(pages); g_free(pages);
@ -268,7 +262,7 @@ static void multifd_send_fill_packet(MultiFDSendParams *p)
packet->flags = cpu_to_be32(p->flags); packet->flags = cpu_to_be32(p->flags);
packet->pages_alloc = cpu_to_be32(p->pages->allocated); packet->pages_alloc = cpu_to_be32(p->pages->allocated);
packet->pages_used = cpu_to_be32(p->pages->num); packet->normal_pages = cpu_to_be32(p->normal_num);
packet->next_packet_size = cpu_to_be32(p->next_packet_size); packet->next_packet_size = cpu_to_be32(p->next_packet_size);
packet->packet_num = cpu_to_be64(p->packet_num); packet->packet_num = cpu_to_be64(p->packet_num);
@ -276,9 +270,9 @@ static void multifd_send_fill_packet(MultiFDSendParams *p)
strncpy(packet->ramblock, p->pages->block->idstr, 256); strncpy(packet->ramblock, p->pages->block->idstr, 256);
} }
for (i = 0; i < p->pages->num; i++) { for (i = 0; i < p->normal_num; i++) {
/* there are architectures where ram_addr_t is 32 bit */ /* there are architectures where ram_addr_t is 32 bit */
uint64_t temp = p->pages->offset[i]; uint64_t temp = p->normal[i];
packet->offset[i] = cpu_to_be64(temp); packet->offset[i] = cpu_to_be64(temp);
} }
@ -288,7 +282,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
{ {
MultiFDPacket_t *packet = p->packet; MultiFDPacket_t *packet = p->packet;
size_t page_size = qemu_target_page_size(); size_t page_size = qemu_target_page_size();
uint32_t pages_max = MULTIFD_PACKET_SIZE / page_size; uint32_t page_count = MULTIFD_PACKET_SIZE / page_size;
RAMBlock *block; RAMBlock *block;
int i; int i;
@ -303,7 +297,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
packet->version = be32_to_cpu(packet->version); packet->version = be32_to_cpu(packet->version);
if (packet->version != MULTIFD_VERSION) { if (packet->version != MULTIFD_VERSION) {
error_setg(errp, "multifd: received packet " error_setg(errp, "multifd: received packet "
"version %d and expected version %d", "version %u and expected version %u",
packet->version, MULTIFD_VERSION); packet->version, MULTIFD_VERSION);
return -1; return -1;
} }
@ -315,33 +309,25 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
* If we received a packet that is 100 times bigger than expected * If we received a packet that is 100 times bigger than expected
* just stop migration. It is a magic number. * just stop migration. It is a magic number.
*/ */
if (packet->pages_alloc > pages_max * 100) { if (packet->pages_alloc > page_count) {
error_setg(errp, "multifd: received packet " error_setg(errp, "multifd: received packet "
"with size %d and expected a maximum size of %d", "with size %u and expected a size of %u",
packet->pages_alloc, pages_max * 100) ; packet->pages_alloc, page_count) ;
return -1; return -1;
} }
/*
* We received a packet that is bigger than expected but inside
* reasonable limits (see previous comment). Just reallocate.
*/
if (packet->pages_alloc > p->pages->allocated) {
multifd_pages_clear(p->pages);
p->pages = multifd_pages_init(packet->pages_alloc);
}
p->pages->num = be32_to_cpu(packet->pages_used); p->normal_num = be32_to_cpu(packet->normal_pages);
if (p->pages->num > packet->pages_alloc) { if (p->normal_num > packet->pages_alloc) {
error_setg(errp, "multifd: received packet " error_setg(errp, "multifd: received packet "
"with %d pages and expected maximum pages are %d", "with %u pages and expected maximum pages are %u",
p->pages->num, packet->pages_alloc) ; p->normal_num, packet->pages_alloc) ;
return -1; return -1;
} }
p->next_packet_size = be32_to_cpu(packet->next_packet_size); p->next_packet_size = be32_to_cpu(packet->next_packet_size);
p->packet_num = be64_to_cpu(packet->packet_num); p->packet_num = be64_to_cpu(packet->packet_num);
if (p->pages->num == 0) { if (p->normal_num == 0) {
return 0; return 0;
} }
@ -354,8 +340,8 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
return -1; return -1;
} }
p->pages->block = block; p->host = block->host;
for (i = 0; i < p->pages->num; i++) { for (i = 0; i < p->normal_num; i++) {
uint64_t offset = be64_to_cpu(packet->offset[i]); uint64_t offset = be64_to_cpu(packet->offset[i]);
if (offset > (block->used_length - page_size)) { if (offset > (block->used_length - page_size)) {
@ -364,9 +350,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
offset, block->used_length); offset, block->used_length);
return -1; return -1;
} }
p->pages->offset[i] = offset; p->normal[i] = offset;
p->pages->iov[i].iov_base = block->host + offset;
p->pages->iov[i].iov_len = page_size;
} }
return 0; return 0;
@ -470,8 +454,6 @@ int multifd_queue_page(QEMUFile *f, RAMBlock *block, ram_addr_t offset)
if (pages->block == block) { if (pages->block == block) {
pages->offset[pages->num] = offset; pages->offset[pages->num] = offset;
pages->iov[pages->num].iov_base = block->host + offset;
pages->iov[pages->num].iov_len = qemu_target_page_size();
pages->num++; pages->num++;
if (pages->num < pages->allocated) { if (pages->num < pages->allocated) {
@ -567,6 +549,10 @@ void multifd_save_cleanup(void)
p->packet_len = 0; p->packet_len = 0;
g_free(p->packet); g_free(p->packet);
p->packet = NULL; p->packet = NULL;
g_free(p->iov);
p->iov = NULL;
g_free(p->normal);
p->normal = NULL;
multifd_send_state->ops->send_cleanup(p, &local_err); multifd_send_state->ops->send_cleanup(p, &local_err);
if (local_err) { if (local_err) {
migrate_set_error(migrate_get_current(), local_err); migrate_set_error(migrate_get_current(), local_err);
@ -651,11 +637,17 @@ static void *multifd_send_thread(void *opaque)
qemu_mutex_lock(&p->mutex); qemu_mutex_lock(&p->mutex);
if (p->pending_job) { if (p->pending_job) {
uint32_t used = p->pages->num;
uint64_t packet_num = p->packet_num; uint64_t packet_num = p->packet_num;
uint32_t flags = p->flags; uint32_t flags = p->flags;
p->iovs_num = 1;
p->normal_num = 0;
if (used) { for (int i = 0; i < p->pages->num; i++) {
p->normal[p->normal_num] = p->pages->offset[i];
p->normal_num++;
}
if (p->normal_num) {
ret = multifd_send_state->ops->send_prepare(p, &local_err); ret = multifd_send_state->ops->send_prepare(p, &local_err);
if (ret != 0) { if (ret != 0) {
qemu_mutex_unlock(&p->mutex); qemu_mutex_unlock(&p->mutex);
@ -665,26 +657,22 @@ static void *multifd_send_thread(void *opaque)
multifd_send_fill_packet(p); multifd_send_fill_packet(p);
p->flags = 0; p->flags = 0;
p->num_packets++; p->num_packets++;
p->num_pages += used; p->total_normal_pages += p->normal_num;
p->pages->num = 0; p->pages->num = 0;
p->pages->block = NULL; p->pages->block = NULL;
qemu_mutex_unlock(&p->mutex); qemu_mutex_unlock(&p->mutex);
trace_multifd_send(p->id, packet_num, used, flags, trace_multifd_send(p->id, packet_num, p->normal_num, flags,
p->next_packet_size); p->next_packet_size);
ret = qio_channel_write_all(p->c, (void *)p->packet, p->iov[0].iov_len = p->packet_len;
p->packet_len, &local_err); p->iov[0].iov_base = p->packet;
if (ret != 0) {
break;
}
if (used) { ret = qio_channel_writev_all(p->c, p->iov, p->iovs_num,
ret = multifd_send_state->ops->send_write(p, used, &local_err); &local_err);
if (ret != 0) { if (ret != 0) {
break; break;
} }
}
qemu_mutex_lock(&p->mutex); qemu_mutex_lock(&p->mutex);
p->pending_job--; p->pending_job--;
@ -724,7 +712,7 @@ out:
qemu_mutex_unlock(&p->mutex); qemu_mutex_unlock(&p->mutex);
rcu_unregister_thread(); rcu_unregister_thread();
trace_multifd_send_thread_end(p->id, p->num_packets, p->num_pages); trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages);
return NULL; return NULL;
} }
@ -922,6 +910,9 @@ int multifd_save_setup(Error **errp)
p->packet->version = cpu_to_be32(MULTIFD_VERSION); p->packet->version = cpu_to_be32(MULTIFD_VERSION);
p->name = g_strdup_printf("multifdsend_%d", i); p->name = g_strdup_printf("multifdsend_%d", i);
p->tls_hostname = g_strdup(s->hostname); 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);
socket_send_channel_create(multifd_new_send_channel_async, p); socket_send_channel_create(multifd_new_send_channel_async, p);
} }
@ -1016,11 +1007,13 @@ int multifd_load_cleanup(Error **errp)
qemu_sem_destroy(&p->sem_sync); qemu_sem_destroy(&p->sem_sync);
g_free(p->name); g_free(p->name);
p->name = NULL; p->name = NULL;
multifd_pages_clear(p->pages);
p->pages = NULL;
p->packet_len = 0; p->packet_len = 0;
g_free(p->packet); g_free(p->packet);
p->packet = NULL; p->packet = NULL;
g_free(p->iov);
p->iov = NULL;
g_free(p->normal);
p->normal = NULL;
multifd_recv_state->ops->recv_cleanup(p); multifd_recv_state->ops->recv_cleanup(p);
} }
qemu_sem_destroy(&multifd_recv_state->sem_sync); qemu_sem_destroy(&multifd_recv_state->sem_sync);
@ -1069,7 +1062,6 @@ static void *multifd_recv_thread(void *opaque)
rcu_register_thread(); rcu_register_thread();
while (true) { while (true) {
uint32_t used;
uint32_t flags; uint32_t flags;
if (p->quit) { if (p->quit) {
@ -1092,17 +1084,16 @@ static void *multifd_recv_thread(void *opaque)
break; break;
} }
used = p->pages->num;
flags = p->flags; flags = p->flags;
/* recv methods don't know how to handle the SYNC flag */ /* recv methods don't know how to handle the SYNC flag */
p->flags &= ~MULTIFD_FLAG_SYNC; p->flags &= ~MULTIFD_FLAG_SYNC;
trace_multifd_recv(p->id, p->packet_num, used, flags, trace_multifd_recv(p->id, p->packet_num, p->normal_num, flags,
p->next_packet_size); p->next_packet_size);
p->num_packets++; p->num_packets++;
p->num_pages += used; p->total_normal_pages += p->normal_num;
qemu_mutex_unlock(&p->mutex); qemu_mutex_unlock(&p->mutex);
if (used) { if (p->normal_num) {
ret = multifd_recv_state->ops->recv_pages(p, &local_err); ret = multifd_recv_state->ops->recv_pages(p, &local_err);
if (ret != 0) { if (ret != 0) {
break; break;
@ -1124,7 +1115,7 @@ static void *multifd_recv_thread(void *opaque)
qemu_mutex_unlock(&p->mutex); qemu_mutex_unlock(&p->mutex);
rcu_unregister_thread(); rcu_unregister_thread();
trace_multifd_recv_thread_end(p->id, p->num_packets, p->num_pages); trace_multifd_recv_thread_end(p->id, p->num_packets, p->total_normal_pages);
return NULL; return NULL;
} }
@ -1156,11 +1147,12 @@ int multifd_load_setup(Error **errp)
qemu_sem_init(&p->sem_sync, 0); qemu_sem_init(&p->sem_sync, 0);
p->quit = false; p->quit = false;
p->id = i; p->id = i;
p->pages = multifd_pages_init(page_count);
p->packet_len = sizeof(MultiFDPacket_t) p->packet_len = sizeof(MultiFDPacket_t)
+ sizeof(uint64_t) * page_count; + sizeof(uint64_t) * page_count;
p->packet = g_malloc0(p->packet_len); p->packet = g_malloc0(p->packet_len);
p->name = g_strdup_printf("multifdrecv_%d", i); p->name = g_strdup_printf("multifdrecv_%d", i);
p->iov = g_new0(struct iovec, page_count);
p->normal = g_new0(ram_addr_t, page_count);
} }
for (i = 0; i < thread_count; i++) { for (i = 0; i < thread_count; i++) {

View file

@ -44,7 +44,8 @@ typedef struct {
uint32_t flags; uint32_t flags;
/* maximum number of allocated pages */ /* maximum number of allocated pages */
uint32_t pages_alloc; uint32_t pages_alloc;
uint32_t pages_used; /* non zero pages */
uint32_t normal_pages;
/* size of the next packet that contains pages */ /* size of the next packet that contains pages */
uint32_t next_packet_size; uint32_t next_packet_size;
uint64_t packet_num; uint64_t packet_num;
@ -62,8 +63,6 @@ typedef struct {
uint64_t packet_num; uint64_t packet_num;
/* offset of each page */ /* offset of each page */
ram_addr_t *offset; ram_addr_t *offset;
/* pointer to each page */
struct iovec *iov;
RAMBlock *block; RAMBlock *block;
} MultiFDPages_t; } MultiFDPages_t;
@ -106,10 +105,18 @@ typedef struct {
/* thread local variables */ /* thread local variables */
/* packets sent through this channel */ /* packets sent through this channel */
uint64_t num_packets; uint64_t num_packets;
/* pages sent through this channel */ /* non zero pages sent through this channel */
uint64_t num_pages; uint64_t total_normal_pages;
/* syncs main thread and channels */ /* syncs main thread and channels */
QemuSemaphore sem_sync; QemuSemaphore sem_sync;
/* buffers to send */
struct iovec *iov;
/* number of iovs used */
uint32_t iovs_num;
/* Pages that are not zero */
ram_addr_t *normal;
/* num of non zero pages */
uint32_t normal_num;
/* used for compression methods */ /* used for compression methods */
void *data; void *data;
} MultiFDSendParams; } MultiFDSendParams;
@ -130,8 +137,8 @@ typedef struct {
bool running; bool running;
/* should this thread finish */ /* should this thread finish */
bool quit; bool quit;
/* array of pages to receive */ /* ramblock host address */
MultiFDPages_t *pages; uint8_t *host;
/* packet allocated len */ /* packet allocated len */
uint32_t packet_len; uint32_t packet_len;
/* pointer to the packet */ /* pointer to the packet */
@ -145,10 +152,16 @@ typedef struct {
uint32_t next_packet_size; uint32_t next_packet_size;
/* packets sent through this channel */ /* packets sent through this channel */
uint64_t num_packets; uint64_t num_packets;
/* pages sent through this channel */ /* non zero pages recv through this channel */
uint64_t num_pages; uint64_t total_normal_pages;
/* syncs main thread and channels */ /* syncs main thread and channels */
QemuSemaphore sem_sync; QemuSemaphore sem_sync;
/* buffers to recv */
struct iovec *iov;
/* Pages that are not zero */
ram_addr_t *normal;
/* num of non zero pages */
uint32_t normal_num;
/* used for de-compression methods */ /* used for de-compression methods */
void *data; void *data;
} MultiFDRecvParams; } MultiFDRecvParams;
@ -160,8 +173,6 @@ typedef struct {
void (*send_cleanup)(MultiFDSendParams *p, Error **errp); void (*send_cleanup)(MultiFDSendParams *p, Error **errp);
/* Prepare the send packet */ /* Prepare the send packet */
int (*send_prepare)(MultiFDSendParams *p, Error **errp); int (*send_prepare)(MultiFDSendParams *p, Error **errp);
/* Write the send packet */
int (*send_write)(MultiFDSendParams *p, uint32_t used, Error **errp);
/* Setup for receiving side */ /* Setup for receiving side */
int (*recv_setup)(MultiFDRecvParams *p, Error **errp); int (*recv_setup)(MultiFDRecvParams *p, Error **errp);
/* Cleanup for receiving side */ /* Cleanup for receiving side */

View file

@ -283,15 +283,13 @@ static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis)
} }
#ifdef UFFD_FEATURE_THREAD_ID #ifdef UFFD_FEATURE_THREAD_ID
if (migrate_postcopy_blocktime() && mis && if (UFFD_FEATURE_THREAD_ID & supported_features) {
UFFD_FEATURE_THREAD_ID & supported_features) { asked_features |= UFFD_FEATURE_THREAD_ID;
/* kernel supports that feature */ if (migrate_postcopy_blocktime()) {
/* don't create blocktime_context if it exists */
if (!mis->blocktime_ctx) { if (!mis->blocktime_ctx) {
mis->blocktime_ctx = blocktime_context_new(); mis->blocktime_ctx = blocktime_context_new();
} }
}
asked_features |= UFFD_FEATURE_THREAD_ID;
} }
#endif #endif
@ -525,6 +523,19 @@ int postcopy_ram_incoming_init(MigrationIncomingState *mis)
return 0; return 0;
} }
static void postcopy_temp_pages_cleanup(MigrationIncomingState *mis)
{
if (mis->postcopy_tmp_page) {
munmap(mis->postcopy_tmp_page, mis->largest_page_size);
mis->postcopy_tmp_page = NULL;
}
if (mis->postcopy_tmp_zero_page) {
munmap(mis->postcopy_tmp_zero_page, mis->largest_page_size);
mis->postcopy_tmp_zero_page = NULL;
}
}
/* /*
* At the end of a migration where postcopy_ram_incoming_init was called. * At the end of a migration where postcopy_ram_incoming_init was called.
*/ */
@ -566,14 +577,8 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)
} }
} }
if (mis->postcopy_tmp_page) { postcopy_temp_pages_cleanup(mis);
munmap(mis->postcopy_tmp_page, mis->largest_page_size);
mis->postcopy_tmp_page = NULL;
}
if (mis->postcopy_tmp_zero_page) {
munmap(mis->postcopy_tmp_zero_page, mis->largest_page_size);
mis->postcopy_tmp_zero_page = NULL;
}
trace_postcopy_ram_incoming_cleanup_blocktime( trace_postcopy_ram_incoming_cleanup_blocktime(
get_postcopy_total_blocktime()); get_postcopy_total_blocktime());
@ -1084,6 +1089,40 @@ retry:
return NULL; return NULL;
} }
static int postcopy_temp_pages_setup(MigrationIncomingState *mis)
{
int err;
mis->postcopy_tmp_page = mmap(NULL, mis->largest_page_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mis->postcopy_tmp_page == MAP_FAILED) {
err = errno;
mis->postcopy_tmp_page = NULL;
error_report("%s: Failed to map postcopy_tmp_page %s",
__func__, strerror(err));
return -err;
}
/*
* Map large zero page when kernel can't use UFFDIO_ZEROPAGE for hugepages
*/
mis->postcopy_tmp_zero_page = mmap(NULL, mis->largest_page_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mis->postcopy_tmp_zero_page == MAP_FAILED) {
err = errno;
mis->postcopy_tmp_zero_page = NULL;
error_report("%s: Failed to map large zero page %s",
__func__, strerror(err));
return -err;
}
memset(mis->postcopy_tmp_zero_page, '\0', mis->largest_page_size);
return 0;
}
int postcopy_ram_incoming_setup(MigrationIncomingState *mis) int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
{ {
/* Open the fd for the kernel to give us userfaults */ /* Open the fd for the kernel to give us userfaults */
@ -1124,32 +1163,11 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
return -1; return -1;
} }
mis->postcopy_tmp_page = mmap(NULL, mis->largest_page_size, if (postcopy_temp_pages_setup(mis)) {
PROT_READ | PROT_WRITE, MAP_PRIVATE | /* Error dumped in the sub-function */
MAP_ANONYMOUS, -1, 0);
if (mis->postcopy_tmp_page == MAP_FAILED) {
mis->postcopy_tmp_page = NULL;
error_report("%s: Failed to map postcopy_tmp_page %s",
__func__, strerror(errno));
return -1; return -1;
} }
/*
* Map large zero page when kernel can't use UFFDIO_ZEROPAGE for hugepages
*/
mis->postcopy_tmp_zero_page = mmap(NULL, mis->largest_page_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (mis->postcopy_tmp_zero_page == MAP_FAILED) {
int e = errno;
mis->postcopy_tmp_zero_page = NULL;
error_report("%s: Failed to map large zero page %s",
__func__, strerror(e));
return -e;
}
memset(mis->postcopy_tmp_zero_page, '\0', mis->largest_page_size);
trace_postcopy_ram_enable_notify(); trace_postcopy_ram_enable_notify();
return 0; return 0;

View file

@ -325,7 +325,8 @@ struct RAMState {
uint64_t xbzrle_bytes_prev; uint64_t xbzrle_bytes_prev;
/* Start using XBZRLE (e.g., after the first round). */ /* Start using XBZRLE (e.g., after the first round). */
bool xbzrle_enabled; bool xbzrle_enabled;
/* Are we on the last stage of migration */
bool last_stage;
/* compression statistics since the beginning of the period */ /* compression statistics since the beginning of the period */
/* amount of count that no free thread to compress data */ /* amount of count that no free thread to compress data */
uint64_t compress_thread_busy_prev; uint64_t compress_thread_busy_prev;
@ -354,6 +355,12 @@ static RAMState *ram_state;
static NotifierWithReturnList precopy_notifier_list; static NotifierWithReturnList precopy_notifier_list;
/* Whether postcopy has queued requests? */
static bool postcopy_has_request(RAMState *rs)
{
return !QSIMPLEQ_EMPTY_ATOMIC(&rs->src_page_requests);
}
void precopy_infrastructure_init(void) void precopy_infrastructure_init(void)
{ {
notifier_with_return_list_init(&precopy_notifier_list); notifier_with_return_list_init(&precopy_notifier_list);
@ -386,6 +393,18 @@ uint64_t ram_bytes_remaining(void)
MigrationStats ram_counters; MigrationStats ram_counters;
static void ram_transferred_add(uint64_t bytes)
{
if (runstate_is_running()) {
ram_counters.precopy_bytes += bytes;
} else if (migration_in_postcopy()) {
ram_counters.postcopy_bytes += bytes;
} else {
ram_counters.downtime_bytes += bytes;
}
ram_counters.transferred += bytes;
}
/* used by the search for pages to send */ /* used by the search for pages to send */
struct PageSearchStatus { struct PageSearchStatus {
/* Current block being searched */ /* Current block being searched */
@ -683,11 +702,10 @@ static void xbzrle_cache_zero_page(RAMState *rs, ram_addr_t current_addr)
* @current_addr: addr of the page * @current_addr: addr of the page
* @block: block that contains the page we want to send * @block: block that contains the page we want to send
* @offset: offset inside the block for the page * @offset: offset inside the block for the page
* @last_stage: if we are at the completion stage
*/ */
static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, static int save_xbzrle_page(RAMState *rs, uint8_t **current_data,
ram_addr_t current_addr, RAMBlock *block, ram_addr_t current_addr, RAMBlock *block,
ram_addr_t offset, bool last_stage) ram_addr_t offset)
{ {
int encoded_len = 0, bytes_xbzrle; int encoded_len = 0, bytes_xbzrle;
uint8_t *prev_cached_page; uint8_t *prev_cached_page;
@ -695,7 +713,7 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data,
if (!cache_is_cached(XBZRLE.cache, current_addr, if (!cache_is_cached(XBZRLE.cache, current_addr,
ram_counters.dirty_sync_count)) { ram_counters.dirty_sync_count)) {
xbzrle_counters.cache_miss++; xbzrle_counters.cache_miss++;
if (!last_stage) { if (!rs->last_stage) {
if (cache_insert(XBZRLE.cache, current_addr, *current_data, if (cache_insert(XBZRLE.cache, current_addr, *current_data,
ram_counters.dirty_sync_count) == -1) { ram_counters.dirty_sync_count) == -1) {
return -1; return -1;
@ -734,7 +752,7 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data,
* Update the cache contents, so that it corresponds to the data * Update the cache contents, so that it corresponds to the data
* sent, in all cases except where we skip the page. * sent, in all cases except where we skip the page.
*/ */
if (!last_stage && encoded_len != 0) { if (!rs->last_stage && encoded_len != 0) {
memcpy(prev_cached_page, XBZRLE.current_buf, TARGET_PAGE_SIZE); memcpy(prev_cached_page, XBZRLE.current_buf, TARGET_PAGE_SIZE);
/* /*
* In the case where we couldn't compress, ensure that the caller * In the case where we couldn't compress, ensure that the caller
@ -767,7 +785,7 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data,
* RAM_SAVE_FLAG_CONTINUE. * RAM_SAVE_FLAG_CONTINUE.
*/ */
xbzrle_counters.bytes += bytes_xbzrle - 8; xbzrle_counters.bytes += bytes_xbzrle - 8;
ram_counters.transferred += bytes_xbzrle; ram_transferred_add(bytes_xbzrle);
return 1; return 1;
} }
@ -1158,6 +1176,15 @@ static void migration_bitmap_sync_precopy(RAMState *rs)
} }
} }
static void ram_release_page(const char *rbname, uint64_t offset)
{
if (!migrate_release_ram() || !migration_in_postcopy()) {
return;
}
ram_discard_range(rbname, offset, TARGET_PAGE_SIZE);
}
/** /**
* save_zero_page_to_file: send the zero page to the file * save_zero_page_to_file: send the zero page to the file
* *
@ -1179,6 +1206,7 @@ static int save_zero_page_to_file(RAMState *rs, QEMUFile *file,
len += save_page_header(rs, file, block, offset | RAM_SAVE_FLAG_ZERO); len += save_page_header(rs, file, block, offset | RAM_SAVE_FLAG_ZERO);
qemu_put_byte(file, 0); qemu_put_byte(file, 0);
len += 1; len += 1;
ram_release_page(block->idstr, offset);
} }
return len; return len;
} }
@ -1198,21 +1226,12 @@ static int save_zero_page(RAMState *rs, RAMBlock *block, ram_addr_t offset)
if (len) { if (len) {
ram_counters.duplicate++; ram_counters.duplicate++;
ram_counters.transferred += len; ram_transferred_add(len);
return 1; return 1;
} }
return -1; return -1;
} }
static void ram_release_pages(const char *rbname, uint64_t offset, int pages)
{
if (!migrate_release_ram() || !migration_in_postcopy()) {
return;
}
ram_discard_range(rbname, offset, ((ram_addr_t)pages) << TARGET_PAGE_BITS);
}
/* /*
* @pages: the number of pages written by the control path, * @pages: the number of pages written by the control path,
* < 0 - error * < 0 - error
@ -1234,7 +1253,7 @@ static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
} }
if (bytes_xmit) { if (bytes_xmit) {
ram_counters.transferred += bytes_xmit; ram_transferred_add(bytes_xmit);
*pages = 1; *pages = 1;
} }
@ -1265,8 +1284,8 @@ static bool control_save_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset, static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
uint8_t *buf, bool async) uint8_t *buf, bool async)
{ {
ram_counters.transferred += save_page_header(rs, rs->f, block, ram_transferred_add(save_page_header(rs, rs->f, block,
offset | RAM_SAVE_FLAG_PAGE); offset | RAM_SAVE_FLAG_PAGE));
if (async) { if (async) {
qemu_put_buffer_async(rs->f, buf, TARGET_PAGE_SIZE, qemu_put_buffer_async(rs->f, buf, TARGET_PAGE_SIZE,
migrate_release_ram() & migrate_release_ram() &
@ -1274,7 +1293,7 @@ static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
} else { } else {
qemu_put_buffer(rs->f, buf, TARGET_PAGE_SIZE); qemu_put_buffer(rs->f, buf, TARGET_PAGE_SIZE);
} }
ram_counters.transferred += TARGET_PAGE_SIZE; ram_transferred_add(TARGET_PAGE_SIZE);
ram_counters.normal++; ram_counters.normal++;
return 1; return 1;
} }
@ -1290,9 +1309,8 @@ static int save_normal_page(RAMState *rs, RAMBlock *block, ram_addr_t offset,
* @rs: current RAM state * @rs: current RAM state
* @block: block that contains the page we want to send * @block: block that contains the page we want to send
* @offset: offset inside the block for the page * @offset: offset inside the block for the page
* @last_stage: if we are at the completion stage
*/ */
static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) static int ram_save_page(RAMState *rs, PageSearchStatus *pss)
{ {
int pages = -1; int pages = -1;
uint8_t *p; uint8_t *p;
@ -1307,8 +1325,8 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage)
XBZRLE_cache_lock(); XBZRLE_cache_lock();
if (rs->xbzrle_enabled && !migration_in_postcopy()) { if (rs->xbzrle_enabled && !migration_in_postcopy()) {
pages = save_xbzrle_page(rs, &p, current_addr, block, pages = save_xbzrle_page(rs, &p, current_addr, block,
offset, last_stage); offset);
if (!last_stage) { if (!rs->last_stage) {
/* Can't send this cached data async, since the cache page /* Can't send this cached data async, since the cache page
* might get updated before it gets to the wire * might get updated before it gets to the wire
*/ */
@ -1341,13 +1359,11 @@ static bool do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block,
ram_addr_t offset, uint8_t *source_buf) ram_addr_t offset, uint8_t *source_buf)
{ {
RAMState *rs = ram_state; RAMState *rs = ram_state;
uint8_t *p = block->host + (offset & TARGET_PAGE_MASK); uint8_t *p = block->host + offset;
bool zero_page = false;
int ret; int ret;
if (save_zero_page_to_file(rs, f, block, offset)) { if (save_zero_page_to_file(rs, f, block, offset)) {
zero_page = true; return true;
goto exit;
} }
save_page_header(rs, f, block, offset | RAM_SAVE_FLAG_COMPRESS_PAGE); save_page_header(rs, f, block, offset | RAM_SAVE_FLAG_COMPRESS_PAGE);
@ -1362,18 +1378,14 @@ static bool do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block,
if (ret < 0) { if (ret < 0) {
qemu_file_set_error(migrate_get_current()->to_dst_file, ret); qemu_file_set_error(migrate_get_current()->to_dst_file, ret);
error_report("compressed data failed!"); error_report("compressed data failed!");
return false;
} }
return false;
exit:
ram_release_pages(block->idstr, offset & TARGET_PAGE_MASK, 1);
return zero_page;
} }
static void static void
update_compress_thread_counts(const CompressParam *param, int bytes_xmit) update_compress_thread_counts(const CompressParam *param, int bytes_xmit)
{ {
ram_counters.transferred += bytes_xmit; ram_transferred_add(bytes_xmit);
if (param->zero_page) { if (param->zero_page) {
ram_counters.duplicate++; ram_counters.duplicate++;
@ -1533,29 +1545,41 @@ static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again)
*/ */
static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset) static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset)
{ {
struct RAMSrcPageRequest *entry;
RAMBlock *block = NULL; RAMBlock *block = NULL;
size_t page_size;
if (QSIMPLEQ_EMPTY_ATOMIC(&rs->src_page_requests)) { if (!postcopy_has_request(rs)) {
return NULL; return NULL;
} }
QEMU_LOCK_GUARD(&rs->src_page_req_mutex); QEMU_LOCK_GUARD(&rs->src_page_req_mutex);
if (!QSIMPLEQ_EMPTY(&rs->src_page_requests)) {
struct RAMSrcPageRequest *entry = /*
QSIMPLEQ_FIRST(&rs->src_page_requests); * This should _never_ change even after we take the lock, because no one
* should be taking anything off the request list other than us.
*/
assert(postcopy_has_request(rs));
entry = QSIMPLEQ_FIRST(&rs->src_page_requests);
block = entry->rb; block = entry->rb;
*offset = entry->offset; *offset = entry->offset;
page_size = qemu_ram_pagesize(block);
/* Each page request should only be multiple page size of the ramblock */
assert((entry->len % page_size) == 0);
if (entry->len > TARGET_PAGE_SIZE) { if (entry->len > page_size) {
entry->len -= TARGET_PAGE_SIZE; entry->len -= page_size;
entry->offset += TARGET_PAGE_SIZE; entry->offset += page_size;
} else { } else {
memory_region_unref(block->mr); memory_region_unref(block->mr);
QSIMPLEQ_REMOVE_HEAD(&rs->src_page_requests, next_req); QSIMPLEQ_REMOVE_HEAD(&rs->src_page_requests, next_req);
g_free(entry); g_free(entry);
migration_consume_urgent_request(); migration_consume_urgent_request();
} }
}
trace_unqueue_page(block->idstr, *offset,
test_bit((*offset >> TARGET_PAGE_BITS), block->bmap));
return block; return block;
} }
@ -1611,7 +1635,7 @@ static int ram_save_release_protection(RAMState *rs, PageSearchStatus *pss,
/* Check if page is from UFFD-managed region. */ /* Check if page is from UFFD-managed region. */
if (pss->block->flags & RAM_UF_WRITEPROTECT) { if (pss->block->flags & RAM_UF_WRITEPROTECT) {
void *page_address = pss->block->host + (start_page << TARGET_PAGE_BITS); void *page_address = pss->block->host + (start_page << TARGET_PAGE_BITS);
uint64_t run_length = (pss->page - start_page + 1) << TARGET_PAGE_BITS; uint64_t run_length = (pss->page - start_page) << TARGET_PAGE_BITS;
/* Flush async buffers before un-protect. */ /* Flush async buffers before un-protect. */
qemu_fflush(rs->f); qemu_fflush(rs->f);
@ -1931,30 +1955,8 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss)
{ {
RAMBlock *block; RAMBlock *block;
ram_addr_t offset; ram_addr_t offset;
bool dirty;
do {
block = unqueue_page(rs, &offset); block = unqueue_page(rs, &offset);
/*
* We're sending this page, and since it's postcopy nothing else
* will dirty it, and we must make sure it doesn't get sent again
* even if this queue request was received after the background
* search already sent it.
*/
if (block) {
unsigned long page;
page = offset >> TARGET_PAGE_BITS;
dirty = test_bit(page, block->bmap);
if (!dirty) {
trace_get_queued_page_not_dirty(block->idstr, (uint64_t)offset,
page);
} else {
trace_get_queued_page(block->idstr, (uint64_t)offset, page);
}
}
} while (block && !dirty);
if (!block) { if (!block) {
/* /*
@ -2129,10 +2131,8 @@ static bool save_compress_page(RAMState *rs, RAMBlock *block, ram_addr_t offset)
* *
* @rs: current RAM state * @rs: current RAM state
* @pss: data about the page we want to send * @pss: data about the page we want to send
* @last_stage: if we are at the completion stage
*/ */
static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss, static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss)
bool last_stage)
{ {
RAMBlock *block = pss->block; RAMBlock *block = pss->block;
ram_addr_t offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS; ram_addr_t offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS;
@ -2156,7 +2156,6 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
xbzrle_cache_zero_page(rs, block->offset + offset); xbzrle_cache_zero_page(rs, block->offset + offset);
XBZRLE_cache_unlock(); XBZRLE_cache_unlock();
} }
ram_release_pages(block->idstr, offset, res);
return res; return res;
} }
@ -2171,7 +2170,7 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
return ram_save_multifd_page(rs, block, offset); return ram_save_multifd_page(rs, block, offset);
} }
return ram_save_page(rs, pss, last_stage); return ram_save_page(rs, pss);
} }
/** /**
@ -2188,12 +2187,9 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
* Returns the number of pages written or negative on error * Returns the number of pages written or negative on error
* *
* @rs: current RAM state * @rs: current RAM state
* @ms: current migration state
* @pss: data about the page we want to send * @pss: data about the page we want to send
* @last_stage: if we are at the completion stage
*/ */
static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss)
bool last_stage)
{ {
int tmppages, pages = 0; int tmppages, pages = 0;
size_t pagesize_bits = size_t pagesize_bits =
@ -2211,7 +2207,7 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
do { do {
/* Check the pages is dirty and if it is send it */ /* Check the pages is dirty and if it is send it */
if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) {
tmppages = ram_save_target_page(rs, pss, last_stage); tmppages = ram_save_target_page(rs, pss);
if (tmppages < 0) { if (tmppages < 0) {
return tmppages; return tmppages;
} }
@ -2230,7 +2226,7 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
offset_in_ramblock(pss->block, offset_in_ramblock(pss->block,
((ram_addr_t)pss->page) << TARGET_PAGE_BITS)); ((ram_addr_t)pss->page) << TARGET_PAGE_BITS));
/* The offset we leave with is the min boundary of host page and block */ /* The offset we leave with is the min boundary of host page and block */
pss->page = MIN(pss->page, hostpage_boundary) - 1; pss->page = MIN(pss->page, hostpage_boundary);
res = ram_save_release_protection(rs, pss, start_page); res = ram_save_release_protection(rs, pss, start_page);
return (res < 0 ? res : pages); return (res < 0 ? res : pages);
@ -2245,13 +2241,11 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
* or negative on error * or negative on error
* *
* @rs: current RAM state * @rs: current RAM state
* @last_stage: if we are at the completion stage
* *
* On systems where host-page-size > target-page-size it will send all the * On systems where host-page-size > target-page-size it will send all the
* pages in a host page that are dirty. * pages in a host page that are dirty.
*/ */
static int ram_find_and_save_block(RAMState *rs)
static int ram_find_and_save_block(RAMState *rs, bool last_stage)
{ {
PageSearchStatus pss; PageSearchStatus pss;
int pages = 0; int pages = 0;
@ -2280,7 +2274,7 @@ static int ram_find_and_save_block(RAMState *rs, bool last_stage)
} }
if (found) { if (found) {
pages = ram_save_host_page(rs, &pss, last_stage); pages = ram_save_host_page(rs, &pss);
} }
} while (!pages && again); } while (!pages && again);
@ -2298,7 +2292,7 @@ void acct_update_position(QEMUFile *f, size_t size, bool zero)
ram_counters.duplicate += pages; ram_counters.duplicate += pages;
} else { } else {
ram_counters.normal += pages; ram_counters.normal += pages;
ram_counters.transferred += size; ram_transferred_add(size);
qemu_update_position(f, size); qemu_update_position(f, size);
} }
} }
@ -2408,40 +2402,6 @@ static void ram_state_reset(RAMState *rs)
#define MAX_WAIT 50 /* ms, half buffered_file limit */ #define MAX_WAIT 50 /* ms, half buffered_file limit */
/*
* 'expected' is the value you expect the bitmap mostly to be full
* of; it won't bother printing lines that are all this value.
* If 'todump' is null the migration bitmap is dumped.
*/
void ram_debug_dump_bitmap(unsigned long *todump, bool expected,
unsigned long pages)
{
int64_t cur;
int64_t linelen = 128;
char linebuf[129];
for (cur = 0; cur < pages; cur += linelen) {
int64_t curb;
bool found = false;
/*
* Last line; catch the case where the line length
* is longer than remaining ram
*/
if (cur + linelen > pages) {
linelen = pages - cur;
}
for (curb = 0; curb < linelen; curb++) {
bool thisbit = test_bit(cur + curb, todump);
linebuf[curb] = thisbit ? '1' : '.';
found = found || (thisbit != expected);
}
if (found) {
linebuf[curb] = '\0';
fprintf(stderr, "0x%08" PRIx64 " : %s\n", cur, linebuf);
}
}
}
/* **** functions for postcopy ***** */ /* **** functions for postcopy ***** */
void ram_postcopy_migrated_memory_release(MigrationState *ms) void ram_postcopy_migrated_memory_release(MigrationState *ms)
@ -2467,14 +2427,12 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms)
/** /**
* postcopy_send_discard_bm_ram: discard a RAMBlock * postcopy_send_discard_bm_ram: discard a RAMBlock
* *
* Returns zero on success
*
* Callback from postcopy_each_ram_send_discard for each RAMBlock * Callback from postcopy_each_ram_send_discard for each RAMBlock
* *
* @ms: current migration state * @ms: current migration state
* @block: RAMBlock to discard * @block: RAMBlock to discard
*/ */
static int postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block) static void postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block)
{ {
unsigned long end = block->used_length >> TARGET_PAGE_BITS; unsigned long end = block->used_length >> TARGET_PAGE_BITS;
unsigned long current; unsigned long current;
@ -2498,15 +2456,13 @@ static int postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block)
postcopy_discard_send_range(ms, one, discard_length); postcopy_discard_send_range(ms, one, discard_length);
current = one + discard_length; current = one + discard_length;
} }
return 0;
} }
static void postcopy_chunk_hostpages_pass(MigrationState *ms, RAMBlock *block);
/** /**
* postcopy_each_ram_send_discard: discard all RAMBlocks * postcopy_each_ram_send_discard: discard all RAMBlocks
* *
* Returns 0 for success or negative for error
*
* Utility for the outgoing postcopy code. * Utility for the outgoing postcopy code.
* Calls postcopy_send_discard_bm_ram for each RAMBlock * Calls postcopy_send_discard_bm_ram for each RAMBlock
* passing it bitmap indexes and name. * passing it bitmap indexes and name.
@ -2515,27 +2471,29 @@ static int postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block)
* *
* @ms: current migration state * @ms: current migration state
*/ */
static int postcopy_each_ram_send_discard(MigrationState *ms) static void postcopy_each_ram_send_discard(MigrationState *ms)
{ {
struct RAMBlock *block; struct RAMBlock *block;
int ret;
RAMBLOCK_FOREACH_NOT_IGNORED(block) { RAMBLOCK_FOREACH_NOT_IGNORED(block) {
postcopy_discard_send_init(ms, block->idstr); postcopy_discard_send_init(ms, block->idstr);
/*
* Deal with TPS != HPS and huge pages. It discard any partially sent
* host-page size chunks, mark any partially dirty host-page size
* chunks as all dirty. In this case the host-page is the host-page
* for the particular RAMBlock, i.e. it might be a huge page.
*/
postcopy_chunk_hostpages_pass(ms, block);
/* /*
* Postcopy sends chunks of bitmap over the wire, but it * Postcopy sends chunks of bitmap over the wire, but it
* just needs indexes at this point, avoids it having * just needs indexes at this point, avoids it having
* target page specific code. * target page specific code.
*/ */
ret = postcopy_send_discard_bm_ram(ms, block); postcopy_send_discard_bm_ram(ms, block);
postcopy_discard_send_finish(ms); postcopy_discard_send_finish(ms);
if (ret) {
return ret;
} }
}
return 0;
} }
/** /**
@ -2605,38 +2563,9 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, RAMBlock *block)
} }
} }
/**
* postcopy_chunk_hostpages: discard any partially sent host page
*
* Utility for the outgoing postcopy code.
*
* Discard any partially sent host-page size chunks, mark any partially
* dirty host-page size chunks as all dirty. In this case the host-page
* is the host-page for the particular RAMBlock, i.e. it might be a huge page
*
* Returns zero on success
*
* @ms: current migration state
* @block: block we want to work with
*/
static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block)
{
postcopy_discard_send_init(ms, block->idstr);
/*
* Ensure that all partially dirty host pages are made fully dirty.
*/
postcopy_chunk_hostpages_pass(ms, block);
postcopy_discard_send_finish(ms);
return 0;
}
/** /**
* ram_postcopy_send_discard_bitmap: transmit the discard bitmap * ram_postcopy_send_discard_bitmap: transmit the discard bitmap
* *
* Returns zero on success
*
* Transmit the set of pages to be discarded after precopy to the target * Transmit the set of pages to be discarded after precopy to the target
* these are pages that: * these are pages that:
* a) Have been previously transmitted but are now dirty again * a) Have been previously transmitted but are now dirty again
@ -2647,11 +2576,9 @@ static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block)
* *
* @ms: current migration state * @ms: current migration state
*/ */
int ram_postcopy_send_discard_bitmap(MigrationState *ms) void ram_postcopy_send_discard_bitmap(MigrationState *ms)
{ {
RAMState *rs = ram_state; RAMState *rs = ram_state;
RAMBlock *block;
int ret;
RCU_READ_LOCK_GUARD(); RCU_READ_LOCK_GUARD();
@ -2663,21 +2590,9 @@ int ram_postcopy_send_discard_bitmap(MigrationState *ms)
rs->last_sent_block = NULL; rs->last_sent_block = NULL;
rs->last_page = 0; rs->last_page = 0;
RAMBLOCK_FOREACH_NOT_IGNORED(block) { postcopy_each_ram_send_discard(ms);
/* Deal with TPS != HPS and huge pages */
ret = postcopy_chunk_hostpages(ms, block);
if (ret) {
return ret;
}
#ifdef DEBUG_POSTCOPY
ram_debug_dump_bitmap(block->bmap, true,
block->used_length >> TARGET_PAGE_BITS);
#endif
}
trace_ram_postcopy_send_discard_bitmap(); trace_ram_postcopy_send_discard_bitmap();
return postcopy_each_ram_send_discard(ms);
} }
/** /**
@ -3073,14 +2988,14 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
i = 0; i = 0;
while ((ret = qemu_file_rate_limit(f)) == 0 || while ((ret = qemu_file_rate_limit(f)) == 0 ||
!QSIMPLEQ_EMPTY(&rs->src_page_requests)) { postcopy_has_request(rs)) {
int pages; int pages;
if (qemu_file_get_error(f)) { if (qemu_file_get_error(f)) {
break; break;
} }
pages = ram_find_and_save_block(rs, false); pages = ram_find_and_save_block(rs);
/* no more pages to sent */ /* no more pages to sent */
if (pages == 0) { if (pages == 0) {
done = 1; done = 1;
@ -3133,7 +3048,7 @@ out:
multifd_send_sync_main(rs->f); multifd_send_sync_main(rs->f);
qemu_put_be64(f, RAM_SAVE_FLAG_EOS); qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
qemu_fflush(f); qemu_fflush(f);
ram_counters.transferred += 8; ram_transferred_add(8);
ret = qemu_file_get_error(f); ret = qemu_file_get_error(f);
} }
@ -3160,6 +3075,8 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
RAMState *rs = *temp; RAMState *rs = *temp;
int ret = 0; int ret = 0;
rs->last_stage = !migration_in_colo_state();
WITH_RCU_READ_LOCK_GUARD() { WITH_RCU_READ_LOCK_GUARD() {
if (!migration_in_postcopy()) { if (!migration_in_postcopy()) {
migration_bitmap_sync_precopy(rs); migration_bitmap_sync_precopy(rs);
@ -3173,7 +3090,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
while (true) { while (true) {
int pages; int pages;
pages = ram_find_and_save_block(rs, !migration_in_colo_state()); pages = ram_find_and_save_block(rs);
/* no more blocks to sent */ /* no more blocks to sent */
if (pages == 0) { if (pages == 0) {
break; break;

View file

@ -55,11 +55,9 @@ void mig_throttle_counter_reset(void);
uint64_t ram_pagesize_summary(void); uint64_t ram_pagesize_summary(void);
int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len); int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len);
void acct_update_position(QEMUFile *f, size_t size, bool zero); void acct_update_position(QEMUFile *f, size_t size, bool zero);
void ram_debug_dump_bitmap(unsigned long *todump, bool expected,
unsigned long pages);
void ram_postcopy_migrated_memory_release(MigrationState *ms); void ram_postcopy_migrated_memory_release(MigrationState *ms);
/* For outgoing discard bitmap */ /* For outgoing discard bitmap */
int ram_postcopy_send_discard_bitmap(MigrationState *ms); void ram_postcopy_send_discard_bitmap(MigrationState *ms);
/* For incoming postcopy discard */ /* For incoming postcopy discard */
int ram_discard_range(const char *block_name, uint64_t start, size_t length); int ram_discard_range(const char *block_name, uint64_t start, size_t length);
int ram_postcopy_incoming_init(MigrationIncomingState *mis); int ram_postcopy_incoming_init(MigrationIncomingState *mis);

View file

@ -1298,8 +1298,9 @@ int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy)
save_section_footer(f, se); save_section_footer(f, se);
if (ret < 0) { if (ret < 0) {
error_report("failed to save SaveStateEntry with id(name): %d(%s)", error_report("failed to save SaveStateEntry with id(name): "
se->section_id, se->idstr); "%d(%s): %d",
se->section_id, se->idstr, ret);
qemu_file_set_error(f, ret); qemu_file_set_error(f, ret);
} }
if (ret <= 0) { if (ret <= 0) {

View file

@ -86,8 +86,6 @@ put_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)"
qemu_file_fclose(void) "" qemu_file_fclose(void) ""
# ram.c # ram.c
get_queued_page(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx"
get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx"
migration_bitmap_sync_start(void) "" migration_bitmap_sync_start(void) ""
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64 migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx" migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx"
@ -113,25 +111,26 @@ ram_save_iterate_big_wait(uint64_t milliconds, int iterations) "big wait: %" PRI
ram_load_complete(int ret, uint64_t seq_iter) "exit_code %d seq iteration %" PRIu64 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_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" 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"
unqueue_page(char *block, uint64_t offset, bool dirty) "ramblock '%s' offset 0x%"PRIx64" dirty %d"
# multifd.c # multifd.c
multifd_new_send_channel_async(uint8_t id) "channel %d" multifd_new_send_channel_async(uint8_t id) "channel %u"
multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %d packet_num %" PRIu64 " pages %d flags 0x%x next packet size %d" multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " pages %u flags 0x%x next packet size %u"
multifd_recv_new_channel(uint8_t id) "channel %d" multifd_recv_new_channel(uint8_t id) "channel %u"
multifd_recv_sync_main(long packet_num) "packet num %ld" multifd_recv_sync_main(long packet_num) "packet num %ld"
multifd_recv_sync_main_signal(uint8_t id) "channel %d" multifd_recv_sync_main_signal(uint8_t id) "channel %u"
multifd_recv_sync_main_wait(uint8_t id) "channel %d" multifd_recv_sync_main_wait(uint8_t id) "channel %u"
multifd_recv_terminate_threads(bool error) "error %d" multifd_recv_terminate_threads(bool error) "error %d"
multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %d packets %" PRIu64 " pages %" PRIu64 multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %u packets %" PRIu64 " pages %" PRIu64
multifd_recv_thread_start(uint8_t id) "%d" multifd_recv_thread_start(uint8_t id) "%u"
multifd_send(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %d packet_num %" PRIu64 " pages %d flags 0x%x next packet size %d" multifd_send(uint8_t id, uint64_t packet_num, uint32_t normal, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " normal pages %u flags 0x%x next packet size %u"
multifd_send_error(uint8_t id) "channel %d" multifd_send_error(uint8_t id) "channel %u"
multifd_send_sync_main(long packet_num) "packet num %ld" multifd_send_sync_main(long packet_num) "packet num %ld"
multifd_send_sync_main_signal(uint8_t id) "channel %d" multifd_send_sync_main_signal(uint8_t id) "channel %u"
multifd_send_sync_main_wait(uint8_t id) "channel %d" multifd_send_sync_main_wait(uint8_t id) "channel %u"
multifd_send_terminate_threads(bool error) "error %d" multifd_send_terminate_threads(bool error) "error %d"
multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %d packets %" PRIu64 " pages %" PRIu64 multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t normal_pages) "channel %u packets %" PRIu64 " normal pages %" PRIu64
multifd_send_thread_start(uint8_t id) "%d" multifd_send_thread_start(uint8_t id) "%u"
multifd_tls_outgoing_handshake_start(void *ioc, void *tioc, const char *hostname) "ioc=%p tioc=%p hostname=%s" multifd_tls_outgoing_handshake_start(void *ioc, void *tioc, const char *hostname) "ioc=%p tioc=%p hostname=%s"
multifd_tls_outgoing_handshake_error(void *ioc, const char *err) "ioc=%p err=%s" multifd_tls_outgoing_handshake_error(void *ioc, const char *err) "ioc=%p err=%s"
multifd_tls_outgoing_handshake_complete(void *ioc) "ioc=%p" multifd_tls_outgoing_handshake_complete(void *ioc) "ioc=%p"

View file

@ -293,6 +293,18 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "postcopy request count: %" PRIu64 "\n", monitor_printf(mon, "postcopy request count: %" PRIu64 "\n",
info->ram->postcopy_requests); info->ram->postcopy_requests);
} }
if (info->ram->precopy_bytes) {
monitor_printf(mon, "precopy ram: %" PRIu64 " kbytes\n",
info->ram->precopy_bytes >> 10);
}
if (info->ram->downtime_bytes) {
monitor_printf(mon, "downtime ram: %" PRIu64 " kbytes\n",
info->ram->downtime_bytes >> 10);
}
if (info->ram->postcopy_bytes) {
monitor_printf(mon, "postcopy ram: %" PRIu64 " kbytes\n",
info->ram->postcopy_bytes >> 10);
}
} }
if (info->has_disk) { if (info->has_disk) {

View file

@ -46,6 +46,15 @@
# @pages-per-second: the number of memory pages transferred per second # @pages-per-second: the number of memory pages transferred per second
# (Since 4.0) # (Since 4.0)
# #
# @precopy-bytes: The number of bytes sent in the pre-copy phase
# (since 7.0).
#
# @downtime-bytes: The number of bytes sent while the guest is paused
# (since 7.0).
#
# @postcopy-bytes: The number of bytes sent during the post-copy phase
# (since 7.0).
#
# Since: 0.14 # Since: 0.14
## ##
{ 'struct': 'MigrationStats', { 'struct': 'MigrationStats',
@ -54,7 +63,9 @@
'normal-bytes': 'int', 'dirty-pages-rate' : 'int', 'normal-bytes': 'int', 'dirty-pages-rate' : 'int',
'mbps' : 'number', 'dirty-sync-count' : 'int', 'mbps' : 'number', 'dirty-sync-count' : 'int',
'postcopy-requests' : 'int', 'page-size' : 'int', 'postcopy-requests' : 'int', 'page-size' : 'int',
'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64' } } 'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64',
'precopy-bytes' : 'uint64', 'downtime-bytes' : 'uint64',
'postcopy-bytes' : 'uint64' } }
## ##
# @XBZRLECacheStats: # @XBZRLECacheStats:

View file

@ -25,7 +25,6 @@ static const VMStateDescription vmstate_tlb_entry = {
.name = "tlb_entry", .name = "tlb_entry",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINTTL(mr, OpenRISCTLBEntry), VMSTATE_UINTTL(mr, OpenRISCTLBEntry),
VMSTATE_UINTTL(tr, OpenRISCTLBEntry), VMSTATE_UINTTL(tr, OpenRISCTLBEntry),

View file

@ -421,7 +421,6 @@ static const VMStateDescription vmstate_tm = {
.name = "cpu/tm", .name = "cpu/tm",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.needed = tm_needed, .needed = tm_needed,
.fields = (VMStateField []) { .fields = (VMStateField []) {
VMSTATE_UINTTL_ARRAY(env.tm_gpr, PowerPCCPU, 32), VMSTATE_UINTTL_ARRAY(env.tm_gpr, PowerPCCPU, 32),
@ -672,7 +671,6 @@ const VMStateDescription vmstate_ppc_cpu = {
.name = "cpu", .name = "cpu",
.version_id = 5, .version_id = 5,
.minimum_version_id = 5, .minimum_version_id = 5,
.minimum_version_id_old = 4,
.pre_save = cpu_pre_save, .pre_save = cpu_pre_save,
.post_load = cpu_post_load, .post_load = cpu_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {

View file

@ -10,7 +10,6 @@ static const VMStateDescription vmstate_cpu_timer = {
.name = "cpu_timer", .name = "cpu_timer",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(frequency, CPUTimer), VMSTATE_UINT32(frequency, CPUTimer),
VMSTATE_UINT32(disabled, CPUTimer), VMSTATE_UINT32(disabled, CPUTimer),
@ -30,7 +29,6 @@ static const VMStateDescription vmstate_trap_state = {
.name = "trap_state", .name = "trap_state",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT64(tpc, trap_state), VMSTATE_UINT64(tpc, trap_state),
VMSTATE_UINT64(tnpc, trap_state), VMSTATE_UINT64(tnpc, trap_state),
@ -44,7 +42,6 @@ static const VMStateDescription vmstate_tlb_entry = {
.name = "tlb_entry", .name = "tlb_entry",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT64(tag, SparcTLBEntry), VMSTATE_UINT64(tag, SparcTLBEntry),
VMSTATE_UINT64(tte, SparcTLBEntry), VMSTATE_UINT64(tte, SparcTLBEntry),
@ -113,7 +110,6 @@ const VMStateDescription vmstate_sparc_cpu = {
.name = "cpu", .name = "cpu",
.version_id = SPARC_VMSTATE_VER, .version_id = SPARC_VMSTATE_VER,
.minimum_version_id = SPARC_VMSTATE_VER, .minimum_version_id = SPARC_VMSTATE_VER,
.minimum_version_id_old = SPARC_VMSTATE_VER,
.pre_save = cpu_pre_save, .pre_save = cpu_pre_save,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINTTL_ARRAY(env.gregs, SPARCCPU, 8), VMSTATE_UINTTL_ARRAY(env.gregs, SPARCCPU, 8),