mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-28 14:00:44 +00:00
Migration pull 2019-08-15
Marcel's vmxnet3 live migraiton fix (that breaks vmxnet3 compatibility but makes it work) Error description improvements from Yury. Multifd fixes from Ivan and Juan. A load of small cleanups from Wei. A small cleanup from Marc-André for a future patch. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEERfXHG0oMt/uXep+pBRYzHrxb/ecFAl1UTEcACgkQBRYzHrxb /ecSxg//bH7hrYMSYR2r4NxAaiR7E/iYz3cd6+zSs15rp2UKDP+sfAj0ovtiYsIu dEHlLiZdS9jBobJ7olebEng0LFgLtRyjt79Toa91aY7LEH1PkPXBl+kH6I52cKMr Ee9AQWDHwiEB3sfGkF9Dogxxeu/VeYgJrhXBgm5+cFRRmUvEr26fzVzPvk7WVzRV MtzGEjpXGCZAVBCz9EnDuSaBPI5cmFCqZUDg1itMX7HU2fRlwByMRVwGI/uIEPR6 j7U3qShyVeLVW+ctYeA1cyyb1UDKRw+D3ahlMIEID/4MxWyRHf6K5h7xUf6x7Wh4 laI+Cm1oxTmPvDkwkGhh/UO3TyNSIPg9uS+XSh/7R3evinJECW9MXFLL7H1fLjNQ K6moR2nUJxYSOqj3AXMRvMGPpeht437fR+7QwCOHZ0Xj/+wHxLTWP5L56qZnOlhX /Fl5vt9bZ3A9T/HwdU6RQ8XHlHdbYF52FYiWmfC7WkCY/TLg9s2RDb6kLCf6Go1f BriuA5ISZ34OfOJOIGNpif8ycvWpQo00vDSqahllbqUqAWZW24HxdsLlzbq9XZU8 1RTnxKPuMJW9RApCVYVkNsH8l7pXhCJXkvsRQwDEs0VW8h7JAGn+ma1gO4ODmocL FwF9ZydOFLpsrvjNBw5DEX6Pogj+jtJq0J1SCjknK7/SmO7Zu1U= =METp -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20190814a' into staging Migration pull 2019-08-15 Marcel's vmxnet3 live migraiton fix (that breaks vmxnet3 compatibility but makes it work) Error description improvements from Yury. Multifd fixes from Ivan and Juan. A load of small cleanups from Wei. A small cleanup from Marc-André for a future patch. # gpg: Signature made Wed 14 Aug 2019 19:00:39 BST # gpg: using RSA key 45F5C71B4A0CB7FB977A9FA90516331EBC5BFDE7 # gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>" [full] # Primary key fingerprint: 45F5 C71B 4A0C B7FB 977A 9FA9 0516 331E BC5B FDE7 * remotes/dgilbert/tags/pull-migration-20190814a: (33 commits) migration: add some multifd traces migration: Make global sem_sync semaphore by channel migration: Add traces for multifd terminate threads qemu-file: move qemu_{get,put}_counted_string() declarations migration/postcopy: use mis->bh instead of allocating a QEMUBH migration: rename migration_bitmap_sync_range to ramblock_sync_dirty_bitmap migration: update ram_counters for multifd sync packet migration: add speed limit for multifd migration migration: add qemu_file_update_transfer interface migration: always initialise ram_counters for a new migration migration: remove unused field bytes_xfer hmp: Remove migration capabilities from "info migrate" migration/postcopy: use QEMU_IS_ALIGNED to replace host_offset migration/postcopy: simplify calculation of run_start and fixup_start_addr migration/postcopy: make PostcopyDiscardState a static variable migration: extract ram_load_precopy migration: return -EINVAL directly when version_id mismatch migration: equation is more proper than and to check LOADVM_QUIT migration: just pass RAMBlock is enough migration: use migration_in_postcopy() to check POSTCOPY_ACTIVE ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
27608c7c66
@ -2141,21 +2141,6 @@ vmxnet3_cleanup_msi(VMXNET3State *s)
|
||||
msi_uninit(d);
|
||||
}
|
||||
|
||||
static void
|
||||
vmxnet3_msix_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(opaque);
|
||||
msix_save(d, f);
|
||||
}
|
||||
|
||||
static int
|
||||
vmxnet3_msix_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(opaque);
|
||||
msix_load(d, f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps b0_ops = {
|
||||
.read = vmxnet3_io_bar0_read,
|
||||
.write = vmxnet3_io_bar0_write,
|
||||
@ -2176,11 +2161,6 @@ static const MemoryRegionOps b1_ops = {
|
||||
},
|
||||
};
|
||||
|
||||
static SaveVMHandlers savevm_vmxnet3_msix = {
|
||||
.save_state = vmxnet3_msix_save,
|
||||
.load_state = vmxnet3_msix_load,
|
||||
};
|
||||
|
||||
static uint64_t vmxnet3_device_serial_num(VMXNET3State *s)
|
||||
{
|
||||
uint64_t dsn_payload;
|
||||
@ -2203,7 +2183,6 @@ static uint64_t vmxnet3_device_serial_num(VMXNET3State *s)
|
||||
|
||||
static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(pci_dev);
|
||||
VMXNET3State *s = VMXNET3(pci_dev);
|
||||
int ret;
|
||||
|
||||
@ -2249,8 +2228,6 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
|
||||
pcie_dev_ser_num_init(pci_dev, VMXNET3_DSN_OFFSET,
|
||||
vmxnet3_device_serial_num(s));
|
||||
}
|
||||
|
||||
register_savevm_live(dev, "vmxnet3-msix", -1, 1, &savevm_vmxnet3_msix, s);
|
||||
}
|
||||
|
||||
static void vmxnet3_instance_init(Object *obj)
|
||||
@ -2440,29 +2417,6 @@ static const VMStateDescription vmstate_vmxnet3_int_state = {
|
||||
}
|
||||
};
|
||||
|
||||
static bool vmxnet3_vmstate_need_pcie_device(void *opaque)
|
||||
{
|
||||
VMXNET3State *s = VMXNET3(opaque);
|
||||
|
||||
return !(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE);
|
||||
}
|
||||
|
||||
static bool vmxnet3_vmstate_test_pci_device(void *opaque, int version_id)
|
||||
{
|
||||
return !vmxnet3_vmstate_need_pcie_device(opaque);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_vmxnet3_pcie_device = {
|
||||
.name = "vmxnet3/pcie",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = vmxnet3_vmstate_need_pcie_device,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_vmxnet3 = {
|
||||
.name = "vmxnet3",
|
||||
.version_id = 1,
|
||||
@ -2470,9 +2424,8 @@ static const VMStateDescription vmstate_vmxnet3 = {
|
||||
.pre_save = vmxnet3_pre_save,
|
||||
.post_load = vmxnet3_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT_TEST(parent_obj, VMXNET3State,
|
||||
vmxnet3_vmstate_test_pci_device, 0,
|
||||
vmstate_pci_device, PCIDevice),
|
||||
VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State),
|
||||
VMSTATE_MSIX(parent_obj, VMXNET3State),
|
||||
VMSTATE_BOOL(rx_packets_compound, VMXNET3State),
|
||||
VMSTATE_BOOL(rx_vlan_stripping, VMXNET3State),
|
||||
VMSTATE_BOOL(lro_supported, VMXNET3State),
|
||||
@ -2508,7 +2461,6 @@ static const VMStateDescription vmstate_vmxnet3 = {
|
||||
},
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
&vmxstate_vmxnet3_mcast_list,
|
||||
&vmstate_vmxnet3_pcie_device,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
@ -161,6 +161,10 @@ static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv)
|
||||
qemu_get_be64s(f, (uint64_t *)pv);
|
||||
}
|
||||
|
||||
size_t qemu_get_counted_string(QEMUFile *f, char buf[256]);
|
||||
|
||||
void qemu_put_counted_string(QEMUFile *f, const char *name);
|
||||
|
||||
int qemu_file_rate_limit(QEMUFile *f);
|
||||
|
||||
#endif
|
||||
|
@ -823,6 +823,25 @@ bool migration_is_setup_or_active(int state)
|
||||
}
|
||||
}
|
||||
|
||||
static void populate_time_info(MigrationInfo *info, MigrationState *s)
|
||||
{
|
||||
info->has_status = true;
|
||||
info->has_setup_time = true;
|
||||
info->setup_time = s->setup_time;
|
||||
if (s->state == MIGRATION_STATUS_COMPLETED) {
|
||||
info->has_total_time = true;
|
||||
info->total_time = s->total_time;
|
||||
info->has_downtime = true;
|
||||
info->downtime = s->downtime;
|
||||
} else {
|
||||
info->has_total_time = true;
|
||||
info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
|
||||
s->start_time;
|
||||
info->has_expected_downtime = true;
|
||||
info->expected_downtime = s->expected_downtime;
|
||||
}
|
||||
}
|
||||
|
||||
static void populate_ram_info(MigrationInfo *info, MigrationState *s)
|
||||
{
|
||||
info->has_ram = true;
|
||||
@ -908,16 +927,8 @@ static void fill_source_migration_info(MigrationInfo *info)
|
||||
case MIGRATION_STATUS_DEVICE:
|
||||
case MIGRATION_STATUS_POSTCOPY_PAUSED:
|
||||
case MIGRATION_STATUS_POSTCOPY_RECOVER:
|
||||
/* TODO add some postcopy stats */
|
||||
info->has_status = true;
|
||||
info->has_total_time = true;
|
||||
info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
|
||||
- s->start_time;
|
||||
info->has_expected_downtime = true;
|
||||
info->expected_downtime = s->expected_downtime;
|
||||
info->has_setup_time = true;
|
||||
info->setup_time = s->setup_time;
|
||||
|
||||
/* TODO add some postcopy stats */
|
||||
populate_time_info(info, s);
|
||||
populate_ram_info(info, s);
|
||||
populate_disk_info(info);
|
||||
break;
|
||||
@ -926,14 +937,7 @@ static void fill_source_migration_info(MigrationInfo *info)
|
||||
/* TODO: display COLO specific information (checkpoint info etc.) */
|
||||
break;
|
||||
case MIGRATION_STATUS_COMPLETED:
|
||||
info->has_status = true;
|
||||
info->has_total_time = true;
|
||||
info->total_time = s->total_time;
|
||||
info->has_downtime = true;
|
||||
info->downtime = s->downtime;
|
||||
info->has_setup_time = true;
|
||||
info->setup_time = s->setup_time;
|
||||
|
||||
populate_time_info(info, s);
|
||||
populate_ram_info(info, s);
|
||||
break;
|
||||
case MIGRATION_STATUS_FAILED:
|
||||
@ -1695,7 +1699,6 @@ void migrate_init(MigrationState *s)
|
||||
* parameters/capabilities that the user set, and
|
||||
* locks.
|
||||
*/
|
||||
s->bytes_xfer = 0;
|
||||
s->cleanup_bh = 0;
|
||||
s->to_dst_file = NULL;
|
||||
s->state = MIGRATION_STATUS_NONE;
|
||||
@ -1908,6 +1911,11 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
|
||||
}
|
||||
|
||||
migrate_init(s);
|
||||
/*
|
||||
* set ram_counters memory to zero for a
|
||||
* new migration
|
||||
*/
|
||||
memset(&ram_counters, 0, sizeof(ram_counters));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2963,6 +2971,7 @@ static MigThrError migration_detect_error(MigrationState *s)
|
||||
{
|
||||
int ret;
|
||||
int state = s->state;
|
||||
Error *local_error = NULL;
|
||||
|
||||
if (state == MIGRATION_STATUS_CANCELLING ||
|
||||
state == MIGRATION_STATUS_CANCELLED) {
|
||||
@ -2971,13 +2980,18 @@ static MigThrError migration_detect_error(MigrationState *s)
|
||||
}
|
||||
|
||||
/* Try to detect any file errors */
|
||||
ret = qemu_file_get_error(s->to_dst_file);
|
||||
|
||||
ret = qemu_file_get_error_obj(s->to_dst_file, &local_error);
|
||||
if (!ret) {
|
||||
/* Everything is fine */
|
||||
assert(!local_error);
|
||||
return MIG_THR_ERR_NONE;
|
||||
}
|
||||
|
||||
if (local_error) {
|
||||
migrate_set_error(s, local_error);
|
||||
error_free(local_error);
|
||||
}
|
||||
|
||||
if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret == -EIO) {
|
||||
/*
|
||||
* For postcopy, we allow the network to be down for a
|
||||
@ -3025,6 +3039,17 @@ static void migration_calculate_complete(MigrationState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void update_iteration_initial_status(MigrationState *s)
|
||||
{
|
||||
/*
|
||||
* Update these three fields at the same time to avoid mismatch info lead
|
||||
* wrong speed calculation.
|
||||
*/
|
||||
s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
|
||||
s->iteration_initial_bytes = migration_total_bytes(s);
|
||||
s->iteration_initial_pages = ram_get_total_transferred_pages();
|
||||
}
|
||||
|
||||
static void migration_update_counters(MigrationState *s,
|
||||
int64_t current_time)
|
||||
{
|
||||
@ -3060,9 +3085,7 @@ static void migration_update_counters(MigrationState *s,
|
||||
|
||||
qemu_file_reset_rate_limit(s->to_dst_file);
|
||||
|
||||
s->iteration_start_time = current_time;
|
||||
s->iteration_initial_bytes = current_bytes;
|
||||
s->iteration_initial_pages = ram_get_total_transferred_pages();
|
||||
update_iteration_initial_status(s);
|
||||
|
||||
trace_migrate_transferred(transferred, time_spent,
|
||||
bandwidth, s->threshold_size);
|
||||
@ -3093,8 +3116,7 @@ static MigIterateState migration_iteration_run(MigrationState *s)
|
||||
|
||||
if (pending_size && pending_size >= s->threshold_size) {
|
||||
/* Still a significant amount to transfer */
|
||||
if (migrate_postcopy() && !in_postcopy &&
|
||||
pend_pre <= s->threshold_size &&
|
||||
if (!in_postcopy && pend_pre <= s->threshold_size &&
|
||||
atomic_read(&s->start_postcopy)) {
|
||||
if (postcopy_start(s)) {
|
||||
error_report("%s: postcopy failed to start", __func__);
|
||||
@ -3186,7 +3208,7 @@ static void *migration_thread(void *opaque)
|
||||
rcu_register_thread();
|
||||
|
||||
object_ref(OBJECT(s));
|
||||
s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
|
||||
update_iteration_initial_status(s);
|
||||
|
||||
qemu_savevm_state_header(s->to_dst_file);
|
||||
|
||||
@ -3251,8 +3273,7 @@ static void *migration_thread(void *opaque)
|
||||
* the local variables. This is important to avoid
|
||||
* breaking transferred_bytes and bandwidth calculation
|
||||
*/
|
||||
s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
|
||||
s->iteration_initial_bytes = 0;
|
||||
update_iteration_initial_status(s);
|
||||
}
|
||||
|
||||
current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
|
||||
|
@ -132,7 +132,6 @@ struct MigrationState
|
||||
DeviceState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
size_t bytes_xfer;
|
||||
QemuThread thread;
|
||||
QEMUBH *cleanup_bh;
|
||||
QEMUFile *to_dst_file;
|
||||
|
@ -1377,22 +1377,16 @@ void postcopy_fault_thread_notify(MigrationIncomingState *mis)
|
||||
* asking to discard individual ranges.
|
||||
*
|
||||
* @ms: The current migration state.
|
||||
* @offset: the bitmap offset of the named RAMBlock in the migration
|
||||
* bitmap.
|
||||
* @offset: the bitmap offset of the named RAMBlock in the migration bitmap.
|
||||
* @name: RAMBlock that discards will operate on.
|
||||
*
|
||||
* returns: a new PDS.
|
||||
*/
|
||||
PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms,
|
||||
const char *name)
|
||||
static PostcopyDiscardState pds = {0};
|
||||
void postcopy_discard_send_init(MigrationState *ms, const char *name)
|
||||
{
|
||||
PostcopyDiscardState *res = g_malloc0(sizeof(PostcopyDiscardState));
|
||||
|
||||
if (res) {
|
||||
res->ramblock_name = name;
|
||||
}
|
||||
|
||||
return res;
|
||||
pds.ramblock_name = name;
|
||||
pds.cur_entry = 0;
|
||||
pds.nsentwords = 0;
|
||||
pds.nsentcmds = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1401,30 +1395,29 @@ PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms,
|
||||
* be sent later.
|
||||
*
|
||||
* @ms: Current migration state.
|
||||
* @pds: Structure initialised by postcopy_discard_send_init().
|
||||
* @start,@length: a range of pages in the migration bitmap in the
|
||||
* RAM block passed to postcopy_discard_send_init() (length=1 is one page)
|
||||
*/
|
||||
void postcopy_discard_send_range(MigrationState *ms, PostcopyDiscardState *pds,
|
||||
unsigned long start, unsigned long length)
|
||||
void postcopy_discard_send_range(MigrationState *ms, unsigned long start,
|
||||
unsigned long length)
|
||||
{
|
||||
size_t tp_size = qemu_target_page_size();
|
||||
/* Convert to byte offsets within the RAM block */
|
||||
pds->start_list[pds->cur_entry] = start * tp_size;
|
||||
pds->length_list[pds->cur_entry] = length * tp_size;
|
||||
trace_postcopy_discard_send_range(pds->ramblock_name, start, length);
|
||||
pds->cur_entry++;
|
||||
pds->nsentwords++;
|
||||
pds.start_list[pds.cur_entry] = start * tp_size;
|
||||
pds.length_list[pds.cur_entry] = length * tp_size;
|
||||
trace_postcopy_discard_send_range(pds.ramblock_name, start, length);
|
||||
pds.cur_entry++;
|
||||
pds.nsentwords++;
|
||||
|
||||
if (pds->cur_entry == MAX_DISCARDS_PER_COMMAND) {
|
||||
if (pds.cur_entry == MAX_DISCARDS_PER_COMMAND) {
|
||||
/* Full set, ship it! */
|
||||
qemu_savevm_send_postcopy_ram_discard(ms->to_dst_file,
|
||||
pds->ramblock_name,
|
||||
pds->cur_entry,
|
||||
pds->start_list,
|
||||
pds->length_list);
|
||||
pds->nsentcmds++;
|
||||
pds->cur_entry = 0;
|
||||
pds.ramblock_name,
|
||||
pds.cur_entry,
|
||||
pds.start_list,
|
||||
pds.length_list);
|
||||
pds.nsentcmds++;
|
||||
pds.cur_entry = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1433,24 +1426,21 @@ void postcopy_discard_send_range(MigrationState *ms, PostcopyDiscardState *pds,
|
||||
* bitmap code. Sends any outstanding discard messages, frees the PDS
|
||||
*
|
||||
* @ms: Current migration state.
|
||||
* @pds: Structure initialised by postcopy_discard_send_init().
|
||||
*/
|
||||
void postcopy_discard_send_finish(MigrationState *ms, PostcopyDiscardState *pds)
|
||||
void postcopy_discard_send_finish(MigrationState *ms)
|
||||
{
|
||||
/* Anything unsent? */
|
||||
if (pds->cur_entry) {
|
||||
if (pds.cur_entry) {
|
||||
qemu_savevm_send_postcopy_ram_discard(ms->to_dst_file,
|
||||
pds->ramblock_name,
|
||||
pds->cur_entry,
|
||||
pds->start_list,
|
||||
pds->length_list);
|
||||
pds->nsentcmds++;
|
||||
pds.ramblock_name,
|
||||
pds.cur_entry,
|
||||
pds.start_list,
|
||||
pds.length_list);
|
||||
pds.nsentcmds++;
|
||||
}
|
||||
|
||||
trace_postcopy_discard_send_finish(pds->ramblock_name, pds->nsentwords,
|
||||
pds->nsentcmds);
|
||||
|
||||
g_free(pds);
|
||||
trace_postcopy_discard_send_finish(pds.ramblock_name, pds.nsentwords,
|
||||
pds.nsentcmds);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -43,10 +43,8 @@ int postcopy_ram_prepare_discard(MigrationIncomingState *mis);
|
||||
|
||||
/*
|
||||
* Called at the start of each RAMBlock by the bitmap code.
|
||||
* Returns a new PDS
|
||||
*/
|
||||
PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms,
|
||||
const char *name);
|
||||
void postcopy_discard_send_init(MigrationState *ms, const char *name);
|
||||
|
||||
/*
|
||||
* Called by the bitmap code for each chunk to discard.
|
||||
@ -55,15 +53,14 @@ PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms,
|
||||
* @start,@length: a range of pages in the migration bitmap in the
|
||||
* RAM block passed to postcopy_discard_send_init() (length=1 is one page)
|
||||
*/
|
||||
void postcopy_discard_send_range(MigrationState *ms, PostcopyDiscardState *pds,
|
||||
unsigned long start, unsigned long length);
|
||||
void postcopy_discard_send_range(MigrationState *ms, unsigned long start,
|
||||
unsigned long length);
|
||||
|
||||
/*
|
||||
* Called at the end of each RAMBlock by the bitmap code.
|
||||
* Sends any outstanding discard messages, frees the PDS.
|
||||
* Sends any outstanding discard messages.
|
||||
*/
|
||||
void postcopy_discard_send_finish(MigrationState *ms,
|
||||
PostcopyDiscardState *pds);
|
||||
void postcopy_discard_send_finish(MigrationState *ms);
|
||||
|
||||
/*
|
||||
* Place a page (from) at (host) efficiently
|
||||
|
@ -33,7 +33,8 @@
|
||||
static ssize_t channel_writev_buffer(void *opaque,
|
||||
struct iovec *iov,
|
||||
int iovcnt,
|
||||
int64_t pos)
|
||||
int64_t pos,
|
||||
Error **errp)
|
||||
{
|
||||
QIOChannel *ioc = QIO_CHANNEL(opaque);
|
||||
ssize_t done = 0;
|
||||
@ -47,7 +48,7 @@ static ssize_t channel_writev_buffer(void *opaque,
|
||||
|
||||
while (nlocal_iov > 0) {
|
||||
ssize_t len;
|
||||
len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
|
||||
len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp);
|
||||
if (len == QIO_CHANNEL_ERR_BLOCK) {
|
||||
if (qemu_in_coroutine()) {
|
||||
qio_channel_yield(ioc, G_IO_OUT);
|
||||
@ -57,7 +58,6 @@ static ssize_t channel_writev_buffer(void *opaque,
|
||||
continue;
|
||||
}
|
||||
if (len < 0) {
|
||||
/* XXX handle Error objects */
|
||||
done = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -75,13 +75,14 @@ static ssize_t channel_writev_buffer(void *opaque,
|
||||
static ssize_t channel_get_buffer(void *opaque,
|
||||
uint8_t *buf,
|
||||
int64_t pos,
|
||||
size_t size)
|
||||
size_t size,
|
||||
Error **errp)
|
||||
{
|
||||
QIOChannel *ioc = QIO_CHANNEL(opaque);
|
||||
ssize_t ret;
|
||||
|
||||
do {
|
||||
ret = qio_channel_read(ioc, (char *)buf, size, NULL);
|
||||
ret = qio_channel_read(ioc, (char *)buf, size, errp);
|
||||
if (ret < 0) {
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
if (qemu_in_coroutine()) {
|
||||
@ -90,7 +91,6 @@ static ssize_t channel_get_buffer(void *opaque,
|
||||
qio_channel_wait(ioc, G_IO_IN);
|
||||
}
|
||||
} else {
|
||||
/* XXX handle Error * object */
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
@ -100,18 +100,20 @@ static ssize_t channel_get_buffer(void *opaque,
|
||||
}
|
||||
|
||||
|
||||
static int channel_close(void *opaque)
|
||||
static int channel_close(void *opaque, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
QIOChannel *ioc = QIO_CHANNEL(opaque);
|
||||
qio_channel_close(ioc, NULL);
|
||||
ret = qio_channel_close(ioc, errp);
|
||||
object_unref(OBJECT(ioc));
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int channel_shutdown(void *opaque,
|
||||
bool rd,
|
||||
bool wr)
|
||||
bool wr,
|
||||
Error **errp)
|
||||
{
|
||||
QIOChannel *ioc = QIO_CHANNEL(opaque);
|
||||
|
||||
@ -125,8 +127,7 @@ static int channel_shutdown(void *opaque,
|
||||
} else {
|
||||
mode = QIO_CHANNEL_SHUTDOWN_WRITE;
|
||||
}
|
||||
if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
|
||||
/* XXX handler Error * object */
|
||||
if (qio_channel_shutdown(ioc, mode, errp) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
@ -135,11 +136,12 @@ static int channel_shutdown(void *opaque,
|
||||
|
||||
|
||||
static int channel_set_blocking(void *opaque,
|
||||
bool enabled)
|
||||
bool enabled,
|
||||
Error **errp)
|
||||
{
|
||||
QIOChannel *ioc = QIO_CHANNEL(opaque);
|
||||
|
||||
if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
|
||||
if (qio_channel_set_blocking(ioc, enabled, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "migration.h"
|
||||
#include "qemu-file.h"
|
||||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define IO_BUF_SIZE 32768
|
||||
#define MAX_IOV_SIZE MIN(IOV_MAX, 64)
|
||||
@ -51,6 +52,7 @@ struct QEMUFile {
|
||||
unsigned int iovcnt;
|
||||
|
||||
int last_error;
|
||||
Error *last_error_obj;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -62,7 +64,7 @@ int qemu_file_shutdown(QEMUFile *f)
|
||||
if (!f->ops->shut_down) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
return f->ops->shut_down(f->opaque, true, true);
|
||||
return f->ops->shut_down(f->opaque, true, true, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -106,6 +108,36 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
|
||||
f->hooks = hooks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get last error for stream f with optional Error*
|
||||
*
|
||||
* Return negative error value if there has been an error on previous
|
||||
* operations, return 0 if no error happened.
|
||||
* Optional, it returns Error* in errp, but it may be NULL even if return value
|
||||
* is not 0.
|
||||
*
|
||||
*/
|
||||
int qemu_file_get_error_obj(QEMUFile *f, Error **errp)
|
||||
{
|
||||
if (errp) {
|
||||
*errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL;
|
||||
}
|
||||
return f->last_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the last error for stream f with optional Error*
|
||||
*/
|
||||
void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err)
|
||||
{
|
||||
if (f->last_error == 0 && ret) {
|
||||
f->last_error = ret;
|
||||
error_propagate(&f->last_error_obj, err);
|
||||
} else if (err) {
|
||||
error_report_err(err);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get last error for stream f
|
||||
*
|
||||
@ -115,14 +147,15 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks)
|
||||
*/
|
||||
int qemu_file_get_error(QEMUFile *f)
|
||||
{
|
||||
return f->last_error;
|
||||
return qemu_file_get_error_obj(f, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the last error for stream f
|
||||
*/
|
||||
void qemu_file_set_error(QEMUFile *f, int ret)
|
||||
{
|
||||
if (f->last_error == 0) {
|
||||
f->last_error = ret;
|
||||
}
|
||||
qemu_file_set_error_obj(f, ret, NULL);
|
||||
}
|
||||
|
||||
bool qemu_file_is_writable(QEMUFile *f)
|
||||
@ -176,6 +209,7 @@ void qemu_fflush(QEMUFile *f)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
ssize_t expect = 0;
|
||||
Error *local_error = NULL;
|
||||
|
||||
if (!qemu_file_is_writable(f)) {
|
||||
return;
|
||||
@ -183,7 +217,8 @@ void qemu_fflush(QEMUFile *f)
|
||||
|
||||
if (f->iovcnt > 0) {
|
||||
expect = iov_size(f->iov, f->iovcnt);
|
||||
ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos);
|
||||
ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos,
|
||||
&local_error);
|
||||
|
||||
qemu_iovec_release_ram(f);
|
||||
}
|
||||
@ -195,7 +230,7 @@ void qemu_fflush(QEMUFile *f)
|
||||
* data set we requested, so sanity check that.
|
||||
*/
|
||||
if (ret != expect) {
|
||||
qemu_file_set_error(f, ret < 0 ? ret : -EIO);
|
||||
qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error);
|
||||
}
|
||||
f->buf_index = 0;
|
||||
f->iovcnt = 0;
|
||||
@ -283,6 +318,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
|
||||
{
|
||||
int len;
|
||||
int pending;
|
||||
Error *local_error = NULL;
|
||||
|
||||
assert(!qemu_file_is_writable(f));
|
||||
|
||||
@ -294,14 +330,16 @@ static ssize_t qemu_fill_buffer(QEMUFile *f)
|
||||
f->buf_size = pending;
|
||||
|
||||
len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
|
||||
IO_BUF_SIZE - pending);
|
||||
IO_BUF_SIZE - pending, &local_error);
|
||||
if (len > 0) {
|
||||
f->buf_size += len;
|
||||
f->pos += len;
|
||||
} else if (len == 0) {
|
||||
qemu_file_set_error(f, -EIO);
|
||||
qemu_file_set_error_obj(f, -EIO, local_error);
|
||||
} else if (len != -EAGAIN) {
|
||||
qemu_file_set_error(f, len);
|
||||
qemu_file_set_error_obj(f, len, local_error);
|
||||
} else {
|
||||
error_free(local_error);
|
||||
}
|
||||
|
||||
return len;
|
||||
@ -327,7 +365,7 @@ int qemu_fclose(QEMUFile *f)
|
||||
ret = qemu_file_get_error(f);
|
||||
|
||||
if (f->ops->close) {
|
||||
int ret2 = f->ops->close(f->opaque);
|
||||
int ret2 = f->ops->close(f->opaque, NULL);
|
||||
if (ret >= 0) {
|
||||
ret = ret2;
|
||||
}
|
||||
@ -338,6 +376,7 @@ int qemu_fclose(QEMUFile *f)
|
||||
if (f->last_error) {
|
||||
ret = f->last_error;
|
||||
}
|
||||
error_free(f->last_error_obj);
|
||||
g_free(f);
|
||||
trace_qemu_file_fclose();
|
||||
return ret;
|
||||
@ -615,6 +654,11 @@ void qemu_file_reset_rate_limit(QEMUFile *f)
|
||||
f->bytes_xfer = 0;
|
||||
}
|
||||
|
||||
void qemu_file_update_transfer(QEMUFile *f, int64_t len)
|
||||
{
|
||||
f->bytes_xfer += len;
|
||||
}
|
||||
|
||||
void qemu_put_be16(QEMUFile *f, unsigned int v)
|
||||
{
|
||||
qemu_put_byte(f, v >> 8);
|
||||
@ -783,6 +827,6 @@ void qemu_put_counted_string(QEMUFile *f, const char *str)
|
||||
void qemu_file_set_blocking(QEMUFile *f, bool block)
|
||||
{
|
||||
if (f->ops->set_blocking) {
|
||||
f->ops->set_blocking(f->opaque, block);
|
||||
f->ops->set_blocking(f->opaque, block, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,8 @@
|
||||
* bytes actually read should be returned.
|
||||
*/
|
||||
typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
|
||||
int64_t pos, size_t size);
|
||||
int64_t pos, size_t size,
|
||||
Error **errp);
|
||||
|
||||
/* Close a file
|
||||
*
|
||||
@ -41,7 +42,7 @@ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
|
||||
* The meaning of return value on success depends on the specific back-end being
|
||||
* used.
|
||||
*/
|
||||
typedef int (QEMUFileCloseFunc)(void *opaque);
|
||||
typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp);
|
||||
|
||||
/* Called to return the OS file descriptor associated to the QEMUFile.
|
||||
*/
|
||||
@ -49,14 +50,15 @@ typedef int (QEMUFileGetFD)(void *opaque);
|
||||
|
||||
/* Called to change the blocking mode of the file
|
||||
*/
|
||||
typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled);
|
||||
typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp);
|
||||
|
||||
/*
|
||||
* This function writes an iovec to file. The handler must write all
|
||||
* of the data or return a negative errno value.
|
||||
*/
|
||||
typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov,
|
||||
int iovcnt, int64_t pos);
|
||||
int iovcnt, int64_t pos,
|
||||
Error **errp);
|
||||
|
||||
/*
|
||||
* This function provides hooks around different
|
||||
@ -97,7 +99,8 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque);
|
||||
* Existing blocking reads/writes must be woken
|
||||
* Returns 0 on success, -err on error
|
||||
*/
|
||||
typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr);
|
||||
typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr,
|
||||
Error **errp);
|
||||
|
||||
typedef struct QEMUFileOps {
|
||||
QEMUFileGetBufferFunc *get_buffer;
|
||||
@ -147,16 +150,17 @@ int qemu_peek_byte(QEMUFile *f, int offset);
|
||||
void qemu_file_skip(QEMUFile *f, int size);
|
||||
void qemu_update_position(QEMUFile *f, size_t size);
|
||||
void qemu_file_reset_rate_limit(QEMUFile *f);
|
||||
void qemu_file_update_transfer(QEMUFile *f, int64_t len);
|
||||
void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
|
||||
int64_t qemu_file_get_rate_limit(QEMUFile *f);
|
||||
int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
|
||||
void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
|
||||
void qemu_file_set_error(QEMUFile *f, int ret);
|
||||
int qemu_file_shutdown(QEMUFile *f);
|
||||
QEMUFile *qemu_file_get_return_path(QEMUFile *f);
|
||||
void qemu_fflush(QEMUFile *f);
|
||||
void qemu_file_set_blocking(QEMUFile *f, bool block);
|
||||
|
||||
size_t qemu_get_counted_string(QEMUFile *f, char buf[256]);
|
||||
|
||||
void ram_control_before_iterate(QEMUFile *f, uint64_t flags);
|
||||
void ram_control_after_iterate(QEMUFile *f, uint64_t flags);
|
||||
void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data);
|
||||
@ -175,6 +179,4 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
|
||||
ram_addr_t offset, size_t size,
|
||||
uint64_t *bytes_sent);
|
||||
|
||||
void qemu_put_counted_string(QEMUFile *f, const char *name);
|
||||
|
||||
#endif
|
||||
|
221
migration/ram.c
221
migration/ram.c
@ -661,6 +661,8 @@ typedef struct {
|
||||
uint64_t num_packets;
|
||||
/* pages sent through this channel */
|
||||
uint64_t num_pages;
|
||||
/* syncs main thread and channels */
|
||||
QemuSemaphore sem_sync;
|
||||
} MultiFDSendParams;
|
||||
|
||||
typedef struct {
|
||||
@ -896,8 +898,6 @@ struct {
|
||||
MultiFDSendParams *params;
|
||||
/* array of pages to sent */
|
||||
MultiFDPages_t *pages;
|
||||
/* syncs main thread and channels */
|
||||
QemuSemaphore sem_sync;
|
||||
/* global number of generated multifd packets */
|
||||
uint64_t packet_num;
|
||||
/* send channels ready */
|
||||
@ -922,7 +922,7 @@ struct {
|
||||
* false.
|
||||
*/
|
||||
|
||||
static int multifd_send_pages(void)
|
||||
static int multifd_send_pages(RAMState *rs)
|
||||
{
|
||||
int i;
|
||||
static int next_channel;
|
||||
@ -954,6 +954,7 @@ static int multifd_send_pages(void)
|
||||
multifd_send_state->pages = p->pages;
|
||||
p->pages = pages;
|
||||
transferred = ((uint64_t) pages->used) * TARGET_PAGE_SIZE + p->packet_len;
|
||||
qemu_file_update_transfer(rs->f, transferred);
|
||||
ram_counters.multifd_bytes += transferred;
|
||||
ram_counters.transferred += transferred;;
|
||||
qemu_mutex_unlock(&p->mutex);
|
||||
@ -962,7 +963,7 @@ static int multifd_send_pages(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int multifd_queue_page(RAMBlock *block, ram_addr_t offset)
|
||||
static int multifd_queue_page(RAMState *rs, RAMBlock *block, ram_addr_t offset)
|
||||
{
|
||||
MultiFDPages_t *pages = multifd_send_state->pages;
|
||||
|
||||
@ -981,12 +982,12 @@ static int multifd_queue_page(RAMBlock *block, ram_addr_t offset)
|
||||
}
|
||||
}
|
||||
|
||||
if (multifd_send_pages() < 0) {
|
||||
if (multifd_send_pages(rs) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pages->block != block) {
|
||||
return multifd_queue_page(block, offset);
|
||||
return multifd_queue_page(rs, block, offset);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -996,6 +997,8 @@ static void multifd_send_terminate_threads(Error *err)
|
||||
{
|
||||
int i;
|
||||
|
||||
trace_multifd_send_terminate_threads(err != NULL);
|
||||
|
||||
if (err) {
|
||||
MigrationState *s = migrate_get_current();
|
||||
migrate_set_error(s, err);
|
||||
@ -1036,6 +1039,7 @@ void multifd_save_cleanup(void)
|
||||
p->c = NULL;
|
||||
qemu_mutex_destroy(&p->mutex);
|
||||
qemu_sem_destroy(&p->sem);
|
||||
qemu_sem_destroy(&p->sem_sync);
|
||||
g_free(p->name);
|
||||
p->name = NULL;
|
||||
multifd_pages_clear(p->pages);
|
||||
@ -1045,7 +1049,6 @@ void multifd_save_cleanup(void)
|
||||
p->packet = NULL;
|
||||
}
|
||||
qemu_sem_destroy(&multifd_send_state->channels_ready);
|
||||
qemu_sem_destroy(&multifd_send_state->sem_sync);
|
||||
g_free(multifd_send_state->params);
|
||||
multifd_send_state->params = NULL;
|
||||
multifd_pages_clear(multifd_send_state->pages);
|
||||
@ -1054,7 +1057,7 @@ void multifd_save_cleanup(void)
|
||||
multifd_send_state = NULL;
|
||||
}
|
||||
|
||||
static void multifd_send_sync_main(void)
|
||||
static void multifd_send_sync_main(RAMState *rs)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1062,7 +1065,7 @@ static void multifd_send_sync_main(void)
|
||||
return;
|
||||
}
|
||||
if (multifd_send_state->pages->used) {
|
||||
if (multifd_send_pages() < 0) {
|
||||
if (multifd_send_pages(rs) < 0) {
|
||||
error_report("%s: multifd_send_pages fail", __func__);
|
||||
return;
|
||||
}
|
||||
@ -1083,6 +1086,9 @@ static void multifd_send_sync_main(void)
|
||||
p->packet_num = multifd_send_state->packet_num++;
|
||||
p->flags |= MULTIFD_FLAG_SYNC;
|
||||
p->pending_job++;
|
||||
qemu_file_update_transfer(rs->f, p->packet_len);
|
||||
ram_counters.multifd_bytes += p->packet_len;
|
||||
ram_counters.transferred += p->packet_len;
|
||||
qemu_mutex_unlock(&p->mutex);
|
||||
qemu_sem_post(&p->sem);
|
||||
}
|
||||
@ -1090,7 +1096,7 @@ static void multifd_send_sync_main(void)
|
||||
MultiFDSendParams *p = &multifd_send_state->params[i];
|
||||
|
||||
trace_multifd_send_sync_main_wait(p->id);
|
||||
qemu_sem_wait(&multifd_send_state->sem_sync);
|
||||
qemu_sem_wait(&p->sem_sync);
|
||||
}
|
||||
trace_multifd_send_sync_main(multifd_send_state->packet_num);
|
||||
}
|
||||
@ -1150,7 +1156,7 @@ static void *multifd_send_thread(void *opaque)
|
||||
qemu_mutex_unlock(&p->mutex);
|
||||
|
||||
if (flags & MULTIFD_FLAG_SYNC) {
|
||||
qemu_sem_post(&multifd_send_state->sem_sync);
|
||||
qemu_sem_post(&p->sem_sync);
|
||||
}
|
||||
qemu_sem_post(&multifd_send_state->channels_ready);
|
||||
} else if (p->quit) {
|
||||
@ -1164,6 +1170,7 @@ static void *multifd_send_thread(void *opaque)
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
trace_multifd_send_error(p->id);
|
||||
multifd_send_terminate_threads(local_err);
|
||||
}
|
||||
|
||||
@ -1173,7 +1180,7 @@ out:
|
||||
*/
|
||||
if (ret != 0) {
|
||||
if (flags & MULTIFD_FLAG_SYNC) {
|
||||
qemu_sem_post(&multifd_send_state->sem_sync);
|
||||
qemu_sem_post(&p->sem_sync);
|
||||
}
|
||||
qemu_sem_post(&multifd_send_state->channels_ready);
|
||||
}
|
||||
@ -1194,6 +1201,7 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque)
|
||||
QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task));
|
||||
Error *local_err = NULL;
|
||||
|
||||
trace_multifd_new_send_channel_async(p->id);
|
||||
if (qio_task_propagate_error(task, &local_err)) {
|
||||
migrate_set_error(migrate_get_current(), local_err);
|
||||
multifd_save_cleanup();
|
||||
@ -1219,7 +1227,6 @@ int multifd_save_setup(void)
|
||||
multifd_send_state = g_malloc0(sizeof(*multifd_send_state));
|
||||
multifd_send_state->params = g_new0(MultiFDSendParams, thread_count);
|
||||
multifd_send_state->pages = multifd_pages_init(page_count);
|
||||
qemu_sem_init(&multifd_send_state->sem_sync, 0);
|
||||
qemu_sem_init(&multifd_send_state->channels_ready, 0);
|
||||
|
||||
for (i = 0; i < thread_count; i++) {
|
||||
@ -1227,6 +1234,7 @@ int multifd_save_setup(void)
|
||||
|
||||
qemu_mutex_init(&p->mutex);
|
||||
qemu_sem_init(&p->sem, 0);
|
||||
qemu_sem_init(&p->sem_sync, 0);
|
||||
p->quit = false;
|
||||
p->pending_job = 0;
|
||||
p->id = i;
|
||||
@ -1254,6 +1262,8 @@ static void multifd_recv_terminate_threads(Error *err)
|
||||
{
|
||||
int i;
|
||||
|
||||
trace_multifd_recv_terminate_threads(err != NULL);
|
||||
|
||||
if (err) {
|
||||
MigrationState *s = migrate_get_current();
|
||||
migrate_set_error(s, err);
|
||||
@ -1478,6 +1488,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp)
|
||||
atomic_read(&multifd_recv_state->count));
|
||||
return false;
|
||||
}
|
||||
trace_multifd_recv_new_channel(id);
|
||||
|
||||
p = &multifd_recv_state->params[id];
|
||||
if (p->c != NULL) {
|
||||
@ -1748,11 +1759,10 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
|
||||
}
|
||||
|
||||
/* Called with RCU critical section */
|
||||
static void migration_bitmap_sync_range(RAMState *rs, RAMBlock *rb,
|
||||
ram_addr_t length)
|
||||
static void ramblock_sync_dirty_bitmap(RAMState *rs, RAMBlock *rb)
|
||||
{
|
||||
rs->migration_dirty_pages +=
|
||||
cpu_physical_memory_sync_dirty_bitmap(rb, 0, length,
|
||||
cpu_physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length,
|
||||
&rs->num_dirty_pages_period);
|
||||
}
|
||||
|
||||
@ -1841,7 +1851,7 @@ static void migration_bitmap_sync(RAMState *rs)
|
||||
qemu_mutex_lock(&rs->bitmap_mutex);
|
||||
rcu_read_lock();
|
||||
RAMBLOCK_FOREACH_NOT_IGNORED(block) {
|
||||
migration_bitmap_sync_range(rs, block, block->used_length);
|
||||
ramblock_sync_dirty_bitmap(rs, block);
|
||||
}
|
||||
ram_counters.remaining = ram_bytes_remaining();
|
||||
rcu_read_unlock();
|
||||
@ -2079,7 +2089,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage)
|
||||
static int ram_save_multifd_page(RAMState *rs, RAMBlock *block,
|
||||
ram_addr_t offset)
|
||||
{
|
||||
if (multifd_queue_page(block, offset) < 0) {
|
||||
if (multifd_queue_page(rs, block, offset) < 0) {
|
||||
return -1;
|
||||
}
|
||||
ram_counters.normal++;
|
||||
@ -2851,12 +2861,9 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms)
|
||||
* with the dirtymap; so a '1' means it's either dirty or unsent.
|
||||
*
|
||||
* @ms: current migration state
|
||||
* @pds: state for postcopy
|
||||
* @block: RAMBlock to discard
|
||||
*/
|
||||
static int postcopy_send_discard_bm_ram(MigrationState *ms,
|
||||
PostcopyDiscardState *pds,
|
||||
RAMBlock *block)
|
||||
static int postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block)
|
||||
{
|
||||
unsigned long end = block->used_length >> TARGET_PAGE_BITS;
|
||||
unsigned long current;
|
||||
@ -2864,23 +2871,21 @@ static int postcopy_send_discard_bm_ram(MigrationState *ms,
|
||||
|
||||
for (current = 0; current < end; ) {
|
||||
unsigned long one = find_next_bit(unsentmap, end, current);
|
||||
unsigned long zero, discard_length;
|
||||
|
||||
if (one <= end) {
|
||||
unsigned long zero = find_next_zero_bit(unsentmap, end, one + 1);
|
||||
unsigned long discard_length;
|
||||
|
||||
if (zero >= end) {
|
||||
discard_length = end - one;
|
||||
} else {
|
||||
discard_length = zero - one;
|
||||
}
|
||||
if (discard_length) {
|
||||
postcopy_discard_send_range(ms, pds, one, discard_length);
|
||||
}
|
||||
current = one + discard_length;
|
||||
} else {
|
||||
current = one;
|
||||
if (one >= end) {
|
||||
break;
|
||||
}
|
||||
|
||||
zero = find_next_zero_bit(unsentmap, end, one + 1);
|
||||
|
||||
if (zero >= end) {
|
||||
discard_length = end - one;
|
||||
} else {
|
||||
discard_length = zero - one;
|
||||
}
|
||||
postcopy_discard_send_range(ms, one, discard_length);
|
||||
current = one + discard_length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2905,16 +2910,15 @@ static int postcopy_each_ram_send_discard(MigrationState *ms)
|
||||
int ret;
|
||||
|
||||
RAMBLOCK_FOREACH_NOT_IGNORED(block) {
|
||||
PostcopyDiscardState *pds =
|
||||
postcopy_discard_send_init(ms, block->idstr);
|
||||
postcopy_discard_send_init(ms, block->idstr);
|
||||
|
||||
/*
|
||||
* Postcopy sends chunks of bitmap over the wire, but it
|
||||
* just needs indexes at this point, avoids it having
|
||||
* target page specific code.
|
||||
*/
|
||||
ret = postcopy_send_discard_bm_ram(ms, pds, block);
|
||||
postcopy_discard_send_finish(ms, pds);
|
||||
ret = postcopy_send_discard_bm_ram(ms, block);
|
||||
postcopy_discard_send_finish(ms);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@ -2937,11 +2941,9 @@ static int postcopy_each_ram_send_discard(MigrationState *ms)
|
||||
* @unsent_pass: if true we need to canonicalize partially unsent host pages
|
||||
* otherwise we need to canonicalize partially dirty host pages
|
||||
* @block: block that contains the page we want to canonicalize
|
||||
* @pds: state for postcopy
|
||||
*/
|
||||
static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
|
||||
RAMBlock *block,
|
||||
PostcopyDiscardState *pds)
|
||||
RAMBlock *block)
|
||||
{
|
||||
RAMState *rs = ram_state;
|
||||
unsigned long *bitmap = block->bmap;
|
||||
@ -2964,54 +2966,30 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
|
||||
}
|
||||
|
||||
while (run_start < pages) {
|
||||
bool do_fixup = false;
|
||||
unsigned long fixup_start_addr;
|
||||
unsigned long host_offset;
|
||||
|
||||
/*
|
||||
* If the start of this run of pages is in the middle of a host
|
||||
* page, then we need to fixup this host page.
|
||||
*/
|
||||
host_offset = run_start % host_ratio;
|
||||
if (host_offset) {
|
||||
do_fixup = true;
|
||||
run_start -= host_offset;
|
||||
fixup_start_addr = run_start;
|
||||
/* For the next pass */
|
||||
run_start = run_start + host_ratio;
|
||||
} else {
|
||||
if (QEMU_IS_ALIGNED(run_start, host_ratio)) {
|
||||
/* Find the end of this run */
|
||||
unsigned long run_end;
|
||||
if (unsent_pass) {
|
||||
run_end = find_next_bit(unsentmap, pages, run_start + 1);
|
||||
run_start = find_next_bit(unsentmap, pages, run_start + 1);
|
||||
} else {
|
||||
run_end = find_next_zero_bit(bitmap, pages, run_start + 1);
|
||||
run_start = find_next_zero_bit(bitmap, pages, run_start + 1);
|
||||
}
|
||||
/*
|
||||
* If the end isn't at the start of a host page, then the
|
||||
* run doesn't finish at the end of a host page
|
||||
* and we need to discard.
|
||||
*/
|
||||
host_offset = run_end % host_ratio;
|
||||
if (host_offset) {
|
||||
do_fixup = true;
|
||||
fixup_start_addr = run_end - host_offset;
|
||||
/*
|
||||
* This host page has gone, the next loop iteration starts
|
||||
* from after the fixup
|
||||
*/
|
||||
run_start = fixup_start_addr + host_ratio;
|
||||
} else {
|
||||
/*
|
||||
* No discards on this iteration, next loop starts from
|
||||
* next sent/dirty page
|
||||
*/
|
||||
run_start = run_end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_fixup) {
|
||||
if (!QEMU_IS_ALIGNED(run_start, host_ratio)) {
|
||||
unsigned long page;
|
||||
unsigned long fixup_start_addr = QEMU_ALIGN_DOWN(run_start,
|
||||
host_ratio);
|
||||
run_start = QEMU_ALIGN_UP(run_start, host_ratio);
|
||||
|
||||
/* Tell the destination to discard this page */
|
||||
if (unsent_pass || !test_bit(fixup_start_addr, unsentmap)) {
|
||||
@ -3022,8 +3000,7 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
|
||||
* (any partially sent pages were already discarded
|
||||
* by the previous unsent_pass)
|
||||
*/
|
||||
postcopy_discard_send_range(ms, pds, fixup_start_addr,
|
||||
host_ratio);
|
||||
postcopy_discard_send_range(ms, fixup_start_addr, host_ratio);
|
||||
}
|
||||
|
||||
/* Clean up the bitmap */
|
||||
@ -3066,18 +3043,17 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
|
||||
*/
|
||||
static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block)
|
||||
{
|
||||
PostcopyDiscardState *pds =
|
||||
postcopy_discard_send_init(ms, block->idstr);
|
||||
postcopy_discard_send_init(ms, block->idstr);
|
||||
|
||||
/* First pass: Discard all partially sent host pages */
|
||||
postcopy_chunk_hostpages_pass(ms, true, block, pds);
|
||||
postcopy_chunk_hostpages_pass(ms, true, block);
|
||||
/*
|
||||
* Second pass: Ensure that all partially dirty host pages are made
|
||||
* fully dirty.
|
||||
*/
|
||||
postcopy_chunk_hostpages_pass(ms, false, block, pds);
|
||||
postcopy_chunk_hostpages_pass(ms, false, block);
|
||||
|
||||
postcopy_discard_send_finish(ms, pds);
|
||||
postcopy_discard_send_finish(ms);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3482,7 +3458,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
|
||||
ram_control_before_iterate(f, RAM_CONTROL_SETUP);
|
||||
ram_control_after_iterate(f, RAM_CONTROL_SETUP);
|
||||
|
||||
multifd_send_sync_main();
|
||||
multifd_send_sync_main(*rsp);
|
||||
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
|
||||
qemu_fflush(f);
|
||||
|
||||
@ -3570,7 +3546,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
||||
ram_control_after_iterate(f, RAM_CONTROL_ROUND);
|
||||
|
||||
out:
|
||||
multifd_send_sync_main();
|
||||
multifd_send_sync_main(rs);
|
||||
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
|
||||
qemu_fflush(f);
|
||||
ram_counters.transferred += 8;
|
||||
@ -3629,7 +3605,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
multifd_send_sync_main();
|
||||
multifd_send_sync_main(rs);
|
||||
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
|
||||
qemu_fflush(f);
|
||||
|
||||
@ -4296,7 +4272,7 @@ static void colo_flush_ram_cache(void)
|
||||
memory_global_dirty_log_sync();
|
||||
rcu_read_lock();
|
||||
RAMBLOCK_FOREACH_NOT_IGNORED(block) {
|
||||
migration_bitmap_sync_range(ram_state, block, block->used_length);
|
||||
ramblock_sync_dirty_bitmap(ram_state, block);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
@ -4322,40 +4298,26 @@ static void colo_flush_ram_cache(void)
|
||||
trace_colo_flush_ram_cache_end();
|
||||
}
|
||||
|
||||
static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
/**
|
||||
* ram_load_precopy: load pages in precopy case
|
||||
*
|
||||
* Returns 0 for success or -errno in case of error
|
||||
*
|
||||
* Called in precopy mode by ram_load().
|
||||
* rcu_read_lock is taken prior to this being called.
|
||||
*
|
||||
* @f: QEMUFile where to send the data
|
||||
*/
|
||||
static int ram_load_precopy(QEMUFile *f)
|
||||
{
|
||||
int flags = 0, ret = 0, invalid_flags = 0;
|
||||
static uint64_t seq_iter;
|
||||
int len = 0;
|
||||
/*
|
||||
* If system is running in postcopy mode, page inserts to host memory must
|
||||
* be atomic
|
||||
*/
|
||||
bool postcopy_running = postcopy_is_running();
|
||||
int flags = 0, ret = 0, invalid_flags = 0, len = 0;
|
||||
/* ADVISE is earlier, it shows the source has the postcopy capability on */
|
||||
bool postcopy_advised = postcopy_is_advised();
|
||||
|
||||
seq_iter++;
|
||||
|
||||
if (version_id != 4) {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (!migrate_use_compression()) {
|
||||
invalid_flags |= RAM_SAVE_FLAG_COMPRESS_PAGE;
|
||||
}
|
||||
/* This RCU critical section can be very long running.
|
||||
* When RCU reclaims in the code start to become numerous,
|
||||
* it will be necessary to reduce the granularity of this
|
||||
* critical section.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
|
||||
if (postcopy_running) {
|
||||
ret = ram_load_postcopy(f);
|
||||
}
|
||||
|
||||
while (!postcopy_running && !ret && !(flags & RAM_SAVE_FLAG_EOS)) {
|
||||
while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) {
|
||||
ram_addr_t addr, total_ram_bytes;
|
||||
void *host = NULL;
|
||||
uint8_t ch;
|
||||
@ -4506,6 +4468,39 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
int ret = 0;
|
||||
static uint64_t seq_iter;
|
||||
/*
|
||||
* If system is running in postcopy mode, page inserts to host memory must
|
||||
* be atomic
|
||||
*/
|
||||
bool postcopy_running = postcopy_is_running();
|
||||
|
||||
seq_iter++;
|
||||
|
||||
if (version_id != 4) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This RCU critical section can be very long running.
|
||||
* When RCU reclaims in the code start to become numerous,
|
||||
* it will be necessary to reduce the granularity of this
|
||||
* critical section.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
|
||||
if (postcopy_running) {
|
||||
ret = ram_load_postcopy(f);
|
||||
} else {
|
||||
ret = ram_load_precopy(f);
|
||||
}
|
||||
|
||||
ret |= wait_for_decompress_done();
|
||||
rcu_read_unlock();
|
||||
trace_ram_load_complete(ret, seq_iter);
|
||||
|
@ -3140,7 +3140,7 @@ static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque,
|
||||
|
||||
CHECK_ERROR_STATE();
|
||||
|
||||
if (migrate_get_current()->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
|
||||
if (migration_in_postcopy()) {
|
||||
rcu_read_unlock();
|
||||
return RAM_SAVE_CONTROL_NOT_SUPP;
|
||||
}
|
||||
@ -3775,7 +3775,7 @@ static int qemu_rdma_registration_start(QEMUFile *f, void *opaque,
|
||||
|
||||
CHECK_ERROR_STATE();
|
||||
|
||||
if (migrate_get_current()->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
|
||||
if (migration_in_postcopy()) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
@ -3810,7 +3810,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque,
|
||||
|
||||
CHECK_ERROR_STATE();
|
||||
|
||||
if (migrate_get_current()->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
|
||||
if (migration_in_postcopy()) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ static struct mig_cmd_args {
|
||||
/* savevm/loadvm support */
|
||||
|
||||
static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
|
||||
int64_t pos)
|
||||
int64_t pos, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
QEMUIOVector qiov;
|
||||
@ -139,12 +139,12 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
|
||||
}
|
||||
|
||||
static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
|
||||
size_t size)
|
||||
size_t size, Error **errp)
|
||||
{
|
||||
return bdrv_load_vmstate(opaque, buf, pos, size);
|
||||
}
|
||||
|
||||
static int bdrv_fclose(void *opaque)
|
||||
static int bdrv_fclose(void *opaque, Error **errp)
|
||||
{
|
||||
return bdrv_flush(opaque);
|
||||
}
|
||||
@ -1246,29 +1246,16 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f)
|
||||
qemu_fflush(f);
|
||||
}
|
||||
|
||||
int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only,
|
||||
bool inactivate_disks)
|
||||
static
|
||||
int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy)
|
||||
{
|
||||
QJSON *vmdesc;
|
||||
int vmdesc_len;
|
||||
SaveStateEntry *se;
|
||||
int ret;
|
||||
bool in_postcopy = migration_in_postcopy();
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (precopy_notify(PRECOPY_NOTIFY_COMPLETE, &local_err)) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
|
||||
trace_savevm_state_complete_precopy();
|
||||
|
||||
cpu_synchronize_all_states();
|
||||
|
||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
|
||||
if (!se->ops ||
|
||||
(in_postcopy && se->ops->has_postcopy &&
|
||||
se->ops->has_postcopy(se->opaque)) ||
|
||||
(in_postcopy && !iterable_only) ||
|
||||
!se->ops->save_live_complete_precopy) {
|
||||
continue;
|
||||
}
|
||||
@ -1291,9 +1278,18 @@ int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only,
|
||||
}
|
||||
}
|
||||
|
||||
if (iterable_only) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f,
|
||||
bool in_postcopy,
|
||||
bool inactivate_disks)
|
||||
{
|
||||
QJSON *vmdesc;
|
||||
int vmdesc_len;
|
||||
SaveStateEntry *se;
|
||||
int ret;
|
||||
|
||||
vmdesc = qjson_new();
|
||||
json_prop_int(vmdesc, "page_size", qemu_target_page_size());
|
||||
@ -1353,6 +1349,42 @@ int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only,
|
||||
}
|
||||
qjson_destroy(vmdesc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only,
|
||||
bool inactivate_disks)
|
||||
{
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
bool in_postcopy = migration_in_postcopy();
|
||||
|
||||
if (precopy_notify(PRECOPY_NOTIFY_COMPLETE, &local_err)) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
|
||||
trace_savevm_state_complete_precopy();
|
||||
|
||||
cpu_synchronize_all_states();
|
||||
|
||||
if (!in_postcopy || iterable_only) {
|
||||
ret = qemu_savevm_state_complete_precopy_iterable(f, in_postcopy);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (iterable_only) {
|
||||
goto flush;
|
||||
}
|
||||
|
||||
ret = qemu_savevm_state_complete_precopy_non_iterable(f, in_postcopy,
|
||||
inactivate_disks);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
flush:
|
||||
qemu_fflush(f);
|
||||
return 0;
|
||||
}
|
||||
@ -1424,6 +1456,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
|
||||
}
|
||||
|
||||
migrate_init(ms);
|
||||
memset(&ram_counters, 0, sizeof(ram_counters));
|
||||
ms->to_dst_file = f;
|
||||
|
||||
qemu_mutex_unlock_iothread();
|
||||
@ -1616,8 +1649,6 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
|
||||
return -1;
|
||||
}
|
||||
|
||||
postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1835,16 +1866,10 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
QEMUBH *bh;
|
||||
} HandleRunBhData;
|
||||
|
||||
static void loadvm_postcopy_handle_run_bh(void *opaque)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
HandleRunBhData *data = opaque;
|
||||
MigrationIncomingState *mis = migration_incoming_get_current();
|
||||
MigrationIncomingState *mis = opaque;
|
||||
|
||||
/* TODO we should move all of this lot into postcopy_ram.c or a shared code
|
||||
* in migration.c
|
||||
@ -1876,15 +1901,13 @@ static void loadvm_postcopy_handle_run_bh(void *opaque)
|
||||
runstate_set(RUN_STATE_PAUSED);
|
||||
}
|
||||
|
||||
qemu_bh_delete(data->bh);
|
||||
g_free(data);
|
||||
qemu_bh_delete(mis->bh);
|
||||
}
|
||||
|
||||
/* After all discards we can start running and asking for pages */
|
||||
static int loadvm_postcopy_handle_run(MigrationIncomingState *mis)
|
||||
{
|
||||
PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_RUNNING);
|
||||
HandleRunBhData *data;
|
||||
|
||||
trace_loadvm_postcopy_handle_run();
|
||||
if (ps != POSTCOPY_INCOMING_LISTENING) {
|
||||
@ -1892,9 +1915,8 @@ static int loadvm_postcopy_handle_run(MigrationIncomingState *mis)
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = g_new(HandleRunBhData, 1);
|
||||
data->bh = qemu_bh_new(loadvm_postcopy_handle_run_bh, data);
|
||||
qemu_bh_schedule(data->bh);
|
||||
mis->bh = qemu_bh_new(loadvm_postcopy_handle_run_bh, mis);
|
||||
qemu_bh_schedule(mis->bh);
|
||||
|
||||
/* We need to finish reading the stream from the package
|
||||
* and also stop reading anything more from the stream that loaded the
|
||||
@ -2407,7 +2429,7 @@ retry:
|
||||
case QEMU_VM_COMMAND:
|
||||
ret = loadvm_process_command(f);
|
||||
trace_qemu_loadvm_state_section_command(ret);
|
||||
if ((ret < 0) || (ret & LOADVM_QUIT)) {
|
||||
if ((ret < 0) || (ret == LOADVM_QUIT)) {
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
@ -81,16 +81,22 @@ migration_bitmap_sync_start(void) ""
|
||||
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_throttle(void) ""
|
||||
multifd_new_send_channel_async(uint8_t id) "channel %d"
|
||||
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_new_channel(uint8_t id) "channel %d"
|
||||
multifd_recv_sync_main(long packet_num) "packet num %ld"
|
||||
multifd_recv_sync_main_signal(uint8_t id) "channel %d"
|
||||
multifd_recv_sync_main_wait(uint8_t id) "channel %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_start(uint8_t id) "%d"
|
||||
multifd_save_setup_wait(uint8_t id) "%d"
|
||||
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_error(uint8_t id) "channel %d"
|
||||
multifd_send_sync_main(long packet_num) "packet num %ld"
|
||||
multifd_send_sync_main_signal(uint8_t id) "channel %d"
|
||||
multifd_send_sync_main_wait(uint8_t id) "channel %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_start(uint8_t id) "%d"
|
||||
ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx"
|
||||
|
@ -220,24 +220,11 @@ static char *SocketAddress_to_str(SocketAddress *addr)
|
||||
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
MigrationInfo *info;
|
||||
MigrationCapabilityStatusList *caps, *cap;
|
||||
|
||||
info = qmp_query_migrate(NULL);
|
||||
caps = qmp_query_migrate_capabilities(NULL);
|
||||
|
||||
migration_global_dump(mon);
|
||||
|
||||
/* do not display parameters during setup */
|
||||
if (info->has_status && caps) {
|
||||
monitor_printf(mon, "capabilities: ");
|
||||
for (cap = caps; cap; cap = cap->next) {
|
||||
monitor_printf(mon, "%s: %s ",
|
||||
MigrationCapability_str(cap->value->capability),
|
||||
cap->value->state ? "on" : "off");
|
||||
}
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
|
||||
if (info->has_status) {
|
||||
monitor_printf(mon, "Migration status: %s",
|
||||
MigrationStatus_str(info->status));
|
||||
@ -370,7 +357,6 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
|
||||
monitor_printf(mon, "]\n");
|
||||
}
|
||||
qapi_free_MigrationInfo(info);
|
||||
qapi_free_MigrationCapabilityStatusList(caps);
|
||||
}
|
||||
|
||||
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
|
||||
|
Loading…
Reference in New Issue
Block a user