mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-24 03:59:52 +00:00
Migration pull 2019-09-12
New feature: UUID validation check from Yury Kotov plus a bunch of fixes. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEERfXHG0oMt/uXep+pBRYzHrxb/ecFAl16TKwACgkQBRYzHrxb /eeeXg//X0n45bzl6yPYELiN1WQdXgLLcvJXioFNEfTCE/XbA5Dkmt0TDYHvmzzJ sO8YDb8mq+5d7+bedaZa53Whzn4CkMJ1bT7812sXRemx25qegdwPobGC4GOKR1Co 2Vd4YEOQfV+OAf3tPWddKtit3mtR0FXpOMauMHbjFC/tbFV9dL6ikeTUsprNYBrY dbJb2I7TyIPv1OjjazmybA3zH00EUYac7Ds6S7Q+gw8K7CfTsECYCm4dfPpiQDu0 eZiNPp+bH0YD2J47pLIfuI1bb0zUtSMRaJ4KJZtO2/dm6mDgG95R63iaSe4DQCO9 lekX/xBOKdJgySUcsLcmMiqRLL3AB/lR8+8FsoVyrGbhcy1N54izPtupwq8tU5bZ +39BUbHcsPCBcXwVVHUQimoH5g/FYAii+KrjDCnSZqFvjmBGnJbcVLwO/f61Sghi ehqfvEiqe6SGnbsxCUcoc1Akz1P/DOYxaTGaAn1wtMrQrkRJhTbrX1pedmTViD5m v31J93AnROGHWi/slsxrO2jXghlo0W7a5TdKh0bul/N/IbGCTFZH1EbNXAJqkxkV 4cKbb86vVJRozsqUCbqrs/WZgQrPXyHaXpN1bUQuA5ofUOBlynj2hrnJXMiCITvW MckOnKp0tgijdUefgIWmmGNCeSEPSZ25Nd6QGqPXdehoT0JBb2U= =W+5Q -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20190912a' into staging Migration pull 2019-09-12 New feature: UUID validation check from Yury Kotov plus a bunch of fixes. # gpg: Signature made Thu 12 Sep 2019 14:48:28 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-20190912a: migration: fix one typo in comment of function migration_total_bytes() migration/qemu-file: fix potential buf waste for extra buf_index adjustment migration/qemu-file: remove check on writev_buffer in qemu_put_compression_data migration: Fix postcopy bw for recovery tests/migration: Add a test for validate-uuid capability tests/libqtest: Allow setting expected exit status migration: Add validate-uuid capability qemu-file: Rework old qemu_fflush comment migration: register_savevm_live doesn't need dev hw/net/vmxnet3: Fix leftover unregister_savevm migration: cleanup check on ops in savevm.handlers iterations migration: multifd_send_thread always post p->sem_sync when error happen Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
85182c96de
@ -183,8 +183,7 @@ another to load the state back.
|
||||
|
||||
.. code:: c
|
||||
|
||||
int register_savevm_live(DeviceState *dev,
|
||||
const char *idstr,
|
||||
int register_savevm_live(const char *idstr,
|
||||
int instance_id,
|
||||
int version_id,
|
||||
SaveVMHandlers *ops,
|
||||
|
@ -2242,13 +2242,10 @@ static void vmxnet3_instance_init(Object *obj)
|
||||
|
||||
static void vmxnet3_pci_uninit(PCIDevice *pci_dev)
|
||||
{
|
||||
DeviceState *dev = DEVICE(pci_dev);
|
||||
VMXNET3State *s = VMXNET3(pci_dev);
|
||||
|
||||
VMW_CBPRN("Starting uninit...");
|
||||
|
||||
unregister_savevm(dev, "vmxnet3-msix", s);
|
||||
|
||||
vmxnet3_net_uninit(s);
|
||||
|
||||
vmxnet3_cleanup_msix(s);
|
||||
|
@ -3078,7 +3078,7 @@ static void spapr_machine_init(MachineState *machine)
|
||||
* interface, this is a legacy from the sPAPREnvironment structure
|
||||
* which predated MachineState but had a similar function */
|
||||
vmstate_register(NULL, 0, &vmstate_spapr, spapr);
|
||||
register_savevm_live(NULL, "spapr/htab", -1, 1,
|
||||
register_savevm_live("spapr/htab", -1, 1,
|
||||
&savevm_htab_handlers, spapr);
|
||||
|
||||
qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine),
|
||||
|
@ -389,7 +389,7 @@ static inline void s390_skeys_set_migration_enabled(Object *obj, bool value,
|
||||
ss->migration_enabled = value;
|
||||
|
||||
if (ss->migration_enabled) {
|
||||
register_savevm_live(NULL, TYPE_S390_SKEYS, 0, 1,
|
||||
register_savevm_live(TYPE_S390_SKEYS, 0, 1,
|
||||
&savevm_s390_storage_keys, ss);
|
||||
} else {
|
||||
unregister_savevm(DEVICE(ss), TYPE_S390_SKEYS, ss);
|
||||
|
@ -381,7 +381,7 @@ static void s390_stattrib_instance_init(Object *obj)
|
||||
{
|
||||
S390StAttribState *sas = S390_STATTRIB(obj);
|
||||
|
||||
register_savevm_live(NULL, TYPE_S390_STATTRIB, 0, 0,
|
||||
register_savevm_live(TYPE_S390_STATTRIB, 0, 0,
|
||||
&savevm_s390_stattrib_handlers, sas);
|
||||
|
||||
object_property_add_bool(obj, "migration-enabled",
|
||||
|
@ -101,7 +101,7 @@ static void s390_tod_realize(DeviceState *dev, Error **errp)
|
||||
S390TODState *td = S390_TOD(dev);
|
||||
|
||||
/* Legacy migration interface */
|
||||
register_savevm_live(NULL, "todclock", 0, 1, &savevm_tod, td);
|
||||
register_savevm_live("todclock", 0, 1, &savevm_tod, td);
|
||||
}
|
||||
|
||||
static void s390_tod_class_init(ObjectClass *oc, void *data)
|
||||
|
@ -68,8 +68,7 @@ typedef struct SaveVMHandlers {
|
||||
int (*resume_prepare)(MigrationState *s, void *opaque);
|
||||
} SaveVMHandlers;
|
||||
|
||||
int register_savevm_live(DeviceState *dev,
|
||||
const char *idstr,
|
||||
int register_savevm_live(const char *idstr,
|
||||
int instance_id,
|
||||
int version_id,
|
||||
const SaveVMHandlers *ops,
|
||||
|
@ -733,7 +733,7 @@ void dirty_bitmap_mig_init(void)
|
||||
{
|
||||
QSIMPLEQ_INIT(&dirty_bitmap_mig_state.dbms_list);
|
||||
|
||||
register_savevm_live(NULL, "dirty-bitmap", 0, 1,
|
||||
register_savevm_live("dirty-bitmap", 0, 1,
|
||||
&savevm_dirty_bitmap_handlers,
|
||||
&dirty_bitmap_mig_state);
|
||||
}
|
||||
|
@ -1030,6 +1030,6 @@ void blk_mig_init(void)
|
||||
QSIMPLEQ_INIT(&block_mig_state.blk_list);
|
||||
qemu_mutex_init(&block_mig_state.lock);
|
||||
|
||||
register_savevm_live(NULL, "block", 0, 1, &savevm_block_handlers,
|
||||
register_savevm_live("block", 0, 1, &savevm_block_handlers,
|
||||
&block_mig_state);
|
||||
}
|
||||
|
@ -2140,6 +2140,15 @@ bool migrate_ignore_shared(void)
|
||||
return s->enabled_capabilities[MIGRATION_CAPABILITY_X_IGNORE_SHARED];
|
||||
}
|
||||
|
||||
bool migrate_validate_uuid(void)
|
||||
{
|
||||
MigrationState *s;
|
||||
|
||||
s = migrate_get_current();
|
||||
|
||||
return s->enabled_capabilities[MIGRATION_CAPABILITY_VALIDATE_UUID];
|
||||
}
|
||||
|
||||
bool migrate_use_events(void)
|
||||
{
|
||||
MigrationState *s;
|
||||
@ -3016,7 +3025,7 @@ static MigThrError migration_detect_error(MigrationState *s)
|
||||
}
|
||||
}
|
||||
|
||||
/* How many bytes have we transferred since the beggining of the migration */
|
||||
/* How many bytes have we transferred since the beginning of the migration */
|
||||
static uint64_t migration_total_bytes(MigrationState *s)
|
||||
{
|
||||
return qemu_ftell(s->to_dst_file) + ram_counters.multifd_bytes;
|
||||
@ -3327,7 +3336,8 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
|
||||
|
||||
if (resume) {
|
||||
/* This is a resumed migration */
|
||||
rate_limit = INT64_MAX;
|
||||
rate_limit = s->parameters.max_postcopy_bandwidth /
|
||||
XFER_LIMIT_RATIO;
|
||||
} else {
|
||||
/* This is a fresh new migration */
|
||||
rate_limit = s->parameters.max_bandwidth / XFER_LIMIT_RATIO;
|
||||
|
@ -290,6 +290,7 @@ bool migrate_postcopy_ram(void);
|
||||
bool migrate_zero_blocks(void);
|
||||
bool migrate_dirty_bitmaps(void);
|
||||
bool migrate_ignore_shared(void);
|
||||
bool migrate_validate_uuid(void);
|
||||
|
||||
bool migrate_auto_converge(void);
|
||||
bool migrate_use_multifd(void);
|
||||
|
@ -201,9 +201,8 @@ static void qemu_iovec_release_ram(QEMUFile *f)
|
||||
/**
|
||||
* Flushes QEMUFile buffer
|
||||
*
|
||||
* If there is writev_buffer QEMUFileOps it uses it otherwise uses
|
||||
* put_buffer ops. This will flush all pending data. If data was
|
||||
* only partially flushed, it will set an error state.
|
||||
* This will flush all pending data. If data was only partially flushed, it
|
||||
* will set an error state.
|
||||
*/
|
||||
void qemu_fflush(QEMUFile *f)
|
||||
{
|
||||
@ -382,8 +381,16 @@ int qemu_fclose(QEMUFile *f)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void add_to_iovec(QEMUFile *f, const uint8_t *buf, size_t size,
|
||||
bool may_free)
|
||||
/*
|
||||
* Add buf to iovec. Do flush if iovec is full.
|
||||
*
|
||||
* Return values:
|
||||
* 1 iovec is full and flushed
|
||||
* 0 iovec is not flushed
|
||||
*
|
||||
*/
|
||||
static int add_to_iovec(QEMUFile *f, const uint8_t *buf, size_t size,
|
||||
bool may_free)
|
||||
{
|
||||
/* check for adjacent buffer and coalesce them */
|
||||
if (f->iovcnt > 0 && buf == f->iov[f->iovcnt - 1].iov_base +
|
||||
@ -401,6 +408,19 @@ static void add_to_iovec(QEMUFile *f, const uint8_t *buf, size_t size,
|
||||
|
||||
if (f->iovcnt >= MAX_IOV_SIZE) {
|
||||
qemu_fflush(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_buf_to_iovec(QEMUFile *f, size_t len)
|
||||
{
|
||||
if (!add_to_iovec(f, f->buf + f->buf_index, len, false)) {
|
||||
f->buf_index += len;
|
||||
if (f->buf_index == IO_BUF_SIZE) {
|
||||
qemu_fflush(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,11 +450,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size)
|
||||
}
|
||||
memcpy(f->buf + f->buf_index, buf, l);
|
||||
f->bytes_xfer += l;
|
||||
add_to_iovec(f, f->buf + f->buf_index, l, false);
|
||||
f->buf_index += l;
|
||||
if (f->buf_index == IO_BUF_SIZE) {
|
||||
qemu_fflush(f);
|
||||
}
|
||||
add_buf_to_iovec(f, l);
|
||||
if (qemu_file_get_error(f)) {
|
||||
break;
|
||||
}
|
||||
@ -451,11 +467,7 @@ void qemu_put_byte(QEMUFile *f, int v)
|
||||
|
||||
f->buf[f->buf_index] = v;
|
||||
f->bytes_xfer++;
|
||||
add_to_iovec(f, f->buf + f->buf_index, 1, false);
|
||||
f->buf_index++;
|
||||
if (f->buf_index == IO_BUF_SIZE) {
|
||||
qemu_fflush(f);
|
||||
}
|
||||
add_buf_to_iovec(f, 1);
|
||||
}
|
||||
|
||||
void qemu_file_skip(QEMUFile *f, int size)
|
||||
@ -761,13 +773,7 @@ ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream,
|
||||
}
|
||||
|
||||
qemu_put_be32(f, blen);
|
||||
if (f->ops->writev_buffer) {
|
||||
add_to_iovec(f, f->buf + f->buf_index, blen, false);
|
||||
}
|
||||
f->buf_index += blen;
|
||||
if (f->buf_index == IO_BUF_SIZE) {
|
||||
qemu_fflush(f);
|
||||
}
|
||||
add_buf_to_iovec(f, blen);
|
||||
return blen + sizeof(int32_t);
|
||||
}
|
||||
|
||||
|
@ -1112,6 +1112,7 @@ static void *multifd_send_thread(void *opaque)
|
||||
rcu_register_thread();
|
||||
|
||||
if (multifd_send_initial_packet(p, &local_err) < 0) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
/* initial packet */
|
||||
@ -1179,9 +1180,7 @@ out:
|
||||
* who pay attention to me.
|
||||
*/
|
||||
if (ret != 0) {
|
||||
if (flags & MULTIFD_FLAG_SYNC) {
|
||||
qemu_sem_post(&p->sem_sync);
|
||||
}
|
||||
qemu_sem_post(&p->sem_sync);
|
||||
qemu_sem_post(&multifd_send_state->channels_ready);
|
||||
}
|
||||
|
||||
@ -4676,5 +4675,5 @@ static SaveVMHandlers savevm_ram_handlers = {
|
||||
void ram_mig_init(void)
|
||||
{
|
||||
qemu_mutex_init(&XBZRLE.lock);
|
||||
register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, &ram_state);
|
||||
register_savevm_live("ram", 0, 4, &savevm_ram_handlers, &ram_state);
|
||||
}
|
||||
|
@ -256,6 +256,7 @@ typedef struct SaveState {
|
||||
uint32_t target_page_bits;
|
||||
uint32_t caps_count;
|
||||
MigrationCapability *capabilities;
|
||||
QemuUUID uuid;
|
||||
} SaveState;
|
||||
|
||||
static SaveState savevm_state = {
|
||||
@ -307,6 +308,7 @@ static int configuration_pre_save(void *opaque)
|
||||
state->capabilities[j++] = i;
|
||||
}
|
||||
}
|
||||
state->uuid = qemu_uuid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -464,6 +466,48 @@ static const VMStateDescription vmstate_capabilites = {
|
||||
}
|
||||
};
|
||||
|
||||
static bool vmstate_uuid_needed(void *opaque)
|
||||
{
|
||||
return qemu_uuid_set && migrate_validate_uuid();
|
||||
}
|
||||
|
||||
static int vmstate_uuid_post_load(void *opaque, int version_id)
|
||||
{
|
||||
SaveState *state = opaque;
|
||||
char uuid_src[UUID_FMT_LEN + 1];
|
||||
char uuid_dst[UUID_FMT_LEN + 1];
|
||||
|
||||
if (!qemu_uuid_set) {
|
||||
/*
|
||||
* It's warning because user might not know UUID in some cases,
|
||||
* e.g. load an old snapshot
|
||||
*/
|
||||
qemu_uuid_unparse(&state->uuid, uuid_src);
|
||||
warn_report("UUID is received %s, but local uuid isn't set",
|
||||
uuid_src);
|
||||
return 0;
|
||||
}
|
||||
if (!qemu_uuid_is_equal(&state->uuid, &qemu_uuid)) {
|
||||
qemu_uuid_unparse(&state->uuid, uuid_src);
|
||||
qemu_uuid_unparse(&qemu_uuid, uuid_dst);
|
||||
error_report("UUID received is %s and local is %s", uuid_src, uuid_dst);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_uuid = {
|
||||
.name = "configuration/uuid",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = vmstate_uuid_needed,
|
||||
.post_load = vmstate_uuid_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8_ARRAY_V(uuid.data, SaveState, sizeof(QemuUUID), 1),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_configuration = {
|
||||
.name = "configuration",
|
||||
.version_id = 1,
|
||||
@ -478,6 +522,7 @@ static const VMStateDescription vmstate_configuration = {
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
&vmstate_target_page_bits,
|
||||
&vmstate_capabilites,
|
||||
&vmstate_uuid,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
@ -684,8 +729,7 @@ static void savevm_state_handler_insert(SaveStateEntry *nse)
|
||||
of the system, so instance_id should be removed/replaced.
|
||||
Meanwhile pass -1 as instance_id if you do not already have a clearly
|
||||
distinguishing id for all instances of your device class. */
|
||||
int register_savevm_live(DeviceState *dev,
|
||||
const char *idstr,
|
||||
int register_savevm_live(const char *idstr,
|
||||
int instance_id,
|
||||
int version_id,
|
||||
const SaveVMHandlers *ops,
|
||||
@ -704,26 +748,6 @@ int register_savevm_live(DeviceState *dev,
|
||||
se->is_ram = 1;
|
||||
}
|
||||
|
||||
if (dev) {
|
||||
char *id = qdev_get_dev_path(dev);
|
||||
if (id) {
|
||||
if (snprintf(se->idstr, sizeof(se->idstr), "%s/", id) >=
|
||||
sizeof(se->idstr)) {
|
||||
error_report("Path too long for VMState (%s)", id);
|
||||
g_free(id);
|
||||
g_free(se);
|
||||
|
||||
return -1;
|
||||
}
|
||||
g_free(id);
|
||||
|
||||
se->compat = g_new0(CompatEntry, 1);
|
||||
pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr);
|
||||
se->compat->instance_id = instance_id == -1 ?
|
||||
calculate_compat_instance_id(idstr) : instance_id;
|
||||
instance_id = -1;
|
||||
}
|
||||
}
|
||||
pstrcat(se->idstr, sizeof(se->idstr), idstr);
|
||||
|
||||
if (instance_id == -1) {
|
||||
@ -1100,7 +1124,7 @@ void qemu_savevm_state_setup(QEMUFile *f)
|
||||
if (!se->ops || !se->ops->save_setup) {
|
||||
continue;
|
||||
}
|
||||
if (se->ops && se->ops->is_active) {
|
||||
if (se->ops->is_active) {
|
||||
if (!se->ops->is_active(se->opaque)) {
|
||||
continue;
|
||||
}
|
||||
@ -1131,7 +1155,7 @@ int qemu_savevm_state_resume_prepare(MigrationState *s)
|
||||
if (!se->ops || !se->ops->resume_prepare) {
|
||||
continue;
|
||||
}
|
||||
if (se->ops && se->ops->is_active) {
|
||||
if (se->ops->is_active) {
|
||||
if (!se->ops->is_active(se->opaque)) {
|
||||
continue;
|
||||
}
|
||||
@ -1227,7 +1251,7 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f)
|
||||
if (!se->ops || !se->ops->save_live_complete_postcopy) {
|
||||
continue;
|
||||
}
|
||||
if (se->ops && se->ops->is_active) {
|
||||
if (se->ops->is_active) {
|
||||
if (!se->ops->is_active(se->opaque)) {
|
||||
continue;
|
||||
}
|
||||
@ -1264,7 +1288,7 @@ int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (se->ops && se->ops->is_active) {
|
||||
if (se->ops->is_active) {
|
||||
if (!se->ops->is_active(se->opaque)) {
|
||||
continue;
|
||||
}
|
||||
@ -1413,7 +1437,7 @@ void qemu_savevm_state_pending(QEMUFile *f, uint64_t threshold_size,
|
||||
if (!se->ops || !se->ops->save_live_pending) {
|
||||
continue;
|
||||
}
|
||||
if (se->ops && se->ops->is_active) {
|
||||
if (se->ops->is_active) {
|
||||
if (!se->ops->is_active(se->opaque)) {
|
||||
continue;
|
||||
}
|
||||
@ -2334,7 +2358,7 @@ static int qemu_loadvm_state_setup(QEMUFile *f)
|
||||
if (!se->ops || !se->ops->load_setup) {
|
||||
continue;
|
||||
}
|
||||
if (se->ops && se->ops->is_active) {
|
||||
if (se->ops->is_active) {
|
||||
if (!se->ops->is_active(se->opaque)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -576,7 +576,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
|
||||
* specific version?
|
||||
*/
|
||||
g_assert(slirp_state_version() == 4);
|
||||
register_savevm_live(NULL, "slirp", 0, slirp_state_version(),
|
||||
register_savevm_live("slirp", 0, slirp_state_version(),
|
||||
&savevm_slirp_state, s->slirp);
|
||||
|
||||
s->poll_notifier.notify = net_slirp_poll_notify;
|
||||
|
@ -415,6 +415,9 @@
|
||||
#
|
||||
# @x-ignore-shared: If enabled, QEMU will not migrate shared memory (since 4.0)
|
||||
#
|
||||
# @validate-uuid: Send the UUID of the source to allow the destination
|
||||
# to ensure it is the same. (since 4.2)
|
||||
#
|
||||
# Since: 1.2
|
||||
##
|
||||
{ 'enum': 'MigrationCapability',
|
||||
@ -422,7 +425,7 @@
|
||||
'compress', 'events', 'postcopy-ram', 'x-colo', 'release-ram',
|
||||
'block', 'return-path', 'pause-before-switchover', 'multifd',
|
||||
'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
|
||||
'x-ignore-shared' ] }
|
||||
'x-ignore-shared', 'validate-uuid' ] }
|
||||
|
||||
##
|
||||
# @MigrationCapabilityStatus:
|
||||
|
@ -41,6 +41,7 @@ struct QTestState
|
||||
int qmp_fd;
|
||||
pid_t qemu_pid; /* our child QEMU process */
|
||||
int wstatus;
|
||||
int expected_status;
|
||||
bool big_endian;
|
||||
bool irq_level[MAX_IRQ];
|
||||
GString *rx;
|
||||
@ -111,6 +112,11 @@ bool qtest_probe_child(QTestState *s)
|
||||
return false;
|
||||
}
|
||||
|
||||
void qtest_set_expected_status(QTestState *s, int status)
|
||||
{
|
||||
s->expected_status = status;
|
||||
}
|
||||
|
||||
static void kill_qemu(QTestState *s)
|
||||
{
|
||||
pid_t pid = s->qemu_pid;
|
||||
@ -124,24 +130,23 @@ static void kill_qemu(QTestState *s)
|
||||
}
|
||||
|
||||
/*
|
||||
* We expect qemu to exit with status 0; anything else is
|
||||
* Check whether qemu exited with expected exit status; anything else is
|
||||
* fishy and should be logged with as much detail as possible.
|
||||
*/
|
||||
wstatus = s->wstatus;
|
||||
if (wstatus) {
|
||||
if (WIFEXITED(wstatus)) {
|
||||
fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU "
|
||||
"process but encountered exit status %d\n",
|
||||
__FILE__, __LINE__, WEXITSTATUS(wstatus));
|
||||
} else if (WIFSIGNALED(wstatus)) {
|
||||
int sig = WTERMSIG(wstatus);
|
||||
const char *signame = strsignal(sig) ?: "unknown ???";
|
||||
const char *dump = WCOREDUMP(wstatus) ? " (core dumped)" : "";
|
||||
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != s->expected_status) {
|
||||
fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU "
|
||||
"process but encountered exit status %d (expected %d)\n",
|
||||
__FILE__, __LINE__, WEXITSTATUS(wstatus), s->expected_status);
|
||||
abort();
|
||||
} else if (WIFSIGNALED(wstatus)) {
|
||||
int sig = WTERMSIG(wstatus);
|
||||
const char *signame = strsignal(sig) ?: "unknown ???";
|
||||
const char *dump = WCOREDUMP(wstatus) ? " (core dumped)" : "";
|
||||
|
||||
fprintf(stderr, "%s:%d: kill_qemu() detected QEMU death "
|
||||
"from signal %d (%s)%s\n",
|
||||
__FILE__, __LINE__, sig, signame, dump);
|
||||
}
|
||||
fprintf(stderr, "%s:%d: kill_qemu() detected QEMU death "
|
||||
"from signal %d (%s)%s\n",
|
||||
__FILE__, __LINE__, sig, signame, dump);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
@ -246,6 +251,7 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
|
||||
g_test_message("starting QEMU: %s", command);
|
||||
|
||||
s->wstatus = 0;
|
||||
s->expected_status = 0;
|
||||
s->qemu_pid = fork();
|
||||
if (s->qemu_pid == 0) {
|
||||
setenv("QEMU_AUDIO_DRV", "none", true);
|
||||
|
@ -708,4 +708,13 @@ void qmp_assert_error_class(QDict *rsp, const char *class);
|
||||
*/
|
||||
bool qtest_probe_child(QTestState *s);
|
||||
|
||||
/**
|
||||
* qtest_set_expected_status:
|
||||
* @s: QTestState instance to operate on.
|
||||
* @status: an expected exit status.
|
||||
*
|
||||
* Set expected exit status of the child.
|
||||
*/
|
||||
void qtest_set_expected_status(QTestState *s, int status);
|
||||
|
||||
#endif
|
||||
|
@ -512,7 +512,8 @@ static void migrate_postcopy_start(QTestState *from, QTestState *to)
|
||||
|
||||
static int test_migrate_start(QTestState **from, QTestState **to,
|
||||
const char *uri, bool hide_stderr,
|
||||
bool use_shmem)
|
||||
bool use_shmem, const char *opts_src,
|
||||
const char *opts_dst)
|
||||
{
|
||||
gchar *cmd_src, *cmd_dst;
|
||||
char *bootpath = NULL;
|
||||
@ -521,6 +522,9 @@ static int test_migrate_start(QTestState **from, QTestState **to,
|
||||
const char *arch = qtest_get_arch();
|
||||
const char *accel = "kvm:tcg";
|
||||
|
||||
opts_src = opts_src ? opts_src : "";
|
||||
opts_dst = opts_dst ? opts_dst : "";
|
||||
|
||||
if (use_shmem) {
|
||||
if (!g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
|
||||
g_test_skip("/dev/shm is not supported");
|
||||
@ -539,16 +543,16 @@ static int test_migrate_start(QTestState **from, QTestState **to,
|
||||
cmd_src = g_strdup_printf("-machine accel=%s -m 150M"
|
||||
" -name source,debug-threads=on"
|
||||
" -serial file:%s/src_serial"
|
||||
" -drive file=%s,format=raw %s",
|
||||
" -drive file=%s,format=raw %s %s",
|
||||
accel, tmpfs, bootpath,
|
||||
extra_opts ? extra_opts : "");
|
||||
extra_opts ? extra_opts : "", opts_src);
|
||||
cmd_dst = g_strdup_printf("-machine accel=%s -m 150M"
|
||||
" -name target,debug-threads=on"
|
||||
" -serial file:%s/dest_serial"
|
||||
" -drive file=%s,format=raw"
|
||||
" -incoming %s %s",
|
||||
" -incoming %s %s %s",
|
||||
accel, tmpfs, bootpath, uri,
|
||||
extra_opts ? extra_opts : "");
|
||||
extra_opts ? extra_opts : "", opts_dst);
|
||||
start_address = X86_TEST_MEM_START;
|
||||
end_address = X86_TEST_MEM_END;
|
||||
} else if (g_str_equal(arch, "s390x")) {
|
||||
@ -556,15 +560,15 @@ static int test_migrate_start(QTestState **from, QTestState **to,
|
||||
extra_opts = use_shmem ? get_shmem_opts("128M", shmem_path) : NULL;
|
||||
cmd_src = g_strdup_printf("-machine accel=%s -m 128M"
|
||||
" -name source,debug-threads=on"
|
||||
" -serial file:%s/src_serial -bios %s %s",
|
||||
" -serial file:%s/src_serial -bios %s %s %s",
|
||||
accel, tmpfs, bootpath,
|
||||
extra_opts ? extra_opts : "");
|
||||
extra_opts ? extra_opts : "", opts_src);
|
||||
cmd_dst = g_strdup_printf("-machine accel=%s -m 128M"
|
||||
" -name target,debug-threads=on"
|
||||
" -serial file:%s/dest_serial -bios %s"
|
||||
" -incoming %s %s",
|
||||
" -incoming %s %s %s",
|
||||
accel, tmpfs, bootpath, uri,
|
||||
extra_opts ? extra_opts : "");
|
||||
extra_opts ? extra_opts : "", opts_dst);
|
||||
start_address = S390_TEST_MEM_START;
|
||||
end_address = S390_TEST_MEM_END;
|
||||
} else if (strcmp(arch, "ppc64") == 0) {
|
||||
@ -575,14 +579,15 @@ static int test_migrate_start(QTestState **from, QTestState **to,
|
||||
" -prom-env 'use-nvramrc?=true' -prom-env "
|
||||
"'nvramrc=hex .\" _\" begin %x %x "
|
||||
"do i c@ 1 + i c! 1000 +loop .\" B\" 0 "
|
||||
"until' %s", accel, tmpfs, end_address,
|
||||
start_address, extra_opts ? extra_opts : "");
|
||||
"until' %s %s", accel, tmpfs, end_address,
|
||||
start_address, extra_opts ? extra_opts : "",
|
||||
opts_src);
|
||||
cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
|
||||
" -name target,debug-threads=on"
|
||||
" -serial file:%s/dest_serial"
|
||||
" -incoming %s %s",
|
||||
" -incoming %s %s %s",
|
||||
accel, tmpfs, uri,
|
||||
extra_opts ? extra_opts : "");
|
||||
extra_opts ? extra_opts : "", opts_dst);
|
||||
|
||||
start_address = PPC_TEST_MEM_START;
|
||||
end_address = PPC_TEST_MEM_END;
|
||||
@ -592,16 +597,16 @@ static int test_migrate_start(QTestState **from, QTestState **to,
|
||||
cmd_src = g_strdup_printf("-machine virt,accel=%s,gic-version=max "
|
||||
"-name vmsource,debug-threads=on -cpu max "
|
||||
"-m 150M -serial file:%s/src_serial "
|
||||
"-kernel %s %s",
|
||||
"-kernel %s %s %s",
|
||||
accel, tmpfs, bootpath,
|
||||
extra_opts ? extra_opts : "");
|
||||
extra_opts ? extra_opts : "", opts_src);
|
||||
cmd_dst = g_strdup_printf("-machine virt,accel=%s,gic-version=max "
|
||||
"-name vmdest,debug-threads=on -cpu max "
|
||||
"-m 150M -serial file:%s/dest_serial "
|
||||
"-kernel %s "
|
||||
"-incoming %s %s",
|
||||
"-incoming %s %s %s",
|
||||
accel, tmpfs, bootpath, uri,
|
||||
extra_opts ? extra_opts : "");
|
||||
extra_opts ? extra_opts : "", opts_dst);
|
||||
|
||||
start_address = ARM_TEST_MEM_START;
|
||||
end_address = ARM_TEST_MEM_END;
|
||||
@ -731,7 +736,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
|
||||
char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
||||
QTestState *from, *to;
|
||||
|
||||
if (test_migrate_start(&from, &to, uri, hide_error, false)) {
|
||||
if (test_migrate_start(&from, &to, uri, hide_error, false, NULL, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -841,20 +846,16 @@ static void test_postcopy_recovery(void)
|
||||
migrate_postcopy_complete(from, to);
|
||||
}
|
||||
|
||||
static void test_baddest(void)
|
||||
static void wait_for_migration_fail(QTestState *from, bool allow_active)
|
||||
{
|
||||
QTestState *from, *to;
|
||||
QDict *rsp_return;
|
||||
char *status;
|
||||
bool failed;
|
||||
|
||||
if (test_migrate_start(&from, &to, "tcp:0:0", true, false)) {
|
||||
return;
|
||||
}
|
||||
migrate(from, "tcp:0:0", "{}");
|
||||
do {
|
||||
status = migrate_query_status(from);
|
||||
g_assert(!strcmp(status, "setup") || !(strcmp(status, "failed")));
|
||||
g_assert(!strcmp(status, "setup") || !strcmp(status, "failed") ||
|
||||
(allow_active && !strcmp(status, "active")));
|
||||
failed = !strcmp(status, "failed");
|
||||
g_free(status);
|
||||
} while (!failed);
|
||||
@ -864,7 +865,17 @@ static void test_baddest(void)
|
||||
g_assert(qdict_haskey(rsp_return, "running"));
|
||||
g_assert(qdict_get_bool(rsp_return, "running"));
|
||||
qobject_unref(rsp_return);
|
||||
}
|
||||
|
||||
static void test_baddest(void)
|
||||
{
|
||||
QTestState *from, *to;
|
||||
|
||||
if (test_migrate_start(&from, &to, "tcp:0:0", true, false, NULL, NULL)) {
|
||||
return;
|
||||
}
|
||||
migrate(from, "tcp:0:0", "{}");
|
||||
wait_for_migration_fail(from, false);
|
||||
test_migrate_end(from, to, false);
|
||||
}
|
||||
|
||||
@ -873,7 +884,7 @@ static void test_precopy_unix(void)
|
||||
char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
||||
QTestState *from, *to;
|
||||
|
||||
if (test_migrate_start(&from, &to, uri, false, false)) {
|
||||
if (test_migrate_start(&from, &to, uri, false, false, NULL, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -916,7 +927,7 @@ static void test_ignore_shared(void)
|
||||
char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
||||
QTestState *from, *to;
|
||||
|
||||
if (test_migrate_start(&from, &to, uri, false, true)) {
|
||||
if (test_migrate_start(&from, &to, uri, false, true, NULL, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -951,7 +962,7 @@ static void test_xbzrle(const char *uri)
|
||||
{
|
||||
QTestState *from, *to;
|
||||
|
||||
if (test_migrate_start(&from, &to, uri, false, false)) {
|
||||
if (test_migrate_start(&from, &to, uri, false, false, NULL, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1003,7 +1014,8 @@ static void test_precopy_tcp(void)
|
||||
char *uri;
|
||||
QTestState *from, *to;
|
||||
|
||||
if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", false, false)) {
|
||||
if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", false, false,
|
||||
NULL, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1049,7 +1061,7 @@ static void test_migrate_fd_proto(void)
|
||||
QDict *rsp;
|
||||
const char *error_desc;
|
||||
|
||||
if (test_migrate_start(&from, &to, "defer", false, false)) {
|
||||
if (test_migrate_start(&from, &to, "defer", false, false, NULL, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1125,6 +1137,68 @@ static void test_migrate_fd_proto(void)
|
||||
test_migrate_end(from, to, true);
|
||||
}
|
||||
|
||||
static void do_test_validate_uuid(const char *uuid_arg_src,
|
||||
const char *uuid_arg_dst,
|
||||
bool should_fail, bool hide_stderr)
|
||||
{
|
||||
char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
||||
QTestState *from, *to;
|
||||
|
||||
if (test_migrate_start(&from, &to, uri, hide_stderr, false,
|
||||
uuid_arg_src, uuid_arg_dst)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* UUID validation is at the begin of migration. So, the main process of
|
||||
* migration is not interesting for us here. Thus, set huge downtime for
|
||||
* very fast migration.
|
||||
*/
|
||||
migrate_set_parameter_int(from, "downtime-limit", 1000000);
|
||||
migrate_set_capability(from, "validate-uuid", true);
|
||||
|
||||
/* Wait for the first serial output from the source */
|
||||
wait_for_serial("src_serial");
|
||||
|
||||
migrate(from, uri, "{}");
|
||||
|
||||
if (should_fail) {
|
||||
qtest_set_expected_status(to, 1);
|
||||
wait_for_migration_fail(from, true);
|
||||
} else {
|
||||
wait_for_migration_complete(from);
|
||||
}
|
||||
|
||||
test_migrate_end(from, to, false);
|
||||
g_free(uri);
|
||||
}
|
||||
|
||||
static void test_validate_uuid(void)
|
||||
{
|
||||
do_test_validate_uuid("-uuid 11111111-1111-1111-1111-111111111111",
|
||||
"-uuid 11111111-1111-1111-1111-111111111111",
|
||||
false, false);
|
||||
}
|
||||
|
||||
static void test_validate_uuid_error(void)
|
||||
{
|
||||
do_test_validate_uuid("-uuid 11111111-1111-1111-1111-111111111111",
|
||||
"-uuid 22222222-2222-2222-2222-222222222222",
|
||||
true, true);
|
||||
}
|
||||
|
||||
static void test_validate_uuid_src_not_set(void)
|
||||
{
|
||||
do_test_validate_uuid(NULL, "-uuid 11111111-1111-1111-1111-111111111111",
|
||||
false, true);
|
||||
}
|
||||
|
||||
static void test_validate_uuid_dst_not_set(void)
|
||||
{
|
||||
do_test_validate_uuid("-uuid 11111111-1111-1111-1111-111111111111", NULL,
|
||||
false, true);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char template[] = "/tmp/migration-test-XXXXXX";
|
||||
@ -1180,6 +1254,12 @@ int main(int argc, char **argv)
|
||||
/* qtest_add_func("/migration/ignore_shared", test_ignore_shared); */
|
||||
qtest_add_func("/migration/xbzrle/unix", test_xbzrle_unix);
|
||||
qtest_add_func("/migration/fd_proto", test_migrate_fd_proto);
|
||||
qtest_add_func("/migration/validate_uuid", test_validate_uuid);
|
||||
qtest_add_func("/migration/validate_uuid_error", test_validate_uuid_error);
|
||||
qtest_add_func("/migration/validate_uuid_src_not_set",
|
||||
test_validate_uuid_src_not_set);
|
||||
qtest_add_func("/migration/validate_uuid_dst_not_set",
|
||||
test_validate_uuid_dst_not_set);
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user