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:
Peter Maydell 2019-08-16 12:00:18 +01:00
commit 27608c7c66
14 changed files with 350 additions and 330 deletions

View File

@ -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
}
};

View File

@ -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

View File

@ -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);

View File

@ -132,7 +132,6 @@ struct MigrationState
DeviceState parent_obj;
/*< public >*/
size_t bytes_xfer;
QemuThread thread;
QEMUBH *cleanup_bh;
QEMUFile *to_dst_file;

View 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);
}
/*

View File

@ -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

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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"

View File

@ -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)